初阶C语言——实用调试技巧【详解】

news2024/11/24 13:31:03

文章目录

  • 1. 什么是bug?
  • 2. 调试是什么?有多重要?
    • 2.1 调试是什么?
    • 2.2 调试的基本步骤
    • 2.3 Debug和Release的介绍
  • 3.学会使用快捷键
  • 4.调试的时候查看程序当前信息
    • 4.1 查看临时变量的值
    • 4.2 查看内存信息
    • 4.3 查看调用堆栈
    • 4.4 查看汇编信息
    • 4.5 查看寄存器信息
  • 5. 一些调试的实例
    • 5.1 实例一
    • 5.2 实例二
    • 5.3 大代码如何调试
  • 6. 如何写出好(易于调试)的代码
    • 6.1 优秀的代码:
    • 6.2 示范
    • 6.3 const的作用
  • 7. 编程常见的错误

1. 什么是bug?

bug是计算机领域专业术语,原意是臭虫。现在用来指代计算机上存在的漏洞。

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

所有发生的事情都一定有迹可循,如果问心无愧,就不需要掩盖也就没有迹象了,如果问心有愧,就必然需要掩盖,那就一定会有迹象,迹象越多就越容易顺藤而上,这就是推理的途径。
顺着这条途径顺流而下就是犯罪,逆流而上,就是真相。

一名优秀的程序员是一名出色的侦探。

2.1 调试是什么?

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

2.2 调试的基本步骤

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

2.3 Debug和Release的介绍

Debug 通常称为调试版本
它包含调试信息,并且不作任何优化,便于程序员调试程序。
Release称为发布版本
它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。

代码:

#include <stdio.h>
int main()
{
	char* p = "hello bit.";
	printf("%s\n", p);
	return 0;
}

上述代码在Debug环境的结果展示:
在这里插入图片描述
上述代码在Release环境的结果展示:
在这里插入图片描述
在环境中选择 debug 选项,才能使代码正常调试。

3.学会使用快捷键

在这里插入图片描述
最常使用的几个快捷键:
F5

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

F9

创建断点和取消断点
断点的重要作用,可以在程序的任意位置设置断点。 这样就可以使得程序在想要的位置随意停止执行,继而一步步执行下去。

F10

逐过程,通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句。

F11

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

CTRL + F5

开始执行不调试,如果你想让程序直接运行起来而不调试就可以直接使用

Fn

辅助功能键

如果一个代码循环一千多次,而我们认为他的错误在四百次的地方时,要怎么调试?
这时我们就可以给他加一个触发断点的条件,或者使用一个if语句来进行判断。如下图所示:
在这里插入图片描述
在这里插入图片描述

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

通过调试下的窗口键来进行查看
在这里插入图片描述

4.1 查看临时变量的值

在调试开始之后,用于观察变量的值。
在这里插入图片描述

4.2 查看内存信息

在调试开始之后,用于观察内存信息。
在这里插入图片描述
显示内存结果:
在这里插入图片描述

4.3 查看调用堆栈

栈:
只能从顶上放入,再从顶上删除
在这里插入图片描述

在这里插入图片描述
通过调用堆栈,可以清晰的反应函数的调用关系以及当前调用所处的位置。

4.4 查看汇编信息

在这里插入图片描述
可以切换到汇编代码。

4.5 查看寄存器信息

在这里插入图片描述
可以查看当前运行环境的寄存器的使用信息。

5. 一些调试的实例

5.1 实例一

实现代码:求 1!+2!+3! …+ n! ;不考虑溢出。

#include <stdio.h>
int main()
{
	int i = 0;
	int sum = 0;//保存最终结果
	int n = 0;
	int ret = 1;//保存n的阶乘
	scanf("%d", &n);
	for (i = 1; i <= n; i++)
	{
		int j = 0;
		for (j = 1; j <= i; j++)
		{
			ret *= j;
		}
		sum += ret;
	}
	printf("%d\n", sum);
	return 0;
}

这时候我们如果3,期待输出9,但实际输出的是15
这时候我们就得通过调试找我们问题。
在这里插入图片描述

