该学会是自己找bug了(vs调试技巧)

简介: 该学会是自己找bug了(vs调试技巧)

程序猿们每天都在写bug?


bug是什么?


1947 年 9 月 9 日:世界上的第一个“Bug”被发现.


日记:


“1949 年 9 月 9 日,我们晚上调试机器的时候,开着的窗户没有纱窗,机器闪烁的亮光几乎吸引来了世界上所有的虫子。果然机器故障了,我们发现了一只被继电器拍死的飞蛾,翅膀大约 4 英寸。”


格蕾丝·霍普(Grace Hopper)用发夹取出飞蛾,把它粘在日志里,并标注:“First actual case of bug being found”(找到了第一个 Bug)。这件计算机史上的奇闻轶事,使“Bug”作为计算机领域的专用词汇,一直沿用至今。


下图是当时的日记图片:



现在的程序员依旧逃不出“Bug”的魔爪,初学者可能大部分时间在写代码,只有少部分时间在找bug.但是大部分已经工作的程序猿,在工作的一天里,20% 的时间是在写代码,80% 的时间是在找 Bug。


讲个笑话:


如果你在一个技术岗位周围听到了一声崩溃的惨叫,不要慌张,这可能是某个程序员找 Bug 找的崩溃了。如果一群程序员同时发出惨叫,那可能是有人把电源线踢掉了。


一、调试是什么?


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


简单来说,调试就是一个在找bug的过程.


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


如果bug的出现是"犯罪",那么每一次调试都是尝试破案的过程.


一件事情的发生都是有迹可循的,顺着思路写代码出现了bug,这相当于犯罪的过程,逆流而上便是调试的工作,这便是寻找真相的过程.


二、两个版本的介绍(Debug和Release)


Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。


Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。



观察Debug区别和Release版本的区别:


测试代码:


#include <stdio.h>
int main()
{
  printf("初阶牛,你好!!!\n");
  return 0;
}


当我们运行之后:


观察比较代码运行后形成的.exe文件在硬盘上存放所占字节大小.


Debug版本:



Release版本:



上述情况可以证明Release版本会对代码进行各种优化,使得代码大小变小.


而Debug版本要保存调试信息,相对占用大小要更大一点.


编译器进行了哪些优化呢?


🌰当我们写出一个数组越界访问的代码时:


#include <stdio.h>
int main()
{
  int i = 0;
  int arr[5] = { 0 };
  for (i = 0; i < 10; i++)//越界访问
  {
    arr[i] = i;
    printf("%d\n", i);
  }
  return 0;
}


Debug版本调试结果:



Release版本调试结果:



不难发现,即使数组越界访问,在Release版本直接被优化掉了,并不会产生报错信息.


补充知识:


你用的是什么编译器?


vs2019?或者vs2022?


其实这些准确来说不能成为编译器,vs称为IDE(集成开发环境)


编辑器+编译器+调试器


三、调试的快捷键


调试时,快捷键的使用可以大大提高我们的调试效率,所以熟练的使用快捷键是很有必要的.



F5:启动调试


经常用来直接跳到下一个断点处。如果没有设置断点就会直接运行.


F9:创建断点和取消断点


断点的重要作用,可以在程序的任意位置设置断点。


这样就可以使得程序在想要的位置随意停止执行,继而一步步执行下去。


F10:逐过程


通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句。,主要用于跳过确定没有问题的函数,不需要进入函数内部一条条语句调试.


F11:逐语句


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


CTRL + F5:开始执行不调试


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


四、调试窗口


4.1 监视窗口(查看变量的值)


按F11进入调试状态,单击"调试"选项卡,选择"窗口"命令,在子菜单中选择"监视命令".


四个监视窗口都是一样的,随意选择一个即可.



在打开的"监视"的窗口中,可以输入想要观察的变量,十分方便,个人是很喜欢vs的调试环境的.推荐使用"监视窗口"观察变量.


请通过调试,观察变量的变化,找出代码出错的地方.


示例:


请用自定义函数的形式编程实现,求s = m!+ n!+ k!,


其中m、n、k从键盘输入(值均小于7)。


#include <stdio.h>
#define Max 7
int Factorial(int m)//计算阶乘的函数
{
  int ret = 0;
  while (m)
  {
    ret *= m;
    m--;
  }
  return ret;
}
int main()
{
  int m = 0, n = 0, k = 0;
  int s = 0;//记录这三个阶乘的和
  printf("请分别输入m,n,k的值:\n");
  scanf("%d%d%d", &m, &n, &k);
  if (m < Max && n < Max && k < Max)
  {
    s=Factorial(m) +Factorial(n) +Factorial(k);//分别调用计算阶乘的函数
    printf("这三个数的阶乘之和是:%d", s);
  }
  else
  {
    printf("很抱歉,你输入的三个数中,有大于7的数.\n");
  }
  return 0;
}


答案:


出错原因:Factorial函数中,ret初始化为0,出现错误,应当初始化为1,因为0与任何数的乘积都为0;

通过监视窗口,不难发现,ret计算阶乘时值一直为0;


4.2 自动窗口


"监视"窗口,要求自己手动输入需要观察的变量.


自动窗口不需要自己输入观察的变量,会自动出现.


缺点是"自动窗口"中的变量会动态显示,只会显示当前正在操作涉及的部分变量,当进入一个函数时,函数外的变量就观察不到.并不推荐使用


4.3 内存窗口



在内存窗口中,可以输入想要观察的变量的内存地址,甚至可以细致到每一个字节.



当然,vs还提供了"调用堆栈",“反汇编”,"寄存器"等多种类型的窗口方便调试,就不一 一介绍了,可以自己去试着调试,观察.


五.编程常见的错误


5.1 编译型错误


编译器会直接标红,例如:


语法错误,


中英文错误


括号不完整等


这类错误很好发现,也能很快的解决,并不是很复杂的错误.根据编程经验就可以解决.


语句后面忘记":"分号



5.2 链接型错误


编译器会给出错误信息,主要在代码中找到错误信息中的标识符,。一般是标识符名不存在或者拼写错误。这也是不难解决的问题.



5.3 运行时错误


这是最难解决的的问题,只有在运行时,发现并不是自己想要的结果.


这类问题只能通过调试,一步步解决,当代码比较复杂时,一步步调试会显得特别繁琐,这时可以借助F9创建断点,和F10逐过程(不进入函数内部),跳过部分没有出问题的代码区域,即使是这样,这类问题还是很难得以解决.



遇见bug不要太难过,也不要过度生气,自己解决就行了,虽然bug的出现让人很头痛,可能几个小时都无法找到原因,但是我们通过调试,在"破案"的过程中,也许也会收获很多,成功"破案"后的喜悦也是很甜的哟!!!


希望各位小伙伴,可以多多尝试调试,这也是一种很重要的能力,提高自己的代码编程能力.


下面是一些可以试着练习调试的代码:


试着找出原因吧!!!


示例1:这段代码是在x86环境下运行



#include <stdio.h>
int main()
{
    int i = 0;
    int arr[10] = { 0 };
    for (i = 0; i <= 12; i++)
    {
        arr[i] = 0;
        printf("初阶牛加油,加油!!!\n");
    }
    return 0;
}


示例2:输入密码


#include <stdio.h>
#define MAX 3
int main()
{
  char arr1[] = { "初阶牛666" };
  char arr2[20];
  printf("请输入密码:\n");
  int i=MAX;
  while(i)
  {
    printf("你还有%d次机会:",i);
    scanf("%s", arr2);
    if (arr1==arr2)
    {
      printf("密码成功");
      break;
    }
    else printf("密码错误,请重新输入:\n");
    i--;//机会-1
  }
  if(i==0)//如果机会用完了
    printf("\n很遗憾你的机会用完了");
  return 0;
}


答案:


示例1;


当i=12时,令arr[12]=0,此时i的地址和arr[12]的地址是同一块空间,会将i赋值为0


至于为什么是12,是由编译器决定的.



示例2:


错误:比较两个字符串不能使用==,调试会发现即使密码输入正确,依旧会显示错误.


解决方法:


if (arr1==arr2)


改成if (strcmp(arr1, arr2)==0)


补充小知识:


strcmp是c语言提供的一种库函数,用于比较两个字符串


此函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续以下对,直到字符不同或达到终止空字符。


返回值 .
小于0 第一个不匹配的字符在 str1 中的值低于 str2 中的值
0 两个字符串的内容相等
大于0 第一个不匹配的字符在 str1 中的值大于在 str2 中的值


代码如下


#include <stdio.h>
#include <string.h>
#define MAX 3
int main()
{
  char arr1[] = { "初阶牛666" };
  char arr2[20];
  printf("请输入密码:\n");
  int i=MAX;
  while(i)
  {
    printf("你还有%d次机会:",i);
    scanf("%s", arr2);
    if (strcmp(arr1, arr2)==0)//判断字符串相等
    {
      printf("密码成功");
      break;
    }
    else printf("密码错误,请重新输入:\n");
    i--;//机会-1
  }
  if(i==0)//如果机会用完了
    printf("\n很遗憾你的机会用完了");
  return 0;
}


