前言
本次博客会是最有料的博客了,这其中的问题尤其是scanf函数对新手很不友好
我们本次
1会讲解其他的一些输入输出函数,分析他们的优劣点
2本次的参考资料来自于 c primer plus
1scanf函数详解
首先大家了解过scanf的功能吗
1大家已经学到这里了,肯定知道,scanf是从输入流读取一个指定格式的数据
因为它的格式会变呀,而且它的参数也会变
关于这个参数改变其实涉及到了函数重载问题,以后会提到
1定义
它的参数先不讲,但是它的返回值得有讲头
我们看看他的返回值是个啥
scanf返回成功转换和分配的字段数;返回值不包括已读取但未分配的字段。返回值0表示未分配任何字段。如果在第一次尝试读取字符时遇到文件结尾字符或字符串结尾字符,则返回值为EOF。
那么这里又有一个问题了,scanf函数是如何读取的呢
2scanf函数的读取
接下来的这句话来自于c primer plus
1scanf读取字符
值得注意的是scanf在读取时可以用'\n' 结束
但是我们要让程序进行就必须要使用换行符
看代码
int main() {
char ch1;
char ch2;
scanf("%c%c", &ch1, &ch2);
printf("%c", ch1);
printf("%c", ch2);
return 0;
}
我们假设输入两个字符a 和‘ ’(空格)
看结果
结果就是只有a 空格看不见 此时读取到了两个字符
那么如果只输入一个a呢,当然在实操中还要输入'\n'来使程序继续哦
此时结果是一样的
但是读取到的不一样 scanf只读取到l一个字符
当然有很多人会有疑惑,那么多打印出来的'\n‘去哪里了
多出来的换行符就会出现在缓存区中只要你再次读取一次就不会再让你输入了
而是直接是下一个字符变为换行
看代码
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main() {
char ch1;
char ch2;
char ch3;
scanf("%c%c", &ch1, &ch2);
printf("%c", ch1);
printf("%c", ch2);
scanf("%c", &ch3);
printf("%c", ch3);
printf("理解了吗?上面有换行哦");
return 0;
}
我们来看结果
本来要读三次的结果只读了两次,因为第三次直接把缓存区中的‘\n’读出来了
2scanf读取数字
那么读取数字有是怎样的呢
数字不像字符一样,数字有大有小,他可以是连续的
那你说怎样辨别两个不同的数字呢
既然是数字我们分辨不同的数字是使用空格 空行('\n')制表符的
举例
int main() {
int a;
int b;
scanf("%d%d", &a, &b);
printf("%d %d", a, b);
return 0;
}
看结果
我们这里是使用空格作为区分数字,也就是一次读取的结束标志
大家可以使用其他的方式来多试几次
3scanf数字与字符混和读取
这个也同样有讲头
我们可以举例
int main() {
int a;
float b;
char ch1;
char ch2;
scanf("%d%c%c%f", &a,&ch1,&ch2,&b);
printf("%d %c %c %f", a,ch1,ch2,b);
system("pause");
return 0;
}
看看结果
这个结果是不是很奇怪呀,注意在混合使用scanf读取时一定要注意数字不要和字符通过空格分开
比如这样
是不是这样就不会出错了
当然我们细心的小伙伴发现了吗
代码中的scanf
scanf("%d%c%c%f", &a,&ch1,&ch2,&b);
它的换位符%d%c%c%f他是不分开的
如果,我们是其分开是不是能够解决问题
直接看结果
看到吗,分开了,也同样没有问题
小总结
你们好幸运,笔者第一次遇到这个问题也是花了好多时间才解决,真的很烦
4scanf函数的读取字符串
这是在读取单词而不是字符串
在读取字符串时以空格 空行('\n')制表符结束,
当然当我们遇到文件结尾字符时可以直接结束
我们首先就得把那EOF文件结尾字符问题解决
我们先来看看EOF
EOF它的值为-1,话不多说直接验证
看代码
这个时候就可以验证了
那么我们怎么使用EOF呢
还是先初步了解一下吧
看代码
int main() {
int num;
int result = scanf("%d", &num);
if (result == EOF) {
printf("读取失败或已到达文件末尾\n");
}
else {
printf("成功读取到数字:%d\n", num);
}
system("pause");
return 0;
}
注意,本次代码是在vc环境下的
主要不知道为什么vs好像不支持scanf返回EOF
那让我们看看vs的结果
现在还搞不懂为什么
system("pause");是使程序不会一闪而过
要使用<stdlib.h>
我们看看vc结果 测试一番
看到没有当scanf遇到了文件结尾字符就会返回EOF
这是咱么第一次了解了文件结尾字符,以后会用作用name
当然这也同样说明了一件事
那么在告诉ctrl+z为模拟文件结尾字符
不同的编译器对于同一个代码可能会产生不同的结果
那么我们接下来看使用scanf输入字符串
首先
scanf都会从第一个非空白字符作为字符串的开始,以下一个空格 空行('\n')制表符作为结束,
大家看这个表可以看懂吗
如果说
我们后面还要继续输入字符或者字符串的话,j就会从剩余的序列中读入
这个我们前面就已经有过讲解了
还是让大家看看代码吧
大家看明明要读取两次可是只读取了一次
为什么呢
空格为第一次结束标志符
换行为第二次结束标志符
所以第二次scanf 接收的值直接为hup
所以scanf函数在接收字符串时是不能有空格的,这就是它的缺陷
那么还有一个疑问 %5s代表什么
它其实就是限定字符串的大小,如果遇到结束的标志那么即便没有达到长度
也会结束
所以呢,scanf只能接收连续的字符串
2getchar与putchar
他俩是单字符的i/o
我们直接看他们的定义
int getchar(void);
int putchar( int c );
当然他们是预处理的宏定义的代码块
putchar返回所写的字符为了指示错误或文件结束条件返回EOF
getchar返回读取的字符。为了指示读取错误或文件结束条件getchar返回EOF.
那么有了这两个就可以解决scanf不能输入接收空格的问题
他们同样也有结束条件遇到EOF就会结束
遇到'\n'就会把输入的值放入缓存区中,
看代码
我们可以输入一些字符,输出它
#include<stdio.h>
int main() {
int ch;
while ((ch = getchar()) != EOF)
{
putchar(ch);
}
return 0;
}
看结果
注意呀,ctrl+z不能出现在一行的末尾只能再另起一行
那么这样我们就可以使用这两个函数,输入输出带空格的字符串
当然 我们仍然要解释只要getchar不返回EOF那么就会一直输入输出
那么为什么ch是int类型的呢 原因在于EOF的值为-1
原因在于int有更大的范围
ok
再来讲解一个万能的清除缓存区代码
int ch;
while((ch=getchar())!=EOF&&ch!='\n');
这个可以把缓存区清理
3puts gets
char *gets( char *buffer );
如果成功,gets函数中的会返回其参数
也就是数组名
int puts( const char *string );
如果成功,返回一个非负值。如果失败,则返回EOF
作为接收打印字符串的函数
gets是有一定的用途的
他两也有相同的地方
gets读取输入,直到遇到换行符,丢掉换行符加入'\0'
把读到的字符串放入数组中
而puts
就是打印某个字符串
并且会自动在该字符串中加入'\n'
看代码
int main() {
char a[100];
gets(a);
puts(a);
puts("what can i say");
puts("黑尼曼");
system("pause");
return 0;
}
看结果
是不是验证了
当然我们的数组必须要大于输入的字符串
否则会出现溢出的现象
所以很多编译器不支持gets的使用
从而又有一种输入函数的诞生
get_s(const char * s,int n)
就是比get多了一个整型数,其实就是为了防止越界
是把读取前n个字符防止越界其他与gets一样
最后
我们来给大家总结一波
1 输入输出是存在缓存区的
2回车是输入的结束标志,但本生是一个字符会存入到输入缓存区中
3解决scanf报错,
直接就来 #define _CRT_SECURE_NO_WARNINGS
最后祝大家开心