通过调试,我们发现问题出现在ret的值上,ret的值为每次结果值的累积效果,所以在循环内部令ret=1,结果就为我们想要的结果。

代码修改后:

#include <stdio.h>
int main()
{
	int i = 0;
	int sum = 0;//保存最终结果
	int n = 0;
	int ret = 1;//保存n的阶乘
	scanf("%d", &n);
	for (i = 1; i <= n; i++)
	{
		ret = 1;
		int j = 0;
		for (j = 1; j <= i; j++)
		{
			ret *= j;
		}
		sum += ret;
	}
	printf("%d\n", sum);
	return 0;
}

运行结果:
在这里插入图片描述

5.2 实例二

#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;
}

在这里插入图片描述
数组越界访问,我们发现程序并不会崩溃而是陷入死循环,这是为什么呢?
在这里插入图片描述
通过调试我们发现arr[12]与i的地址一样,改变arr[12]就改变了i
在这里插入图片描述

arr与i之间到底空几个空间取决于编译器的内存分配
vc6.0 中间没有空间
gcc 中间空一个整形
vs 中间空两个整形

注: 这个代码的运行结果是和环境相关的!

5.3 大代码如何调试

在这里插入图片描述
例如我们写过的三子棋,当出现问题时,我们可以在感觉有问题的模块放上断点来进行调试。

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

6.1 优秀的代码:

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

常见的coding技巧:

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

6.2 示范

模拟实现库函数:strcpy
strcpy
string copy —— 字符串拷贝

在这里插入图片描述
代码演示:

#include <stdio.h>
#include <assert.h>
//strcpy函数返回的是目标空间的起始地址

char* my_strcpy(char* dest, const char* src)
{
	//断言 - 保证指针的有效性
	assert(dest && src);
	char* ret = dest;
	//把src指向的字符串拷贝到dest指向是的数组空间,包括\0字符
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}

int main()
{
	char arr1[] = "hello world";
	char arr2[20] = { 0 };
	//链式访问
	printf("%s\n", my_strcpy(arr2, arr1));

	return 0;
}

6.3 const的作用

代码演示:

#include <stdio.h>
//代码1
void test1()
{
	int n = 10;
	int m = 20;
	int* p = &n;
	*p = 20;//ok?
	p = &m; //ok?
	printf("%d\n", m);
}
void test2()
{
	//代码2
	int n = 10;
	int m = 20;
	const int* p = &n;
	p = &m; //ok
	//*p = 20;//no
	printf("%d\n", m);
}
void test3()
{
	int n = 10;
	int m = 20;
	int* const p = &n;
	*p = 20; //ok
	//p = &m; //no
	printf("%d\n", m);
}
int main()
{
	//测试无cosnt的
	test1();
	//测试const放在*的左边
	test2();
	//测试const放在*的右边
	test3();
	return 0;
}

结论:
const修饰指针变量的时候:

  1. const 放在*的左边, *p不能改了,也就是p指向的内容,不能通过p来改变了。但是p是可以改变的,p可以指向其他的变量
  2. const 放在的右边,限制的是p,p不能改变,但是p指向的内容p,是可以通过p来改变的

练习:

模拟实现一个strlen函数
参考代码:

#include <stdio.h>
#include <assert.h>
int my_strlen(const char* str)
{
	int count = 0;
	assert(str != NULL);
	while (*str)//判断字符串是否结束
	{
		count++;
		str++;
	}
	return count;
}
int main()
{
	const char* p = "abc";
	//测试
	int len = my_strlen(p);//strlen函数求\0之前字符串的长度
	printf("len = %d\n", len);
	return 0;
}

7. 编程常见的错误

1.编译型错误

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

例如语句后的分号
在这里插入图片描述

2. 链接型错误

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

例如:
在这里插入图片描述

3.运行时错误

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

关于调试技巧的讲解七七就分享到这了,有什么问题或者需要改进的地方欢迎评论区留言,或者私信都可以哦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/385336.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

混凝土搅拌站远程监控解决方案

