scanf和缓冲区的一切

<!--从缓冲区到输入列表-->

程序获取输入时的过程比我们想象的复杂  我们考虑一个简单粗暴完整的程序
 

#include <stdio.h>
int main(){
    int n;
    scanf("%d", &n);
    printf("%d\n", n);
    return 0;
}

 

程序运行到scanf()时会停止  请求外界输入

也许你输入了125然后回车了

但事实上 你从键盘上输入的是字符'1''2''5'  还有换行符'\n'  (因为你键入了回车)

在你按回车键之前  字符'1''2''5'都处于一个叫做缓冲区的位置里

回车键是特殊的  它先将字符'\n'添加到缓冲区 随后便清除缓冲区  将其中的所有字符发送到一个叫做输入列表的地方

scanf函数以及其他标准输入函数便会立刻从输入列表中获取内容

 

上述程序按照%d的规则从输入列表中获取字符  它获取了'1''2''5'  并且将其转变为整数125  存入了变量n中

对于那些从输人列表中获取输入的函数  它们并不知道什么是整数  因为整数是编程中的概念  而无论是缓冲区还是输入列表  其中只有字符  所以“获取整数”只是从结果上看的

再多说一点  由于每个字符是一个字节  所以便有了字节流这个术语

我们继续考虑上面的程序  你要求scanf获取一个整数到n中  它完成了

但是并没有结束  因为输入列表并不干净  回车符'\n'仍然留在输入列表中

 

所以如果程序如下
 

#include <stdio.h>
int main(){
    int n;
    char ch;
    scanf("%d", &n);
    printf("%d", n);
    scanf("%c", &ch);    //! 不会停止等待
    printf("%c", ch);
    return 0;
}

我们仍然键入125并且回车  那么第二个scanf将不会给你输入的机会  因为缓冲区中剩余的'\n'已经足够填饱ch的肚子
 

 

 

再考虑下一个程序
 

#include <stdio.h>
int main(){
    int n;
    char ch1, ch2;
    scanf("%c%d%c", &ch1, &n, &ch2);
    printf("ch1 = %c\n", ch1);
    printf("n = %d\n", n);
    printf("ch2 = %c\n", ch2);
    return 0;
}

我们的键入仍然是125回车

结果是ch1 == '1'  n == 25  ch2 == '\n'


格式说明符对于scanf是十分重要的   它便是“规则” 告诉scanf如何从输入列表中获取字符 并且如何做转换

时刻记住输入列表中的内容全是字符  规律就会十分容易

还有需要注意的是  尽管输入列表中的内容都是字符  但是字符还有分类  比如空白符  数字字符  字母字符等
 

 

%d 忽略前置空白符  获取连续数字字符 直到遇上非数字字符或者输入列表尾为止

但是如果忽略到空白符之后遇到的时非数字字符 那么就直接结束

获取前的输入列表

' '  ' '  ' '  'k'  'o'  'w'  '\n'

获取后

'k'  'o'  'w'  '\n'

 

%f 这个比较复杂 但是我们只要明白从何时开始 到何时为止即可
假如输入列表是这样

' '  ' '  '2'  '.'  '5'  '.'  '2'  '1'  '4'  'f'  'g'  '\n'

那么%f获取后 列表变为

'.'  '2'  '1'  '4'  'f'  'g'  '\n'

 

 

%c 直接获取一个字符到目标变量 “看见什么吃什么”



由于所有输入函数都共享同一个输入列表  所以在整数和字符的混合输入中可能出错

如果你不清楚在获取一个整数以后的下一个获取是否为字符 加上下面的语句是最保险的

while(getchar() != '\n') continue;

它将清除输入列表

 

 

 

 

尽管是写给初学者的  也有点太累赘了

反正我是绝对耐不下性子读完别人写的这么长的博客 (除非像我说得这么清楚明白  呵呵哒)

 

 

转载于:https://my.oschina.net/u/1780798/blog/372014

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值