到目前为止,c语言初阶的内容就全部更新完成了,感谢大家的支持!!!


后面就是c语言进阶的内容了.


目录
相关文章
|
算法 数据安全/隐私保护 Windows
|
7月前
|
Windows
Design Expert 13安装教程 Windows版:解压+自定义路径+Crack替换指南
Design-Expert 13 是全球最专业的实验设计(DOE)软件,支持因子设计、响应面法(RSM)、混料设计等,界面友好、操作简便,无需统计基础即可高效建模与优化。
|
4月前
|
人工智能 前端开发 小程序
从知识库问答到企业系统集成:智能体接入客户域名的工程化实践
如何让用户通过客户自己的域名访问智能体?如何让智能体读取或操作客户内部系统?
439 3
|
5月前
|
人工智能 运维 机器人
RAG、Agentic RAG 和 AI Memory 到底有什么区别?
它们合在一起,回答的是同一个问题:AI 怎么从“回答当前问题”,变成“参与长期工作”。RAG 让它会查资料;Agentic RAG 让它更会查资料;Memory 让它能带着过去的上下文继续工作。当这三者组合起来,AI 才更像一个长期协作的助手,而不只是一个每次都要重新介绍背景的聊天窗口。
475 0
RAG、Agentic RAG 和 AI Memory 到底有什么区别?
|
7月前
|
安全 算法 定位技术
企业安全团队如何配合公安协查?IP查询在电子取证中的技术实践
本文详解企业安全团队如何规范留存IP日志、高效开展IP查询与溯源,支撑公安网络犯罪协查。聚焦《网络安全法》合规要求,结合批量定位、风险标注、多源交叉验证等实操技术,助企业构建可追溯、可审计、可采信的电子证据链。
|
7月前
|
数据采集 存储 人工智能
AI时代下,中小团队数据治理的轻量化落地指南
沙淘金数据运营负责人分享中小团队数据治理实战经验:破除“大厂专属”误区,提炼4步轻量化落地法(明确需求→规范源头→简易清洗→闭环应用),结合阿里云、DataWorks、钉钉等生态工具,低成本实现数据提效。
|
10月前
|
SQL 人工智能 安全
手把手教你调出“懂你”的AI:大模型微调实战与资源管理
本文深入浅出讲解大模型微调核心知识:用生活化比喻解析学习率、训练轮数、批量大小、截断长度和LoRA秩五大关键参数;提供适配不同显存的实操配置表;分享Liger Kernel、DeepSpeed等省显存技巧;并强调定量、定性与效率三维评估。零基础也能快速上手定制专属AI。
980 11
手把手教你调出“懂你”的AI:大模型微调实战与资源管理
|
存储 安全 大数据
网安工程师必看!AiPy解决fscan扫描数据整理难题—多种信息快速分拣+Excel结构化存储方案
作为一名安全测试工程师,分析fscan扫描结果曾是繁琐的手动活:从海量日志中提取开放端口、漏洞信息和主机数据,耗时又易错。但现在,借助AiPy开发的GUI解析工具,只需喝杯奶茶的时间,即可将[PORT]、[SERVICE]、[VULN]、[HOST]等关键信息智能分类,并生成三份清晰的Excel报表。告别手动整理,大幅提升效率!在安全行业,工具党正碾压手动党。掌握AiPy,把时间留给真正的攻防实战!官网链接:https://www.aipyaipy.com,解锁更多用法!
|
12月前
|
移动开发 小程序 数据可视化
一次开发多端覆盖!Uni+PHP 源码搭建校园外卖跑腿平台,小程序 + H5+App 全搞定!
UniApp+PHP校园外卖跑腿源码,一次开发覆盖小程序、H5、App,1小时快速上线!支持外卖+跑腿双功能,高并发不卡顿,0技术门槛,全开源可定制,助力创业者低成本抢占校园服务市场,轻松运营千亿蓝海。
|
XML JSON API
苏宁商品详情API秘籍!轻松获取商品详情数据
苏宁商品详情API基于RESTful架构,支持JSON/XML格式,通过AppKey、AppSecret与签名三重认证,结合OAuth 2.0实现安全调用。开发者可获取商品名称、价格、销量、库存、促销等实时数据,适用于电商分析与商业智能。接口强制使用HTTPS协议,支持POST/GET请求,统一采用UTF-8编码,确保数据传输安全可靠。
1038 1