почему второй printf печатает значение мусора

57
7

это исходный код

#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?

спросил(а) 2014-01-05T20:01:00+04:00 6 лет, 8 месяцев назад
1
Решение
98

Проблема здесь в том, что возвращение от 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);

ответил(а) 2014-01-05T20:03:00+04:00 6 лет, 8 месяцев назад
80

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

ответил(а) 2014-01-05T20:03:00+04:00 6 лет, 8 месяцев назад
70

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

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

ответил(а) 2014-01-05T20:04:00+04:00 6 лет, 8 месяцев назад
57

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

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

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

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

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

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

ответил(а) 2014-01-05T20:08:00+04:00 6 лет, 8 месяцев назад
57

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

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

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

return &k;
}

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

ответил(а) 2014-01-05T20:03:00+04:00 6 лет, 8 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема