编程最重要的技术—调试(以C语言代码为例)

简介: 编程最重要的技术—调试(以C语言代码为例)

世界上第一个bug


image.png

  • 第一次被发现的导致计算机错误的飞蛾,也是第一个计算机程序错误。
  • 这只飞蛾就引生出了bug的概念。
  • bug是在应用程序投入生产之前发现的错误。 导致程序工作不佳、生产错误结果或崩溃的编程错误。


1.学会调试很重要

1.1 调试是什么?


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

我们在写完程序后,时常会因为达不到预期效果而苦闷,可以说,代码出现了bug,那么我们如何去寻找程序的错误?

调试是一个简单但又非常重要的技巧,有人说,程序员写代码只要20%的时间,而调试除错占用了80%的时间。这句话非常的形象。

可以说调试就是一个尝试破案的过程,它能够找到导致程序运行效果不佳的错误。

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

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


1.2 调试的基本步骤


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


2.Debug与Release


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



我们看以下这段代码:

#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("hello!\n");
  }
  return 0;
}


在Debug环境下,该程序运行结果为:



b1b390f75c3b49fd843afac3e71a5ae9.png


而在Release环境下运行结果为:

28725e79bbf24f9890e37ebbf3617182.png


可以看到Release的优化使得程序运行没有报错而是正常运行,这体现了Release的特性,当然,Release的优化使得程序不能再进行调试,使得我们不能一步步侦察发现程序的错误所在。

还有一点就是,Release版本文件进行优化后,其文件比Debug版本文件的大小小很多。


3.调试的基本快捷键


设置断点


我们点击代码语句序号前的灰色部分便可以设置断点


55aedc44cb924705a6d5bbddac5e6c29.png


F5

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

F9

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

F10

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

F11

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


ctrl + F5


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

以上这些基本的快捷键必须要掌握。


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


4.1 查看临时变量的值

  • 在调试开始之后,用于观察变量的值。
  • 调试开始后点击调试,在窗口处选择监视(1,2,3,4,随便点击一个),当然也可以选择自动窗口(程序自动显示出变化的量)。

在监视窗口中,我们可以输入想观测量的信息从而进行观测。


a7857b9fe7be42f099fdb0f86166010e.png

4.2 查看内存信息

  • 在调试开始之后,用于观察内存信息。
  • 用于观察变量在内存中的地址。
  • 用于观察变量此时的大小。

4b29f69b866e49569fa4c75c97e27986.png


4.3 查看调用堆栈

  • 通过调用堆栈,可以清晰的反应函数的调用关系以及当前调用所处的位置。
  • 可以观察函数的进栈和出栈。

fe01c8e2b0a741a2a0f1a406d910d522.png


4.4 查看汇编信息

  • 在调试开始之后,有两种方式转到汇编:
    1.第一种方式:右击鼠标,选择【转到反汇编】;
    2.在调试窗口选项里可以进入。
  • 查看汇编信息可以让我们更加清楚在VS环境下程序是如何运行的(代码运行的顺序)。


0421640042d74e7ea924919ca1cea8ef.png



37f79caf3db04e29941d8c8d07acac5d.png


调试的时候查看程序当前的信息可以是我们更加的贴近代码运行的过程,从而使我们的思维更加的细化。


5.如何写出好的代码


  1. 代码运行正常
  2. bug很少
  3. 效率高
  4. 可读性高
  5. 可维护性高
  6. 注释清晰
  7. 文档齐全
  • 常见的coding技巧:
  1. 使用assert
  2. 尽量使用const
  3. 养成良好的编码风格
  4. 添加必要的注释
  5. 避免编码的陷阱。
  • 示范:
    模拟实现库函数:strcpy


#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* dest,const char* sor)
{
  assert(dest && sor);
  char* n = dest;
  while (*dest++ = *sor++)
  {
    ;
  }
  return n;
}
int main()
{
  char arr1[1000] = "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$";
  char arr2[1000];
  printf("开始的arr1:");
  printf("%s\n", arr1);
  printf("请输入要复制过去的内容:\n");
  gets(arr2);
  printf("复制后的arr1:");
  printf("%s\n", my_strcpy(arr1, arr2));
  return 0;
}


  • 注意:
    1.要分析参数的设计(命名,类型),返回值类型的设计;
    2.野指针和空指针的危害。


6.编程常见的错误


6.1 编译型错误

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


6.2 链接型错误

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

6.3 运行时错误

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

温馨提示:

做一个有心人,积累排错经验。

讲解重点:

介绍每种错误怎么产生,出现之后如何解决。

总结

  • 一定要熟练掌握调试技巧。
  • 初学者可能80%的时间在写代码,20%的时间在调试。但是一个程序员可能20%的时间在写程序,但是80%的时间在调试。
  • 这里所讲的都是一些简单的调试。
  • 以后可能会出现很复杂调试场景:多线程程序的调试等。
  • 多多使用快捷键,提升效率。


最重要的一点:

当我们在看别人的代码看不懂时,一定要将其代码调试去仔细看看其中程序运行的量的变化过程,然后再思考总结,领悟别人的解题思维,这样才能将知识灌输到自己的大脑中,而不是看到不懂的或者是不会的就去问,当然好问也是一种技巧,但是一定是思考过的去问才能达到获知的效果!

相关文章
|
1月前
|
NoSQL C语言 索引
十二个C语言新手编程时常犯的错误及解决方式
C语言初学者常遇错误包括语法错误、未初始化变量、数组越界、指针错误、函数声明与定义不匹配、忘记包含头文件、格式化字符串错误、忘记返回值、内存泄漏、逻辑错误、字符串未正确终止及递归无退出条件。解决方法涉及仔细检查代码、初始化变量、确保索引有效、正确使用指针与格式化字符串、包含必要头文件、使用调试工具跟踪逻辑、避免内存泄漏及确保递归有基准情况。利用调试器、编写注释及查阅资料也有助于提高编程效率。避免这些错误可使代码更稳定、高效。
215 12
|
1月前
|
存储 搜索推荐 C语言
深入C语言指针,使代码更加灵活(二)
深入C语言指针,使代码更加灵活(二)
|
1月前
|
存储 程序员 编译器
深入C语言指针,使代码更加灵活(一)
深入C语言指针,使代码更加灵活(一)
|
1月前
|
C语言
深入C语言指针,使代码更加灵活(三)
深入C语言指针,使代码更加灵活(三)
深入C语言指针,使代码更加灵活(三)
|
2月前
|
安全 C语言
在C语言中,正确使用运算符能提升代码的可读性和效率
在C语言中,运算符的使用需要注意优先级、结合性、自增自减的形式、逻辑运算的短路特性、位运算的类型、条件运算的可读性、类型转换以及使用括号来明确运算顺序。掌握这些注意事项可以帮助编写出更安全和高效的代码。
49 4
|
1月前
|
C语言
C语言调试
C语言调试
16 0
|
1月前
|
C语言
C语言练习题代码
C语言练习题代码
|
2月前
|
存储 算法 C语言
C语言手撕实战代码_二叉排序树(二叉搜索树)_构建_删除_插入操作详解
这份二叉排序树习题集涵盖了二叉搜索树(BST)的基本操作,包括构建、查找、删除等核心功能。通过多个具体示例,如构建BST、查找节点所在层数、删除特定节点及查找小于某个关键字的所有节点等,帮助读者深入理解二叉排序树的工作原理与应用技巧。此外,还介绍了如何将一棵二叉树分解为两棵满足特定条件的BST,以及删除所有关键字小于指定值的节点等高级操作。每个题目均配有详细解释与代码实现,便于学习与实践。
|
2月前
|
存储 算法 C语言
C语言手撕实战代码_二叉树_构造二叉树_层序遍历二叉树_二叉树深度的超详细代码实现
这段代码和文本介绍了一系列二叉树相关的问题及其解决方案。其中包括根据前序和中序序列构建二叉树、通过层次遍历序列和中序序列创建二叉树、计算二叉树节点数量、叶子节点数量、度为1的节点数量、二叉树高度、特定节点子树深度、判断两棵树是否相似、将叶子节点链接成双向链表、计算算术表达式的值、判断是否为完全二叉树以及求二叉树的最大宽度等。每道题目均提供了详细的算法思路及相应的C/C++代码实现,帮助读者理解和掌握二叉树的基本操作与应用。
|
2月前
|
存储 算法 C语言
C语言手撕实战代码_循环单链表和循环双链表
本文档详细介绍了用C语言实现循环单链表和循环双链表的相关算法。包括循环单链表的建立、逆转、左移、拆分及合并等操作;以及双链表的建立、遍历、排序和循环双链表的重组。通过具体示例和代码片段,展示了每种算法的实现思路与步骤,帮助读者深入理解并掌握这些数据结构的基本操作方法。