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

#include<stdio.h>

int *fun();
int main()    
{
   int *ptr;
   ptr=fun();
   printf("%d",*ptr);
   printf("%d",*ptr);
}
int * fun()
{
   int k=4;//If auto then cannot print it two times.....stack will be changed
   return(&k);
}

O/P: 4
    -2

Вызов printf() в первый раз выводит правильное значение.

Вызов любой функции (даже printf()) сразу после вызова fun(). На этот раз функция printf() выводит мусорное значение. Почему это происходит? Почему мы не получаем мусорное значение во время самого первого оператора печати????


person Prithvi Raj    schedule 27.07.2012    source источник


Ответы (3)


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

Учитывая это, вероятно, происходит следующее: fun возвращает указатель на место хранения k. Эта часть стека больше не является надежной, потому что функция, выделившая ее, завершила работу. Тем не менее, никто еще не переписал его, поэтому 4 все еще там, где он был написан. Затем main готовится вызвать printf. Для этого он получает первый аргумент *ptr. Для этого он загружается с точки ptr места, которая является (бывшим) адресом k, поэтому в нагрузку попадает та 4, которая там есть. Эти 4 хранятся в регистре или стеке для передачи в printf. Затем адрес строки формата "%d" сохраняется для передачи в printf. Затем вызывается printf. В этот момент printf использует большой объем стека и записывает новые данные там, где раньше было k. Однако число 4, которое было передано в качестве аргумента, находится в безопасном месте, где должны быть аргументы для printf, поэтому printf напечатает его. Затем printf возвращается. Затем основная процедура готовится снова вызвать printf. На этот раз, когда он загружается с того места, где указывает ptr, 4 больше нет; это какое-то значение, которое было записано во время первого вызова printf. Таким образом, это значение передается в printf и печатается.

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

person Eric Postpischil    schedule 27.07.2012

Почему это вас удивляет? Поведение не определено, но в наблюдении того, что вы наблюдали, нет ничего необычного.

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

Это то, что вы наблюдаете в своем эксперименте. Несмотря на то, что переменной k больше не существует, указатель ptr по-прежнему указывает на свое прежнее местоположение. И это прежнее местоположение по-прежнему содержит последнее значение k, то есть 4.

Самый первый printf "успешно" получает копию этого значения для печати. И тот самый первый printf на самом деле тот, который повторно использует старую ячейку памяти и перезаписывает прежнее значение k. Все дальнейшие попытки разыменования ptr будут показывать, что 4 больше нет, поэтому ваш второй printf печатает что-то другое.

person AnT    schedule 27.07.2012

Переменная k является локальной для fun(), что означает, что она будет уничтожена, когда функция вернется. Это очень плохой метод кодирования и всегда будет приводить к проблемам.

И причина, по которой первый printf возвращает правильное значение:

Прежде всего, он может возвращать или не возвращать значение. Дело в том, что k записано где-то в памяти стека. В первый раз, когда функция возвращает значение, printf может получить правильное значение, потому что эта часть памяти может существовать какое-то время. Но это не гарантируется.

person dejavu    schedule 27.07.2012