【C】实用调试技巧

目录

 

调试

Debug和Release

快捷键

查看程序当前信息

调试案例

如何写出好的代码

模拟实现库函数:strcpy


调试

新手程序员80%的时间在写代码,20%的时间在调试,老程序员20%的时间在写代码,80%的时间在调试。

什么是调试?

控制代码一步步执行,根据各种信息找到程序错误原因的过程就叫调试。

为什么需要调试?

当我们的代码出错的时候,只看表面的代码很多时候是看不出问题所在的,我们需要通过调试看到代码里面的东西。

Debug和Release

我们编译器中的代码可以生成两种版本:Debug和Release。

在代码还没执行过的时候,我们的文件中只有三个文件

执行完debug版本,多出debug文件 

再执行依次release版本,多出release文件

 区别

debug为调试版本,它包含调试信息,且不做任何优化

release为发布版本,进行了各种优化,代码大小和性能都是最优

快捷键

F5

启动调试,经常和F9配合跳到下一个断点。

F9

创建断点、取消断点

断点:控制程序停止,鼠标点击左侧也可创建断点

条件断点:

当程序满足设置的条件时停下,常用在循环内。

 例:设条件表达式,当 i ==10时停下,

 当下一个断点为该断点时,按下F5,直接执行到 i ==10时停止。

F10

逐条处理,将函数看为一整条指令

F11

进入函数内部

Ctrl+F5

直接执行程序不调试

注:如果键盘上有Fn键则需要Fn+以上快捷键才生效

更多快捷键点这里

查看程序当前信息

查看临时变量

 

 查看调用堆栈

清楚地反应函数调用关系级当前所处函数

 查看汇编信息

查看寄存器信息 

调试案例

下列代码输出结果是什么?

int main()
{
	int i = 0;
	int arr[10] = { 0 };
	for (i = 0; i <= 12; i++)
	{
		arr[i] = 0;
		printf("Hello");
	}
	return 0;
}

答案:死循环

一起通过调试来探究一下

 

通过调试可以看到在 i 处于0~11时一切正常(访问时为0,再设成0),当访问到第十二个下标的时候,进来发现 i 是12,当把 arr [12] 设成0的时候,i 也变成了0,由此就可以得到答案:arr [12] 就是 i ,当 i 被设为0,再次进入循环,由此出现死循环。

 打印出两个变量的地址,可以看到他们的地址是一样的。

为什么会出现地址一样的情况?

在栈区中存储数据的方式是先使用高地址再使用低地址的。而数组随着下标的增长,地址是从低到高变化的。

 当 i 和arr 之间有适当的距离时,利用数组越界操作就可能覆盖到 i 。而每个编译器的情况都是不一样的。

如何写出好的代码

1、使用 assert 避免空指针。

2、尽量使用 const 。

3、添加必要注释。

模拟实现库函数:strcpy

strcpy 是将一个字符串拷贝到另一个字符串变量中的函数。需要包含头文件<string.h>.

void my_strcpy(char* arr1, char* arr2)
{
	while (*arr2!='\0')
	{
		*arr1 = *arr2;
		arr1++;
		arr2++;
	}
	*arr1 = *arr2;//将最后的'\0'也拷贝进去
}

第一次优化:

void my_strcpy(char* arr1, char* arr2)
{
	while (*arr2!='\0')
	{
		*arr1++ = *arr2++;//赋值完后直接++
	}
	*arr1 = *arr2;//将最后的'\0'也拷贝进去
}

第二次优化:

void my_strcpy(char* arr1, char* arr2)
{
	while (*arr1++ = *arr2++)//(*arr1++ = *arr2++)最后返回赋值字符的ASCII码值
	{                        //最后先赋值'\0',再判断循环条件为假,退出循环
		;//执行空语句
	}
}

第三次优化:

void my_strcpy(char* arr1, const char* arr2)//因为赋值的字符串是不需要进行改变的,所以const修饰
{
	while (*arr1++ = *arr2++)//(*arr1++ = *arr2++)最后返回赋值字符的ASCII码值
	{                        //最后先赋值'\0',再判断循环条件为假,退出循环
		;//执行空语句
	}
}

第四次优化:

void my_strcpy(char* arr1, const char* arr2)//因为赋值的字符串是不需要进行改变的,所以const修饰
{
	assert(arr2 != NULL);//断言arr2不为空指针,若为空指针,程序报错
	assert(arr1 != NULL);
	while (*arr1++ = *arr2++)//(*arr1++ = *arr2++)最后返回赋值字符的ASCII码值
	{                        //最后先赋值'\0',再判断循环条件为假,退出循环
		;//执行空语句
	}
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值