当前位置: 首页 > news >正文

【C语言】调试技巧

目录

一、什么是bug?

二、调试

1.一般调试的步骤

2.Debug 和 Release

三、调试环境准备

 四、调试时要查看的信息

1.查看临时变量的值

2.查看内存信息 

 3.查看调用堆栈

 4.查看反汇编信息

5.查看寄存器 

五、练习

六、常见的coding技巧

七、const的作用 

八、编程常见的错误


一、什么是bug?

我们平时会口头说 bug ,报错,waring(报警)等,bug 英文的意思是虫子,然而在计算机发展史上的第一只 Bug ,真的是因为一只飞蛾意外走入一电脑而引致故障,因此Bug从原意为臭虫引申为程序错误。

当我们

 

 这个时候就需要我们的调试 来开启新大陆

关于程序错误的 参考资料

二、调试

平时敲代码,总会遇到与一些问题导致程序执行不过去,你可能在那一直盯着刚写完的代码看(心里想这到底哪里出错了,但是就是没有找打错误的原因),这时就需要我们平时了解到的调试来解决问题(起先使用可能不熟练,慢慢来)

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

1.一般调试的步骤

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

2.Debug 和 Release

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

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

接下来调试下方代码

#include<stdio.h>
int main() 
{char* p = "hello word!";printf("%s\n",p);return 0;
}

在debug版本下 (执行程序)文件名.exe  是几十KB

而在release版本下  是 几 KB(原因是代码大小和运行速度上都是最优的)

再看下方代码

#include<stdio.h>
int main() 
{int i = 0;int arr[10] = { 0 };for (i = 0; i <= 12;i++){arr[i] = 0;printf("haha\n");}return 0;
}

在 vs2022 x86 debug 的环境下 

该程序的【执行结果】 无限循环打印 haha

而在release版本下 

 

没有死循环 打印了13行的haha

二者区别是因为:变量在内存中开辟的顺序发生了变化,影响到了程序执行的结果

三、调试环境准备

 如果要对代码进行调试首先要准备好调试的环境

就是要在debug版本下,才能使代码正常调试

(点击开始调试)或者按F5

在这里介绍一些调试的快捷键

  • F5  启动调试,经常用来直接跳到下一个断点处 
  • F9  创建断点和取消断点。 断点的重要作用,可以在程序的任意位置设置断点。
    这样就可以使得程序在想要的位置随意停止执行,继而一步步执行下去
  • F11  逐语句,就是每次都执行一条语句,但是这个快捷键可以使我们的执行逻辑进入函数内部(这是最长用的)
  • F10  逐过程,通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句
  • Ctrl + F5 开始执行不调试,如果你想让程序直接运行起来而不调试就可以直接使用

其他快捷键

 四、调试时要查看的信息

1.查看临时变量的值

在按调试后,观察变量的值

例如 输入 i

 

一直按F11当 i 的值变为 11时  i值的变化(0-11)

2.查看内存信息 

 

在内存窗口 输入 &i(找到i 的内存地址)

 3.查看调用堆栈

反映的是调用逻辑

 4.查看反汇编信息

 

5.查看寄存器 

五、练习

【例 1】

//实现代码:求 1!+2!+3! ...+ n! ;不考虑溢出
int main()
{int i = 0;int sum = 0;//保存最终结果int n = 0;int ret = 1;//保存n的阶乘scanf("%d", &n);for (i = 1; i <= n; i++){int j = 0;for (j = 1; j <= i; j++){ret *= j;}sum += ret;}printf("%d\n", sum);return 0;
}

 输入 1,输入2 和我们预想的结果一样,但当我们输入 3 的时候结果应该是 9 实际输出结果为:

 打印的结果出错了

接着进行调试,当调试到 i= 2是 正常的

 调试到 j = 3 是 ret 应该是 6 ,但是发现 ret由4 变到 12

 经果分析我们发现 原来是ret 每次进入内层的for循环 ret 的值接着上次的执行结果继续算

这时 我们在内层for循环上方加上  ret  =1;

//实现代码:求 1!+2!+3! ...+ n! ;不考虑溢出
#include<stdio.h>
int main()
{int i = 0;int sum = 0;//保存最终结果int n = 0;int ret = 1;//保存n的阶乘scanf("%d", &n);for (i = 1; i <= n; i++){int j = 0;ret = 1;//添加的代码for (j = 1; j <= i; j++){ret *= j;}sum += ret;}printf("%d\n", sum);return 0;
}

 【例 2 】死循环的原因

