调试意义、步骤及方式

调试

1.什么是bug?

在这里插入图片描述

一只死在继电器上的飞蛾,被戏称为计算机史上的一个“bug”。

调试便是找bug的过程。

2.调试是什么?有多重要?

2.1调试

调试(Debugging/Debug),又称除错,是发现和减少计算机程序或电子仪器设备中程序错误的一个过程。

2.2调试的基本步骤

  • 发现程序错误存的存在
  • 以隔离,消除等方式对错误进行定位
  • 确定错误产生的原因
  • 提出纠正错误的解决方法
  • 对程序错误予以改正,重新测试

发现bug的可能是:1.程序员自己 2.测试人员3.客户

2.3Debug和Release的介绍

Debug通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序

Release称为发布版本,它往往是进行各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好的使用

使用Debug和Release分别进行运行后,文件夹中会产生对应的两个文件

在这里插入图片描述

使用Debug版本可以进行调试等操作,Release版本则没有调试信息

在这里插入图片描述

2.3.1常用的快捷键及功能
1.F5

启动调试,经常用来直接跳到下一个断点处。

2.F9

创建断点和取消断点

断点的重要作用,可以在程序的任意位置设置断点。

这样就可以使得程序在想要的位置随意停止执行,继而一步步执行下去。

在这里插入图片描述

选中需要停止的行后,使用快捷按键F9即可设置断点。在使用F5调试程序时将会在第11行停止调试。

多个断点位置,F5后将会在下一个逻辑断点处停下。

在这里插入图片描述

如图第一个断点的位置在第13行(一个循环体结构中),我们在该断点继续执行语句,那么逻辑的下一个断点将会是它的第二次循环而不是第15行的断点。

断点也可以通过鼠标直接单击断点位置进行添加和取消断点。

条件断点

鼠标右击断点可对断点进行条件设置,
图中我们对断点进行了条件设置,条件为当i==5时,该断点生效。如图:

在这里插入图片描述生效后如图:

在这里插入图片描述

i==5时生效,停止输出后面的语句。

3.F10

逐过程,就是每次都执行一条语句,一个过程可以是一次函数调用或一条语句。

F10与F11在普通的语句中没有什么区别,有区别的是函数上。

F10会把函数当作普通的语句直接跳过,而F11可以进入函数内部查看函数运行的过程

4.F11

逐语句,就是每次都执行一条语句,但是这个快捷键可以使我们的执行逻辑进入函数内部(这是最常用的)。

5.CTRL+F5

开始执行不调试,如果你想让程序不调试直接运行

3.调试的时候查看程序当前信息

3.1查看临时变量的值

在调试开始之后,用于观察变量的值。

调试起来后,才可以查看下面的选项。

在这里插入图片描述

3.1.1自动窗口

自动串口可以自动获取变量的值。

不过,在调试的过程(比如进入函数内部),那么当前的变量会自动消失,被函数内部的变量取代。(过于自作主张)观察数据不方便。

在这里插入图片描述

简言之,就是会自动获取变量的监视窗口。

3.1.2监视

在调试开始之后,用于观察变量的值。

在这里插入图片描述

3.1.2.1数据结构怎么监视多个数据

数组结构在函数中正常的查看只能查看第一个数据。

我们可以使用(a,个数)来获取对应个数的数组元素。

在这里插入图片描述

a,10就是获取10个元素的。

3.1.3内存的查看及解析

调试后可通过窗口——>内存,查看内存

在这里插入图片描述

内存中的数据解析:

在这里插入图片描述

3.1.4调用堆栈

在调试的情况下,在调试窗口——>调用堆栈

可以查看函数的调用情况(谁被谁调用),

在这里插入图片描述

上面的函数被下面的函数调用:

行9被行13调用,而行13被行17调用……

在这里插入图片描述

数据结构中的栈;

4.一个调试的案例

对数组进行越界访问。

# define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