一、项目背景 随着大规模的基础设施建设&#xff0c;对混凝土搅拌设备的需求量日益增加&#xff0c;对其技术指标的要求也日益提高&#xff0c;其技术性能将直接关系到工程的质量和使用寿命。而混凝土生产的质量是在生产过程中形成的&#xff0c;而非最终强度的检测。混凝土生…

10 面向接口编程(上):一切皆服务,服务基于协议

按照面向接口编程的理念&#xff0c;将每个模块看成是一个服务&#xff0c;服务的具体实现我们其实并不关心&#xff0c;我们关心的是服务提供的能力&#xff0c;即接口协议。那么框架主体真正要做的事情是什么呢&#xff1f;其实是&#xff1a;定义好每个模块服务的接口协议&a…

That引导的宾语从句

That引导的宾语从句指的是that为宾语从句的引导词。宾语从句&#xff1a;置于动词、介词等词性后面&#xff0c;在句子中起宾语作用的从句叫做宾语从句。宾语从句分为三类&#xff1a;动词的宾语从句&#xff0c;介词的宾语从句和形容词的宾语从句。 一、that引导的宾语从句(在…

《数据万象带你玩转视图场景》第一期:avif图片压缩详解

前言随着硬件的发展&#xff0c;不管是手机还是专业摄像设备拍出的图片随便可能就有几M&#xff0c;甚至几十M&#xff0c;并且现在我们处于随处可及的信息海洋里&#xff0c;海量的图片带来了存储问题、带宽问题、加载时延问题等等。对图片信息进行有效的压缩处理无疑会极大的…

ARM架构Ubuntu下使用Docker安装MySQL

大家好&#xff0c;我是中国码农摘星人。 欢迎分享/收藏/赞/在看&#xff01; 由于ARM架构的限制&#xff0c;许多软件还没有做到完全适配&#xff0c;CentOS、MySQL等软件安装频繁出错。于是决定做一栏相关软件环境安装的文章。 基础信息 Apple M1 ProUbuntu 22.04 运行 使…

Python 如何安装 MySQLdb ?

人生苦短 我用python Python 标准数据库接口为 Python DB-API&#xff0c; Python DB-API为开发人员提供了数据库应用编程接口。 Python 数据库接口支持非常多的数据库&#xff0c; 你可以选择适合你项目的数据库&#xff1a; GadFlymSQLMySQLPostgreSQLMicrosoft SQL Serve…

来 CSDN 三年,我写了一本Python书

大家好&#xff0c;我是朱小五。转眼间已经来 CSDN 3年了&#xff0c;其中给大家一共分享了252篇Python文章。 但这三年&#xff0c;最大的收获还是写了一本Python书&#xff01; 在这个自动化时代&#xff0c;我们有很多重复无聊的工作要做。想想这些你不再需要一次又一次地做…

站内信箱系统的设计与实现

技术&#xff1a;Java、JSP等摘要&#xff1a;在经济全球化和信息技术成为发展迅速的今时今日&#xff0c;人们通过电子邮件收发进行信息传递已经成为主流。随着互联网和网络办公的发展&#xff0c;电子邮件正在被广泛应用在人们的日常生活中。跟据调查研究统计&#xff0c;在全…

文件系统-

文件系统 是一个面向用户的可视化管理类型的操作系统 其实就是管理硬盘的基本单位扇区&#xff0c;然后将存储数据可视化管理给用户 文件系统包含两个部分 文件的集合和目录结构 对于用户和系统来说文件系统时不一样的 操作系统只解释可执行文件 文件内部结构 文件就是基本…

【JVM】详解Java内存区域和分配

这里写目录标题一、前言二、运行时数据分区2.1程序计数器(PC)2.2 Java虚拟机栈2.3 本地方法栈2.4 Java堆2.5 方法区2.5.1 运行时常量池2.6 直接内存三、HotSpot虚拟机对象探秘3.1 对象的创建3.2 对象的内存布局3.3 对象的访问定位一、前言 C/C需要自行回收和释放已经没用的对象…

2023年 Java 发展趋势

