fgets не работает после scanf - PullRequest
10 голосов
/ 07 мая 2011
#include <stdio.h>
#include <string.h>
#include <ctype.h>

void delspace(char *str);

int main() {
    int i, loops;
    char s1[101], s2[101];

    scanf("%d", &loops);

    while (loops--) {
        fgets(s1, 101, stdin);
        fgets(s2, 101, stdin);
        s1[strlen(s1)] = '\0';
        s2[strlen(s2)] = '\0';

        if (s1[0] == '\n' && s2[0] == '\n') {
            printf("YES\n");
            continue;
        }

        delspace(s1);
        delspace(s2);

        for (i = 0; s1[i] != '\0'; i++)
            s1[i] = tolower(s1[i]);

        for (i = 0; s2[i] != '\0'; i++)
            s2[i] = tolower(s2[i]);

        if (strcmp(s1, s2) == 0) {
            printf("YES\n");
        }
        else {
            printf("NO\n");
        }
    }

    return 0;
}

void delspace(char* str) {
    int i = 0;
    int j = 0;
    char sTmp[strlen(str)];

    while (str[i++] != '\0') {
        if (str[i] != ' ') {
            sTmp[j++] = str[i];
        }
    }
    sTmp[j] = '\0';
    strcpy(str, sTmp);
}

После того, как я ввел «loop», «s1» автоматически присваивалась пустая строка. Как это случилось? Я уверен, что моя клавиатура работает нормально.

Ответы [ 7 ]

18 голосов
/ 07 мая 2011

scanf() читает именно то, что вы просили, оставляя следующий \n в конце этой строки в буфере, где fgets() будет читать его. Либо сделайте что-нибудь, чтобы использовать символ новой строки, либо (мое предпочтительное решение) fgets(), а затем sscanf() из этой строки.

5 голосов
/ 07 мая 2011

scanf оставляет пробел во входном буфере, включая символы новой строки.Чтобы использовать fgets для чтения следующей строки, вам необходимо вручную удалить остаток текущей строки:

int c;
do{
    c = getchar();
}while(c != EOF && c != '\n');
2 голосов
/ 07 мая 2011

Вайн,

Geekoaur хорошо ответил на ваш вопрос, я просто указываю на еще одну "проблему" с вашим кодом.

Строка s1[strlen(s1)] = '\0'; - это no-op , если s1 уже правильно завершено нулем, ДО того, как выполнится.

Но если s1 НЕ уже все правильно завершено нулем, ДО того, как эта строка будет выполнена (и вам не повезло), это вызовет:

Это потому, что strlen в основном находит индекс существующего нулевого терминатора и возвращает его! Вот действительная неоптимизированная реализация strlen:

int strlen(char *string) {
    int i = 0;
    while(string[i] != '\0') {
        ++i;
    }
    return i;
}

Итак ... Если вы ДЕЙСТВИТЕЛЬНО беспокоитесь о том, что строки НЕ заканчиваются нулем, тогда вы должны сделать что-то вроде:

  • string[sizeof(string)]='\0'; on local автоматические строки (где компилятор "знает" размер строки);
  • или string[SIZE_OF_STRING] для всех других строк, где SIZE_OF_STRING является (чаще всего) константой #define 'd или переменной, которую вы поддерживаете специально для хранения текущего SIZE (не длины) динамически назначаемого строка.

И если вы ДЕЙСТВИТЕЛЬНО, ДЕЙСТВИТЕЛЬНО, ДЕЙСТВИТЕЛЬНО беспокоитесь о том, что строки не заканчиваются нулем (например, вы имеете дело с «грязными» методами библиотеки (как, например, ATMI Tuxedo)), вы ТАКЖЕ 'очистите "ваши" строки возврата перед передачей их в подозрительные методы библиотеки с помощью:

  • до: memset(string, NULL, SIZE_OF_STRING);
  • invoke: DirtyFunction(/*out*/string);
  • после: string[SIZE_OF_STRING]='\0'

SIG11 - это полный пакет для поиска, потому что (если вы не «зацепите» их с сигнальным процессором и не скажете иначе, они приводят к тому, что unix жестко завершает вашу программу, поэтому вы ничего не можете зарегистрировать (после факта), чтобы помочь выяснить, откуда взялся этот ад, особенно учитывая, что во многих случаях строка кода, которая выбрасывает SIG11, находится рядом с фактической причиной строки, теряющей нулевой терминатор.

Это имеет для вас смысл?

Ура, приятель. Кит.

PS: ВНИМАНИЕ: strncpy НЕ всегда обнуляется ... вы, вероятно, имели в виду strlcpy. Я научился этому нелегко ... когда разбился счет на 60 миллионов долларов.


РЕДАКТИРОВАТЬ:

К вашему сведению: вот «безопасная» (неоптимизированная) версия strlen, которую я назову strnlen (полагаю, это должно быть в stdlib . Sigh.).

// retuns the length of the string (capped at size-1)
int strnlen(char *string, int size) {
    int i = 0;
    while( i<size && string[i]!='\0' ) {
        ++i;
    }
    return i;
}
1 голос
/ 09 сентября 2016

просто поставьте scanf("%d\n",&loops);

вместо scanf("%d",&loops);

1 голос
/ 07 февраля 2014

Я знаю, что это очень старый.Я новичок в c и хотел проверить мой метод, который использует getchar:

#include <stdio.h>

int main()
{

    printf("Please enter your name\n");
    char string[10];

    scanf("%s", string);
    printf("Hello %s\n", string);

    //getchar();  # un commenting this line, fgets perfectly works!!
    printf("Please enter your name again\n");

    fgets ( string, 10, stdin );     

    printf("Hello again %s", string);

    getchar();
}
0 голосов
/ 14 июня 2018

Я решил вашу проблему следующим образом. Теперь ваша программа работает нормально. Если у вас есть какие-либо сомнения, вы можете спросить меня.

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

    int main()
    {
        int i, age;
        char phone[10];
        char name[100];
        printf("ENTER YOUR NAME:");
        fgets(name , 100 , stdin);

        printf("ENTER YOUR AGE:");
        scanf("%d",&age);

        printf("ENTER YOUR PHONE NUMBER:");
        scanf(" ");
        fgets(phone,10,stdin);


        printf("\nStudent detail\n");
        printf("Name: ");
        fputs(name , stdout );
        printf("Age: %d\n",age);
        printf("Phone Number: ");
        puts(phone);
        printf("----\n");
        return 0;

    }
0 голосов
/ 23 февраля 2018

Следующее работает, если fgets() пропускается после использования scanf()

Сказав:

scanf("%d", &loops);

Скажи:

char garbage[100];

fgets(garbage,100,stdin);

Это сохранит все, что осталось от входного буфера, в переменную мусора.

Это эффективно очистит входной буфер и позволит впоследствии использовать fgets().

EDIT: Недавно я узнал, что есть более простое решение, чем приведенное выше. Если вы скажете getchar () после scanf (), это позволит вам без проблем использовать fgets (). getchar () получит следующий символ во входном буфере, который в этом случае будет '\ n'. Как только вы удалите '\ n' из входного буфера, fgets будет работать нормально.

...