当前位置:首页 » 《随便一记》 » 正文

程序员养成金手指——调试造就优秀_乔乔家的龙女仆的博客

7 人参与  2022年05月10日 12:34  分类 : 《随便一记》  评论

点击全文阅读


目录

    • 传统艺能😎
    • 过渡区🤣
    • 正片开始👀
    • Bug👏
    • 调试的重要性👏
    • 调试基本步骤👏
    • Debug与Release👏
    • 快捷键👏
    • 如何写出易于调试(优秀)的代码👏
    • 常见的coding技巧👏

传统艺能😎

小编是大一菜鸟不赘述,欢迎大佬指点江山(QQ:1319365055)
此前博客点我!点我!请搜索博主 【知晓天空之蓝】点我!点我!请搜索博主 【知晓天空之蓝】或扫码进入!
乔乔的gitee代码库(打灰人 )欢迎访问,点我!
在这里插入图片描述

(https://blog.51cto.com)感谢支持!

过渡区🤣

现在是北京时间13:45,周末,其实昨天想着今天给自己放个假。今天5点过醒了,整个人却没啥精力,不知道是不想动还是懒,宅在床上,又恶性循环来写博客了。太对啦,大学周末生活就该一点一线😅

在这里插入图片描述

正片开始👀

Bug👏

bug意为臭虫,计算机术语里就是幺蛾子,对,你的程序又出幺蛾子了。为什么要叫bug?关于这个还有段有趣的历史

有一天赫柏正愉快地敲着Mark Ⅱ的代码时,计算机突然就停止运作了,那时的计算机远不如现在小巧,赫柏他们只能一个个排查计算机庞大的处理器群,经过一段时间的排查后停机原因终于被找到了。原来是一只飞蛾被计算机的光和热吸引,触发了电脑的短路,当然这只可怜的飞蛾也一命呜呼了按理说一般人也就是把飞蛾拿走,然后重启下电脑也就完事了,但赫柏显然不是一般人她小心翼翼地把这只飞蛾拿了下来,然后把它工工整整地粘在了记事本上… …

这就是历史上第一个 bug 的诞生。

调试的重要性👏

我估计前期我们找 bug 都是用眼睛瞅,特别是我们这种大一的刚接触的,现在还好,到了以后需要写大工程的时候,眼瞅不头疼的才是大哥,对于一个成熟程序员20%时间写代码而80%时间在调试代码。
我们写代码就是一个推理的过程,整个流程的正确与错误都是有迹可循的,推理的途径就是这些迹象。
一名优秀的程序员就是一个优秀的侦探,找到迹象,顺流而下是错误,顺流而上是真相,调试就是我们破案的过程。
在这里插入图片描述

调试基本步骤👏

1.找错(进行隔离,消除来定位错误)
2.知道错因
3.寻找解决办法
4.纠正,重测

Debug与Release👏

Debug(Debugging),即排错,称为调试版本,不作任何优化,包含调试信息,便于我们调试程序。
Release ,即释放,成为测试版本,往往进行各种优化,让代码在大小和运行速度上都是最优的,面向用户,可以很好的使用。但是!注意Release版本是没法进行调试的。

快捷键👏

在调试过程中,掌握一些快捷键会大大增加我们的效率。以vs2019为例,我们先会设置断点如图(行标左侧设置)
在这里插入图片描述
断点设置在需检查代码的任意位置,运行到这一步就会停下给我们报告。断点完F5调试,执行窗口弹出后就会发现调试就会出现更多内容,我框出来的在之前记录C语言学习时都有用到。

在这里插入图片描述
注意F5是调试,Ctrl+F5是运行,通常会使用会F5跳到想要的断点处,有些电脑上比较装怪,快捷键没反应的,建议多按一个Fn键试试,Fn是功能辅助键,相当于一个开关,本质上 F5+Fn = F5。需要强调的是逐语句和逐过程,如果你想看每个细节,不放过每一个角落就用逐语句,两者的力度是不一样的,逐过程会跳过代码里的函数部分。
vs玩家重点推荐 Ctrl+k+c,注释选中行;Ctrl+k+u,取消注释,熟练运用会很方便。
其余还有很多不赘述,下面准备了超全的实用快捷键用法:

想深入了解的铁子戳这里
在这里插入图片描述
除了用调试验证代码的正确性,还可以用于研究具体的问题,举个栗子:
这道题是Nice的面试真题

请说明下面代码是否能正常运?运行结果是什么?为什么会出现这个结果?

int main()
{
int i = 0;
int arr[10] = { 0 };
for (i = 0; i <= 12; i++)
{
arr[i] = 0;
printf(“hehe\n”);
}
return 0;
}

这里当我们打开调试窗口直接开调:
在这里插入图片描述很直观的可以发现,哦,原来是i与arr[12]相同,我们发现在arr[12]改变时i第的值也会随之改变,那我就直接取出他们都地址看一看是不是一样的。
在这里插入图片描述
OMG,是一样的。但我们这里的调试只能看到现象,他底层的原理我们要自己思考。
其死循环的逻辑大致是这样的,我们创建了一个变量i,arr,他们都是局部变量,而局部变量时放在栈上的,栈区上内存使用习惯是先使用高地址存储空间,再使用低地址。这里注意,我们开始给的十个大小的空间,i的变量是到12,这里明显是越界访问,但为什么没有报错停下来?结合我们刚刚监视的结果,我们再把格局打开:
数组随着下标的增长,地址是由低到高的变化,在我数组适当越界时,如果i和arr之间的空间适当的话,就有可能使arr向后越界时就访问到了i,造成了循环变量的i改变,最终会死循环。

在这里插入图片描述
这种错误其实存在偶然性,首先i和arr[12]相同,只是恰巧,但如果我把i换成11,结果就大相径庭了,我只形成了越界但没有改变循环变量i的值。其次,这个代码是严重依赖环境的,比如在VC 6.0里面i和arr就是连续的,gcc里面i和arr之间有一个空间。
打趣的是,我们在Release版本里面是不会报错并且会停下来,其实在刚刚的截图里面也是会报错的,但是!死循环停不下来,他根本没时间来报错。Rlease的优化并不是万能的,不要期待利用Release版本来掩盖代码的bug,最好的做法就是不要越界。

如何写出易于调试(优秀)的代码👏

1.硬性要求运行正常
2.bug少(估计没人敢保证零bug吧)
3.效率高

在这里插入图片描述
4.可读性高
在这里插入图片描述
5.可维护性(容易修改与二创)
6.注释(方便阅读)
7.文档齐全

常见的coding技巧👏

1.使用assert
意为断言,在代码执行前设的前哨,比如我们函数传参时,当我传的内容变成空指针,后面如果函数进行解引用操作,对于空指针解引用是会造成程序崩溃的,是很危险的,所以我们用assert当监护人能快一步该诉我们问题在这里;设置assert也是一个好习惯,面试官见了直呼老司机!

# include<assert.h>
void my_str(char* a, char* b)
{
	assert(a != NULL && b != NULL);//断言
	while (*b != '\0')
	{
		*a = *b;
		b++;
		a++;
	}
	*a = *b;
}
int main()
{
	char arr[10] = {0};
	char arr2[] = "bit";
	my_str(NULL, arr2); // 故意设成NULL程序会崩溃
	printf("%s\n", arr);

	return 0;
}

在这里插入图片描述
效果如上图就会显示断言失败。

2.尽量使用const
const我之前博客写过的常变量修饰符。
就上面模拟strcpy函数,如果有天有个内鬼改了你的代码,写成 *b = *a,就拷反了,编译器也会傻不拉叽的输出,尽管结果什么都没有。那怎么办呢?我在开头就定义好

char* my_str(const char *a,const char* b)

这样不管你咋改,我 *a,*b都是无法改变的。

注意const int *p=&a , const 在 * 左边时,修饰的是指针指向的内容,指针变量不影响 ;在 * 右边是,修饰指针本身,指针变量不能修改,其内容可以通过指针来改变。
3,形成良好的编码风格
4.注释!注释!注释!(好习惯讲三次)
5.避免编码陷阱

今天就到这里了,摸了家人们。
在这里插入图片描述


点击全文阅读


本文链接:http://zhangshiyu.com/post/39841.html

调试  代码  变量  
<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1