命令行参数
在之前的学习中,main函数—般都是没有参数的,对应的,在运行时,—般就是直接输入可执行的程序文件名(例如. / main )
但是,实际上main函数是可以有参数的。可以将任何过去无参数的main函数替换成下面这种有参数的main函数
int main(int argc,char **argv)
{
//......
}
在这里,main函数有两个参数
第一个参数是整数型,会传入命令行参数的个数,程序运行时就可以接收到。
第二个参数是char **,其中储存了用户从命令行传递进来的参数。
如果程序可执行文件名为main,则在命令行中输入./main hello world,就会得到argc为 3 , argv[0]为./main ,argv[1]为hello ,argv[2]为world。如果有更多参数也可以以此类推。
命令行参数默认都是空格分隔,但是如果希望包含空格的一个字符串作为参数,则需要在输入参数时用引号将其包裹起来。
如果程序可执行文件名为main,则在命令行中输入 . / main “hello world” is my greet,会得到argc为 5 , argv[0]为./main ,argv[1]为hello world , argv[2]为is ,argv[3]为my , argv[4]为greet .
任何被接收到的argv参数都可以被当做正常的字符串在代码里使用。在很多程序的设计中,需要根据接收到的参数来决定程序的执行方式,这时候,学会使用argc和argv就显得很重要了。
1、(对)在main函数中用于接收命令行参数的函数参数中,第一个是命令行参数的个数。
2、(错)命令行中键入./sort --min时,我们得到的argv[]是–min。
并不应该是–min,而应该是. / sort
3、(错)在int main(int argc,char **argv)中argc取到的是main函数的参数个数。
如果是main函数的参数的话,就固定为2了,肯定不对。它取到的应该是命令行中键入的参数个数。
4、(错)命令行读入的参数是从命令行键入的可执行程序路径(程序名)后一个空格开始计算。
并不是,可执行程序路径会被视为首个参数。
文件操作
在读文件的时候需要先有一个可以访问到文件的文件指针(file pointer),它是一个FILE类型的指针。
可以通过下面的方式声明一个文件指针。
FILE *fp;
这时候,如果对一个文件进行操作,需要先使用
fp = fopen(文件路径,访问模式);
将文件指针和文件关联起来,其中第一个参数是一个字符串,对应了希望访问的文件路径。第二个参数是访问模式,它可以是表示只读模式的"r”,也可以是表示只写模式的"w",还可以是在文件未尾追加的"a”。
将文件指针和文件关联起来后,就可以通过【fgetc(fp);】获得当前指针之后位置的一个字符了,每获得一个字符,指针会向后移动一个字符(如果到达文件尾部则会返回EOF )。
这时通过【fputc( 'c ', fp);】的方式将字符·c·写入到fp关联的文件内了。
了解到这些信息后,就可以实现将一个文件复制到另一个文件内的函数了,例如:
void filecopy(FILE *in_fp, FILE *out_fp)
{
char ch;
while ((ch = fgetc(in_fp)) != EOF)
{
fputc(ch,out_fp);
}
}
这个函数接收的两个参数都是文件指针。这个函数会通过一个可读模式的文件指针逐字符地读取,并且通过一个可写模式的文件指针逐字符地将所有字符写出,从而起到复制文件内容的作用。
需要注意,在给文件指针进行命名的时候,要避开stdin、stdout和stderr这三个名称。因为这三个名称其实已经用于标准输入、标准输出、标准错误的文件指针。
看到的stdin、stdout和stderr 这三个文件指针可以直接使用
通过【fgetc(stdin);】获得来自标准输入的字符,也可以通过【fputc(ch,stdout);】或【fputc(ch,stderr);】将变量ch 中的字符输出到标准输出或标准错误中的。
除了fgetc和fputc之外,还可以使用fscanf和fprintf函数。这两个函数都很像已经很熟悉的scanf和printf函数,只是不过,scanf和printf可以被看作 fscanf和fprintf 的特例。
使用fscanf从文件指针in_fp进行读取时,可以写成:
fscanf(in_fp,“%c",&a);
而如果写
fscanf(stdin,"%c",&a );
这将完全与下面直接使用scanf的方式等价。
scanf("%c", &a) ;
类似地,使用fprintf向文件指针out_fp进行写出时,可以写成:
fprintf(out_fp,“%c", a);
而如果写
fprintf( stdout,"%c", a);
这将完全与下面直接使用printf的方式等价。
printf("%c", a);
在使用文件并且确定不再继续使用后,要通过下面所示的方式将文件指针f与文件的关联断开。
可以将它视为和fopen相反的一个操作。
fc1ose(fp);
如果不在程序中使用fclose,程序正常结束时,程序会为所有打开的文件调用fclose 。
stdin、stdout其实也是被打开的文件指针,如果觉得用不到的话,其实也是可以使用fclose将他们关闭掉的。
调试代码
通过 gdb 可以看见变量值的变化、决定程序什么时候继续执行下一步或是发现奇怪的内存访问行为
要充分的利用gdb帮助找到程序编写时候的问题,需要在编译时使用-g作为一个编译参数(否则你将看不见函数名、变量名,而只能看到运行时的内存地址),例如:
gcc -o program -g main.c
这时候,再通过
gdb ./ program
将程序在gdb提供的一个“受控制的环境”中运行起来。
这时候会看到一系列关于gdb的说明和下面这样一个等待通过命令进行调试的命令行。
(gdb)
最基本的gdb 使用:
1、如果输入 l ( list 的首字母),gdb 会列出带着行号的10行程序,可以根据这个行号进行进一步的调试。l 之后可以加行号作为参数,列出这一行开始的10行
2、如果输入 b ( breakpoint 的首字母),则表示设置程序运行的断点,程序运行到断点时就会暂停运行。b之后既可以加函数名作为参数(例如当有一个函数名为 func 时,可以写b func),使程序在调用某一函数时暂停,也可以加行号作为参数(例如 b 5 表示在第五行设置一个断点),使程序在运行某一行时暂停。
3、如果输入r (run 的首字母),程序则会开始运行,并且暂停在设置断点的位置。
。。运行暂停时,如果输入p表达式(print 的首字母)则表示在当前断点运行这个表达式并查看它的值。例如 p ++age[0] 表示让 age[0] 自增1并查看自增后的值。注意:这个表达式会对之后的程序继续运行造成影响。
。。运行暂停时,如果输入n (next 的首字母)程序会执行暂停位置后的下一条语句并再次暂停。
。。运行暂停时,如果输入c (continue的首字母)程序会继续执行到下一关断点再暂停(如果没有断点就会执行直到结束)。