Почему мы не можем определить переменную в выражении условия цикла 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?
«так же, как мы можем определить в цикле for?»: То, что вы написали в примерах, тоже не работает с for
. В цикле for
предложение init (которое может быть объявлением переменной) отделяется от условия ;
, а не ,
. Наличие объявления внутри выражения, как в (int c = getchar()) != EOF
, совершенно невозможно в синтаксисе языка. ChatGPT предлагает вам ерунду.
ОТ: Почему вам нужно/хотите использовать while()
вместо очевидного for()
, которое является одновременно идиоматическим и синтаксически правильным?
«Чат GPT 4.0 и Perplexity.ai предложили…» Они не заменяют учебные материалы. Они действительно не умеют программировать. Изучение языка программирования методом проб и ошибок, скорее всего, приведет к большому разочарованию.
Цикл 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 (;;)
). Это мнение, но я бы не рекомендовал его для общего использования.
@JonathanLeffler Спасибо за ваш комментарий. Мне казалось, что совершенно ясно (дальше переработано), что этим предложением я выражаю свое мнение; предпочтение более простым конструкциям, чем присваивание в управляющем выражении while или дублирующем вызове getchar()
при использовании for
-цикла.
Нет. Это запрещено синтаксисом языка, но 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
, которое можно использовать для выполнения того, что хочет ОП, и оно имеет некоторые ограничения. Последнее - лучше с точки зрения чего?
Легче рассуждать об истине, чем лживое выражение. На самом деле мои вопросы были только для того, чтобы помочь вам улучшить свой ответ.
@AllanWind Включено ваше предложение. Спасибо.
Синтаксис оператора 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
для завершения цикла.
Потому что синтаксис языка допускает одно, но не другое.