#include<stdio.h>
int main() 
{int i = 0;int arr[10] = { 0 };for (i = 0; i <= 12;i++){arr[i] = 0;printf("haha\n");}return 0;
}

调试后发现 

 

六、常见的coding技巧

  • 使用assert(断言,是一个宏,在release版本中会自动优化掉)
  • 尽量使用const(下面会讲到用法)
  •  养成良好的编码风格
  • 添加必要的注释
  • 避免编码的陷阱

【例】模拟实现库函数strcpy、

库函数strcpy 

//模拟实现strcpy
#include<stdio.h>
#include<assert.h>
char* my_strcpy(char *des,const char *src)
{assert(des != NULL);assert(src != NULL);//避免字符串为空char* temp = des;while (*des){*des = *src;des++;src++;}return (temp);
}
int main()
{char* str = "ab";char arr[20] = "xxxxxxxxxx";printf("%s\n",my_strcpy(arr,str));return 0;
}

优化

#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* des,const char *src) 
{assert(des != NULL);assert(src != NULL);char* temp = des;//用于返回首元素地址while (*temp++ = *src++);return des;
}
int main() 
{char *arr1 = "abcdef";char* arr2[20] = {0};printf("%s\n",my_strcpy(arr2,arr1));return 0;
}

七、const的作用 

const 在 * 左边

int num =0;
int n = 0;
const int *p =&num; 
p = &n;  //ok
*p = 20; //error

const 在 * 右边

int n = 1000;
int num = 0;
int * const p = &num; //限制了指针变量本身
p = &n; //error
*p = 20;//ok 

 【小总结】

const 修饰指针变量的时候:

  1. const放在 * 左边,修饰的是指针指向的内容,保证指针指向的内容不被修改。但是指针变量可以修改
  2. const 放在* 右边,修饰的是指针变量本身,保证指针变量本身不被修改。但是可以修改指针指向的内容

练习:模拟实现strlen

//模拟实现strlen
#include<stdio.h>
#include<assert.h>
int my_strlen(const char* str) 
{assert(str != NULL);int count = 0;while (*str) {count++;str++;}return count;
}
int main() 
{char* str = "abcdefg";printf("%d\n",my_strlen(str));return 0;
}

八、编程常见的错误

  • 编译型错误

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

  • 链接型错误

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

  • 运行时错误

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

相关文章:

【C语言】调试技巧

目录 一、什么是bug? 二、调试 1.一般调试的步骤 2.Debug 和 Release 三、调试环境准备 四、调试时要查看的信息 1.查看临时变量的值 2.查看内存信息 3.查看调用堆栈 4.查看反汇编信息 5.查看寄存器 五、练习 六、常见的coding技巧 七、const的作用 八、编程常见…...

MySQL SUBSTRING_INDEX() 函数的详细介绍

MySQL SUBSTRING_INDEX() 从给定字符串中返回指定数量的分隔符出现之前的子字符串。 当指定数字为正数时从最终分隔符的左侧返回子字符串&#xff0c;当指定数字为负数时从最终分隔符的右侧返回子字符串。 如果指定的次数大于分隔符的出现次数&#xff0c;则返回的子字符串将…...

开源数据库Mysql_DBA运维实战 (DML/DQL语句)

DML/DQL DML INSERT 实现数据的 插入 实例&#xff1a; DELETE 实现数据的 删除 实例&#xff1a; UPDATE 实现数据的 更新 实例1&#xff1a; 实例2&#xff1a; 实例3&#xff1a; DQL DML/DQL DML语句 数据库操纵语言&#xff1a; 插入数据INSERT、删除数据DELE…...

【LangChain】Memory

概要 大多数LLM应用都有对话界面。对话的一个重要组成部分是能够引用对话中先前介绍的信息。至少&#xff0c;对话系统应该能够直接访问过去消息的某些窗口。更复杂的系统需要有一个不断更新的世界模型&#xff0c;这使得它能够执行诸如维护有关实体及其关系的信息之类的事情。…...

Java并发编程(六)线程池[Executor体系]

