一、scanf
从第一个非空白字符开始读取,直到遇到空白字符为止(不包含空白字符)。
缺点:
1. 不能读取空格、制表符,因为被当作“分隔符”处理了!
2. 可能导致越界。
比如下面的代码:
#include <stdio.h>
int main()
{
//把用户名和密码用字符串的方式实现
char name[16];
printf("请输入用户名:");
scanf("%s",name); //数组名本身就是个地址,不用加取址符&
printf("用户名:%s\n",name);
return 0;
}
这里我们输入用户名:zhang san 输出的结果是:zhang
输入的zhang 和 san 之间有空白字符(空格),所以遇到空格停止了!
二、gets
不包括行末的回车符。
缺点:字符串长度不受控制,会导致越界
比如下面的代码:
#include <stdio.h>
int main()
{
//把用户名和密码用字符串的方式实现
char name[8];
printf("请输入用户名:");
gets(name);
printf("用户名:%s\n",name);
return 0;
}
这里我们输入用户名:zhang san li si 输出的结果是:zhang zhang san li si
输入的字符明显超出了定义的8 - 1 = 7(字符串最后是0)个字符的长度,但是并没有提示报错!
二、fgets
fgets会指定字符串的大小,如果超出数组大小,会自动根据定义数组的长度截断。fgets比gets安全,使用gets编译时会警告!
回车符也被读到字符串(除非输入数据太多)。
比如下面的代码:
#include <stdio.h>
int main()
{
//把用户名和密码用字符串的方式实现
char name[8];
printf("请输入用户名:");
fgets(name,8,stdin); //第二个参数8就是要求的长度,也可以用sizeof(name)表示
printf("用户名:%s\n",name);
return 0;
}
我们输入li si(李四),得到的结果如下:
有2次换行,fgets把回车确认输入的回车换行符存入了字符串里:'l' 'i' ' ' 's' 'i' '/n' '\0' 一共7个字符。
如果输入的字符串超出了定义的长度,输出的结果会根据长度进行截断,确定输入结束的回车符 '\n' 没有带到字符串中。
fgets函数进阶用法:
fgets函数用来从文件中读入字符串。fgets函数的调用形式如下:fgets(str,n,fp); 此处,
str是存放在字符串的起始地址;
n是一个int类型变量;
fp是文件指针。
函数的功能是从fp所指文件中读入n-1个字符放入str为起始地址的空间内;如果在未读满n-1个字符之时,已读到一个换行符或一个EOF(文件结束标志),则结束本次读操作,读入的字符串中最后包含读到的换行符。因此,确切地说,调用fgets函数时,最多只能读入n-1个字符。读入结束后,系统将自动在最后加'\0',并以str作为函数值返回。
要去掉fgets()最后带的 '\0',只要用 s[strlen(s)-1]='\0'; 即可。
fgets不会像gets那样自动地去掉结尾的 '\n',所以程序中手动将 '\n' 位置处的值变为'\0',代表输入的结束。
针对于fgets,还要再说两句,下面这种用法,是安全的判断文件读取结束或者出错的好方式,切忌不能使用while(!feof(fp)),还有对于fgets的第二个参数是最大能读取文件字符的个数,一般最大的长度是1024字节。
while(fgets(..., stream)){
/* ... */
}
if(ferror(stream)){
/* ... */
}