堆中存的都是地址,而且地址对应一个栈中的变量值。
栈中存的都是变量值,在堆中对应一个地址。这么理解堆和栈有问题吗
首先,你要搞清楚来龙去脉。为什么要有堆和堆栈
我们看一个简单的程序
int n;
int foo(int x)
{
int y = x - 1;
if (y == 0) return 123;
else return foo(y);
}
int main()
{
...
}
注意看int n
int x int y有什么区别?
发现没有,程序里只有一个n,但是,只要foo被调用一次,就必须有一个独立的x和y,如果foo又调用了自身,那么又得来一套x y
并且每次调用的x y都不能干扰到被它调用的那个函数里的x y
如果你能理解这个需求,那么就能理解为什么要堆栈。
堆栈的作用就是,当我们调用一次函数的时候,就把这个函数里面的参数、局部变量全部一套放在堆栈上
当我们从函数里返回的时候,函数里变量、参数没用了,我们就收回去。我们向一个方向堆放这些变量,又反方向收回去,所以才用堆栈。
如果没有堆栈,管理这些变量非常麻烦。
然后说下堆,堆解决的问题就是程序运行的时候在全局内存里动态分配的存放的问题。比如说
int main() {
scanf("%d", &n);
int * arr = (int *)malloc(sizeof(int) * n);
...
}
这里,arr这个变量是在堆栈上,因为它是一个局部变量。
而它指向的内存,就是在堆上。
堆上这里存放的就是一个数组,而不是你说的,堆上存放指针。
int main() {
int data[100];
scanf("%d", &n);
int * arr = &data[0];
...
}
这个程序,arr指向的是局部变量数组data的首地址,虽然是指针,但是没有用到堆。
只有用new(c++)、 malloc等,才在堆上分配空间。堆的好处在于,它是全局的,所以可以跨函数调用,比如
int * getdata() {
int data[100];
int * arr = &data[0];
return arr;
}
这个程序就不行,因为data是在堆栈上定义的,出了函数就没用了。
得这么写
int * getdata() {
int * arr = (int *)malloc(sizeof(int) * n);
return arr;
}
放在堆上的那块内存,在离开函数后仍然有效。
但是要注意,c语言不会像堆栈那样主动释放堆上的内存,你得注意在不用的时候主动去释放它们,以免占用不必要的空间。
堆中存的都是地址(这句话前面已经找到反例了,int * arr = (int *)malloc(sizeof(int) * n); 堆栈中存放的是实际的值),而且地址对应一个栈中的变量值。(不一定,你可以用全局变量、堆上的变量或者任何地方的变量来存储指针,甚至,没有任何变量来存储指针,这个时候,你的程序没办法使用这个地址,也没办法释放它,就叫做内存泄漏)
栈中存的都是变量值,在堆中对应一个地址。
void memleak() {
malloc(sizeof(int) * n);
}
这里,没有任何变量指向分配的空间
栈中存的都是变量值,在堆中对应一个地址。栈中也可以是指针
int * arr = (int *)malloc(sizeof(int) * n);
arr就是指针。
栈中还存放了参数和程序的返回地址,不过一般这些对程序员透明。或者说一般程序员是不感兴趣的。
但是,注意,黑客是可以利用它做文章的。比如说,黑客可以构造一个超过缓冲区长度的参数,传给一个有缺陷的函数,造成缓冲区溢出,溢出之后,可以改变函数的返回地址,从而执行黑客需要执行的代码
不对,堆栈是没有关系的两种数据结构,在程序中堆负责用户分配和释放内存的管理,栈负责存储系统分配的变量和函数的调用。等于说一个是跟程序员有关,一个是跟编译器有关,程序中的变量的存储空间都是在栈省分配的,malloc和new这样分配内存的操作才是在堆中进行的。
你所说的堆存的地址应该指得是分配的地址吧,分配的地址最后会存储到栈中对应的指针变量中,但这并不表示栈中的变量都对应的堆中的内存;就算概念上栈中某些变量存储了堆分配的内存,栈实际存储的也是指向内存的变量,也就是栈中存储的都是程序中定义的变量(以及函数),而其值可能是用户从堆分配的也可能不是。
所以堆和栈不是那种关系。