C语言-实用调试技巧

201 阅读4分钟

实用调试技巧

一、调试

1. bug是程序中存在的缺陷或错误,从而导致程序的运行结果不符合预期

2. 调试就是除错,是发现和减少程序错误的一个过程

3. Debug称为调试版本,包含调试的各种信息,通常所占内存空间比release版本大,不对代码进行优化,便于程序员调试程序

4. Release称为发布版本,对代码进行各种优化,在运行大小和速度方面都是最优的,便于用户使用

例:

#include <stdio.h>
int main()
{
int i=0;
int arr[10]={0};
for(i=0;i<=12;i++)
 {
 arr[i]=0;
 printf("haha\n");
 }
 return 0;
}

● 如果在Debug版本下运行,程序会进入死循环,而在Release版本下则不会,这是因为Release版本对其进行了优化

● 为什么Debug版本下会陷入死循环?

1. 这是因为创建变量i需要开辟栈区空间,栈区空间内存使用习惯是先使用高地址,后使用低地址

2. 而数组随下标的增加,由低地址向高地址变化

3. 若数组与i之间存在适当空间,利用数组越界的操作则可能覆盖变量i的内存空间,这时变量i随越界的数组元素被赋值为0,一直满足i<=12,陷入死循环

图解如下:

屏幕截图 2024-12-10 092425.png

二、Windows环境调试介绍

1. 调试需在Debug版本下进行

2. 一些快捷键的使用:

● F5:启动调试,通常用来直接跳到下一个断点处

● Ctrl+F5:开始执行不调试,让程序运行起来但不调试

● F9:创建和删除断点,可以在任意位置设置断点,使程序运行到设置的断点处暂停执行

● F10:在主函数内部逐过程调试,一个过程可以是一条语句,也可以是一次函数调用,但并不会进入调用函数的内部

● F11:从主函数开始逐语句调试,执行逻辑会进入调用函数的内部,这区别于F10

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

● 利用F10,F11或程序运行到断点处暂停执行时通过调试的窗口查看临时变量,内存,反汇编等相关信息

屏幕截图 2024-12-10 172236.png

三、一些调试实例

例:模拟实现strcpy函数,将一个字符串的内容拷贝到另一个字符串中

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* arr1,const char* arr2)//定义一个字符串拷贝函数,arr1是目标空间指针,arr2是源字符串指针
                                            //const char* arr2避免了源字符串内容被改变
                                            //返回值为目标空间的起始地址,是为了实现函数的链式访问
{         
    char* ret=arr1;
	assert(arr1 != NULL && arr2 != NULL);//断言指针arr1和arr2不是空指针,若为空指针调试时会报错
	while (*arr1++ = *arr2++)//*arr++表示先解引用指针arr,再将arr+1
                             //每将源字符串的一个字符拷贝到目标空间后,指针加一
                             //直到将源字符串的'\0'拷贝过去使表达式的结果为假,循环结束
	{
		;
	}
    return ret;
}
int main()
{
	char arr1[] = "XXXXXXXXXXXXXXXXXXXXXX";
	char arr2[] = "hello.";
	my_strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

例:const修饰指针变量

#include <stdio.h>
void test1()
{
	int a = 10;
	int b = 20;
	int* p = &a;
	*p = 60;
	*p = &b;
}
void test2()
{
	int a = 10;
	int b = 20;
	const int* p = &a;//const放在*左边,不能改变p所指向对象a的值,但能改变p的值
	*p = 60;
	p = &b;
}
void test3()
{
	int a = 10;
	int b = 20;
	int* const p = &a;//const放在*右边,不能改变p的值,即不能改变它所指向的对象,但能改变所指向对象a的值
	*p = 60;
	p = &b;
}

系统提示错误:

屏幕截图 2024-12-08 160801.png

由此可见,

const放在*左边,不能改变指针所指向对象的值,但能改变指针的值

const放在*右边,不能改变指针的值,但能改变指针所指向对象的值

四、编译常见错误

1. 编译型错误:编译器报错的错误,如语法错误一条语句结束未加分号等

2. 链接型错误:一般是指标识符错误,包括标识符名不存在或拼写错误。如调用函数时,该函数此前未定义或调用时函数名拼写错误

3. 运行时错误:程序正常运行,但结果不符合预期,需通过调试逐步定位问题,较难发现