Как правильно читать серию символов, используя getchar? - PullRequest
0 голосов
/ 08 октября 2019

У меня есть два примера исходного кода. Я всегда использовал первый пример, но, как ни странно, символ «0» я нахожу в начале массива (чего во втором примере не бывает). Почему в первом примере символ «0» помещается в начало массива?

example1:

/*
    Enter a sentence: ciao
    0 -> \0
    1 -> c
    2 -> i
    3 -> a
    4 -> o
    5 -> \0
*/

#include <stdio.h>
#define MAX 6

int main(void) {
    int i = 0;
    char ch, last_char, sentence[MAX] = { };

    printf("Enter a sentence: ");

    while ((ch = getchar()) != '\n' && i++ < MAX) {
        sentence[i] = ch;
    }

    for(i = 0; i < MAX; ++i) {
        if(sentence[i] == '\0')
            printf("%d -> \\0\n", i);
        else
            printf("%d -> %c\n", i, sentence[i]);
    }
    return 0;
}

example2:

/*
    Enter a sentence: ciao
    0 -> c
    1 -> i
    2 -> a
    3 -> o
    4 -> \0
    5 -> \0
*/

#include <stdio.h>
#define MAX 6

int main(void) {
    int i = 0;
    char ch, last_char, sentence[MAX] = { };

    printf("Enter a sentence: ");

    while ((ch = getchar()) != '\n') {
        sentence[i] = ch;
        if(i++ >= MAX - 1) break;   
    }

    for(i = 0; i < MAX; ++i) {
        if(sentence[i] == '\0')
            printf("%d -> \\0\n", i);
        else
            printf("%d -> %c\n", i, sentence[i]);
    }
    return 0;
}

Ответы [ 3 ]

1 голос
/ 08 октября 2019

Это потому, что вы делаете i++ в состоянии while. Таким образом, он увеличивается на i до , и вы используете его в качестве индекса в назначении. Вы можете проверить индекс, не увеличивая его, и выполнить автоинкремент в присваивании.

    while ((ch = getchar()) != '\n' && i < MAX) {
        sentence[i++] = ch;
    }

Вы должны фактически изменить порядок операндов &&. Нет смысла читать символ, если вы достигли конца массива и не сможете его назначить.

    while (i < MAX && (ch = getchar()) != '\n') {
        sentence[i++] = ch;
    }
1 голос
/ 08 октября 2019

Есть много «правильных» решений;«лучшее» - это вопрос мнения, но ваше первое решение семантически неверно, а второе излишне неэлегантно.

Первое можно «исправить», инициализировав i в -1, но это небыть идиоматичнымТакже ни одно из ваших предложений не проверяет EOF, который может возникнуть, например, при перенаправлении ввода из файла или при комбинации клавиш CTRL для конкретной платформы.

Следующее локализует индексную переменную и проверяет EOF:

for( int i = 0;
     i < MAX &&                   // Will fit in buffer AND 
     (ch = getchar()) != '\n' &&  // is not newline AND
     ch != EOF;                   // is not end-of-file
     i++ ;
{
    sentence[i] = ch ;
}         

Это имеет смысл, поскольку оно точно отражает ваш выходной цикл. Локализация, если i предотвращает проблемы обслуживания, которые могут возникнуть из-за использования i для различных целей в этом коде. Вы должны аналогичным образом локализовать выходной индекс.

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

char sentence[MAX + 1] ;

ограничивающего под-выраженияi < MAX - 1, или лучше i < sizeof(sentence) - 1 - последний защищает от изменений в объявлении sentence, возможно, используя что-то отличное от MAX при будущем обслуживании или повторном использовании.

1 голос
/ 08 октября 2019
while ((ch = getchar()) != '\n' && i++ < MAX) {
    sentence[i] = ch;
}

Начните с i=0. Мы видим, не является ли читаемый символ новой строкой, и если это так, мы видим, если i меньше MAX. После этого i увеличивается (теперь это 1). Если сравнение было истинным, мы устанавливаем sentence[i] (что совпадает с sentence[1]) в ch. Таким образом, первая позиция, sentence[0], никогда не назначается. Это ошибка.

Во втором примере у вас есть цикл for, который является правильным, поскольку увеличение i происходит последним.

...