GitHub 语言统计表明&#xff0c;Java在编程语言中排名第二&#xff0c;而在2022年的TIOBE指数中&#xff0c;Java排在第四。 抛开排名&#xff0c;Java是自诞生以来企业使用率最高的编程语言&#xff0c;作为一种编程语言&#xff0c;它比许多竞争对手都有更多的优点&#xf…

【C/C++】逗号表达式、算术运算符优先级

一、逗号表达式 1、如下图中代码&#xff0c;为变量d赋值&#xff0c;d的值为逗号表达式中的哪一个呢&#xff1f; 运行结果&#xff1a;d的值为6 2、再举个例子 运行结果&#xff1a;d的结果还是6 3、再举个例子 运行结果 以上面三种不同的逗号表达式为例&#xff0c;…

IronOCR 2023.3.2 Crack by Xacker

适用于 .NET 2023.3.2 的 IronOCR 提高了从 PDF 阅读文本时的可靠性。2023 年 3 月 2 日 - 10:22 新版本特征 添加了与 Amazon AWS (Amazon Linux) 的兼容性。添加了对各种旧版 Linux 发行版的兼容性。提高了从 PDF 阅读文本时的可靠性。创建可搜索的 PDF 时提高了速度和保真度…

JVM调优面试题——基础知识

文章目录1、JDK&#xff0c;JRE以及JVM的关系2、编译器到底干了什么事&#xff1f;3、类加载机制是什么&#xff1f;3.1、装载(Load)3.2、链接(Link)3.3、初始化(Initialize)4、类加载器有哪些&#xff1f;5、什么是双亲委派机制&#xff1f;6、介绍一下JVM内存划分&#xff08…

[蓝桥杯] 数学与简单DP问题

文章目录 一、简单数学问题习题练习 1、1 买不到的数目 1、1、1 题目描述 1、1、2 题解关键思路与解答 1、2 饮料换购 1、2、1 题目描述 1、2、2 题解关键思路与解答 二、DP问题习题练习 2、1 背包问题 2、1、1 题目描述 2、1、2 题解关键思路与解答 2、2 摘花生 2、2、1 题目…

收个滴滴Offer:从小伙三面经历,看看需要学点啥?

说在前面 在尼恩的&#xff08;50&#xff09;读者社群中&#xff0c;经常有小伙伴&#xff0c;需要面试大厂。 后续结合一些大厂的面试真题&#xff0c;给大家梳理一下学习路径&#xff0c;看看大家需要学点啥&#xff1f; 这里也一并把题目以及参考答案&#xff0c;收入咱…

Spring 容器创建初始化,获取bean流程分析

Spring 容器创建初始化&#xff0c;获取bean流程分析 Spring 容器创建初始化 流程分析 1、首先读取bean.xml 文件 2、扫描指定的包 com.hspedu.spring.component 2.1、扫描包&#xff0c;得到bean的class对象&#xff0c;排除包下不是bean的 2.2、扫描将bean信息封装BeanDef…

python之selenium库安装及用法(定位法、获取文本、文本框输入、鼠标点击、滑动滚动条)

一、selenium库安装 pip install selenium二、浏览器驱动安装 谷歌浏览器驱动下载地址&#xff1a;https://chromedriver.storage.googleapis.com/index.html 根据你电脑的谷歌浏览器版本&#xff0c;下载相应的就行。我下载的是110.0.5481.XX中的chromedriver_win32.zip 下载…

无公网IP快解析实现U+随时随地访问

现阶段商品从生产到消费者手中要经过多个环节&#xff0c;为实现对每一个环节进行管理&#xff0c;越来越多的企业选择通过信息化手段来实现。供应链管理系统配合供应链中各实体的业务需求&#xff0c;使操作流程和信息系统紧密配合&#xff0c;做到各环节无缝链接&#xff0c;…

【C++】string类的使用

目录 一、标准库中的string类 二、string类的常用接口 1、string类对象的常见构造 2、string类对象的容量操作 2.1、size 与 length 2.2、capacity 与 reserve 2.3、resize 2.4、总结 3、string类对象的访问及遍历操作 3.1、operator[] 与 at 3.2、begin end 3.3、…