C语言vs环境实用的调试技巧

一、前言

bug是啥?翻译中它是臭虫的意思
Bug一词的原意是“昆虫”或“虫子”;而在电脑系统或程序中隐藏着的一些未被发现的缺陷或问题,人们也叫它“bug”。“Bug”的创始人格蕾丝·赫柏(Grace Murray Hopper),是一位为美国海军工作的电脑专家,也是最早将人类语言融入到电脑程序的人之一。而代表电脑程序出错的“bug” 这名字,正是由赫柏所取的。1947年9月9日,赫柏对Harvard Mark II设置好17000个继电器进行编程后,技术人员正在进行整机运行时,它突然停止了工作。于是他们爬上去找原因,发现这台巨大的计算机内部一组继电器的触点之间有一只飞蛾,这显然是由于飞蛾受光和热的吸引,飞到了触点上,然后被高电压击死。所以在报告中,赫柏用胶条贴上飞蛾,并把“bug”来表示“一个在电脑程序里的错误”,“Bug”这个说法一直沿用到今天。
在这里插入图片描述

图片文字出自 Drake

二、我们在写代码中常见的错误

1.编译型错误

这种直接看错误提示消息(双击),解决问题,或者我们可以凭借经验就可以搞定,相对来说比较简单。例如我们一般的语法错误,句末少了’;'等。

2.链接型错误

看错误提示消息,主要在代码中找到错误消息中的标识符,然后定位问题所在。例如调用函数时函数未定义,拼写错误(函数名写错了)

3.运行时错误

这种是最隐蔽的,要借助调试逐步定位问题。

三、调试的基本知识

1.什么是调试?

找bug的过程就叫做调试

2.vs环境的两种版本

debug与release版本

版本名含义适用人群原因
debug调试版本程序员不做任何优化便于程序员调试程序(文件里面包含了调试信息)
release发布版本用户进行了各种优化使得程序在代码大小和运行速度上是最优的(不能调试)

三、windows系统下的调试技巧

1.调试环境的准备(环境改为debug)

2.一些快捷键的使用

快捷键含义
F5+F9的配合使用F9切换断点;F5执行完代码断点前的代码,停在断点处
F10逐过程,不关注里面是怎么执行的,关注我们的结果(不会进入函数内部,直接得到函数结果)
F11逐语句,不放过任何细节(能进入函数内部,观察函数的实现)
Shift+F11进入函数内部后,不想继续观察函数,我们可以跳出函数,回到主函数
Ctrl+F5不调试直接执行
Shift+F5跳出调试

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

特别注意:下列出现的窗口信息需要我们进入调试窗口才能看到
在这里插入图片描述
自动窗口:自动把程序执行到这个位置的上下文环境中某些变量添加在这
局部变量:展示我们上下文环境中,就在这个局部范围内,一些局部变量的相关信息
监视:不管执行哪一句,值始终放着
内存:观察内存变换
反汇编:查看汇编代码
寄存器:我们可以观察程序执行寄存器变量
调用堆栈:可以反应函数调用逻辑

4.我们要多多动手,尝试调试

四、我们的实际演练

1.我们第一个需要调试的代码是为了各阶乘的和

在这里插入图片描述
说明:这个代码我们在逐语句分析的时候,发现问题出现在3的阶乘,我们再次进入调试,再逐语句分析很挫,所以我们可以在问题语句附近添加断点,设置for语句的条件,调试代码更高效

2.这个代码理解起来有难,但是这种类型的代码修改必须借助调试

#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable:6031)
#include<stdio.h>
int main()
{
	int i = 0;
	int arr[10]= {1,2,3,4,5,6,7,9,10};
	for (i = 0; i <=12; i++)
	{
		printf("hehe\n");
		arr[i] = 0;
	}
	return 0;
}

实验结果:代码是一个死循环,一直在打印hehe
想要理解这个代码,我们必须要知道:
1.栈区的默认使用规则:先使用高地址然后才使用低地址的空间
2.数组的地址是连续的,是随着下标增长而增长的
在这里插入图片描述
这种类型的错误因为在不同编译器它们的内存空间分配是不同的,所以我们设置的判断语句不同

vc6.0环境下<=10就死循环了
gcc编译器<=11就死循环了
vs2013 <=12就死循环了

在vs环境中i<=12它是死循环,为什么在i<=11它会报错误

因为i<=11,栈空间被破坏了
i<=12时,他不会报错,是因为12进入死循环没有机会停下代码,如果停下了也同样会报错误

很有趣的现象在debug环境下这个代码为死循环,然而我们在release版本结果就打印13个hehe
我们不妨打印他们各自的地址

在这里插入图片描述
这个很好的验证了我们画的那个图是正确的;并且还验证了release环境下进行了优化
那么要怎么样才能在两种版本切换的时候,出现完全不同的结果的呢?

我们的数组不能越界,越界可能导致死循环。

五、如何写出好(易于调试)的代码

a,优秀代码的7个要素

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

b,运用常用的coding技巧

  1. 使用assert
  2. 尽量使用const
  3. 养成良好的编程风格
  4. 添加必要的注释
  5. 避免编程的陷阱
    补充:
    assert();断言
    头文件:<assert.h>
    实际意义:assert函数发现问题把问题抛出来,在哪有问题,利于程序员把当前代码的问题解决掉
    const的用法
    例如 const int num=10;表示这个变量num是不允许更改的
    注意区分指针const

const int * p//修饰的是p不能通过p来改变p的值
int * const p//修饰的是我们的p,p的值不能被更改

六、结语

欢迎大家指出不足

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

含目的基因的质粒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值