C语言调试大作战:与VS编译器共舞,上演一场“捉虫记”的艺术与科学

news2024/11/19 18:32:49

少年们好,我是博主那一脸阳光,我们接下来介绍C语言的调试和bug的分享。
引言:
“如果你曾经在深夜与一串神秘莫测的C代码狭路相逢,彼此瞪大眼睛,犹如牛仔对决般紧张刺激;或者你曾试图驯服一段狂野不羁的循环,却发现自己陷入了一个深不见底的逻辑黑洞,那么恭喜你,你已经正式加入了C语言调试者联盟!在这个奇妙的编程世界里,我们可不是简单的码农,更像是手持放大镜和捕虫网的侦探,以寻找并消灭那些狡猾又隐秘的’小bug’为己任。今天,让我们一同展开这场充满笑声与泪水、挫折与突破的C语言调试奇幻之旅,看看那些让程序员们既爱又恨的’小家伙们’是如何诞生,又是如何被我们智勇双全地一一拿下!”

关于BUG的由来和故事

"Bug"一词在计算机领域的起源,与硬件故障和软件缺陷有着紧密联系。关于这个词的由来,有两种广为流传的故事:

硬件故障导致的“虫子”事件:

其中一个故事追溯到早期计算机的时代,具体时间大约在20世纪40年代末至50年代初。这个故事描述的是美国哈佛大学的马克-II(Mark II)电子管计算机发生的一次故障。1947年9月9日,计算机科学家格蕾丝·赫柏(Grace Hopper)在检查这台机器时发现了一个由于飞蛾误入继电器触点而引发的故障。工作人员把这只飞蛾从设备中取出,并把它粘贴在了日志本上,旁边标注着“First actual case of bug being found”(首次发现实际的bug)。从此,“bug”开始被广泛用来指代计算机系统中的错误或故障。
工程术语的沿用:

另一个版本的历史背景更为久远,甚至早于计算机的发明。在电气工程和其他工程领域,早在19世纪,“bug”就已经作为行话使用,用来描述机械设备中的小故障或设计问题。托马斯·爱迪生(Thomas Edison)在他的个人通信中就曾使用过“bug”来形容技术问题。当计算机出现后,这个术语自然而然地过渡到了新兴的计算机科学领域,继续用于表示程序或硬件的错误。
无论是哪种起源,最终“bug”成为了软件开发和信息技术行业内的通用词汇,用来指代程序代码中导致程序行为异常的问题。相应的,“debugging”即调试,指的是寻找并修复这些程序错误的过程。

在这里插入图片描述

什么是调试(debug)

当我们发现程序中存在的问题的时候,那下⼀步就是找到问题,并修复问题。
这个找问题的过程叫称为调试,英⽂叫debug(消灭bug)的意思。
调试⼀个程序,⾸先是承认出现了问题,然后通过各种⼿段去定位问题的位置,可能是逐过程的调
试,也可能是隔离和屏蔽代码的⽅式,找到问题所的位置,然后确定错误产⽣的原因,再修复代码,
重新测试。

Debug和Release

在这里插入图片描述
在VS上编写代码的时候,就能看到有 debug 和 release 两个选项,分别是什么意思呢
Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序;
程序员在写代码的时候,需要经常性的调试代码,就将这⾥设置为 debug ,这样编译产⽣的是
debug 版本的可执⾏程序,其中包含调试信息,是可以直接调试的。
Release 称为发布版本,它往往是进⾏了各种优化,使得程序在代码⼤⼩和运⾏速度上都是最优的,
以便⽤⼾很好地使⽤。当程序员写完代码,测试再对程序进⾏测试,直到程序的质量符合交付给⽤⼾
使⽤的标准,这个时候就会设置为 release ,编译产⽣的就是 release 版本的可执⾏程序,这个
版本是⽤⼾使⽤的,⽆需包含调试信息等。
在这里插入图片描述对⽐可以看到从同⼀段代码,编译⽣成的可执⾏⽂件的⼤⼩,release版本明显要⼩,⽽debug版本明
显⼤。

VS牛仔侦探福尔摩斯的快捷键西部抓“BUG”大戏

