字符串输入
如果想把一个字符串读取到程序中,必须首先预留存储字符串的空间,然后使用输入函数来获取这个字符串,C库提供了三个读取字符串的函数:scanf()、gets()和fgets()。
1 |
char *name; scanf("%s", name); |
如果通过上面的代码来创建存储空间,可能会通过编译器,但是在读入name的时候,name会覆盖程序中的数据和代码,并可能导致程序异常终止。这个是
scanf()把信息复制到由name指定的地址中,而在这种情况下,参数是个
,name可能指向任何地方。
gets()(get string)函数对于交互式程序非常方便,它从系统的标准输入设备(通常是键盘)获得一个字符串。因为字符串没有预定的长度,所以gets()函数通过判断遇到的第一个换行符(\n)结束输入,按回车键可以产生这个字符。它读取换行符之前(不包括换行符)的所有字符,并在这些字符后添加一个空字符(\0)。
1 |
[clef@rhel6164 c]$ cat test1.c #include<stdio.h> #define MAX 81 int main(void) { char name[MAX]; char *ptr; //指向char的指针 printf("Please input your name.\n"); ptr = gets(name); //使用一个地址吧字符串赋值给name //gets()函数使用return关键字返回字符串的地址 printf("name, %s\n", name); printf("ptr, %s\n", ptr); return 0; } |
编译&运行:
1 |
[clef@rhel6164 c]$ gcc test1.c /tmp/ccDJ9AHw.o: In function `main': //因为gets()函数不检查存储区是否能够容纳实际输入的数据,可以用后面的fgets()函数替换gets()函数 test1.c:(.text+0x1a): warning: the `gets' function is dangerous and should not be used. [clef@rhel6164 c]$ ./a.outPlease input your name.clefname, clef //这里ptr和name的内容是一样的ptr, clef |
如果在gets()函数在读取字符串时
,它就返回一个空(或0)地址,这个空地址被称为
,并且stdio.h里面定义的常量
来表示,可以用下面的代码来进行一些错误检测。
1 |
while(get(name) != NULL) |
也可以通过
来完成上面的错误检测。
1 |
while((ch = getchar()) != EOF) |
:空指针和空字符是不一样的,不要混淆。空指针是一个地址,而空字符是一个char类型的数据对象其值为0,数字上都可以用0表示,但是概念不同:NULL是一个指针,而0是一个char类型的常量。
因为gets()函数不会检查存储区是否能够容纳实际输入的数据,多出来的字符简单地溢出到相邻的内存区,所以上面的代码在编译的时候会有warning。fgets()函数和gets()函数的不同:
- 它需要第二个参数来说明最大读入字符数。如果这个参数值为n,fgets()就会读取最多n-1个字符或者读完一个换行符为止(因为会自动添加一个空字符(\n)),由这两者中最先满足的那个结束输入。
- 如果fgets()读取到换行符,就会把它存到字符串里,而不是像gets()那样丢弃。
- 它还需要第三个参数来说明读哪一个文件,从键盘上读取数据时,可以使用stdin(代表standard input)作为参数,这个标识符在stdio.h中定义。
1 |
[clef@rhel6164 c]$ cat test1.c #include<stdio.h> #define MAX 81 int main(void) { char name[MAX]; char *ptr; printf("Please input your name.\n"); ptr = fgets(name, MAX, stdin); printf("name, %s\n", name); printf("ptr, %s\n", ptr); return 0; } |
编译&运行:
1 |
[clef@rhel6164 c]$ gcc test1.c //这里就没有warning出现 [clef@rhel6164 c]$ ./a.out Please input your name. clef name, clef //注意这里的换行符,因为fgets()函数没有丢弃输入的换行符 ptr, clef [clef@rhel6164 c]$ |
scanf()函数可以使用%s格式来读入一个字符串,scanf()函数和gets()函数的主要区别在于如何决定字符串何时结束。scanf()函数更基于获得单词(get word)而不是获取字符串(get string)。scanf()函数有两种方法决定输入结束,无论哪一种都是遇到的第一个非空白字符开始
字符串输出
C语言有三个输出字符串的标准库函数:puts()、fputs()和printf()
puts()函数使用很简单,只需要给出字符串参数的地址,它遇到空字符(\0)就会结束输出(所以必须要有空字符)。puts()函数在显示字符串的时候,会自动在其后添加一个换行符(\n)。
1 |
[clef@rhel6164 c]$ cat test1.c #include<stdio.h> #define DEF "I am a #defined string." int main(void) { char str1[80] = "An array was initialized to me."; const char * str2 = "A pointer was initialized to me."; puts("I'm an argument to puts()."); //直接用字符串做参数 puts(DEF); //用宏定义做参数 puts(str1); puts(str2); puts(&(str1[5])); //必须用括号strl1[5],因为str1将会首先结合&,然后在[5]结合,将出错 puts(str2+4); return 0; } |
编译&执行:
1 |
[clef@rhel6164 c]$ gcc ./test1.c [clef@rhel6164 c]$ ./a.out I'm an argument to puts(). I am a #defined string. An array was initialized to me. A pointer was initialized to me. ray was initialized to me. inter was initialized to me. |
fputs()函数puts()函数面向文件版本,两者主要的区别是:
- fputs()函数需要第二个参数来说明要写的文件,可以使用stdout(standard output)作为参数来进行输出显示。
- 与puts()函数不同,fputs()函数并不为输出自动添加换行符。
读取一行并把它回显在下一行,用下面的两种循环都可以办到
1 |
char line[81]; while(gets(line)) //遇到文件结尾,gets()函数就会返回空指针,循环结束 puts(line); |
1 |
char line[81]; while(fgets(line,81,stdin)) fputs(line,stdout); |
如同puts()函数一样,printf()函数在输出字符串的时候同样需要一个字符串地址作为参数,但是printf()函数没有puts()函数方便,但是它可以格式化多种数据类型,输出的时候也不自动添加换行符。