почему второй 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
первая printf() печатает 35, которая является значением k, но
В основном() второй printf печатает значение мусора, а не печать 35.why?
Проблема здесь в том, что возвращение от 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
. Один улов вызываемая функция теперь должен сообщить программе, когда это делается с Retun от fun
. Для этого free
звонок после второго вызова printf
j=fun();
printf("%d\n",*j);
printf("%d\n",*j);
free(j);
Программа вызывает неопределенное поведение. Вы не можете вернуть указатель на автоматическую локальную переменную. Эта переменная больше не существует после возвращения fun
. В этом случае результат, который вы получите, может быть ожидаемым или неожиданным.
Никогда не возвращайте указатель на автоматическую локальную переменную
Вы возвращаете локальное значение, которое хранится в стеке. Когда вы выходите из функции, он стирается. Вы получаете undefined behaviour
.
В вашем случае stack
не изменяется после возвращения функции, поэтому в первый раз вы получаете правильное значение. Это не то же самое во все времена.
Как уже говорили другие, ваша программа вызывает неопределенное поведение.
Это означает, что все может случиться, когда поведение не определено.
В вашем случае происходит следующее: Возвращается адрес переменной, сидящей в стеке. После возврата из функции следующий вызов функции может - и будет - повторно использовать это пространство.
Между вызовом функции, ошибочно возвращающим этот адрес и вызов с использованием значения, ничего не происходит - в вашем случае. Имейте в виду, что даже это может быть разным в системах, где могут возникать прерывания, а также на системах с сигналами, способными прерывать обычный запуск программы.
Первый вызов printf()
теперь использует стек для своей собственной цели - возможно, это даже сам вызов, который перезаписывает старое значение. Таким образом, второй вызов printf()
получает значение, записанное в эту память.
Что касается неопределенного поведения, все может случиться.
Оба ошибочны, поскольку вы печатаете значение, которое больше не существует: память для хранения int k
в функции работает только во время выполнения функции; вы не можете вернуть ссылку (указатель) на нее, поскольку она больше не будет ссылаться ни на что значимое.
Вместо этого будет работать следующее:
int *fun()
{
static int k=35;
return &k;
}
Статическое ключевое слово "говорит", что память должна "выжить", даже если функция не запущена, поэтому возвращаемый указатель будет действительным.