C语言从入门到进阶——第8讲:VS实用调试技巧

文章目录

  • [1. 什么是bug?](#1. 什么是bug?)
  • [2. 什么是调试(debug)?](#2. 什么是调试(debug)?)
  • [3. Debug 和 Release](#3. Debug 和 Release)
  • [4. VS调试快捷键](#4. VS调试快捷键)
    • [4.1 环境准备](#4.1 环境准备)
    • [4.2 核心调试快捷键](#4.2 核心调试快捷键)
  • [5. 监视和内存观察](#5. 监视和内存观察)
    • [5.1 监视](#5.1 监视)
    • [5.2 内存窗口](#5.2 内存窗口)
  • [6. 调试举例1:阶乘求和问题](#6. 调试举例1:阶乘求和问题)
  • [7. 调试举例2:数组越界导致死循环](#7. 调试举例2:数组越界导致死循环)
  • [8. 调试举例3:数组传参的调试](#8. 调试举例3:数组传参的调试)
  • [9. 编程常见错误归类](#9. 编程常见错误归类)
    • [9.1 编译型错误](#9.1 编译型错误)
    • [9.2 链接型错误](#9.2 链接型错误)
    • [9.3 逻辑型错误](#9.3 逻辑型错误)

1. 什么是bug?

bug本意是"昆虫"或"虫子",现在一般是指在电脑系统或程序中,隐藏着的一些未被发现的缺陷或问题,简称程序漏洞

"Bug"的创始人格蕾丝·赫柏(Grace Murray Hopper),她是一位为美国海军工作的电脑专家。1947年9月9日,格蕾丝·赫柏对Harvard Mark II设置好17000个继电器进行编程后,技术人员正在进行整机运行时,它突然停止了工作。于是他们爬上去找原因,发现这台巨大的计算机内部一组继电器的触点之间有一只飞蛾,这显然是由于飞蛾受光和热的吸引,飞到了触点上,然后被高电压击死。所以在报告中,赫柏用胶条贴上飞蛾,并把"bug"来表示"一个在电脑程序里的错误","Bug"这个说法一直沿用到今天。

2. 什么是调试(debug)?

当我们发现程序中存在问题时,下一步就是找到问题并修复问题。

这个找问题的过程称为调试 ,英文叫debug(消灭bug)。

调试一个程序,首先要承认出现了问题,然后通过各种手段定位问题的位置(可能是逐过程调试,也可能是隔离和屏蔽代码的方式),找到问题所在后确定错误产生的原因,再修复代码并重新测试。

3. Debug 和 Release

在VS上编写代码时,会看到有debugrelease两个选项,二者区别如下:

特性 Debug(调试版本) Release(发布版本)
核心用途 程序员调试程序 交付用户使用
调试信息 包含完整调试信息 无调试信息
代码优化 不做任何优化 进行多种优化(代码大小、运行速度最优)
文件大小 较大 较小

程序员开发阶段需将VS设置为Debug模式,便于调试;程序测试通过后切换为Release模式,生成用户使用的最终版本。

4. VS调试快捷键

4.1 环境准备

首先需将VS环境设置为Debug模式,如图:

4.2 核心调试快捷键

快捷键 功能说明
F9 创建断点和取消断点;右击断点可以设置条件断点(满足指定条件才触发)
F5 启动调试,直接跳到下一个断点(需配合F9使用)
F10 逐过程调试:执行一个过程(函数调用或单条语句),不进入函数内部
F11 逐语句调试:执行单条语句,可进入函数内部观察细节(函数调用处需用F11)
CTRL + F5 开始执行不调试:直接运行程序,无需进入调试模式

更多VS快捷键参考:http://blog.csdn.net/mrlisky/article/details/72622009

5. 监视和内存观察

调试过程中,可通过监视窗口内存窗口 观察变量的值及存储情况,前提是已启动调试(F5、F10或F11进入调试状态)。

示例代码:

c 复制代码
#include <stdio.h>
int main()
{
    int arr[10] = { 0 };
    int num = 100;
    char c = 'w';
    int i = 0;
    for (i = 0; i < 10; i++)
    {
        arr[i] = i;
    }
    return 0;
}

5.1 监视

菜单栏【调试】->【窗口】->【监视】,打开任意一个监视窗口(监视1~4均可)。

在监视窗口的"名称"列输入要观察的变量名、数组名等,即可实时查看其值。

5.2 内存窗口

如果监视窗口看的不够仔细,也可以观察变量在内存中的存储情况。

菜单栏【调试】->【窗口】->【内存】,打开任意一个内存窗口(内存1~4均可)。

在内存窗口中观察数据:

在内存窗口的"地址"栏输入变量地址(如&arr&num),即可查看该地址处的内存数据(以16进制形式展示)。

除此之外,调试时还可打开自动窗口、局部变量、反汇编、寄存器等窗口。

6. 调试举例1:阶乘求和问题

1!+2!+3!+...+10!的和,以下代码运行结果错误,通过调试定位问题:

c 复制代码
#include <stdio.h>
int main()
{
    int n = 0;
    int i = 1;
    int ret = 1;
    int sum = 0;
    for(n = 1; n <= 10; n++)
    {
        for(i = 1; i <= n; i++)
        {
            ret *= i;
        }
        sum += ret;
    }
    printf("%d\n", sum);
    return 0;
}

调试思路

  1. 设断点:在sum += ret;处设置断点(F9);
  2. 启动调试(F5),通过监视窗口观察retsum的值;
  3. 发现ret未在每次计算新阶乘前重置为1,导致累加错误;
  4. 修复方案:在内部循环前添加ret = 1;

7. 调试举例2:数组越界导致死循环

在VS2022、X86、Debug环境下,以下代码执行后死循环,调试分析原因:

c 复制代码
#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("hehe\n");
    }
    return 0;
}

调试分析

  1. 内存布局:栈区内存从高地址向低地址分配,变量i的地址高于arr数组的地址;
  2. 数组越界:当i=12时,arr[12]越界访问,恰好覆盖变量i的内存;
  3. 死循环原因:arr[12] = 0导致i被错误地重置为0,循环条件i <= 12永远成立。
  • 栈区内存分配顺序与编译器、系统位数(X86/X64)、编译模式(Debug/Release)相关;
  • X64或Release模式下,内存布局可能相反,该代码可能不会死循环。

8. 调试举例3:数组传参的调试

c 复制代码
void test1(int d[])
{

}

int main()
{
	int data[10] = {1,3,5,7,9};
	test1(data);
	return 0;
}
c 复制代码
void test2(int a[3][5])
{

}

int main()
{
	int arr[3][5] = {1,2,3,4,5 ,2,3,4,5,6 ,3,4,5,6,7};
	test2(arr);
	return 0;
}

调试思路

  1. 在数组传参的函数内部打断点,快速跳转到函数
  2. 调试进入函数,在监视窗口观察数组的内容:
    • 一维数组:在监视窗口输入数组名,元素个数(如d,10
    • 二维数组:在监视窗口输入数组名,行数(如a,3
    • 不加元素个数/行数时,调试器无法完整展示数组内容,只能看到首元素或起始地址,如图:

调试核心原则:明确代码预期执行流程,通过调试验证实际执行是否与预期一致,根据差异点定位问题。

9. 编程常见错误归类

9.1 编译型错误

  • 本质:语法错误
  • 常见原因:缺少分号、括号不匹配、关键字拼写错误
  • 排查方法:查看错误列表的提示信息,双击错误可跳转到错误位置或附近

9.2 链接型错误

  • 本质:标识符未定义或引用失败
  • 常见原因:标识符不存在、标识符拼写错误、头文件未包含、引用的库不存在

9.3 逻辑型错误

  • 本质:代码逻辑错误(编译和链接均无错误,但出现运行时崩溃、结果异常等问题)
  • 常见原因:数组越界、空指针访问、变量未初始化
  • 排查方法:必须通过调试逐步定位问题,观察程序执行过程中的变量值、内存状态等
相关推荐
m0_531237171 小时前
C语言-数组
c语言·开发语言·算法
2401_876907521 小时前
Type-C连接器的常见故障和解决方法
c语言·开发语言
啊阿狸不会拉杆1 小时前
《计算机视觉:模型、学习和推理》第 4 章-拟合概率模型
人工智能·python·学习·算法·机器学习·计算机视觉·拟合概率模型
ADDDDDD_Trouvaille1 小时前
2026.2.20——OJ92-94题
c++·算法
宇木灵2 小时前
C语言基础-四、函数
c语言·开发语言·前端·学习
HoneyMoose2 小时前
Jenkins 更新时候提示 Key 错误
java·开发语言
csbysj20202 小时前
XSLT `<template>` 标签详解
开发语言
hansang_IR2 小时前
【题解】类欧几里得算法
c++·数学·算法·类欧几里得