Как инициализировать несколько переменных в цикле for (;;) в C? - PullRequest
30 голосов
/ 28 июля 2010

Я думал, что можно инициализировать несколько переменных в цикле for:

for (int i = 0, char* ptr = bam; i < 10; i++) { ... }

Но я только что обнаружил, что это невозможно.GCC выдает следующую ошибку:

ошибка: ожидаемый безусловный идентификатор перед 'char'

Действительно ли вы не можете инициализировать переменные разных типовfor петля?

Ответы [ 7 ]

45 голосов
/ 28 июля 2010

Вы можете (но, как правило, не должны) использовать локальный тип структуры.

for ( struct { int i; char* ptr; } loopy = { 0, bam };
      loopy.i < 10 && * loopy.ptr != 0;
      ++ loopy.i, ++ loopy.ptr )
    { ... }

Начиная с C ++ 11, вы можете более элегантно инициализировать отдельные части, если они не зависят от локальной переменной:

for ( struct { int i = 0; std::string status; } loop;
      loop.status != "done"; ++ loop.i )
    { ... }

Это просто почти читабельно, чтобы реально использовать.


C ++ 17 запланирован для решения проблемы со структурированными привязками :

for ( auto [ i, status ] = { 0, ""s }; status != "done"; ++ i )

Тем не менее, подробный набор функций и синтаксис все еще в движении.

17 голосов
/ 28 июля 2010

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

int i = 0, char *ptr = bam;

тоже.Первым предложением цикла for может быть (C99 §6.8.5.3) «объявление» или «пустое выражение».Обратите внимание, что вы можете сделать:

int i = 0, *j = NULL;
for(int i = 0, *j = NULL;;){}

, потому что i и *j имеют тип int.Точный синтаксис для объявления дан в §6.7

13 голосов
/ 28 июля 2010

Если вам действительно нужны переменные, чтобы оставаться в области действия цикла, вы можете написать

{ char* ptr = bam; for (int i = 0; i < 10; i++) { ... } }

Это немного некрасиво, но работает.

7 голосов
/ 28 июля 2010

Попробуйте это:

int i;
char* ptr;
for (i = 0, ptr = bam; i < 10; i++) { ... }
0 голосов
/ 18 августа 2018

Вы также можете сделать:

for (int i = 0; i < 10; i++) {
    static char* ptr = bam;
}
0 голосов
/ 20 июля 2016

Я думаю, что языки, которым они учат вас в наши дни, предназначены для того, чтобы надевать на вас наручники и гнить ваш мозг, так что вы просто молчите и соединяете блоки lego в очень ограниченной форме, в которой они должны соединяться, чтобы вы создали посредственнуювещи.Прелесть C в том, что вы можете следовать правилам и хитроумно получать то, что хотите.Вот как вы пишете этот цикл с дополнительными инициализаторами.Вот рабочий пример, который показывает, как соединить расширенный цикл с первым.Вы используете первый для пиратства его переменных, и они остаются в области видимости.Вы используете фиктивную переменную, чтобы внешний цикл запускался один раз.Умный компилятор заметит этот факт и обнулит цикл с помощью развертки цикла.Так что для вас это просто выгода.Затем второй массив использует некоторые переменные из первого объявления и второго объявления и выполняется до завершения.Это тривиальный пример, означающий, что вы сможете понять, как это сделать, не выполняя сложного броска в некотором объеме.Потому что эту технику можно использовать с макросами, когда они написаны таким образом, чтобы создать красивое перечисление структуры следующего поколения, например, «для значения в массиве do», которых у меня много.

#include "stdio.h"
int
main(int argc, char **argv)
{
    const int max=7;
    const char *array[7] = {
    "hello","you","kids","who","don't","know","malloc\n"
    };

    for(int i=0,count=max,$=1;$;$=0)
    for(const char **p=array;count<max;i++)
    {
        printf("%s ",p[i]);
    }
}

Естьздесь ничего не пропало.Этот метод объединения цикла с циклом one shot for был использован для встраивания в вызов, чтобы получить перечислитель для этого хэш-объекта, и запуска перечисления, чтобы получить значения, извлеченные для ключа и значения, а также для удобства созданияони как пустые указатели для пользователя, он просто должен назвать их.Затем они заполняются, и перечисление продолжается до тех пор, пока все ключи и значения не будут выполнены.Если пользователь прерывает итерацию, весь каскад циклов однокадрового разваливания развалится так, как нам хотелось бы, потому что их, вероятно, даже нет, поскольку они были созданы с простыми операциями, которые, как может видеть компилятор, развернут цикл.Таким образом, в основном это позволяет вам расширить синтаксис, чтобы делать такие вещи без штрафа.

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

0 голосов
/ 28 июля 2010

Согласно http://linuxsoftware.co.nz/cppgrammar.html#for-init-statement вы можете получить только простое объявление или выражение (которое не может содержать объявление) в операторе for-init. Это означает, что ответ отрицательный (если я правильно проанализировал BNF :))

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...