概述 在处理大量任务时,重复利用线程可以提高程序执行效率,因此线程池应运而生。 它是一种重用线程的机制,可以有效降低内存资源消耗提高响应速度。当任务到达时&#xff0c;任务可以不需要的等到线程创建就能立即执行线程池可以帮助我们更好地管理线程的生命周期和资源使用,…...

macOS CLion 使用 bits/stdc++.h

macOS 下 CLion 使用 bits/stdc.h 头文件 terminal运行 brew install gccCLion里配置 -D CMAKE_CXX_COMPILER/usr/local/bin/g-11...

PS出现的问题——为什么PS另存的格式少了很多

在WIN11系统里面新安装的22和23版本PS会出现另存格式少的情况 解决方式&#xff1a;编辑——首选项——文件处理——开启旧版储存为 解决...

【Linux】进程通信篇Ⅱ:共享内存、消息队列、信号量

文章目录 一、共享内存1.1 一些接口1. shmget 函数&#xff1a;申请一个 system v 的共享内存块2. ftok 函数&#xff1a;设置唯一标识码3. shmctl 函数&#xff1a;控制 system v 的共享内存块&#xff08;可以删除、查看...&#xff09;4. shmat 函数&#xff1a;将进程与共享…...

8.14 校招 内推 面经

绿泡泡&#xff1a; neituijunsir 交流裙&#xff0c;内推/实习/校招汇总表格 1、半导体芯片一周资讯 - 小米OPPO之后&#xff0c;星纪魅族调整芯片业务&#xff0c;今年应届生或被全部优化&#xff0c;英伟达2024推出比H100更快的芯片 半导体芯片一周资讯 - 小米OPPO之后&…...

阿里云服务器安装部署Docker使用教程

本文阿里云百科分享如何在云服务ECS实例上&#xff0c;部署并使用Docker。Docker是一款开源的应用容器引擎&#xff0c;具有可移植性、可扩展性、高安全性和可管理性等优势。开发者可将应用程序和依赖项打包到一个可移植的容器中&#xff0c;快速发布到Linux机器上并实现虚拟化…...

WebRTC | ICE详解

目录 一、Candidate种类与优先级 二、ICE策略 1. iceServers 2. iceTransportPolicy 三、P2P连接 1.Nat类型 &#xff08;1&#xff09;完全锥型NAT &#xff08;2&#xff09;IP限制锥型NAT &#xff08;3&#xff09;端口限制锥型NAT &#xff08;4&#xff09;对称…...

网络设备(防火墙、路由器、交换机)日志分析监控

外围网络设备&#xff08;如防火墙、路由器、交换机等&#xff09;是关键组件&#xff0c;因为它们控制进出公司网络的流量。因此&#xff0c;监视这些设备的活动有助于 IT 管理员解决操作问题&#xff0c;并保护网络免受攻击者的攻击。通过收集和分析这些设备的日志来监控这些…...

2023年国赛数学建模思路 - 复盘:人力资源安排的最优化模型

文章目录 0 赛题思路1 描述2 问题概括3 建模过程3.1 边界说明3.2 符号约定3.3 分析3.4 模型建立3.5 模型求解 4 模型评价与推广5 实现代码 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 描述 …...

Compute shader SV 理解图

本图转子&#xff1a;【Computeshader】个人总结_蒋伟博的博客-CSDN博客...

生信豆芽菜-多种算法计算免疫浸润

网址&#xff1a;http://www.sxdyc.com/immuneInfiltration 一、使用方法 1、数据准备 一个全编码蛋白的表达谱基因&#xff0c;其中行为基因&#xff0c;列为样本 第一列为基因为行名&#xff0c;不能重复 2、选择计算的方法&#xff08;这里提供了5种免疫计算的方法&#x…...

逆向破解学习-单机斗地主

