2014-10-22 3 views
-2

Выходной код кода 11,11, неопределенное значение ....... пожалуйста, объясните?Указатель как аргумент функции?

#include <stdio.h> 

void f(int **const p); 

int main() 
{ 
    int i = 10; 
    int *p = &i; 
    f(&p); 
    printf("%d ", *p); 
    printf("%d ", *p); 
} 

void f(int **const p) 
{ 
    int j = 11; 
    *p = &j; 
    printf("%d ", **p); 
} 
+3

На какой нечестивой системе '% d' print' "неопределенное значение" '?? –

+1

@ TheParamagneticCroissant: ну, в конце концов, это неопределенное поведение. :) –

+0

@ DanielKamilKozar Точно ...: P –

ответ

8

Это undefined behavior потому, что вы установили *p, чтобы указать на локальный переменный, и как только функция выходит из всех локальных переменных выходит из области видимости, которые дают вам оборванный указатель.


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

+4

В этом случае это не имеет никакого значения. –

+2

@Jefffrey Вам не нужен оператор 'return' для возврата из функции, функция автоматически возвращается после ее завершения. –

+2

@Jefffrey Через «выходной» аргумент 'p'? –

6

здесь:

*p = &j; 

объем j меньше, чем объем p. Когда функция f возвращается, значение, сохраненное в p, более недействительно. Следовательно, неопределенное поведение.

1

Область действия переменной является локальной для функции, в которой она определена. В вашем случае j является локальным для функции f.Variable j больше не виден вне функции f.and, следовательно, p становится висящим указателем. Если вы ожидаете вывода как 11 11 11 тогда вам нужно объявить j как статическую переменную.

1

Как только вы выйдете функцию f(), переменная j выходит из области видимости, пока указатель p является все еще указывает на этот адрес памяти. Это неопределенное поведение.

Упрощенная рядный версия кода, прокомментировал, что происходит:

int main() 
{ 
    int *p;    //create pointer 
    { 
    int j = 11;  //create j in local scope 
    p = &j;   //set p to point at j (refered to as address A from now) 
    printf("%d ", *p);//print value at A "11 " 
    }     //j goes out of scope 
    printf("%d ", *p); /*print value at A "11 11 " 
         ***UB: as memory at A is not used to store j any more, 
         printf() can use it to store variables for its own use*/ 
    printf("%d ", *p); /*print value at A "11 11 GARBAGE" 
         ***UB: as memory at A is not used to store j any more, 
         the previous printf() call touched A at some point 
         changing the contents (and thus the read value)*/ 
} 

Честно говоря, я удивлён, что призыв к первому printf() не затирать память перед выводом его.

Вы не можете полагаться на второй printf, выводящий «правильное значение». Даже в этом простом примере поведение, видимое, продиктовано только реализацией, и другой компилятор, скорее всего, справится с этим по-разному.
Просто изменив код, очень, вероятно, что выход изменится, например, объявив новую переменную до того, как printf, скорее всего, перепишет память и остановит вывод из правильного.

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