int main() {
	int i = 0;
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	for ( i = 0; i <= 12; i++)
	{
		arr[i] = 0;
		printf("haha\n");
	}

	return 0;
}

上面的代码运行后可能会出现循环。

原因:

下图所示,未定义的第12个数组元素默认的值为12,且与i的大小相同

在这里插入图片描述

接着运行程序对arr[12]进行修改,发现i也等于0:

在这里插入图片描述

原因就是:

在这里插入图片描述

5.如何写出好的代码(易于调试)

5.1优秀的代码

  1. 代码正常运行
  2. bug很少
  3. 效率高
  4. 可读性高
  5. 可维护性高
  6. 注释清晰
  7. 文档齐全

常见的coding技巧

  1. 使用assert
  2. 尽量使用const
  3. 养成良好的编码风格
  4. 添加必要的注释
  5. 避免编码的陷阱
技巧1:assert

断言,直接拦截错误

例子:编写函数完成strcpy库函数的功能,使用assert进行拦截空指针

# define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <assert.h>

//2.实现库函数strcpy
void my_strcpy(char* dest, char* str) {
	//断言,判断,如果错误讲直接报错
	assert(str != NULL);
	//因为是赋值所以为真,但*str等于0时,*dest也等于0,ASCII码值为0,为假停止
	while (*dest++ = *str++) {
		;
	}
}

int main() {
	char ch1[20] = "XXXXXXXXXXXXX";
	char ch2[] = "hello World!";
    
	int* p = NULL;
	//my_strcpy(ch1, ch2);
	my_strcpy(ch1, p);
	printf("%s", ch2);
}

assert返回错误的位置:

在这里插入图片描述

技巧2:const

const 修饰指针变量

1.const 放在*号左边(const int *p= &num;)

意思是:p指向的对象不能通过p来改变了,但是p本身的值可以改变

2.const放在*号右边(int* const p = &num;)

意思是:p指向的对象是可以通过p来改变的,但不能修改p变量本身的值

1.const 放在*号左边

普通的变量可以使用赋值进行修改:

int num = 10;
num = 20;

使用const修饰后就不能修改:

const int num = 10;
num = 20;//报错:表达式必须是可以修改的左值

但使用const修饰后也并非不可以改,可以获取指针进行修改:

const int num = 10;
int *p= &num;
*p = 20;
printf("%d", num);

使用const修饰指针变量后,就不能通过指针变量修改变量了:

const int num = 10;
const int *p= &num;
*p = 20;//报错:表达式必须是可以修改的左值

指针变量指向的对象不能改变,但指针可以改变

const int num = 10;
const int *p= &num;
int n = 10;
//*p = 20;//erro
p = &n;//ok
2.const放在*号右边

限制p变量本身

const int num = 10;
int* const p = &num;
int n = 20;
p = &n;
使用assert和const优化求字符长度的函数
# define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>

//传入数据使用const修饰,防止出现bug时被修改
int my_strlen(const char* str) {
    //判断是否是空指针
	assert(str != NULL);
	int count = 0;
	while (*str != '\0')
	{
		count++;
		str++;
	}

	return count;
}

int main() {
	char str[] = "hello World!";
	int len = my_strlen(str);
	printf("%d", len);
}

6.编程常见的错误

6.1编译型错误(语法错误)

直接看错误提示信息(双击),解决问题。或者凭借经验就可以搞定。相对简单。

6.2链接型错误(出现在链接期间)

链接型错误(出现在链接期间)- 找不到符号(1.不存在。2.写错了)

看错误提示信息,主要在代码中找到错误信息中的标识符,然后定位问题所在。一般是标识符名不存在或者拼写错误

例如:

int a = 0;
int b = 0;
int c = Add(a,b);//未定义
//无法解析外部符号Add

printf("%d",c);

无法通过点击跳转到对应位置

6.3运行时错误

借助调试,逐步定位问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值