Стек выделения памяти

В стеке память зарезервирована для main который мы называем кадр стека для main функция.

Когда мы называем Add функция, память зарезервирована сверху стека. в Add кадр стека функций, a а также b местные указатели и c является целым числом, которое вычисляет сумму, а затем мы возвращаем ссылку. c является локальной переменной Add функция.

Теперь, когда Add выполнение функции завершено, пространство памяти в стеке также освобождается, поэтому, когда мы пытаемся получить доступ к этому адресу в main с указателем pТо, к чему мы пытаемся получить доступ, — это в основном освобожденное пространство. Компилятор выдает предупреждение, но почему он по-прежнему выводит значение 5 правильно?

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

Yay     5

Потому что, как в куче, нам нужно назначить указатель на null после освобождения или мы еще можем получить к нему доступ? Это как то связано здесь?

/* void Hello()
{
printf("Yay");
} */

int* Add(int *a,int *b)
{
int c=*a+*b;
return &c;
}

int main()
{
int a=1,b=4;
int *p=Add(&a,&b);
// Hello();
printf("\t%d",*p);
return 0;
}

6

Решение

Если предположить, c местный int переменная, доступ c после вызова функции undefined-behavior и может распечатать ожидаемый результат, или может сделать что-то неожиданное.

Хоть C не требует, но обычно это реализуется с использованием стека. По соображениям производительности, когда функция возвращается, она оставляет область стека без изменений. Вот почему вы видите ценность 5 то есть 1+4, Но вы никогда не должны рассчитывать на это.


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

+----------------+
|  c = 42        |
|''''''''''''''''|     +----------------+
|                |     |                |
.  ADD FUNCTION  .     . HELLO FUNCTION .
|                |     |                |
+----------------+     +----------------+
|  b = 4         |     |  b = 4         |
|''''''''''''''''|     |''''''''''''''''|
|  a = 1         |     |  a = 1         |
|''''''''''''''''|     |''''''''''''''''|
|                |     |                |
.  MAIN FUNCTION .     .  MAIN FUNCTION .
|                |     |                |
+----------------+     +----------------+

На диаграмме выше я попытался визуально представить, как может выглядеть стек, когда вы внутри Add функция и Hello функция. Ты это видишь Hello не портит стековую память, которая была зарезервирована для c в Add функция.

Вы можете проверить это, переписав Hello функционировать как

void Hello()
{
int i = 42;
printf("Yay - %d\n", i);
}

Может распечатать 42 в main,

8

Другие решения

Чтобы полностью понять это, я рекомендую вам изучить ассемблер для вашего процессора и посмотреть, как компилируется ваш код. На данный момент, я думаю, может помочь, если я скажу, что возврат из функции не вызывает никакой функции освобождения памяти, он просто настраивает регистры, и поскольку между добавлением и печатью вы не сделали ничего, что изменило бы значение в стеке «освобождается», Вы получите номер. Попробуйте вызвать функцию, которая возвращает .. pfft i dunno 77 между ними (но сохраните ее в локальной переменной!), И вы получите другой результат. Изучите сборку, будьте хорошим программистом.

1

TL; DR ответ, это неопределенное поведение. Ты не можешь reasonify любой вывод вышеуказанного исполнения. Не удивляйтесь, если в итоге будет напечатан номер вашего мобильного телефона или почтовый индекс. 🙂

По истечении срока действия то, что происходит с расположением стека, зависит от среды. Если не требуется, пространство стека выделяется для c не может быть использован повторно, и, следовательно, вы видите считается правильным выходной, но все же является не определено. Когда-нибудь, в другой среде, вы можете увидеть другой ответ.

Мистер Мотит Джайн«s ответ дает очень подробное объяснение этого.

1

Hello Функция не помещает ничего нового в стек, так как не имеет авто-переменных. Следовательно, область памяти, которая была ранее занята c все еще без изменений. + Изменить Hello так что он изменяет память, и вы измените значение в p,

void Hello(void)
{
//This will overwrite the memory previously containing '5' with '3`, the number
//of characters output by the printf() function.
int grub = printf("Yay");
}
0

Я думаю, это потому, что вы не определили «переменную стека» в функции Hello, когда я запускаю следующую программу:

#include <stdio.h>

void Hello()
{
int tt = 100;
int tt1 = 5000;
printf("Yay");
}

int* Add(int *a,int *b)
{
int c=*a+*b;
return &c;
}

int main()
{
int a=1,b=4;
int *p=Add(&a,&b);
Hello();
printf("\t%d",*p);
return 0;
}

Это печатает 5000 в моем линуксе 1 в моем Mac, во всяком случае, я думаю, что они оба неожиданное значение.

0
По вопросам рекламы [email protected]