当前位置: 首页 > 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 指令就可以实现弹窗的全屏和拉伸了。* 给…...

python学习day39

图像数据与显存 知识点回顾 1.图像数据的格式&#xff1a;灰度和彩色数据 2.模型的定义 3.显存占用的4种地方 a.模型参数梯度参数 b.优化器参数 c.数据批量所占显存 d.神经元输出中间状态 4.batchisize和训练的关系 import torch import torchvision import torch.nn as nn imp…...

大模型的LoRa通讯详解与实现教程

一、LoRa通讯技术概述 LoRa(Long Range)是一种低功耗广域网(LPWAN)通信技术,由Semtech公司开发,特别适合于物联网设备的长距离、低功耗通信需求。LoRa技术基于扩频调制技术,能够在保持低功耗的同时实现数公里甚至数十公里的通信距离。 LoRa的主要特点 长距离通信:在城…...

Nginx 事件驱动理解

在做埋点采集服务的过程中&#xff0c;主要依靠openresty加lua脚本来实现采集。高并发还是主要依靠nginx来实现。而其核心就是事件驱动/多路io复用&#xff08;epoll机制&#xff09;&#xff0c;不同的linux服务器都有对应的实现方式。 而epoll机制就是&#xff0c;应用启动的…...

大陆4D毫米波雷达ARS548调试

本文介绍了大陆ARS548毫米波雷达的调试与测试流程&#xff0c;主要包括以下内容&#xff1a; 设备参数&#xff1a;最大检测距离301m&#xff08;可调93-1514m&#xff09;&#xff0c;支持gPTP时间同步。 接线调试&#xff1a; Windows需使用USB-RJ45转换器 Linux可直接连接网…...

慢慢欣赏linux 之 last = switch_to(prev, next)分析

last switch_to(prev, next); 为什么需要定义last作为调用switch_to之前的prev的引用 原因如下&#xff1a; struct task_struct * switch_to(struct task_struct *prev,struct task_struct *next) {... ...return cpu_switch_to(prev, next);> .global cpu_switch_tocpu_…...

Git 使用大全:从入门到精通

Git 是目前最流行的分布式版本控制系统&#xff0c;被广泛应用于软件开发中。本文将全面介绍 Git 的各种功能和使用方法&#xff0c;包含大量代码示例和实践建议。 文章目录 Git 基础概念版本控制系统Git 的特点Git 的三个区域Git 文件状态 Git 安装与配置安装 GitLinuxmacOSWi…...

Boost ASIO 库深入学习(3)

Boost ASIO 库深入学习&#xff08;3&#xff09; UDP简单通信导论 在继续深入前&#xff0c;我们不妨也来点碎碎念&#xff0c;因为UDP通信协议的模型与TCP是不同的&#xff0c;这种差异正是理解“无连接通信”的关键所在。我们下面要构建的&#xff0c;是一个经典的UDP通信…...

windows10下搭建nfs服务器

windows10下搭建nfs服务器 有参考这篇博客 Windows10搭建NFS服务 - fuzidage - 博客园 下载 NFS Server这个app 通过网盘分享的文件&#xff1a;nfs1268 (1).exe 链接: https://pan.baidu.com/s/1rE4h710Uh-13kWGXvjkZzw 提取码: mwa4 --来自百度网盘超级会员v5的分享 下载后…...

Excel自动分列开票工具推荐

软件介绍 本文介绍一款基于Excel VBA开发的自动分列开票工具&#xff0c;可高效处理客户对账单并生成符合要求的发票清单。 软件功能概述 该工具能够将客户对账单按照订单号自动拆分为独立文件&#xff0c;并生成可直接导入发票清单系统的标准化格式。 软件特点 这是一款体…...

wpf Behaviors库实现支持多选操作进行后台绑定数据的ListView

<ListView ItemsSource"{Binding SchemeItems}" SelectionMode"Extended" VerticalAlignment"Stretch" HorizontalAlignment"Stretch"><ListView.ContextMenu><ContextMenu><MenuItem Header"删除" …...