2015-03-01 3 views
0

Я писал простую программу, чтобы проверить, как работает область действия переменных, но я получаю неожиданные результаты, поэтому я надеялся, что вы можете дать мне понять их. Я составил этот кодC++ - Значение локальных неинициализированных переменных

#include<iostream> 
using namespace std; 

void myFunction1() 
    { 
    int e; 
    cout << e << endl; 
    e++; 
    cout << e << endl<<endl; 
    } 

int main() 
    { 
    cout << "MAIN" << endl; 
    int a,b,c,d; 
    cout << "a= " << a << endl; 
    cout << "b= " << b << endl; 
    cout << "c= " << c << endl; 
    cout << "d= " << d << endl<<endl; 
    cout << "MY_FUNC" << endl; 
    myFunction1(); 
    myFunction1(); 
    myFunction1(); 
    } 

и получил этот выход

MAIN 
a= -1617852976 
b= 32767 
c= 0 
d= 0 

MY_FUNC 
32675 
32676 

32676 
32677 

32677 
32678 

Итак, есть две вещи, которые я действительно не понимаю,

1) В основной функции() Я создавая 4 переменные int (a, b, c, d) БЕЗ их инициализации, поэтому я ожидаю, что они будут принимать разные значения каждый раз, когда я запускаю код. Странно то, что первая переменная (а) всегда различна, а остальные всегда принимают те же значения (b = 32767, c = d = 0)

2) Выход функции мне еще незначителен. Опять же, я создаю переменную e без ее инициализации, поэтому в первый раз он принимает случайное значение (в примере, e = 32675) ..... тогда я увеличиваю его на единицу, чтобы он печатал 32675 и 32676, и это звучит правильно.

Но как второй раз я вызываю функцию, e сохраняет предыдущее значение (32676)? Я думал, что e был создан каждый раз, когда я вызываю myFunction1() и удаляется в конце функции, так что e каждый раз принимает разные случайные значения (так как я не инициализирую его). Почему значение e сохраняется, даже если переменная выходит за пределы области видимости?

+1

Никакой результат не является неожиданным, если у вас есть неопределенное поведение. – chris

+1

Это просто неопределенное поведение для использования неинициализированных переменных. –

+0

Чтение неинициализированных переменных - это неопределенное поведение, * что-либо может случиться, включая взрывы и демоны, вылетающие из вашего носа. (за исключением того, что эта переменная является символом char, тогда она просто не определена, и вы не получаете демонов/взрывов). – tux3

ответ

2

Неинициализированные примитивные значения просто не определены. Они могут иметь любую ценность.

2

Это неопределенное поведение. Поэтому нет смысла анализировать поведение этой программы.

-2

Я объясню, что обычно происходит, но это неопределенное поведение, и вы не должны использовать его в своих интересах.

Итак, что такое «мусор», о котором каждый всегда говорит, когда он сталкивается с непредсказуемым поведением своего приложения? На самом деле это всего лишь данные, оставшиеся в памяти от предыдущих вызовов функций и других нормальных действий программы. Обнуление памяти на самом деле является дорогостоящим (так что в Windows память обычно обнуляется только на бесплатных виртуальных страницах с помощью 0-приоритетного процесса). Итак, у вас есть этот «мусор», но как вы его получите?

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

Но, когда у вас есть отладочная сборка, компилятор добавляет некоторый код, что облегчает вам отладку: память, к которой у вас не должно быть доступа, будет иметь очень четкую структуру, например 0xffffffff или 0xcececece или что-то подобное, что вы можете легко идентифицировать в программе просмотра памяти. Но трудно определить эти значения, когда они находятся в системных номерах базы 10.

1

В основной функции() я создаю 4 ИНТ переменные (а, б, в, г) без инициализации их, так что я ожидаю, что они предположить другое значение каждый раз, когда я запускаю код

Данное допущение является ошибочным. Они могут имеют различное значение при каждом запуске кода, но они могут и не быть. Может произойти все, что угодно. Точка UB заключается в том, что вы должны отбросить все ваши предположения.

Но как второй раз я вызываю функцию, e сохраняет предыдущее значение (32676)? Я думал, что e был создан каждый раз, когда я вызываю myFunction1() и удаляется в конце функции, так что e каждый раз принимает различное случайное значение (так как я его не инициализирую)

Он делает. Если вы замените «случайный» на более правильный «произвольный», то результаты, которые вы видите, соответствуют этому шаблону.

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

0

Хороший способ помочь вам понять это, чтобы объяснить с точки зрения распределения памяти.

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

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

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

Надеюсь, что это поможет =)

Смежные вопросы