欢迎来到编程世界的狂野西部,这里的治安官不叫警长,而是一位身怀绝技的“VS牛仔侦探福尔摩斯”。他以Visual Studio为马鞍,代码行作为疆界,手握一连串神奇的快捷键法器,誓要在这片充满神秘bug的边陲之地,上演一场又一场惊心动魄、笑料百出的抓“小偷”(BUG)好戏。

当夜幕降临,小镇沉睡,罪恶悄然滋生。别慌,瞧!我们的“VS牛仔侦探福尔摩斯”已经整装待发:

F9:设置断点,犹如布下天罗地网 —— 就像牛仔在小偷必经之路埋伏设陷阱,等待他们自投罗网;

F10:逐过程追踪,玩转逻辑迷宫 —— 福尔摩斯抽着烟斗,步步为营,每按一下F10就如同推开一扇门,揭示下一个可能藏匿犯罪线索的房间;

F11:步入函数内部,深挖地下暗道 —— 牛仔侦探奋不顾身跳入深深的洞穴,钻进函数的核心地带,挖掘那些潜藏最深的小bug;

F5:启动调试列车,全速追捕逃犯 —— 随着一声汽笛长鸣,搭载着智慧与勇气的F5列车疾驰而出,直奔目标,将那些试图逃脱的小bug逮个正着!

还有那神秘的Ctrl+5,这可是牛仔侦探的秘密武器,它如同瞬间移动到任意场景的魔法帽,让侦探能够迅速切换至第五个监视窗口,随时洞察案发现场的每个角落,确保任何蛛丝马迹都无处遁形。

准备好你的键盘和鼠标,跟随这位集西部牛仔的勇猛与福尔摩斯般智谋于一身的“VS牛仔侦探福尔摩斯”,踏上这场风趣幽默、紧张刺激的编程西部冒险,看他是如何运用这些神奇快捷键,在虚拟世界中惩治邪恶,维护程序正义的吧!
总结:
那程序员怎么调试代码呢?
F9:创建断点和取消断点
断点的作⽤是可以在程序的任意位置设置断点,打上断点就可以使得程序执⾏到想要的位置暂定执
⾏,接下来我们就可以使⽤F10,F11这些快捷键,观察代码的执⾏细节。
条件断点:满⾜这个条件,才触发断点
F5:启动调试,经常⽤来直接跳到下⼀个断点处,⼀般是 和F9配合使⽤。
F10:逐过程,通常⽤来处理⼀个过程,⼀个过程可以是⼀次函数调⽤,或者是⼀条语句。
F11:逐语句,就是每次都执⾏⼀条语句,但是这个快捷键可以使我们的执⾏逻辑进⼊函数内部。在函数调⽤的地⽅,想进⼊函数观察细节,必须使⽤F11,如果使⽤F10,直接完成函数调⽤。
CTRL + F5:开始执⾏不调试,如果你想让程序直接运⾏起来⽽不调试就可以直接使⽤。

实际的使用

在这里插入图片描述
我们发现加了断点以后,调试的时候,居然跳过了断点前的代码,这样通过断点减少了程序员遇到的问题,想象一下有一万行代码前五千行代码都没得问题,如果一行一行调试即使你摁F10速度再快依旧需要很长时间,但是我们有了断点以后发现了节省了很多时间,让程序员对修改代码,查找的bug方式给方便和简洁。

F10的使用和F11的使用

在这里插入图片描述
F10:是过程意思是说,它会一条一条往下执行到了,test哪里它不会进入函数的内部而是直接算出结果,
F11:F11就是可以进入函数的内部一条一条的进行调试以及使用。 ``F11比F10更注重细节。

不调试代码直接执行用CTRL+F5即可

监视以及断点的实际应用

在这里插入图片描述C语言通过监视窗口可以看到i是如何递增的,在正常情况下这段代码i会打印到9以后,因为不满足接下来的循环条件而结束循环,但是如果我们想看第八次循环呢?那么是不是摁F10来实现呢?这里就需要了F9断点加上限制条件以及使用。

