2016-10-31 5 views
0

Насколько я знаю, переменная «q» и адрес выходит из области действия после завершения функции fun(). Итак, почему вывод кода «20 10»?Почему выход «20 10», а не значение «Мусор» («Висячие указатели»)?

int *p2; 
void fun(int *ptr) 
{ 
    int q=10; 
    ptr=&q; 
    p2 = ptr; 
} 

int main() 
{ 
    int r=20; 
    int *p = &r; 
    fun(p); 
    printf("%d %d",*p,*p2); 
    return 0; 
} 
+3

Потому что это неопределенное поведение. –

+1

Как вы сообщаете стоимость мусора от ненужной стоимости? Ваш '10' - значение мусора, равно как и любое другое значение мусора. – AnT

+1

'10' - это мусор. – chux

ответ

0

Это чистый undefined behavior.

Доступ к недействительной памяти вызывает UB. (Просто потому, что вы можете написать код) Вы не должны этого делать.

То, что 20 10 вполне может считаться мусором, поскольку, как только вы вызываете UB, выход не может быть оправдан каким-либо образом.

FWIW, проблема с доступом к p2 говоря *p2, разыменования p1 просто отлично, как и в параметрах C данные передаются с помощью передачи по значению, так что любое изменение ptr внутри функции не будут влиять на фактическую переменную ptr (не *ptr) в вызывающем.

0

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

, а как другие сказали, UB = UB, UB включает в себя, по-видимому работает

3

Как уже упоминалось другие, сохранение адреса локальной переменной, то пытается разыменования этот адрес после завершения функции является undefined behavior.

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

При этом многие компиляторы обычно не будут изменять часть стека, используемую функцией после ее возвращения. Это дополнительная работа, которая обычно не нужна. Итак, сразу после того, как fun возвращает, локальные переменные все еще содержат свои старые значения.

При вызове printf указатель p2 разыменовывается перед вызовом printf. Поскольку до этого не было вызвано никаких других функций, значение a от последнего вызова до fun еще не было перезаписано. Итак, вы читаете старое значение.

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

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

+0

С другой стороны, на многих встроенных платформах прерывание, которое происходит после возвращения функции, скорее всего, скроет фрейм стека, ранее используемый этой функцией; так как прерывания часто могут возникать в непредсказуемые моменты, а это значит, что в большинстве случаев нельзя сказать ничего полезного о содержимом прежних кадров стека. – supercat

0

Как указано другими, у вас есть неопределенное поведение, поэтому выход может быть любым.

Однако, помимо неопределенного поведения у вас есть ошибка, на которую стоит сосредоточиться.

переписывание кода, чтобы избежать UB может быть:

void fun(int *ptr){ 
    int q=10; 
    ptr=&q; 
} 

int main(){ 
    int r=20; 
    int *p = &r; 
    fun(p); 
    printf("%d",*p); 
    return 0; 
} 

Этот код нормально, и выход будет 20. Дело в том, что указатель p передается по значению. Таким образом, любые изменения, сделанные внутри функции, теряются при возврате функции. Другими словами, p в основном не изменен и по-прежнему указывает на r.

Если вы хотите изменить значение указателя в функции, передайте его как двойной указатель. Например, void fun(int **ptr), чтобы он выглядел как *ptr = ... и вызывал функцию как fun(&p)

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