Разве вы не можете использовать оператор `,` для определения переменной в выражении цикла while в C?

Почему мы не можем определить переменную в выражении условия цикла while так же, как мы можем определить в цикле for?

Например:

#include <stdio.h>


int main() {
    while((int c = getchar()) != EOF) 
         printf("%c", c);
    
    return 0;
}

Чат GPT 4.0 и Perplexity.ai предложили мне приведенный выше фрагмент кода. Но, видимо, это запрещено; Я узнал это методом проб и ошибок. Я также попробовал использовать оператор ,.

Пример:

#include <stdio.h>

int main() {
    while((int c = getchar(), c != EOF) 
         printf("%c", c);
    
    return 0;
}

Поскольку значением условной проверки будет только самое правое выражение (c != EOF), поскольку использовался оператор ,. Но даже тогда компилятор его не скомпилировал. Итак, как мы можем определить переменную в условном выражении цикла while?

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

Ken White 02.09.2024 06:04

«так же, как мы можем определить в цикле for?»: То, что вы написали в примерах, тоже не работает с for. В цикле for предложение init (которое может быть объявлением переменной) отделяется от условия ;, а не ,. Наличие объявления внутри выражения, как в (int c = getchar()) != EOF, совершенно невозможно в синтаксисе языка. ChatGPT предлагает вам ерунду.

user17732522 02.09.2024 06:07

ОТ: Почему вам нужно/хотите использовать while() вместо очевидного for(), которое является одновременно идиоматическим и синтаксически правильным?

Fe2O3 02.09.2024 06:51

«Чат GPT 4.0 и Perplexity.ai предложили…» Они не заменяют учебные материалы. Они действительно не умеют программировать. Изучение языка программирования методом проб и ошибок, скорее всего, приведет к большому разочарованию.

Gerhardh 02.09.2024 08:41
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
120
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Цикл while (6.8.5.1) ожидает управляющее выражение (6.5), но int c = getchar() — это объявление с инициализатором (6.7). В C объявление не является выражением. Вы можете использовать оператор запятая в управляющем выражении в следующих строках:

#include <stdio.h>

int main() {
    { // scope of the variable c
        int c;
        while(c = getchar(), c != EOF)
            printf("%c", c);
    }
}

Первая часть for-цикла — это предложение, которое разрешает объявления (6.8.5.3), и вы объявляете несколько переменных одного типа, разделяя их запятой:

for(int c, y, a; ...)

По моему мнению, присваивание в управляющем выражении труднее читать, поэтому я предпочитаю более простые конструкции, такие как:

#include <stdio.h>

int main() {
    for(;;) {
        int c = getchar();
        if (c == EOF) break;
        printf("%c", c);
    }
}

Я не согласен с предложенной организацией последнего примера (с использованием for (;;)). Это мнение, но я бы не рекомендовал его для общего использования.

Jonathan Leffler 02.09.2024 15:04

@JonathanLeffler Спасибо за ваш комментарий. Мне казалось, что совершенно ясно (дальше переработано), что этим предложением я выражаю свое мнение; предпочтение более простым конструкциям, чем присваивание в управляющем выражении while или дублирующем вызове getchar() при использовании for-цикла.

Allan Wind 02.09.2024 18:35

Нет. Это запрещено синтаксисом языка, но GCCкомпилятор (а также clang) допускает это как расширение, известное как выражение оператора .

Выражение оператора GCC позволяет вам использовать локальные переменные внутри выражения. Возьмем ваш пример кода в качестве примера: мы можем объявить локальную переменную c в выражении цикла while при использовании компилятора GCC, но она не будет доступна в теле цикла, поскольку она доступна только внутри выражения.

Используя расширение выражения оператора GCC, ваш пример кода можно записать так:

#include <stdio.h>

int main() {
    while(({int c = getchar(); c == EOF ? 0 : putchar(c);})) 
         ;
    return 0;
}

@AllanWind Это вопрос ОП, как мы можем определить переменную в условном выражении цикла while? - что запрещено на C языке. В своем посте я предоставил подробную информацию о расширении компилятора gcc, которое можно использовать для выполнения того, что хочет ОП, и оно имеет некоторые ограничения. Последнее - лучше с точки зрения чего?

H.S. 02.09.2024 08:12

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

Allan Wind 02.09.2024 08:14

@AllanWind Включено ваше предложение. Спасибо.

H.S. 02.09.2024 08:34

Синтаксис оператора while не позволяет объявлять переменные в управляющем выражении (это выражение, а не объявление). Вместо этого вы можете использовать цикл for, хотя код будет повторяться:

   /* ^^ preceding code ^^ */
   for (int c = getchar(); c != EOF; c = getchar())
       /* loop statement */;

Если повторение вызова getchar() недопустимо и переменная c должна быть изолирована, тогда цикл while можно поместить внутри включающего блока, определяющего переменную c:

   /* ^^ preceding code ^^ */
   {
       /* local declarations for the loop */
       int c;
       while ((c = getchar()) != EOF)
           /* loop statement */;
   }

Другой вариант, упомянутый в других ответах, — использовать бесконечный цикл с условным оператором break для завершения цикла.

Другие вопросы по теме