【C语言-调试技巧】爷傲奈我何?bug来治你

【C语言-调试技巧】爷傲奈我何?bug来治你,第1张

前言

调试对程序员来说是必不可少的,没人能保证一辈子写的代码一个bug都没有。所以学会调试,很重要。

没有手绘封面了,apple pencil丢了。。。


1. 调试 1.1 调试是什么?

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

1.2 怎么调试?
  • 发现错误
  • 通过 隔离 、消除 等方式,定位错误
  • 确定错误原因
  • 思考解决办法
  • 实现解决办法,对程序除错
  • 重新测试
1.3 Debug 和 Release

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


2. Windows下的调试 2.1 调试环境

在环境选项中选 Debug

2.2 调试快捷键

F5
启动调试
常用于跳到下一个断点

F9
创建/取消断点
让程序在你希望的地方(至少是有意义的代码处)停下来

F10
逐过程
过程:一次函数调用,一条语句,都是一个过程

F11
逐语句
一次只执行一条语句,常用于进入函数内部

Ctrl + F5
不调试,直接执行程序

2.3 调试的重要部分:“监视”

开始调试后,在“调试” – “窗口” 里,可以任意找到想监视的信息


3. 调试实例 3.1 例1
#include
int main()
{
	int i = 0;
	int n = 0;
	int sum = 0;
	int ret = 1;
	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;
结果:15
 3! + 2! + 1= 6+2+1 = 9
 为什么得到15}

对 ret 的需求是每次存储 n 的阶乘,但是调试发现,ret 的值一直累加,正确代码应该是这样:

#include
int main()
{
	int i = 0;
	int n = 0;
	int sum = 0;
	scanf("%d", &n);
	for (i = 1; i <= n; i++)
	{
		int ret = 1;
		int j = 0;
		for (j = 1; j <= i; j++)
		{
			ret *= j;
		}
		sum += ret;
	}
	printf("%d\n", sum);
	return 0;
}

调试过程中,时刻观察程序走向是不是和脑中构思好的一致

3.2 例2
#include
int main()
{
	int arr[10] = { 0 };
	int i = 0;
	for (i = 0; i <= 12; i++)
	{
		arr[i] = 0;
		printf("hehe\n");
	}
	return 0;
}
结果:死循环/报错(越界访问)

是的,这里越界访问了,但是根据 vs 的内存使用规则,越界访问的 arr[12] 刚好是 i ,每当程序要结束 , i 就又被赋成 0 ,导致死循环

vs在栈区使用空间,总是从高地址开始使用
vs数组的使用中,随着下标增加,地址由低到高

*静态区是右下角的方格,不知道怎么跑上去了 -_-


4. 如何写出好,还易于调试的代码? 4.1 优秀的代码
  1. 运行正常
  2. bug很少
  3. 效率高
  4. 可读性高
  5. 可维护性高
  6. 注释明了
  7. 文档齐全
4.2 如何向优秀代码靠近?
  1. 使用assert(断言,我视它为保安)
  2. 尽量使用const
  3. 良好代码风格(适合的缩进,空格之类)
  4. 添加必要的注释(明了简洁)
  5. 避免代码的陷阱
4.3 优秀代码示例(多向优秀代码学习)
#include
#include
//************
//= char* my_strcpy( dst , src ) - Copy one string over another
// 
//= Purpose:
//			Copies the string "src" into the spot
// 			specified  by dest ; assumes enough room.
// 
//= Entry:
//			char* dst - string over which "src" is to be copied 
//			const char* src - string to be copied over "dst"
//
// = Exit:
//			The address of "dst"
//**************

char* my_strcpy(char* dst, const char* src)
{
	char* tool = dst;
	//两个形参都不为NULL
	assert(dst && src);

	while (*tool++ = *src++)// ; = 0
	{
		//copy src over dst}
	return

	; dst}
int
main ()char
{
	[ str1]= "Coding is funny!" ;char
	[ str230]= 0 { } ;printf
	("%s\n",my_strcpy (,str2) str1);return
	0 ;}
#
4.4 const 的作用

const:赋予常量属性

看看例子(参考前辈的例子)

include//代码1 
void
test1 ()int
{
    = n 10 ;int
    = m 20 ;int
    * =p & ;n*
    =p 20 ;//ok?=
    p & ;m//ok? }
void
test2 ()//代码2
{
     int
    = n 10 ;int
    = m 20 ;const
    int *= p & ;n*
    =p 20 ;//ok?=
    p & ;m//ok? }
void
test3 ()int
{
    = n 10 ;int
    = m 20 ;int
    * const= p & ;n*
    =p 20 ;//ok? =
    p & ;m//ok?  }
int
main ()//测试无cosnt的
{
    test1
   ();//测试const放在*的左边
    test2
    ();//测试const放在*的右边
    test3
    ();return
    0 ;} 

总结:就是看 const 在谁的左边

  1. 在 * 左边,就是修饰指针变量指向的内容:
    指针指向的值被赋予常量属性
  2. 在 * 右边,就是修饰指针变量:
    指针变量里的地址被赋予常量属性

5. 编程常见错误 5.1 编译型错误

多是语法问题,双击错误信息,根据错误信息修正即可

5.2 链接型错误

多是 标识符不存在 、 拼写错误 、 没有声明

5.3 运行时错误

逐步调试,细心对照:“是否和脑中构思的相同?”

5.4 通向 “无bug” 的捷径

不断积累排错经验,两点之间线段最短,脚踏实地就是最快的捷径


今天的分享就到这里


培根的blog,不断进步
:粉丝、阅读量不是初衷,写博客是为了倒逼自己输出,提升自己,不浮躁,不虚荣

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/1296064.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-06-10
下一篇2022-06-10

发表评论

登录后才能评论

评论列表(0条)

    保存