none
关于scanf和printf缓冲的问题 RRS feed

  • 问题

  • 一个小程序,其中有以下几句:

    char c1,c2;

    scanf("%c",&c1);

    printf("%c",c1);

    scanf("%c",&c2);

    printf("%c",c2);

    这样,run以后,输入c1以后就不能输入c2,是否是因为c1的内容从缓冲区传到内存以后,缓冲区还会残留换行符?

    后来把

    scanf("%c",&c2);

    printf("%c",c2);改成了:

    scanf("%c",&c2);

    printf("%s",c2);

    却可以,为什么?%s和%c有什么不同?

    另外,在:

    char c1,c2;

    scanf("%c",&c1);

    printf("%c",c1);

    scanf("%c",&c2);

    printf("%c",c2);

    这段程序中,run了以后,输入c1时直接敲回车键,会有何结果?似乎又可以输入c2了?

    这具体是什么原因?求教

    2010年12月5日 6:28

答案

  • 一个小程序,其中有以下几句:

    char c1,c2;

    scanf("%c",&c1);

    printf("%c",c1);

    scanf("%c",&c2);

    printf("%c",c2);

    这样,run以后,输入c1以后就不能输入c2,是否是因为c1的内容从缓冲区传到内存以后,缓冲区还会残留换行符?

    %s和%c有什么不同?

    Hi 任一雄,

    欢迎来Microsoft论坛。

    根据对你问题的分析,当第一次输入c1后,要用flushall函数清除缓存区,再输入c2。

    >>%s和%c有什么不同?

    %s 对应的是字符串; %c 对应的是字符;

    >>对于要求输入c1后还要输入c2

    请把程序改成

    char c1,c2;
    scanf("%c",&c1);
    printf("%c",c1);
    _flushall();
    scanf("%c",&c2);
    printf("%c",c2);

    以下链接是关于_flushall()的:http://baike.baidu.com/view/656661.htm 

     

    如果你还有什么问题,请让我知道。另外,如果你解决了问题,请把有用的回答标记为答案。

    谢谢!

    Lucy

     

    • 已标记为答案 任一雄 2010年12月8日 11:20
    2010年12月7日 8:03
    版主
  • Hi 任一雄,

    1.如果输入的是"a b” 则 c1='a'; c2='  ';

    2.如果输入的是"a" 按回车键 再输入 "b" 则 c1='a'; c2='  ';

    3.如果输入的是“ab” 则 c1='a'; c2=' b';

    4.如果输入的是“abc” 则 c1='a'; c2=' b';

     

    因为在程序看来回车键(\n)和空格键都是一个字符,所以在情况1,2中把前两个字符分别按顺序赋给了c1,c2;

    当使用_flushall() 后就把scanf存在缓冲区的数据全删掉了。再输入的值就可以赋给c2。

     

    有_flushall()的程序的具体变化请看下面:

    scanf("%c",&c1); // 输入值  (如输入 'a'+回车键 则把第一个字符赋给c1  c1='a')
    printf("%c",c1);  // 输出c1 的值 (显示a)
    _flushall();         //把缓冲区的值删除 (删除存在缓冲区的  \n) 
    scanf("%c",&c2);//再次输入值 (如 'd‘ c2=d)
    printf("%c",c2); //输出c2的值  (显示d)

    没有_flushall()的程序变化请看下面:

    scanf("%c",&c1); // 输入值  (如输入 'a'+回车键 则把第一个字符赋给c1  c1='a' ;把第二个字符赋给了c2 c2即 回车键的值)
    printf("%c",c1);  // 输出c1 的值 (显示a)
    scanf("%c",&c2);

    printf("%c",c2); //输出c2的值  (显示c2='

    ')

     

    如果你还有什么问题,请让我知道。另外,如果你解决了问题,请把有用的回答标记为答案。

    谢谢!

    Lucy

     

    2010年12月8日 3:57
    版主
  • Hi 任一雄,

    1.整个过程其实是 输入设备->内存缓冲区->程序。例如

    .当我们输入”abc”时,这时候缓冲区的内容是 “abc”

    .用程序的scanf("%c", &c1) 语句,就把a字符保存到变量c1中,这时缓存区的内容为 “bc”’a’被保存到内存中了。

    2.>>而且连用scanf的话,缓冲区中会不断的积累曾输入的字符,那么缓冲区满的时候才会自动清除缓冲区

    不是的,按第一点说的,scanf是把字符保存到变量中。键盘输入的内容会不断的积累在缓冲区。缓冲区满了不会自动清除缓冲区。

    3.>>每次用scanf,敲回车输入数据,都会把一个换行符送到缓冲区

    每次敲回车,都会把一个换行符送到缓冲区,和scanf无关。

     

    如果你还有什么问题,请让我知道。另外,如果你解决了问题,请把有用的回答标记为答案。

    谢谢!

    Lucy

     

    • 已标记为答案 任一雄 2010年12月8日 11:20
    2010年12月8日 9:59
    版主