在这里插入图片描述
设计条件即可,这时候我们摁F10开始调试以后,我们就可以看到i从八开始进行打印以及循环的使用。

编程界的福尔摩斯

欢迎来到编程界的伦敦贝克街221B,只不过这里的侦探并非那位叼着烟斗、手持放大镜的福尔摩斯先生,而是我们英勇无畏的“VS福尔摩斯”。在这个由代码构筑的城市里,小偷不再偷金银珠宝,他们专偷程序的稳定性和效率——这些捣蛋鬼就是我们俗称的"BUG"。

我们的主人公“VS福尔摩斯”,凭借其无所不能的Visual Studio监视器和内存检查工具两大法宝,在错综复杂的函数丛林中游刃有余。他用监视器如鹰眼般精准定位每个变量的一举一动,通过内存观察则像显微镜一样洞察那些隐匿在数据结构深处的小bug们。

每当夜幕降临,城市陷入宁静,程序员们的噩梦却悄然开始。然而,不用担心,因为“VS福尔摩斯”已整装待发,他以调试窗口为笔记本,以断点为陷阱,挥舞着单步执行的大侦探手杖,誓要将每一个企图破坏代码和谐的小bug“窃贼”捉拿归案。

这段充满欢笑与智慧的抓“贼”故事即将上演,让我们跟随“VS福尔摩斯”的脚步,一同踏上这场妙趣横生又充满挑战的编程冒险之旅,看他是如何利用强大的VS工具,如同现实世界中的福尔摩斯那样,破解一个个看似无解的编程谜团,将那些令人头疼不已的小bug“小偷”一网打尽!
比如:`

#include <stdio.h>`
int main()
{
	int arr[10] = { 0 };
	int num = 100;
	char c = 'w';
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		arr[i] = i;
	}
	return 0;
}

我们来分析一下上面的代码

