Вход в C. Scanf перед получением. Проблема

Я новичок в 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;
}

Он позволяет вводить идентификатор, но просто пропускает остальную часть ввода. Если я изменю порядок следующим образом:

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

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

Это будет работать. Хотя я НЕ МОГУ изменить порядок, и он мне нужен как есть. Кто-нибудь может мне помочь ? Возможно, мне нужно использовать какие-то другие функции. Спасибо!


person Dmitri    schedule 02.03.2010    source источник
comment
gets(3): Функцию gets() нельзя использовать безопасно. Из-за отсутствия проверки границ и неспособности вызывающей программы надежно определить длину следующей входящей строки использование этой функции позволяет злоумышленникам произвольно изменять функциональность работающей программы с помощью атаки переполнения буфера. Настоятельно рекомендуется использовать функцию fgets() во всех случаях. (См. FSA.) Не используйте его.   -  person Bertrand Marron    schedule 02.03.2010
comment
Вкратце: если вы используете gets, летающие бешеные атакующие оцелоты вырвут вам глазницы. Так что не надо.   -  person Tyler McHenry    schedule 02.03.2010
comment
scanf зло — c-faq.com/stdio/scanfprobs.html   -  person jschmier    schedule 03.03.2010
comment
gets(b); изменить на scanf(" %19[^\n]", b);   -  person BLUEPIXY    schedule 15.03.2015
comment
Очевидно, OP новичок в C, зачем продолжать говорить о безопасности. Он просто хочет реализовать что-то для начинающих.   -  person Timothy Leung    schedule 18.10.2015
comment
Не используйте get для создания дыр в безопасности. Используйте fgets.   -  person    schedule 04.08.2017


Ответы (7)


Пытаться:

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

gets читает только '\n', который оставляет scanf. Кроме того, вы должны использовать fgets not gets: http://www.cplusplus.com/reference/clibrary/cstdio/fgets/, чтобы избежать возможного переполнения буфера.

Изменить:

если вышеуказанное не работает, попробуйте:

...
scanf("%d", &a);
getc(stdin);
...
person IVlad    schedule 02.03.2010
comment
Хм. Я пробовал scanf(%d\n, &a); но, похоже, это не работает. После того, как я ввожу идентификатор, я просто не вижу, чтобы программа делала что-то еще. - person Dmitri; 02.03.2010
comment
Ух ты! Спасибо! Это сработало безупречно! Спасибо за совет по поводу fgets. Обязательно воспользуюсь!! Спасибо! - person Dmitri; 02.03.2010
comment
scanf("\n") делает не то, что вы думаете - он потребляет все последовательные пробельные символы, поэтому не возвращается до тех пор, пока не будет буферизован не пробельный символ. - person Toby Speight; 24.06.2019

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
person AndiDog    schedule 02.03.2010
comment
Потрясающий!! Большое спасибо! - person Dmitri; 02.03.2010
comment
Кроме того, использование scanf("%d%*c", &a) должно работать. Термин %*c приводит к тому, что scanf читается в одном символе (новая строка), но звездочка приводит к отбрасыванию значения. Это заставит scanf съедать новую строку, не требуя отдельного вызова функции. - person bta; 02.03.2010
comment
Вы представляете оба варианта так, как будто они имеют одинаковую основу, но scanf настолько сложно использовать должным образом, что гораздо лучше избегать его использования полностью (см. ссылку на часто задаваемые вопросы comp.lang.c). Просто выберите вариант 2. - person jamesdlin; 03.03.2010

scanf не будет потреблять \n, поэтому он будет взят gets, которые следуют за scanf. очистить входной поток после 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;
}
person vinayak    schedule 16.11.2010
comment
И fflush(stdin), и fflush(NULL) в некоторых библиотеках C сбрасывают stdout и stderr, но это совершенно непереносимо! - person Tarnay Kálmán; 30.11.2010

вы должны сделать это.

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

для чтения ввода из scanf после чтения через gets.

person Madan Ram    schedule 04.08.2013

Просто используйте 2 функции gets()

Если вы хотите использовать gets() после scanf(), убедитесь, что вы используете 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;
}

Для объяснения ([email protected]);

person Isaac Balintuma    schedule 09.01.2016
comment
добро пожаловать в СО! Пожалуйста, помните, что английский не является родным языком для всех здесь, поэтому старайтесь публиковать грамматически правильные ответы, а не использовать «u» вместо «вы» — что не будет работать с Google Translate! - person Dave Mulligan; 09.01.2016

scanf("%d", &a); не может прочитать результат, потому что %d принимает только десятичные целые числа. Таким образом, вы добавляете \n в начале следующего scanf, чтобы игнорировать последний \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;
}
person Rogério De Leon Pereira    schedule 05.07.2016
comment
Добавлено объяснение @Coatless - person Rogério De Leon Pereira; 05.07.2016

Функция 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

person Duy Đặng    schedule 05.01.2017