2014-01-05 2 views
1

это исходный кодпочему второй PRINTF печатает значение мусора

#include <stdio.h> 
#include <stdlib.h> 

int *fun(); 

int main() 
{ 
    int *j; 
    j=fun(); 
    printf("%d\n",*j); 
    printf("%d\n",*j); 
    return 0; 
} 

int *fun() 
{ 
    int k=35; 
    return &k; 
} 

output-

35 
1637778 

первым Е() печатает 35, который является значением, но к

В главный() второй printf печатает значение мусора, а не печать 35.why?

+0

ответ здесь http://stackoverflow.com/questions/20880084/pointers-and-function-arguments/20880143#20880143 – HAL9000

ответ

3

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

1

Оба неверны, так как вы печатаете значение, которое больше не существует: память для хранения int k в функции нормально только тогда, когда функция выполняется; вы не можете вернуть ссылку (указатель) на нее, поскольку она больше не будет ссылаться ни на что значимое.

В следующем, вместо этого, будет работать:

int *fun() 
{ 
    static int k=35; 

    return &k; 
} 

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

5

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

Несмотря на то, что локальный технически разрушен, когда fun возвращается, C runtime ничего не делает, чтобы активно его уничтожить. Следовательно, ваше первое использование *j - это , работающее, потому что память для местного еще не написана. Реализация printf, скорее всего, может быть написана просто с использованием собственных локалей в методе. Следовательно, во втором использовании *j вы имеете в виду все местные printf, а не k.

Для выполнения этой работы вам необходимо вернуть адрес, который указывает на значение, которое проживает дольше fun. Как правило, в C это достигается с malloc

int *fun() { 
    int* pValue = malloc(sizeof(int)); 
    *pValue = 23; 
    return pValue; 
} 

Поскольку возвращение malloc жизни, пока вы звоните free это будет действовать на нескольких использований printf. Один улов - это вызывающая функция, которая теперь должна сообщать программе, когда она выполняется с повторным соединением fun. Для того, чтобы сделать этот вызов free после второго вызова printf

j=fun(); 
printf("%d\n",*j); 
printf("%d\n",*j); 
free(j); 
+0

+1 для 'malloc' – sujin

+0

, но стека следует за lifo, поэтому k следует сначала удалить из стека , так как первый printf() дает правильный результат –

+0

@ user3162531 в общем случае C фактически не удаляет значения стека при возврате из функции. Он просто настраивает указатель стека, чтобы вернуться к вызывающей функции. До тех пор, пока локальное явно не будет написано другим фрагментом кода, значение, как правило, будет оставаться доступным. Никогда не зависеть от этого поведения, хотя это всего лишь артефакт большинства реализаций. – JaredPar

2

Вы возвращаетесь местного значения оно сохраняется в стеке. Когда вы выходите из функции, он стирается. Вы получаете undefined behaviour.

В вашем случае stack не изменяется после возвращения функции, поэтому в первый раз вы получаете правильное значение.Это не то же самое во все времена.

1

Как уже говорили другие, ваша программа вызывает неопределенное поведение.

Это означает, что ничего не может произойти, если поведение не определено.

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

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

Первый вызов printf() теперь использует стек для своей собственной цели - возможно, это даже сам вызов, который перезаписывает старое значение. Таким образом, второй вызов printf() получает значение, записанное в эту память.

Что касается неопределенного поведения, все может случиться.