fgets из проблем с stdin [C] - PullRequest
2 голосов
/ 02 марта 2010

Я пишу программу, которая работает с файлами. Мне нужно иметь возможность вводить данные в виде структур и в конечном итоге читать их. На данный момент у меня проблема с этим кодом:

typedef struct {
    char* name;
    .....
}employeeRecord;
employeeRecord record;

char name[50];

if(choice == 1)
    {
        /*Name*/
        printf("\nEnter the name:");
        fgets(name,50,stdin);
        record.nameLength = strlen(name) -1;
        record.name = malloc(sizeof(char)*record.nameLength);
        strcpy(record.name,name);
        /*Other data, similar format...*/

Если я хочу, например, указать адрес и номер телефона и попросить указать каждый из них подряд (поэтому адрес в значительной степени идентичен указанному выше, за исключением замены имени на адрес), я обнаружил, что ввод пропускается. Я имею в виду, что у меня нет шансов ввести это. Выход на самом деле Введите имя: Введите адрес: (и вот где он запрашивает ввод)

Ответы [ 3 ]

3 голосов
/ 02 марта 2010

Новая строка все еще находится в stdin от предыдущего вызова функции, которая не считала новую строку из ввода. Очистите stdin, читая, пока не прочтете новую строку - , а не , сбросив stdin, как предлагали другие.

РЕДАКТИРОВАТЬ: Спасибо Alok, за исправление!

2 голосов
/ 02 марта 2010

Вы, вероятно, использовали scanf для чтения choice перед вызовом fgets для чтения имени.scanf, возможно, оставил символ новой строки в stdin, который ваш код ошибочно принимает за ввод пустого имени.Если это действительно так, попробуйте не использовать scanf (используйте fgets для получения choice и используйте atoi для преобразования в int или strcmp для сравнения с "1 \ n" и т. Д.),В противном случае код должен работать с приведенными ниже модификациями, чтобы учесть тот факт, что fgets также считывает завершающий символ новой строки в буфер (который вы, вероятно, хотите удалить):

  #define MY_LENOF(x) (sizeof(x)/sizeof((x)[0])) 

  char choice[3] = { 0 }; /* example of how to initialize to all NULs */
  if (!fgets(choice, MY_LENOF(choice), stdin)) {
    fprintf(stderr, "Premature end of input\n");
    exit(1);
  }

  if (strcmp(choice, "1\n") == 0) {  
    /*Name*/
    printf("\nEnter the name:");
    if (!fgets(name, MY_LENOF(name), stdin)) {
      /* if fgets fails it leaves name unchanged, so we reset it to "" */
      name[0] = '\0';
    }
    /* good practice to use srtnlen in order not to overrun fixed buffer */
    /*  not necessarily a problem with fgets which guarantees the trailing NUL */
    size_t nameLength = strnlen(name, MY_LENOF(name));
    assert(name[nameLength] == '\0');
    if (nameLength - 1 > 0 && name[nameLength - 1] == '\n') {
      /* strip trailing newline */
      name[--nameLength] = '\0';
    } else if (nameLength >= MY_LENOF(name) - 1) {
      fprintf(stderr, "Name is too long\n");
      exit(1);
    } else {
      fprintf(stderr, "Premature end of input\n");
      exit(1);
    }

    record.nameLength = nameLength;
    record.name = malloc(sizeof(char)*(record.nameLength + 1));
    strcpy(record.name, name);
2 голосов
/ 02 марта 2010

Я попробовал ваш код и не могу воспроизвести проблему. Следующий код работает так, как вы ожидаете, он запрашивает имя, ждет, пока вы введете имя, затем запрашивает адрес и т. Д.

Мне интересно, не нужно ли вам читать stdin и очищать его, прежде чем запрашивать дополнительные данные?

typedef struct {
    char* name;
    char* address;
}employeeRecord;

int readrecord(employeeRecord &record)
{
   char name[50];
   char address[100];

   printf("\nenter the name:");
   fgets(name, sizeof(name), stdin);
   record.nameLength = strlen(name) + 1;
   record.name = malloc(sizeof(char)*record.nameLength);
   strcpy(record.name,name);

   printf("\nenter the address:");
   fgets(address, sizeof(address), stdin);

   ...    
}

Кстати, вы хотите добавить 1 к strlen (имя), а не вычесть 1. или, если вы хотите, чтобы имя сохранялось в вашей записи без завершающего нуля, вам нужно использовать memcpy для копирования строки в вашу запись, а не зЬгср.

Edit:

Я вижу из комментариев, что вы используете scanf для чтения значения выбора, это оставляет \ n во входном буфере, который затем берется вашим первым вызовом fgets. Вместо этого вам следует использовать fgets для чтения в строке выбора, а затем sscanf для анализа значения из входных данных. как это

int choice;
char temp[50];
fgets(temp, sizeof(temp), stdin);
sscanf(temp, "%d", &choice);

Это должно сделать весь вопрос о том, чтобы смыть стандартный stdin.

...