gudanbeiying 发表于 2023-3-23 13:30:12

C语言scanf录入字符,字符串

本帖最后由 gudanbeiying 于 2023-3-23 15:26 编辑

当用scanf录入一个字符串的时候会把最后的回车记录在缓冲区里,当下一次用scanf录入一个字符的时候会把缓冲区里的回车直接录入。
#include<stdio.h>
int main()
{
        char a;
        char b;
        printf("输入a:");
        scanf("%s",a);
        printf("a = %s",a);
        printf("输入b:");
        scanf("%c",&b);
        printf("b = %c",b);
    return 0;
}
   这里我输入 a回车,会直接跳过b的输入,因为b直接被缓冲区的回车赋值了。

但是为什么要是我将b设置为字符数组,然后第二个scanf给b录入字符串:
#include<stdio.h>
int main()
{
        char a;
        char b;
        printf("输入a:");
        scanf("%s",a);
        printf("a = %s",a);
        printf("输入b:");
        scanf("%s",&b);
        printf("b = %s",b);
    return 0;
}
    这里我输入 aaa回车,结果为a = aaa输入b:(这里我输入bbb回车)bbb(回车),结果为b=bbb
为什么第二段代码在赋值b的时候没有被缓冲区的回车影响,可以正常输入,而且在输出b的时候也没有体现出回车符号,而只有bbb?第一次scanf输入是缓冲区留下的回车去哪了?

dolly_yos2 发表于 2023-3-23 13:37:50

本帖最后由 dolly_yos2 于 2023-3-23 13:40 编辑

因为遇到 %s 描述符会自动跳过前导空白,而 %c 不会跳过任何字符
供您参考:https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3047.pdf#subsubsection.7.23.6.2
8 Input white-space characters are skipped, unless the specification includes a [, c, or n specifier.347)
347)These white-space characters are not counted against a specified field width.

isdkz 发表于 2023-3-23 13:39:49

问题的关键在于scanf的使用方式和字符串格式化输入的处理。

在第一个代码示例中,当你使用scanf("%c", &b)时,scanf会读取缓冲区中的下一个字符,而这个字符正好是第一次输入字符串时的回车符(换行符)。换行符会被立即读取并赋值给b,这就是为什么没有等待你输入新的字符。

在第二个代码示例中,你使用了scanf("%s", &b)。%s表示字符串输入,这里的关键区别在于字符串输入格式化会自动跳过缓冲区中的空格、制表符和换行符。所以当第二次调用scanf时,它会自动忽略缓冲区中的换行符,然后等待你输入新的字符串。当你输入"bbb"并按回车后,这个新的字符串就被赋值给b。此时,换行符在第二次scanf时已经被忽略了,因此在输出时也不会显示出来。

总结一下,当使用%c格式化输入时,scanf会立即读取缓冲区中的下一个字符,包括换行符;而当使用%s格式化输入时,scanf会自动跳过空格、制表符和换行符,直到遇到有效的字符输入。这就是为什么在第二个示例中,即使缓冲区中有换行符,也能正常输入字符串。

gudanbeiying 发表于 2023-3-23 13:58:52

isdkz 发表于 2023-3-23 13:39
问题的关键在于scanf的使用方式和字符串格式化输入的处理。

在第一个代码示例中,当你使用scanf("%c", & ...

懂了懂了,我还想问就是,我在做PAT考试题的时候,在我用scanf录入了一个整型变量的前提下比如 5回车,然后下面我要给字符型数组录入字符串,我用scanf %s,系统就不给我判满分,但是我把scanf换成,getchar();先清理掉缓冲区的回车,然后用gets()录入字符串就是满分,那scanf写法没啥问题呀,为啥就不是满分呢?

isdkz 发表于 2023-3-23 14:00:56

gudanbeiying 发表于 2023-3-23 13:58
懂了懂了,我还想问就是,我在做PAT考试题的时候,在我用scanf录入了一个整型变量的前提下比如 5回车,然 ...

在PAT考试题中,这个问题可能是由于缓冲区处理和输入格式的不同要求导致的。当你使用scanf读取一个整型变量后,缓冲区中的换行符没有被消耗,所以下一个scanf读取字符串时可能会受到影响。虽然scanf("%s")会自动跳过空格、制表符和换行符,但在实际评测环境中,输入和换行符的处理可能有所不同,这可能导致了你的解答没有得到满分。

当你使用getchar()清空缓冲区后再使用gets()读取字符串,你手动处理了缓冲区中的换行符。这样可以确保在读取字符串时,不会受到先前输入整数时留在缓冲区的换行符的影响。因此,这个解决方案在评测系统中可以得到满分。

在实际编程中,为了避免类似问题,你可以在需要的时候使用getchar()或者其他方法清空缓冲区。这可以确保你的输入不会受到先前输入遗留在缓冲区的字符的影响。

dolly_yos2 发表于 2023-3-23 14:13:30

本帖最后由 dolly_yos2 于 2023-3-23 14:15 编辑

gudanbeiying 发表于 2023-3-23 13:58
懂了懂了,我还想问就是,我在做PAT考试题的时候,在我用scanf录入了一个整型变量的前提下比如 5回车,然 ...

会不会这个要录入的字符串可能含有空格等空白字符? %s 会在遇到这类字符时停止,而 fgets 会读入直到遇到换行符或达到输入数量限制。这两种函数的行为是不同的
另外已经不止是不建议使用 gets 了,这一函数在新版本的 C 语言中已经被删除了

gudanbeiying 发表于 2023-3-23 15:32:27

dolly_yos2 发表于 2023-3-23 14:13
会不会这个要录入的字符串可能含有空格等空白字符? %s 会在遇到这类字符时停止,而 fgets 会读入直到 ...

不太清楚,这个题没涉及到文件呀,fgets不是从文件中录入吗,我作题的时候这两种写法的运行结果完全一样,各种情况也都没问题,我自己也调试过在缓冲区有回车的时候,下面用scanf录入字符串,确实不会把回车录到字符串内,但考试系统就是不给这个scanf写法打满分

dolly_yos2 发表于 2023-3-23 15:35:55

gudanbeiying 发表于 2023-3-23 15:32
不太清楚,这个题没涉及到文件呀,fgets不是从文件中录入吗,我作题的时候这两种写法的运行结果完全一样 ...

标准输入也是文件(stdin)
我指的情况是这个字符串里面有空格,可以试一下用 scanf 读入带空格的字符串看看是什么效果

gudanbeiying 发表于 2023-3-23 15:48:13

dolly_yos2 发表于 2023-3-23 15:35
标准输入也是文件(stdin)
我指的情况是这个字符串里面有空格,可以试一下用 scanf 读入带空格的字符串 ...

带空格的话就只会录入空格之前的,比如 aaa bbb就只会录入aaa
页: [1]
查看完整版本: C语言scanf录入字符,字符串