Не удалось выяснить логическую ошибку в программе на Си - PullRequest
5 голосов
/ 17 мая 2011

Программа, которая печатает свои входные данные по одному слову в строке.

int main() {

    int c;

    while ((c=getchar()) != EOF) {

        if (c== ' ' || c== '\n' ||c == '\t')
                putchar('\n');
        else {
            putchar(c);
        }
    }
    return 0;
}

Вышеуказанная программа печатает результат правильно, по одному слову в строке. После соответствующего изменения условия я ожидал, что программа ниже также напечатает одно слово в строке. Однако я не получаю правильный результат. Я делаю какую-то глупую ошибку или что-то не так?

int main() {

    int c;

    while ((c=getchar()) != EOF) {

        if (c != ' ' || c != '\n' || c != '\t')
            putchar(c);
        else {
            putchar('\n');
        }
    }

    return 0;

}

Ответы [ 8 ]

16 голосов
/ 17 мая 2011

правильное изменение условия:

if (!(c == ' ' || c == '\n' || c == '\t'))

или

if (c != ' ' && c != '\n' && c != '\t')

См. Закон де Моргана

4 голосов
/ 17 мая 2011

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

Для первой проблемы я бы использовал isspace вместо прямого сравнения с символами пробелов, о которых вы знаете (кстати, устраняя источник проблемы, с которой вы столкнулись). Во-вторых, вы можете добавить некоторую логику, чтобы пропустить все последовательные символы пробела, когда вы встречаете первый, или вы можете добавить флаг для записи новой строки, если и только если текущий символ является пробелом и предыдущий символ, который вы написали, не был новой строкой.

Кроме того, вы можете читать слова, используя scanf с преобразованием %s:

char buffer[256];

while (scanf("%255s", buffer))
    printf("%s\n", buffer);

Этот подход, однако, накладывает верхний предел на размер одного слова. При нормальных обстоятельствах это редко бывает проблемой, но в зависимости от характера ввода это может / может быть.

3 голосов
/ 17 мая 2011

Вам нужно изменить || с на && с, то есть изменить

        if (c != ' ' || c != '\n' || c != '\t')

до

        if (c != ' ' && c != '\n' && c != '\t')

т.е. «ЕСЛИ не может быть равно пробелу И не может быть равно возвращаемому И не может быть равно табуляция ТО ...»

2 голосов
/ 17 мая 2011

Помните ваши классы логического программирования:

!(A || B) == (!A && !B)
!(A && B) == (!A || !B)

Другими словами: ваше состояние должно читаться так:

if ( c != ' ' && c != '\n' && c != '\t' )
1 голос
/ 17 мая 2011

Вы можете сделать то, что сказал MByD, или вы можете изменить свои или (||) на и (&&).

0 голосов
/ 17 мая 2011

Вам нужно немного больше изучить Законы Деморгана . Недостаточно изменить комбинационные операторы с "||" для "&&" вы также должны отрицать все объединяемые элементы, чтобы получить тот же набор решений.

0 голосов
/ 17 мая 2011

Противоположность A or B or C равна not A and not B and not C, поэтому используйте:

if(c != ' ' && c != '\n' && c != '\t')
0 голосов
/ 17 мая 2011

Ошибка в вашем условном выражении.Когда вы отрицаете первое выражение

!(c== ' ' || c== '\n' ||c == '\t')

, вы получаете:

c!= ' ' && c!= '\n' &&c != '\t'

, а не вы определили свой вопрос.

Помните:

(A && B) совпадает с (! A ||! B)

...