在C语言中输入。使用gets前先使用scanf。问题。

11

我对C语言还比较陌生,我在输入程序数据时遇到了问题。

我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
   int a;
   char b[20];

   printf("Input your ID: ");
   scanf("%d", &a);

   printf("Input your name: ");
   gets(b);   

   printf("---------");

   printf("Name: %s", b);   

   system("pause");
   return 0;
}

它允许输入ID,但它只跳过了其余的输入。如果我像这样更改顺序:

printf("Input your name: ");
   gets(b);   

   printf("Input your ID: ");
   scanf("%d", &a);

它会起作用。尽管如此,我不能更改顺序,我需要保持原样。有人能帮助我吗?也许我需要使用其他函数。谢谢!


1
gets()函数不能安全使用。由于它缺乏边界检查,并且调用程序无法可靠地确定下一个输入行的长度,因此使用此函数会使恶意用户通过缓冲区溢出攻击任意更改正在运行的程序的功能。强烈建议在所有情况下使用fgets()函数。(请参见FSA。)不要使用它。 - Bertrand Marron
3
简而言之,如果你使用gets函数,会有狂暴的攻击性美洲豹扑向你并撕开你的眼窝。因此,请不要使用该函数。 - Tyler McHenry
2
scanf邪恶的 - http://c-faq.com/stdio/scanfprobs.html - jschmier
2
gets(b); change to scanf(" %19[^\n]", b); - BLUEPIXY
2
显然,OP是C语言的新手,为什么还要谈论安全问题呢?他只是想以初学者的方式实现一些东西。 - Timothy Leung
不要使用gets函数,因为会产生安全漏洞,请使用fgets函数。 - user7854936
8个回答

12

尝试:

scanf("%d\n", &a);

gets函数只读取scanf留下的'\n',而且应该使用fgets而不是gets:http://www.cplusplus.com/reference/clibrary/cstdio/fgets/,以避免可能发生的缓冲区溢出。

编辑:

如果上述方法不起作用,请尝试:

...
scanf("%d", &a);
getc(stdin);
...

嗯,我尝试了scanf("%d\n", &a); 但似乎不起作用。在我输入ID之后,我就看不到程序做任何其他事情了。 - Dmitri
哇!太棒了!它完美无缺地工作了!感谢您关于fgets的建议。我一定会使用它!!谢谢! - Dmitri
scanf("\n") 并不是你想象中的那样 - 它会消耗 所有连续的空白字符,因此只有在缓冲区中存在非空格字符时才会返回。 - Toby Speight

8

scanf不会消耗换行符,因此它与fgets天生就是敌人。不要将它们混在一起,除非有一个好的解决方案。以下两个选项都可以使用:

// Option 1 - eat the newline
scanf("%d", &a);
getchar(); // reads the newline character

// Option 2 - use fgets, then scan what was read
char tmp[50];
fgets(tmp, 50, stdin);
sscanf(tmp, "%d", &a);
// note that you might have read too many characters at this point and
// must interprete them, too

另外,使用 scanf("%d%*c", &a) 也可以正常运行。 %*c 这个符号会让 scanf 读入一个字符(换行符),但星号则会导致该值被丢弃。这将使 scanf 吃掉换行符,而无需进行单独的函数调用。 - bta
你把这两个选项都呈现得平起平坐,但是 scanf 很难正确使用,因此最好完全避免使用它(请参见 comp.lang.c FAQ 链接)。直接选择第二个选项即可。 - jamesdlin

3

scanf不会消耗 \n,所以它将被后面的gets获取。像这样在scanf之后刷新输入流。

#include <stdlib.h>
#include <string.h>

int main(void) {
   int a;
   char b[20];

   printf("Input your ID: ");
   scanf("%d", &a);
   fflush(stdin);
   printf("Input your name: ");
   gets(b);   

   printf("---------");

   printf("Name: %s", b);   

   system("pause");
   return 0;
}

2
在某些C库中,fflush(stdin)和fflush(NULL)都会刷新stdout和stderr,但这完全不可移植! - Tarnay Kálmán

1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
        int a;
        char b[20];
        printf("Input your ID: ");
        scanf("%d", &a);
        getchar();
        printf("Input your name: ");
        gets(b);
        printf("---------");
        printf("Name: %s", b);
        return 0;
}



Note: 
  If you use the scanf first and the fgets second, it will give problem only. It will not read the second character for the gets function. 

  If you press enter, after give the input for scanf, that enter character will be consider as a input f or fgets.

0

scanf("%d", &a); 无法读取回车符,因为 %d 只接受十进制整数。所以在下一个 scanf 的开头添加一个 \n 来忽略缓冲区内的最后一个 \n

然后,scanf("\n%s", b); 现在可以无问题地读取字符串,但是 scanf 在遇到空格时停止读取。所以将 %s 更改为 %[^\n]。它的意思是:“读取除了 \n 之外的所有内容”

scanf("\n%[^\n]", b);

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    int a;
    char b[20];

    printf("Input your ID: ");
    scanf("%d", &a);

    printf("Input your name: ");
    scanf("\n%[^\n]", b);
    //first \n says to ignore last 'return'
    //%[^\n] read until find a 'return'  
    printf("---------\n");
    printf("Name: %s\n\n", b);   

    system("pause");
    return 0;
}

Explantion added @Coatless - Rogério De Leon Pereira

0

只需使用2个gets()函数

当您想在scanf()之后使用gets()时,确保您使用了2个gets()函数,并且对于上述情况,请编写以下代码:

int main(void) {
   int a;
   char b[20];

   printf("Input your ID: ");
   scanf("%d", &a);

//the change is here*********************
   printf("Input your name: ");
   gets(b);
   gets(b);   
//the change is here*********************

   printf("---------");

   printf("Name: %s", b);   

   system("pause");
   return 0;
}

欢迎来到SO!请记住,英语不是每个人的母语,因此请尽量发布语法正确的答案,而不是使用'u'代替'you' - 这在谷歌翻译中是行不通的! - Dave Mulligan

0

你应该这样做。

    fgetc(stdin);
    scanf("%c",&c);
    if(c!='y')
    {
        break;
    }
    fgetc(stdin);

在读取 gets 函数之后,使用 scanf 从输入中读取数据。


0

scanf函数在尝试解析除字符以外的内容之前会自动删除空格。 %c%n%[]是不删除前导空格的例外。

gets会读取上一个scanf剩下的换行符。使用getchar();捕获换行符。

scanf("%d", &a);
getchar(); // catches the newline character omitted by scanf("%d")
gets(b);

https://wpollock.com/CPlus/PrintfRef.htm


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接