上一篇讲了调试,今天通过一个举例回忆一下上一篇内容吧!
1. 回顾:调试举例
在VS2022、X86、Debug的环境下,编译器不做任何优化的话,下⾯代码执⾏的结果是啥?
#include <stdio.h>
int main()
{
int i = 0;
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//0~9
for (i = 0; i <= 12; i++)
{
arr[i] = 0;
printf("hehe\n");
}
return 0;
}
陷入循环
调试观察问题:
会发现 arr 和 i 的值一模一样,则我们对其取地址观察:
发现地址是一样的,所以是在这里出现了问题。
1.栈区内存的使⽤习惯是从⾼地址向 低地址使⽤的,所以变量i的地址是 较⼤的。arr数组的地址整体是⼩ 于i的地址。
2.数组在内存中存储的时候的特点:随着下标的增长,数组的地址是由低到高变化的。
所以根据代码,就能理解为什么是左 边的代码布局了。
如果是左边的内存布局,那随着数组下标的增⻓,往后越界就有可能覆盖到i,这样就可能造成循环的。
这⾥为什么 i 和 arr 数组之间恰好空出来2个整型的空间呢?这⾥确实是巧合,在不同的编译 器下可能中间的空出的空间⼤⼩是不⼀样的,代码中这些变量内存的分配 和地址分配是编译器指定的,所以的 不同的编译器之间就有差异了。所以这个题⽬是和环境相关的。
所以代码要进行以下修改:
所以,只有调试才能观察到程序内部执⾏的细节,就像医⽣给病⼈做B超,CT⼀样。
注意:栈区的默认的使⽤习惯是先使⽤⾼地址,再使⽤低地址的空间,但是这个具体还是要编译器的 实现。
⽐如: 在VS上切换到X64,这个使⽤的顺序就是相反的,在Release版本的程序中,这个使⽤的顺序也是相反的。
(在运行时,如果进入函数没有数组的全部内容,则需要输入数组名+“,(查看的数组个数)”
调试过程中,要做到⼼中有数,也就是程序员⾃⼰⼼⾥要清晰的知道希望代码怎么执⾏,然后再去看 代码有没有按照我们预定的路线在执⾏。
调试是需要反复去动⼿练习的,调试是可以增加程序员对代码的理解和掌控的,掌握了调试的能⼒, 就能看到本质,就像能给程序做B超⼀样,对程序内部⼀览⽆余。
2. 编译型错误
编译型错误⼀般都是语法错误,这类错误⼀般看错误信息就能找到⼀些蛛丝⻢迹的,双击错误信息也 能初步的跳转到代码错误的地⽅或者附近。编译错误,随着语⾔的熟练掌握,会越来越少,也容易解决。
3.链接型错误
看错误提⽰信息,主要在代码中找到错误信息中的标识符,然后定位问题所在。⼀般是因为 :
标识符名不存在
拼写错误
头⽂件没包含
引⽤的库不存在
4.运行错误
运⾏时错误,是千变万化的,需要借助调试,逐步定位问题,调试解决的是运⾏时问题。
(学习内容无偿分享,各位大佬觉得有帮助的话,三连哈,就是对我最大的支持!)