Возврат адреса поведения локальной переменной

Возможный дубликат:
Можно ли получить доступ к памяти локальной переменной за пределами ее области?

вход:

#include <stdlib.h>
#include <stdio.h>
int func2(void);
int* func1(void);

int func2(void)
{
    int* b;
    b = func1();
    printf("%d", *b);
    printf("%d", *b);
    printf("%d", *b);
}

int* func1()
{
    int a = 13;
    return &a;
}

int main()
{
    func2();
}

Выход:

13 -1077824828 -1077824828

Может кто-нибудь объяснить, что произошло в стеке и ОС? Почему после получения значения указателя результат изменился с 13 на мусор?


person Nizarazo    schedule 13.09.2012    source источник
comment
Повторяющееся число бесконечность плюс один. Это неопределенное поведение.   -  person Cat Plus Plus    schedule 14.09.2012
comment
Кроме того, func2 ничего не делает return, хотя и определено с типом возвращаемого значения int.   -  person Daniel Fischer    schedule 14.09.2012
comment
Чтобы ответить на вопрос: в вашем конкретном случае первый вызов printf() перезаписывает 13, оставшийся в стеке после вызова func1().   -  person Mysticial    schedule 14.09.2012
comment
Не определен стандартом языка. Идеально определяется реализацией.   -  person Pavel Radzivilovsky    schedule 14.09.2012


Ответы (2)


Конечно. Результат будет различаться между отладкой и выпуском (чистым). Локальная переменная - это EBP-(некоторое смещение), если вы посмотрите на сборку. Это означает, ВЫШЕ В СТЕКЕ, как в "далее".

Это адрес, который вы возвращаете.

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

person Pavel Radzivilovsky    schedule 13.09.2012
comment
зачем printf передавать параметры в стек? разве они не отправляются напрямую в буфер stdout? - person Nizarazo; 14.09.2012
comment
Нет, и это важно: компилятор, производящий код вызывающей стороны, не должен знать, что означает printf и, в частности, что эта функция собирается делать - например, работать со stdout. - person Pavel Radzivilovsky; 15.09.2012

Вызов printf создает новый кадр стека, который перезаписывает место, ранее занятое a.

person StoryTeller - Unslander Monica    schedule 13.09.2012
comment
Может быть, а может и нет. Вы не можете рассуждать в общем смысле о том, что происходит, когда вы вызываете неопределенное поведение. - person Ed S.; 14.09.2012
comment
Конечно вы можете. Дима прав. Он отлично определен, но зависит от платформы. - person Pavel Radzivilovsky; 14.09.2012