在返回指针类型的函数中定义自动变量,然后返回这个变量的值给主函数中某相应指针,则会发生错误。我想问的是:
在调用完一个函数之后,编译器是怎么样撤销其自动变量的,
是断开变量名与内存地址的联系或是断开变量名与内存的联系然后再撤销原来内存的内容呢?
总而言之,撤销某一变量在内存中的实际动作到底是什么?
在返回指针类型的函数中定义自动变量,然后返回这个变量的值给主函数中某相应指针,则会发生错误。我想问的是:
在调用完一个函数之后,编译器是怎么样撤销其自动变量的,
是断开变量名与内存地址的联系或是断开变量名与内存的联系然后再撤销原来内存的内容呢?
总而言之,撤销某一变量在内存中的实际动作到底是什么?
这个问题牵扯到汇编的知识
系统分配空间时,基本上牵扯到堆和栈。
你的问题是栈引起的。栈的基本操作是push和pop,就是把数据压入栈和弹出。push 操作把数据压入栈顶,然后函数才可以使用。pop操作把数据弹出,然后就不可以使用了。这些操作都发生在栈的顶部,他有个特性。就是最后入栈的数据先弹出来。
当函数a调用函数b,而b中又调用函数c时候,操作如下:
在调用函数b前,在栈的顶部分配函数b需要用到的全部局部变量。进入函数b。
然后,在调用函数c之前,把c所用到的数据压入栈的顶部,进入函数c。
现在,情况是函数a的数据在栈的最下面,b的在中间,c的在最上面。
然后,在c返回之前,把c的所有局部数据弹出。这些数据就不可用了。
现在,情况是函数a的数据在栈的最下面,b的在最上面
接着,在b返回前,把b的局部数据弹出,它们此时在a中就不能引用了
接着,a也是一样,在返回前,弹出全部局部数据。
我不赞同你引用子函数中变量的地址,虽然有时候不会出错。
但是,那些行为是没有保障的。
“没有保障”意味着:有可能成功,有可能造成崩溃。具体的行为跟编译器有关。
有些编译器,在子函数退出的时候,只弹出栈,并不做特殊处理,那么你引用子函数中变量的地址,基本上会成功。
但是有些编译器,在子函数退出的时候,把弹出栈的内容都填为0。那么当你访问地址为0的变量的时候,将会弹出“非法访问”的对话框,然后强迫关闭该程序。
还有,a调用b,也有好多中情况。
1. a给b分配局部变量, b函数结束时直接返回,由a来清除那些局部变量的空间
2。a给b分配局部变量, b函数结束时先自己清除那些局部变量,然后返回
3。b在自己开始执行前分配空间,b函数结束时直接返回,由a来清除那些局部变量的空间
4。b在自己开始执行前分配空间,b函数结束时先自己清除那些局部变量,然后返回
另外,再加上参数传递的顺序。这样就产生了不同的函数调用方式。也就构成了平时的:pascal call 、 c call 、std call 等不同的调用方式。
这些东西,只有你真正的明白栈的操作及底层的具体实现后,才能明白那句经常在c语言课堂上听到的:“c语言每调用一个函数就给它分配空间,当退出时,释放该空间。”的真正含义了。
"pop操作把数据弹出"
是怎么样把数据弹出的?
"但是有些编译器,在子函数退出的时候,把弹出栈的内容都填为0。那么当你访问地址为0的变量的时候,将会弹出“非法访问”的对话框,然后强迫关闭该程序。"
那个是 内容和地址都为0吗?
不是真的做一个弹出的动作,只不过是形象一点的说而已,弹出其实是把内存最顶端的数据首先取消,然后后面数据向上移动,于是有弹出的说法。
函数不是和数据在一个区的,弹出以后不是填0,是填null,注意null其实和0是不同的。函数推出时全部局部变量就挂了,有返回的就返回。
为什么说是“数据向上移动"呢?
我在课本上看到的只是指向栈顶的指针在移动啊
是不是就是说:撤消一个变量就是在栈区弹出这个变量所对应的数据,此时变量所对应的地址及在该地址中所存内容都被取消,
而当被调用函数结束后,所有该函数的局部变量都被撤消