Инициализация всех переменных в C в одной строке и неинициализированное значение


На языке Си, это

int x, y, z = 0;

То же самое, что и это?

int x = 0;
int y = 0;
int z = 0;

Также, если я просто скажу int a;, кажется, что значение a равно нулю, даже если оно неинициализировано, но не неопределенно, как описано в , каким будет значение неинициализированной переменной?

4 3

4 ответа:

Нет, эти два понятия не эквивалентны.

int x, y, z = 0;

В этой строке x и y будут иметь неопределенное значение, в то время как z инициализируется до нуля.

Однако вы можете сохранить его в "одной строке" за цену некоторой многословности:
int x = 0, y = x, z = y;

Теперь все три инициализируются одним и тем же значением (тем, которое вы дали x). Чтобы инициализировать одну переменную другой, все, что требуется, - это предварительно определить инициализатор. И это работает, даже если он находится на той же линии. Вышеупомянутое также позволит вам довольно легко изменять начальное значение для всех переменных.

В качестве альтернативы, если вы находите предыдущий стиль некрасивым, вы можете заставить его работать в двух строках:
int x, y, z;
x = y = z = 0;
Но теперь это назначение, а не инициализация.

Также, если я просто скажу int a;, кажется, что значение a равно нулю, даже если оно неинициализировано, но не неопределенно, как описано в том, каким будет значение неинициализированной переменной?

"неопределенное значение" не имеет значения. значит "не-ноль". В нуле нет ничего, что делало бы его недопустимым кандидатом на начальное значение переменных. Некоторые" полезные " компиляторы нуль инициализируют переменные в отладочных сборках. Он может скрывать зловещие ошибки, если вы также не обращаете внимания на предупреждения компилятора.

Это:

int x, y, z = 0;

Не то же самое, что

int x = 0, y = 0, z = 0;

Или

int x = 0;
int y = 0;
int z = 0;

В первом случае инициализируется только z, а во втором - все три.

Если значение не инициализировано, его значение является неопределенным, а чтение неинициализированной переменной - неопределенным поведением, и тот факт, что после чтения она имеет значение 0, является результатом неопределенного поведения.

Утверждение типа

 int x, y, z = 0;

Инициализирует только последнюю переменную, z; x и y остаются неинициализированными.

Возможный эквивалент

int x = 0;
int y = 0;
int z = 0;

Будет

int x, y, z;
x = y = z = 0;

Что говорит,

Кроме того, если я просто скажу int a;, кажется, что значение a равно нулю, даже если оно неинициализировано

Это зависит от того, что если переменная имеет статическую длительность хранения, то она будет неявно инициализирована до 0.

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

Чтобы ответить на ваш второй (более интересный) вопрос (который, возможно, заслуживает отдельного вопроса):

Термин "unitialized " просто означает, что ни одно значение не присваивается явно при создании экземпляра; значение-это все, что происходит в соответствующем месте памяти в это время. Некоторые среды заполняют стек с нулем в начале выполнения, поэтому в тривиальных примерах ноль вероятен. Однако это не будет верно все время, так как стек перетекает во время выполнения и содержит различные значения, оставшиеся от ранее выполненного кода.

Например, в следующем, вероятно, что a в fn() не будет нулем для каждого вызова (или, возможно, любого вызова) и будет меняться между вызовами:

void fn()
{
    static int i = 1 ;
    volatile int a ;
    printf( "Call %d: a = %d\n", i, a ) ;
    i++ ;
    a = i ;
}

int main()
{
    for( int i = 0; i < 10; i++ )
    {
        fn() ;
    }
}

В моем тесте (на ideone.com) он вывел следующее:

Call 1: a = 134513970
Call 2: a = 2
Call 3: a = 3
Call 4: a = 4
Call 5: a = 5
Call 6: a = 6
Call 7: a = 7
Call 8: a = 8
Call 9: a = 9
Call 10: a = 10

Как видите во втором и последующих вызовах он содержит все, что осталось в этом месте от предыдущего вызова, потому чтото же самое расположение стека используется повторно. Другой шаблон вызова-например, вставка вызова функции до или после fn() приведет к другому и менее предсказуемому результату, когда эта область стека будет повторно использоваться другими функциями. Например, когда я изменил тело цикла следующим образом:

        rand() ;
        fn() ;

В результате получилось:

Call 1: a = 1433091188
Call 2: a = 1433091188
Call 3: a = 1433091188
Call 4: a = 1433091188
Call 5: a = 1433091188
Call 6: a = 1433091188
Call 7: a = 1433091188
Call 8: a = 1433091188
Call 9: a = 1433091188
Call 10: a = 1433091188