1.Debug 和Release版本的介绍
Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。
Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优
的,以便用户很好地使用。
代码编译完成后,会生成debug和release版本(生成对应的.exe文件),release版本经过优化,所占内存空间大小变小
2.常用的快捷键
2.1调试中常用的快捷键:
F5
启动调试,经常用来直接跳到下一个断点处。
F9
创建断点和取消断点
断点的重要作用,可以在程序的任意位置设置断点。
这样就可以使得程序在想要的位置随意停止执行,继而一步步执行下去。
F10
逐过程,通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句。
F11
逐语句,就是每次都执行一条语句,但是这个快捷键可以使我们的执行逻辑进入函数内部(这是最长用的)。
CTRL + F5
开始执行不调试,如果你想让程序直接运行起来而不调试就可以直接使用。
2.2 编译中常用的快捷键:
Ctrl + Z
撤回上一步操作
Ctrl + X
剪切当前行代码
Ctrl + F
查找文件中所要查找的内容
Ctrl + A
全选
3. 调试实例
3.1 实例一
实现代码:求 1!+2!+3! …+ n! ;不考虑溢出。(求n的阶乘之和)
1!+2!+3!应该等于9,但是打印输出的结果却是15
这时候就需要用到调试来解决
计算1!,sum=1,没出现问题
计算2!,ret=2,sum=3,没问题
但是,在计算3!时,发现 ret =12,3的阶乘应该为6,ret=2*6
所以,我们发现在每一次计算阶乘时都应该将ret的值赋成1
3.2 实例二
判断以下代码的输出结果
#include <stdio.h>
int main()
{
int i = 0;
int arr[10] = {0};
for(i=0; i<=12; i++)
{
arr[i] = 0;
printf("hehe\n");
}
return 0;
}
代码会死循环的打印hehe,按照代码逻辑:虽然数组越界访问,但是打印13个hehe,循环应该结束
通过调试,发现for循环在执行第13打印的时候,把arr[12]的值改为0的同时,i 的值也被修改为0,所以导致循环无法停止
再对arr[12]和i 分别取地址,发现二者的地址相同,也就是说指向的是同一块空间
具体原因是为啥呢?
局部变量的开辟是在栈区开辟的,而栈区的使用习惯是先使用高地址处的空间,再使用低地址,i 变量最先创建,再创建数组空间,而数组是随着下标的增长地址由低到高变换的,如果数组进行越界访问就有可能覆盖到i的值,出现死循环。这里的越界几个空间取决于编译器,而不能死记2个内存空间
应当切记,数组不能越界访问
补充Debug和Release版本的区别
栈区的使用习惯先使用高地址,再使用低地址 在Debug版本下 i 在高地址处,arr 在低地址处
而在Release版本下 i 在低地址处 arr在高地址处,也就是说release版本更改了栈区开辟的顺序
在Debug版本中, 数组的下标由低地址到高地址的过程中,for循环造成越界访问,覆盖了i的值导致一直死循环
而release版本下 for循环虽然越界了但是没有覆盖到i的值,所以不会一直死循环,而是会打印出13个hehe。
release版本对内存的开辟发生变化,改变了默认的由低到高开辟内存空间。这样的优化有好处,一定程度上避免代码出现死循环。
4. 如何写出优秀的代码
4.1模拟实现strcpy
版本1:
略显冗余,\0和字符的处理是分开的
版本2:
版本3:
const 修饰 * src 表示的是src中指向的对象内容不可改变,但是src本身可改变
最终版本:
4.2 模拟实现strlen
断言,返回类型,const修饰
5. const修饰的含义
同时在左右两侧加上const修饰表示即不可修改p所指向的对象的值,也不可修改p变量本身