目录
前言:这里我们的编写环境是VS2019及VS2022。
调用堆栈
-
调用堆栈是什么
概念:调用堆栈反映的是函数的调用逻辑
在哪:首先我们要找到调用堆栈在哪里,而找到调用堆栈的前提是我们的程序已经是调试状态了。
然后再根据下图,找到调用堆栈:
-
调用堆栈的使用
首先,我们先来一段简单的函数调用,用来直观感受:
void test2()
{
printf("hehe\n");
}
void test1()
{
test2();
}
void test()
{
test1();
}
int main()
{
test();
return 0;
}
接下来,我们启动调试,然后找到调用堆栈,观察函数调用的细节:
然后会出现下面的场景:
这代表的意思是:由上到下依次发生函数调用
这里我们发现其实main()函数也是被其他函数调用的(先不做过多解释)
再接着我们按F11继续调试:
当调用完所有函数后,再依次从列表中消失,直到整个程序结束
补充:栈是一种数据结构,特点是:元素后进先出 (可从上图每次都是顶上的元素先出去得直观看到)
栈区内存使用
下面看代码:
#include <stdio.h>
//前提:VS,x86,debug模式下验证
int main()
{
int i = 0;
int arr[10] = { 0 };
for (i = 0; i <= 12; i++)
{
arr[i] = 0;
printf("hehe\n");
}
return 0;
}
该代码执行结果为:hehe(死循环)
为什么呢?
-
通过调试观察内部运行
这里我们可以看到初始化后的数组:
当数组下标为9的元素的值也改为0时:
开始发生越界:
但当i=12时,奇怪的事情发生了:
我们再调试一步:
此时我们要思考是否变量i和arr[12]使用的同一块空间。
通过进一步调试可以看出,它们的地址相同,由此得出二者使用的是同一块空间
下面进行画图分析一下产生该现象的原因,此前我们需要明白两个知识点:
知识点1.
栈区上内存使用习惯是由高地址向低地址处使用
知识点2.
数组随着下标的增长,地址是由低到高变化的
再结合下图:
注意:
- 如果我们将循环判断条件改为i<=11或i<=10,程序在运行时会报错,原因是数组越界访问
- 而循环判断条件i<=12不报错的原因是:数组元素覆盖到i,该程序进行死循环,即使已经越界也没空给你报出这个错误
-
提示
我们不要因为害怕i被数组覆盖到就将变量i创建到数组的后面去:
最本质的原因是数组越界访问,而把问题归结到创建变量的顺序上就属于本末倒置了。