输入溢出到后续输入中

时间:2014-05-08 19:01:52

标签: c user-input

我试图获得多个连续的用户输入,稍后将打印。只要你没有输入比边界更长的字符串,它就能正常工作,但是当你输入更长的东西时,它会溢出到下一个输入中。例如,此代码:

printf("Enter student's first name:\t");
char nameF[20];
scanf("%20s", nameF);

printf("Enter student's last name:\t");
char nameL[20];
scanf("%20s", nameL);

printf("Enter student's ID Number:\t");
char id[9];
scanf("%9s", id);

printf("Enter student's e-mail:\t");
char mail[26];
scanf("%26s", mail);

结果如下:

Enter student's first name:     01234567890123456789012345
Enter student's last name:      Enter student's ID Number:      0123456789012345
Enter student's e-mail:

First:          01234567890123456789
Last:
ID Number:      012345678
E-mail:         9012345

为了有一堵代码墙,我跳过了打印功能。如果你想看到它,请告诉我,我会添加它。

应该注意的是,我尝试fgets(),结果非常相似。如果我用scanf()替换每个fgets(var, sizeof(var), stdin);行,我会得到:

Enter student's first name:     01234567890123456789012345
Enter student's last name:      Enter student's ID Number:      0123456789012345
Enter student's e-mail:

First:          0123456789012345678
Last:           9012345

ID Number:      01234567
E-mail:         89012345

当我在getchar()语句之后插入scanf()时,它忽略了溢出输入,但仍然跳过下一次扫描。我尝试了一次性输入变量,我已经研究过其他输入法,但似乎无法找到任何帮助。我确信这对于有经验的人来说是一个非常简单的解决方案,但我只用了几个星期就学习了C,所以我不知道指针和结构之外的东西。

我几乎可以保证有人会发现这个副本 - 他们总是这样做 - 但是我确实搜索过,大约一个小时,我找不到任何有用的东西。

提前感谢您提供的任何帮助。

编辑:我理解为什么输入会溢出到下一个输入。它保存第一个 x 字符,其余字符保留在缓冲区中并输入到下一个输入扫描中。

我想更狭隘的问题是:如何清除或转移输入缓冲区,以便如果用户输入他们赢得的额外字符并保留在缓冲区中?

3 个答案:

答案 0 :(得分:3)

我相信scanf正在使用缓冲输入。它允许您输入字符,直到您按Enter键。此时,它会指定您指定的20,然后将剩余的缓冲区用作下一个scanf调用的输入。 fgets的结果更具可预测性,下一个字符串用前一个缓冲区的残余填充。

但是,我不能解释为什么姓氏是空白的,但电子邮件不在第一个例子中。

查看here以获取如何刷新提前输入的示例。您可以编写如下函数:

void flushInput(void)
{
    int c;
    while((c = getchar()) != '\n' && c != EOF)
    /* discard */ ;
}

...然后在每个flushInput();后调用scanf()

作为补充说明,我相信您应该在scanf来电中指定少一个字符。看起来......

char nameF[20];
scanf("%20s", nameF);

...将20个字符放入nameF'\0'终结符超出了数组的范围。 fgets似乎正确地将终结符放在指定的大小内。

答案 1 :(得分:2)

有一个一个接一个的问题:

char nameF[20];
scanf("%20s", nameF);

这是不正确的;格式字符串中的大小不计算尾随空值,因此您必须在变量定义中使用20,格式为20,格式为21,变量定义为21:

char nameF[21];
scanf("%20s", nameF);

原始代码意味着您可以轻松地使用一个变量使用其尾随空值来破坏另一个变量。

这与C的大多数其他部分不同,您指定整个长度,函数保留终止空字节的最后一个字节(例如:fgets())。在一个理想的世界中,不一致性是固定的,但它存在于那里,因为标准I / O库是在70年代后期创建的,并且如果C标准改变了行为,则会有太多代码被破坏。所以,你必须意识到这个怪癖并相应地解决它。

另请注意,当它到达指定格式的末尾时,scanf()会在行上留下任何剩余数据以供下一次输入。如果您想要逐行输入,请阅读一行数据(fgets()或POSIX getline()),然后使用sscanf()进行扫描。这通常是一种更好的经营方式。

char line[4096];

if (fgets(line, sizeof(line), stdin) == 0)
    ...handle EOF...
if (sscanf(line, "%19s", nameF) != 1)
    ...handle format error...

请注意,您应该针对EOF错误检查每个原始输入函数(fgets()),并针对正确的转换次数对sscanf()scanf()进行错误检查。

答案 2 :(得分:0)

这不是程序错误但是我会告诉你当超出范围时会发生什么。 。 。 实际上,范围内的字符存储在ID中,其他字符被覆盖到字符中并存储到它的下一个变量即电子邮件中。 。 程序没有告知输入电子邮件,因为该值是从id溢出而我们存储在电子邮件中,因此电子邮件已包含ID溢出的值 。 我希望它会对你有所帮助