试玩 破解思路 9000 是成功的代码 Hook代码 import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XposedHelpers; import de.robv.android.xposed.callbacks.XC_LoadPackage; public class HookComJuneGameDouDiZhu extends HookImpl{ Override p…...

matplotlib绘制位置-时序甘特图

文章目录 1 前言2 知识点2.1 matplotlib.pyplot.barh2.2 matplotlib.legend的handles参数 3 代码实现4 绘制效果5 总结参考 1 前言 这篇文章的目的是&#xff0c;总结记录一次使用matplotlib绘制时序甘特图的经历。之所以要绘制这个时序甘特图&#xff0c;是因为22年数模研赛C…...

数据库概述、部署MySQL服务、必备命令、密码管理、安装图形软件、SELECT语法 、筛选条件

Top NSD DBA DAY01 案例1&#xff1a;构建MySQL服务器案例2&#xff1a;密码管理案例3&#xff1a;安装图形软件案例4&#xff1a;筛选条件 1 案例1&#xff1a;构建MySQL服务器 1.1 问题 在IP地址192.168.88.50主机和192.168.88.51主机上部署mysql服务练习必备命令的使用 …...

概率论与数理统计:第四章:随机变量的数字特征

文章目录 Ch4. 随机变量的数字特征1. 数学期望E(X)(1)数学期望的概念1.离散型①一维离散型随机变量X的数学期望&#xff1a; E X EX EX②一维离散型随机变量的函数的期望&#xff1a; E [ g ( X ) ] E[g(X)] E[g(X)]③二维离散型随机变量的函数的期望&#xff1a; E [ g ( X , …...

解决饿了么ui的对话框缩放和移动

import Vue from "vue";// v-dialogDrag: 弹窗拖拽水平方向伸缩 /** 使用方法* 将以下代码复制到一个js文件中&#xff0c;然后在入口文件main.js中import引入即可&#xff1b;* 给elementUI的dialog上加上 v-dialogDrag 指令就可以实现弹窗的全屏和拉伸了。* 给…...

网络编程(Modbus进阶)

思维导图 Modbus RTU&#xff08;先学一点理论&#xff09; 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议&#xff0c;由 Modicon 公司&#xff08;现施耐德电气&#xff09;于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

DingDing机器人群消息推送

文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人&#xff0c;点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置&#xff0c;详见说明文档 成功后&#xff0c;记录Webhook 2 API文档说明 点击设置说明 查看自…...

Python 实现 Web 静态服务器(HTTP 协议)

目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1&#xff09;下载安装包2&#xff09;配置环境变量3&#xff09;安装镜像4&#xff09;node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1&#xff09;使用 http-server2&#xff09;详解 …...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...

华为OD机试-最短木板长度-二分法(A卷,100分)

此题是一个最大化最小值的典型例题&#xff0c; 因为搜索范围是有界的&#xff0c;上界最大木板长度补充的全部木料长度&#xff0c;下界最小木板长度&#xff1b; 即left0,right10^6; 我们可以设置一个候选值x(mid)&#xff0c;将木板的长度全部都补充到x&#xff0c;如果成功…...

Vue 模板语句的数据来源

&#x1f9e9; Vue 模板语句的数据来源&#xff1a;全方位解析 Vue 模板&#xff08;<template> 部分&#xff09;中的表达式、指令绑定&#xff08;如 v-bind, v-on&#xff09;和插值&#xff08;{{ }}&#xff09;都在一个特定的作用域内求值。这个作用域由当前 组件…...

云原生周刊:k0s 成为 CNCF 沙箱项目

开源项目推荐 HAMi HAMi&#xff08;原名 k8s‑vGPU‑scheduler&#xff09;是一款 CNCF Sandbox 级别的开源 K8s 中间件&#xff0c;通过虚拟化 GPU/NPU 等异构设备并支持内存、计算核心时间片隔离及共享调度&#xff0c;为容器提供统一接口&#xff0c;实现细粒度资源配额…...

基于鸿蒙(HarmonyOS5)的打车小程序

1. 开发环境准备 安装DevEco Studio (鸿蒙官方IDE)配置HarmonyOS SDK申请开发者账号和必要的API密钥 2. 项目结构设计 ├── entry │ ├── src │ │ ├── main │ │ │ ├── ets │ │ │ │ ├── pages │ │ │ │ │ ├── H…...

在golang中如何将已安装的依赖降级处理,比如:将 go-ansible/v2@v2.2.0 更换为 go-ansible/@v1.1.7

在 Go 项目中降级 go-ansible 从 v2.2.0 到 v1.1.7 具体步骤&#xff1a; 第一步&#xff1a; 修改 go.mod 文件 // 原 v2 版本声明 require github.com/apenella/go-ansible/v2 v2.2.0 替换为&#xff1a; // 改为 v…...