debug和release的区别
debug包含调试信息 文件通常都比release版本大
调试代码快捷键
实例1:数组越界访问
实例1代码在bebug版本下可能会死循环(不同编译器结果不同)
局部变量是在栈区上分配内存的
实例1中 i 和 arr 都是局部变量
1.栈区的默认使用:
先使用高地址处的空间 再使用低地址的空间
2.数组随着下标的增长 地址是由低到高的
根据这两条信息可以推断出 i 和 arr 在栈区上的相对位置
死循环解释:
1.i和数组arr都是局部变量 局部变量都是在栈区上使用的
且栈区是先使用高地址再使用低地址的空间 所以i会创建在比arr高的地址上
循环开始的时候 随着数组下标的增长 地址由低到高
在数组越界访问的时候 就有可能访问到i的地址 改变i的值 从而进入死循环
但在release版本下 此代码不会报错
原因:在debug模式下,变量的分配空间顺序与变量的声明顺序一致。先声明就先分配空间。
在release版本下,对数组进行了优化,会先分配数组的空间 也就是arr在高地址 i在低地址
也就不会发生数组越界访问到i的情况
解决方法:可以先声明数组然后再声明变量i
实例2:调用堆栈的使用
如图代码 main 函数 调用 test1函数 test1函数 调用test2函数
函数的调用也是在栈上开辟空间的
调用堆栈:像栈一样的形式来展示函数调用的逻辑
从顶上放元素 也先从顶上出元素
调用完函数后 从顶上开始结束函数 最后来到main函数这里
调用堆栈很好的反映了函数是如何一步一步的调用的
实例3:计算阶乘1!+2!+3!+...+n!
此代码有错 当输入n = 3时 结果本应该时 1!+2!+3! =9 但程序结果却是15
通过F10一步一步调试 原因如下:
发现当计算2!的时候 ret 的变成了2 也就是说ret的累乘效果没有取消, ret == 2的结果一直在往后的循环中累计使用,导致ret一直在变大 结果也跟着变大。
想要计算的是1!+2!+...+n!
但是此代码算成了1!+1!2!+1!2!3!+...+1!2!...n!
计算阶乘的原理: 输出1-n的数字 然后乘到一个变量(ret)上去 也就是说 影响结果因素只有输入的n的大小,变量ret只是用来接收乘积结果的。
错误的原因就在这里:ret变量的值没有重复初始化为1
通过一步步调试 很快就找到了错误的原因
此代码还有可以进行优化 :利用 ret 的累乘效果 原理:n!=(n-1)!*n
在每一次for循环结束前 及时把ret加到sum上去
实例4:模拟字符串拷贝函数strcpy()
strcpy函数功能 拷贝source(源头)字符串到 Destination(目的地) 拷贝的字符包括'\0'
模拟strcpy函数 my_strcpy
原理:把要拷贝的数组传参之后 解引用对被覆盖的数组进行赋值 判断条件为*str != '\0'
最后再把'\0'字符拷贝
由于把'\0'字符也一并拷贝过去了 printf打印的时候 遇到\0停止打印 打印结果相同
此代码有四个地方可以优化
1.
while循环条件可以改成复合赋值符的形式
2.
给非被覆盖数组const修饰
原因:用const修饰 防止数组传参的时候不小心写反了 这时候 src就是被覆盖数组 程序就会报错 因为const修饰的常变量 无法被修改
3.
assert断言
防止dest和src传过来的时候是空指针 影响拷贝
4.
返回值
拷贝完成后,将dest的首元素地址返回
完整代码如下:
最后用相同的思路模拟求字符串长度的函数strlen()