【C++内存管理】浅析C++中函数调用时的内存分配-函数调用过程中其他函数相关的内存分布

本文解析了一段C++代码中看似未被调用的print函数为何被执行的问题。通过详细分析内存布局,揭示了由于数组越界导致函数指针被错误放置在返回地址处,从而在函数结束时意外调用了print函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include<iostream>
using namespace std;
void print()
{
	cout<<"hello world"<<endl;
}
 
void test()
{
	int arr[1];
	arr[2]=(int)print;
}
 
int main()
{
	test();
	return 0;
}

以上代码,运行结果为:

[Hyman@Hyman-PC cplus]$ g++ array.cpp 
[Hyman@Hyman-PC cplus]$ ./a.out 
hello world

问题:为什么上述代码中根本没有调用print函数的语句,但是却打印出来了hello world的?


     在上一篇文章《浅析C++中函数调用时的内存分配-函数局部变量的内存分配》 中,最后留下了一个很有意思的问题,在代码中没有任何一个语句调用了 print() 函数,结果 print() 函数却被执行了。现在就对该问题进行分析:

  首先,我们先说明下C++中内存结构的分布,如下图所示:




    整个内存从低地址到高地址一次分为代码段、数据区、堆区、栈区、和命令行参数、系统变量存储区。

    代码段负责存放程序的各种指令,数据区主要存放全局数据、静态数据,而堆区是进行内存分配的地方,栈区是在进行局部变量存放的地方(栈顶是动态变化的),最上面的是存放系统变量和命令行参数等等。

    我们再看一下在执行一个函数时,函数怎么在栈区分配地址:


    在函数执行过程中,首先在栈中放入函数调用前的各个寄存器的执行状态,因为函数结束时需要将函数寄存器的值回到原位,然后存入形参(这点还有争议,和我之前看过的资料不一样,资料上说形参应该存到局部变量前面,但是我通过做实验并查看相关汇编代码,实际形参的存储位置应该如图),然后存入函数的返回地址(所谓返回地址就是函数结束后的下一条语句地址),然后是函数返回值(为返回值预留空间),最后是函数的局部变量。

    在这个例子中,我们定义了一个只含有一个元素的整形数组arr[1],然后数组越界把arr[2]存放了函数print的地址。

    先看此时的内存分布(只看局部变量部分):


     从图中可以看到,我们将print的函数地址放入了本该是函数返回地址的地方,这就导致test函数一结束就调用了print函数,也就打印出了”hello world”,这也就是在我们看来为什么没有调用函数print函数的语句,print函数却被调用的原因了。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值