全部回复

  • 一个小程序,其中有以下几句:

    char c1,c2;

    scanf("%c",&c1);

    printf("%c",c1);

    scanf("%c",&c2);

    printf("%c",c2);

    这样,run以后,输入c1以后就不能输入c2,是否是因为c1的内容从缓冲区传到内存以后,缓冲区还会残留换行符?

    %s和%c有什么不同?

    Hi 任一雄,

    欢迎来Microsoft论坛。

    根据对你问题的分析,当第一次输入c1后,要用flushall函数清除缓存区,再输入c2。

    >>%s和%c有什么不同?

    %s 对应的是字符串; %c 对应的是字符;

    >>对于要求输入c1后还要输入c2

    请把程序改成

    char c1,c2;
    scanf("%c",&c1);
    printf("%c",c1);
    _flushall();
    scanf("%c",&c2);
    printf("%c",c2);

    以下链接是关于_flushall()的:http://baike.baidu.com/view/656661.htm 

     

    如果你还有什么问题,请让我知道。另外,如果你解决了问题,请把有用的回答标记为答案。

    谢谢!

    Lucy

     

    • 已标记为答案 任一雄 2010年12月8日 11:20
    2010年12月7日 8:03
    版主
  • 其实您说的我都知道,我也确实知道flush可以清除掉缓冲区里的内容,只是我想了解一下在程序运行过程中scanf缓冲区中内容的具体变化情况,以及每个scanf语句执行后缓冲区内残留的东西。 请告知缓冲区变化机理,谢谢了
    2010年12月7日 11:22
  • Hi 任一雄,

    1.如果输入的是"a b” 则 c1='a'; c2='  ';

    2.如果输入的是"a" 按回车键 再输入 "b" 则 c1='a'; c2='  ';

    3.如果输入的是“ab” 则 c1='a'; c2=' b';

    4.如果输入的是“abc” 则 c1='a'; c2=' b';

     

    因为在程序看来回车键(\n)和空格键都是一个字符,所以在情况1,2中把前两个字符分别按顺序赋给了c1,c2;

    当使用_flushall() 后就把scanf存在缓冲区的数据全删掉了。再输入的值就可以赋给c2。

     

    有_flushall()的程序的具体变化请看下面:

    scanf("%c",&c1); // 输入值  (如输入 'a'+回车键 则把第一个字符赋给c1  c1='a')
    printf("%c",c1);  // 输出c1 的值 (显示a)
    _flushall();         //把缓冲区的值删除 (删除存在缓冲区的  \n) 
    scanf("%c",&c2);//再次输入值 (如 'd‘ c2=d)
    printf("%c",c2); //输出c2的值  (显示d)

    没有_flushall()的程序变化请看下面:

    scanf("%c",&c1); // 输入值  (如输入 'a'+回车键 则把第一个字符赋给c1  c1='a' ;把第二个字符赋给了c2 c2即 回车键的值)
    printf("%c",c1);  // 输出c1 的值 (显示a)
    scanf("%c",&c2);

    printf("%c",c2); //输出c2的值  (显示c2='

    ')

     

    如果你还有什么问题,请让我知道。另外,如果你解决了问题,请把有用的回答标记为答案。

    谢谢!

    Lucy

     

    2010年12月8日 3:57
    版主
  • 哦,您看看我理解的对不对:使用printf和scanf时是行缓冲,有换行符或缓冲区满时把字符送到内存,但是缓冲区中仍然残留着所有字符,比如输入c1后,缓冲区中的'a'送到c1,换行符送到c2,但缓冲区中仍然残留着'a'和换行符,而且连用scanf的话,缓冲区中会不断的积累曾输入的字符,是这样吗?那么缓冲区满的时候才会自动清除缓冲区,或者除非用户使用_flushall();而且,printf和scanf是共用一个缓冲区?

    每次用scanf,敲回车输入数据,都会把一个换行符送到缓冲区,

    可以这样理解吗?

    2010年12月8日 5:03
  • Hi 任一雄,

    1.整个过程其实是 输入设备->内存缓冲区->程序。例如

    .当我们输入”abc”时,这时候缓冲区的内容是 “abc”

    .用程序的scanf("%c", &c1) 语句,就把a字符保存到变量c1中,这时缓存区的内容为 “bc”’a’被保存到内存中了。

    2.>>而且连用scanf的话,缓冲区中会不断的积累曾输入的字符,那么缓冲区满的时候才会自动清除缓冲区

    不是的,按第一点说的,scanf是把字符保存到变量中。键盘输入的内容会不断的积累在缓冲区。缓冲区满了不会自动清除缓冲区。

    3.>>每次用scanf,敲回车输入数据,都会把一个换行符送到缓冲区

    每次敲回车,都会把一个换行符送到缓冲区,和scanf无关。

     

    如果你还有什么问题,请让我知道。另外,如果你解决了问题,请把有用的回答标记为答案。

    谢谢!

    Lucy

     

    • 已标记为答案 任一雄 2010年12月8日 11:20
    2010年12月8日 9:59
    版主
  • 多谢了,也就是说使用scanf时,相当于先读入缓冲区,然后再在缓冲区和内存的具体变量之间做一次“剪切”,这样,缓冲区也会清除该内容
    2010年12月8日 11:19
  • 我想是跟__cdecl调用约定有关,scanf,printf是__cdecl约定,函数执行过后不会帮你处理堆栈

    在汇编中调用C库的_scanf和_printf都要

    push n个参数
    push 一个format
    call _scanf
    add esp, 4*n

    最后的add指令就是处理了栈中的参数,或许在C/C++中也需要同样的处理


    C/C++ and Aragaki yui's big fan.
    2010年12月9日 1:18
  • Hi 任一雄,

    不用谢,欢迎以后常来MSDN论坛。

     

    天天开心!

    Lucy

    2010年12月10日 2:23
    版主