Почему не работает использование нескольких ifs, но работает использование ifs и else if внутри цикла while?

Это был мой код без использования else if:

#include <stdio.h>

main()
{
    long s = 0, t = 0, n = 0;
    int c;
    while ((c = getchar()) != EOF)
        if (c == ' ')
            ++s;
        if (c == '\t')
            ++t;
        if (c == '\n')
            ++n;
    printf("spaces: %d tabulations: %d newlines: %d", s, t, n);
}

Это код, использующий else if:

#include <stdio.h>

main()
{
    long s = 0, t = 0, n = 0;
    int c;
    while ((c = getchar()) != EOF)
        if (c == ' ')
            ++s;
        else if (c == '\t')
            ++t;
        else if (c == '\n')
            ++n;
    printf("spaces: %d tabulations: %d newlines: %d", s, t, n);
}

По какой-то причине отказ от использования else if не работает. Какова причина? Я знаю, что использование if делает это одно за другим, а использование else if останавливается на первом истинном утверждении. Это имеет разницу в производительности. Во всяком случае, не используя else if в этом конкретном (если не в другом) цикле while, похоже, это не работает.

Спасибо.


person Philosophical Ragdoll    schedule 30.01.2018    source источник
comment
C — это не Python. Отступ не означает, что все операторы if являются частью одного и того же блока.   -  person StoryTeller - Unslander Monica    schedule 30.01.2018
comment
Отсутствует { } вокруг всего этого.   -  person Oliver Charlesworth    schedule 30.01.2018
comment
первый пример работает, потому что первый оператор if только обернут во время. Второй пример полностью обернут в while. Я бы сказал, что второй пример работает. Сначала нет.   -  person Jean-François Fabre    schedule 30.01.2018
comment
Возможно, вы захотите прочитать это, но не уверены, что это правильный дубликат stackoverflow.com/questions/11734604/   -  person StoryTeller - Unslander Monica    schedule 30.01.2018
comment
Спасибо, парни. Это полностью показывает, насколько важно забыть об одной изогнутой скобке. Это означает, что я могу использовать if и else if без фигурных скобок, верно? P.S. Я новичок в C, так что извините за такой глупый пост.   -  person Philosophical Ragdoll    schedule 30.01.2018


Ответы (3)


С правильным отступом ваша первая программа выглядит так:

#include <stdio.h>

main()
{
    long s = 0, t = 0, n = 0;
    int c;
    while ((c = getchar()) != EOF)
        if (c == ' ')
            ++s;
    if (c == '\t')
        ++t;
    if (c == '\n')
        ++n;
    printf("spaces: %d tabulations: %d newlines: %d", s, t, n);
}

Тело цикла while представляет собой один оператор.

if ... else if ... else if ... else все образует одно большое утверждение. Разделив ваши условия на несколько операторов (if, if, if), вы переместили все, кроме первого, из цикла while.

Чтобы избежать этой проблемы, всегда используйте составной оператор (т. е. блок: { ... }) в качестве тела оператора while или if.

Кстати, main() не является действительным C с 1999 года. Должно быть int main(void).

person melpomene    schedule 30.01.2018
comment
Спасибо, очень ценю это. Также я изучаю C из оригинальной книги Брайана Кернигана, которая в основном используется без возвращаемого типа данных, как это было в 1980-х годах. Я использовал Visual Studio для его компиляции, и он не дал никаких ошибок. Однако спасибо за поправку. - person Philosophical Ragdoll; 30.01.2018

Из стандарта (выбраны только соответствующие части грамматики правила)

   iteration-statement: while ( expression ) statement

   statement: selection-statement

   selection-statement:
             if ( expression ) statement
             if ( expression ) statement else statement

Вы пишете оператор итерации, состоящий из while(expression) и одного оператора. Этот оператор в вашем случае является оператором выбора - теперь проверьте его. Если вы не используете else if или else, это не один оператор, а несколько операторов со всеми, кроме одного, в операторе while, остальные находятся за его пределами.

Ваш код в основном означает это

  while ((c = getchar()) != EOF){ <--- the selection statement
    if (c == ' ')
        ++s;
  }<-- 
  if (c == '\t')
        ++t;
  if (c == '\n')
        ++n;

Постановка скобок в блоки и отступы заставят вас воздержаться от подобного рода ошибок.

person user2736738    schedule 30.01.2018

Поскольку вы забыли фигурные скобки вокруг while, он перебирает только первый оператор if, затем выходит из цикла и оценивает два других оператора if.

Кроме того, почему вы не используете оператор switch?

while ((c = getchar()) != EOF) {
    switch(c) {
       case ' ':
          ++s;
          break; 
       case  '\t':
          ++t;
          break;
       case '\n':
          ++n;
          break;
    }
}
printf("spaces: %d tabulations: %d newlines: %d", s, t, n);
person Chronocidal    schedule 30.01.2018