```c
#include <stdio.h>

这一行是预处理器指令,它告诉编译器在编译之前先包含stdio.h头文件。stdio.h(Standard Input Output)包含了标准输入输出函数的声明,例如 printf() 和 scanf() 等。虽然在这个示例中并未使用这些函数,但在实际编程中,我们通常会包含这个头文件以备后续可能的输入输出操作。

C
int main()
{

main() 函数是 C 语言程序执行的起点,它是程序的入口点。main() 返回一个整数值,用来表示程序的退出状态,0 表示正常结束。

C
    int arr[10] = { 0 };

这里声明了一个具有10个元素的一维整数数组 arr,并使用初始化列表 { 0 } 初始化所有元素为0。实际上,只给一个初始值时,C语言会将剩余的元素也默认初始化为该初始值,所以数组 arr 的所有元素都被初始化为0。

C
    int num = 100;
    char c = 'w';

接着声明了两个变量:一个整型变量 num 赋值为100,另一个字符型变量 c 赋值为字符 ‘w’。不过,在这段代码片段中,这两个变量没有被进一步使用,它们可能是为了展示如何声明和初始化不同类型的变量。

C
    int i = 0;

声明并初始化一个整数变量 i 作为循环计数器,它的初始值设为0。

C
    for (i = 0; i < 10; i++)
    {
        arr[i] = i;
    }

这是一个经典的for循环结构。循环从 i 为0开始,每次循环迭代都会递增 i 的值,直到 i 不再小于10为止。在循环体内,数组 arr 的每个元素通过下标 i 被赋值为当前 i 的值。因此,当循环结束后,数组 arr 的内容将是 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]。

C
    return 0;
}

最后,main() 函数返回0,表明程序已成功执行完毕且无错误。

综上所述,此段C语言代码的主要功能是对一个大小为10的整数数组 arr 进行初始化,使得其存储从0到9的连续整数。同时展示了如何声明和初始化其他类型(如整型和字符型)的变量,尽管在这段特定代码中它们未被实际使用。
在这里插入图片描述
好,我们接下来来观察一下内存。

在这里插入图片描述
很多少年在这里看不懂了,这是什么啊,这其实就是内存的一个分配,这设计到一个东西叫做函数栈帧后期会给大家分享,剩下就是我们如何理解这个内存呢?我们在地址处输入arr,arr是一个数组,数组本身就是一个地址,正常要用&操作符的,但是arr是一个数组所以不需要。

调试举例

求 1!+2!+3!+4!+…10! 的和,我们知道阶乘的公式是要求1!+2!+3!+4!+…+10!的和,首先我们明确阶乘(Factorial)的定义:对于任意正整数n,n!表示的是所有小于等于n且大于0的整数的乘积。

公式如下: n! = 1 * 2 * 3 * … * (n-1) * n

所以,要计算1!到10!的和,我们可以逐个计算每个数的阶乘然后相加。下面是具体计算过程:

Markdown
1! = 1
2! = 2 * 1 = 2
3! = 3 * 2 * 1 = 6
4! = 4 * 3 * 2 * 1 = 24
5! = 5 * 4 * 3 * 2 * 1 = 120
6! = 6 * 5 * 4 * 3 * 2 * 1 = 720
7! = 7 * 6 * 5 * 4 * 3 * 2 * 1 = 5040
8! = 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1 = 40320
9! = 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1 = 362880
10! = 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1 = 3628800
求和:
1! + 2! + 3! + 4! + ... + 9! + 10!
= 1 + 2 + 6 + 24 + 120 + 720 + 5040 + 40320 + 362880 + 3628800

将上述阶乘值相加得到最终结果。由于这是一个手动计算的过程,我这里直接给出计算器的结果:

1! + 2! + 3! + 4! + ... + 9! + 10! = 5,006,550

请看下⾯的代码:

#include <stdio.h>
//写⼀个代码求n的阶乘
int main()
{
 int n = 0;
 scanf("%d", &n);
 int i = 1;
 int ret = 1;
 for(i=1; i<=n; i++)
 {
 ret=ret*i;
 }
return 0;
}

特例代码和内存

在这里插入图片描述

  1. 栈区内存的使⽤习惯是从⾼地址向 低地址使⽤的,所以变量i的地址是 较⼤的。arr数组的地址整体是⼩ 于i的地址。
  2. 数组在内存中的存放是:随着下标 的增⻓,地址是由低到⾼变化的。 所以根据代码,就能理解为什么是左 边的代码布局了。 如果是左边的内存布局,那随着数组 下标的增⻓,往后越界就有可能覆盖 到i,这样就可能造成死循环的。为什么i和arr
    数组之间恰好空出来2个整型的空间 呢?这⾥确实是巧合,在不同的编译 器下可能中间的空出的空间⼤⼩是不 ⼀样的,代码中这些变量内存的分配
    和地址分配是编译器指定的,所以的 不同的编译器之间就有差异了。所以 这个题⽬是和环境相关的。

从这个理解我们能够体会到调试的重要性,只有调试才能观察到程序内部执⾏的细节,就像医⽣给病 ⼈做B超,CT⼀样。在这片充满狂野西部风情的C语言编程疆域,我们摇身一变成为Visual Studio(VS)编译舞台上的牛仔程序员,骑着代码骏马,在栈区、堆区和静态存储区这三大内存荒原上演绎了一场别具一格、笑料百出的捉虫大戏。这些如同草原上狡猾狐狸的小bug们,总是在不经意间躲进内存区域的沟壑之间,却不知我们的牛仔眼明手快,正握紧VS编译器这把熠熠生辉的六发左轮,准备在内存的广袤天地中来一场酣畅淋漓的追逐赛。

我们在栈区狭长的峡谷里与递归bug斗智斗勇,犹如牛仔在曲折蜿蜒的山道上追踪狡猾的羚羊;在堆区那片辽阔无垠的草原上,面对动态分配带来的迷雾重重,我们化身成精准定位的猎人,一次次击中那些藏匿其中的bug群落;而在静态区永恒不变的石漠之中,我们探寻全局变量的神秘踪迹,展现出了牛仔般的坚韧与耐心。

未来的编程拓荒之路上,让我们戴上牛仔帽,腰挎VS编译器这把威力无比的“Bug终结者”,在栈、堆、静态区的三重奏中翩翩起舞,演绎更多令人捧腹又不失智慧的“牛仔捉虫记”。不论是遭遇坎坷还是收获荣耀,每个在VS编译舞台上挥洒汗水的“内存牛仔”都将化身为英勇且诙谐的英雄,用他们的奇思妙想和过硬技能,为这片编程世界的内存荒原带来欢笑与和谐!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1389667.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++入门案例——通讯录管理系统 控制台项目

前言 C入门案例——通讯录管理系统 & 控制台项目 目录 前言总体概览实体类设计显示页面和退出系统 添加联系人逻辑拆解相关代码 显示联系人逻辑拆解相关代码 根据名字删除联系人逻辑拆解相关代码 根据名字查找联系人逻辑拆解相关代码 修改联系人逻辑拆解相关代码 清空所有…

如何公网远程访问Axure RP制作的本地web页面【内网穿透】

文章目录 前言1.在AxureRP中生成HTML文件2.配置IIS服务3.添加防火墙安全策略4.使用cpolar内网穿透实现公网访问4.1 登录cpolar web ui管理界面4.2 启动website隧道4.3 获取公网URL地址4.4. 公网远程访问内网web站点4.5 配置固定二级子域名公网访问内网web站点4.5.1创建一条固定…

Angular系列教程之组件

文章目录 前言组件的基本概念组件与指令的关系在模板中使用组件总结 前言 在Angular中&#xff0c;组件是构建Web应用程序的核心单元。它们允许我们将UI划分为独立且可重用的部分&#xff0c;并通过数据绑定和事件处理等机制来实现交互性。本文将介绍Angular组件的基本概念&am…

2024大数据“打假”:什么才是真湖仓一体?

编者按&#xff1a;近年来&#xff0c;随着金融、制造、政务、交通、医疗等行业数字化转型深入&#xff0c;大量智慧应用涌现&#xff0c;使得构建强大的数据分析技术栈成为必须&#xff0c;也让“湖仓一体”成为热门词汇。但面对市场中各色各样的湖仓技术&#xff0c;众多行业…

【漏洞复现】Kubernetes PPROF内存泄漏漏洞(CVE-2019-11248)

Nx01 产品简介 Kubernetes&#xff08;简称K8S&#xff09;是Google在2014年开源的一个容器集群管理系统。它用于容器化应用程序的部署、扩展和管理&#xff0c;目标是让部署容器化应用简单且高效。 Nx02 漏洞描述 漏洞存在于Kubernetes的1.18.6版本之前&#xff0c;可能导致未…

某侠网js逆向wasm解析

本次目标地址如下&#xff0c;使用base64解密获得 aHR0cHM6Ly93d3cud2FpbWFveGlhLm5ldC9sb2dpbg 打开网址&#xff0c;本次的目标是登录接口&#xff0c;如下图 本文主要讲解wasm的解析&#xff0c;所以对其他参数不做逆向处理&#xff0c;本次由wasm加密的参数只有sign一个&a…

07 整合SSM的快速理解

1.1 第一问&#xff1a;SSM整合需要几个IoC容器&#xff1f; 两个容器 本质上说&#xff0c;整合就是将三层架构和框架核心API组件交给SpringIoC容器管理&#xff01; 一个容器可能就够了&#xff0c;但是我们常见的操作是创建两个IoC容器&#xff08;web容器和root容器&…

记一次小黄站渗透过程,实操!

前言 记录某一次无意点开的一个小网站的渗透过程&#xff0c;幸运的是搭建平台是phpstudy&#xff0c;cms是beecms&#xff0c;beecms有通用漏洞&#xff0c;然后去网上找了资料&#xff0c;成功getshell并获取服务器权限。 渗透过程 无意点开一个网站&#xff0c;发现网站比…

【操作系统】在阅读论文:OrcFS: Orchestrated file system for flash storage时需要补充的基础知

在阅读论文&#xff1a;OrcFS: Orchestrated file system for flash storage是需要补充的基础知识 这篇论文是为了解决软件层次之间的信息冗余问题 To minimize the disk traffic, the file system buffers the updates and then flushes them to the disk as a single unit, …

datawhale 大模型理论基础 引言

学习地址&#xff1a;大模型理论基础 一、什么是语言模型&#xff08;Language Model) 语言模型其实是一个概率模型&#xff0c;给每一个句子列表计算一个概率值&#xff1a; p(x1​,…,xL​) 例如&#xff1a; p(the, mouse, ate, the, cheese)0.02…

解决若依Vue3前后端分离---路由切换时显示白屏

解决若依Vue3前后端分离---路由切换时显示白屏 1.问题重述 解决基于Vue3若依前后端分离项目中出现的路由正常切换但是就是不显示数据的问题&#xff0c;也就是不发起网络请求的问题。 找到如下位置中AppMain.vue文件 将除了css中的代码进行替换成如下的代码。 <template&g…

Python数据分析案例34——IMDB电影评论情感分析(Transformer)

电影评论的情感分析 案例背景 很多同学对电影系列的数据都比较喜欢&#xff0c;那我就补充一下这个最经典的文本分类数据集&#xff0c;电影情感评论分析。用神经网络做。对国外的英文评论文本进行分类&#xff0c;看是正面还是负面情感。 数据集介绍 数据集&#xff1a;IMDb…

C# wpf 获取控件的刷新时机

文章目录 前言一、为何需要刷新时机&#xff1f;例子一、隐藏控件后截屏例子二、修改控件大小后做计算 二、如何实现&#xff1f;1.使用动画2.使用TaskCompletionSource 三、完整代码四、使用示例1、隐藏工具条截屏2、修改宽高后获取ActualWidth、ActualHeight 总结 前言 做wp…

Codeforces Round 920 (Div. 3) F题 根号分治,后缀和,后缀和的后缀和

Problem - F - Codeforces 我看的这位UP的视频讲解 &#xff1a; Codeforces Round 920 (Div. 3) F题 根号分治 详解_哔哩哔哩_bilibili 目录 题意&#xff1a; 思路&#xff1a; 后缀和的后缀和: 后缀和的后缀和的中间段如何求&#xff1a; ———— 根号分治: 核心…

2024极新生态营再出发,携手华为云点燃AI技术与商业创新的火花

“ 成功的风口是时间加产品竞争力 ” 文&#xff5c;欣桐&凯丰 编辑 | 云舒 出品&#xff5c;极新 2023年大模型获得突破性进展&#xff0c;正在带来新一轮科技革命和产业变革&#xff0c;众多头部企业在一年内完成了产品迭代、拿到多轮融资&#xff0c;初创企业更是如…

Java-网络爬虫(三)

文章目录 前言一、爬虫的分类二、跳转页面的爬取三、网页去重四、综合案例1. 案例三 上篇&#xff1a;Java-网络爬虫(二) 前言 上篇文章介绍了 webMagic&#xff0c;通过一个简单的入门案例&#xff0c;对 webMagic 的核心对象和四大组件都做了简要的说明&#xff0c;以下内容…

不是人才用不起,而是AI巡检更有性价比!

在许多行业中&#xff0c;如煤炭、电力、化工等&#xff0c;安全生产是至关重要的。这就需要通过巡检&#xff0c;对设备运行状态进行实时监测&#xff0c;及时发现并处理潜在的安全隐患&#xff0c;从而降低事故发生的概率。但是传统的巡检方式通常依赖于人工进行&#xff0c;…

odoo17 | Qweb模板简介

前言 到目前为止&#xff0c;我们的房地产模块的界面设计还相当有限。构建列表视图很简单&#xff0c;因为只需要字段列表。表单视图也是如此&#xff1a;尽管使用了几个标签&#xff0c;如 <group>标签或 <page>标签 &#xff0c;但在设计方面几乎没什么可做的。…

【Java数据结构】04-图(Prim,Kruskal,Dijkstra,topo)

5 图 推荐辅助理解 【视频讲解】bilibili Dijkstra Prim 【手动可视化】Algorithm Visualizer &#xff08;https://algorithm-visualizer.org/&#xff09; 【手动可视化】Data Structure Visualizations (https://www.cs.usfca.edu/~galles/visualization/Algorithms.ht…