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

【C语言初阶(19)】实用的 VS 调试技巧

文章目录

  • Ⅰ 调试的介绍
  • Ⅱ 常用调试快捷键
  • Ⅲ 调试的时候查看程序当前信息
    • ⒈查看临时变量的值
    • ⒉查看内存信息
    • ⒊查看调用堆栈
    • ⒋查看汇编信息
    • ⒌查看寄存器信息
  • Ⅳ 观察形参指针指向的数组
  • Ⅴ 易于调试的代码该如何编写
    • ⒈const 修饰指针变量
    • ⒉良好代码示范
  • Ⅵ 编程中常见的错误

Ⅰ 调试的介绍

1. 什么是调试

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

2. 调试的基本步骤

  1. 发现程序的错误的存在(开发 → 测试 → 用户)。
  2. 以隔离、消除等方式对错误进行定位。
  3. 确定错误产生的原因。
  4. 提出纠正错误的解决办法。
  5. 对程序错误允以改正,重新测试。

3. Debug 和 Release 的介绍

  • Debug 称为调试版本,它包含有各种调试信息,且不作任何优化,所占空间更大。
  • Release 称为发布版本,此版本进行了优化,不包含调试信息,用户使用的以及测试人员检测的都是这个版本。

在这里插入图片描述

4. 调试环境的准备

  • 在环境中选择 Debug 选项,只有在这里才可以进行调试。

Ⅱ 常用调试快捷键

  • 注意:以下所有快捷键如果不起作用的话,请搭配 FN 键使用。

F5

  • 启动调试:用于直接跳到下一个断点处,经常和 F9 成对使用。

F9

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

F10

  • 逐过程调试:通常用于处理一个过程,一个过程可以是一次函数调用,或是一条语句。
  • 当碰到函数调用时,不会进到函数内部,无法观测到函数体内部的细节。

F11

  • 逐语句调试:每次都执行一条语句,可以进入函数体观察函数内部的细节。

CTRL + F5

  • 开始执行不调试:用于让程序直接运行起来而不进行调试,学习编程初期使用的最多的就是这个。

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

  • 进入调试之后,在调试窗口中才能看到下面的信息。

在这里插入图片描述

⒈查看临时变量的值

  • 在调试开始之后,用于观察变量内存放的值的变化。
  • 自动窗口与监视窗口都能够观察到局部变量的信息。

在这里插入图片描述

自动窗口与监视窗口的区别

  • 自动窗口会自动显示所有局部变量的信息(不管你是否需要),随着调试的进程,自动窗口内所观察的变量有时会自动出现,有时又会自动消失。
  • 监视需要程序员手动输入(想观察谁就输入谁),观察的变量不会随着调试的进程而消失,强雷建议使用监视窗口来观察局部变量的值。

⒉查看内存信息

在这里插入图片描述

⒊查看调用堆栈

调用堆栈

  • 调用堆栈,反应的是函数的调用关系。
  • 后期当遇到很复杂的函数关系的时候,就可以使用调用堆栈来理清函数之间的调用关系。

举个栗子

  • 现有以下代码:

在这里插入图片描述

  • main 函数调用了 test1,test1调用了 test2,test2 → test3。
  • 而 main 函数又是被其他函数所调用的。
  • 函数调用采用的是数据结构中 的先进后出的特性,先调用的函数后结束。

⒋查看汇编信息

  • 查看 C 语言代码所翻译出来的汇编代码。

在这里插入图片描述

⒌查看寄存器信息

  • 用于查看当前运行环境的寄存器的使用信息。

在这里插入图片描述

Ⅳ 观察形参指针指向的数组

  • 众所周知,在给函数传数组名的时候,传递的是数组首元素的地址;
  • 这样一来的话,在函数内部调试的时候,只是输入个数组名就不能很好的观察到数组内部的值的变化。

在这里插入图片描述

  • 但是,只要在我们想要观察的数组指针变量名后面加上 " 逗号 " 和 " 想要观察的元素个数 " 就可以很好观察到数组内部元素的值了。

在这里插入图片描述

二维数组同理

  • 如果将二维数组名作为参数传给函数的话,观察函数形参的二维数组指针也就只能观察到原数组第一行的内容。
  • 因为二维数组的数组名为第一行的地址。

Ⅴ 易于调试的代码该如何编写

1. 什么是高质量的代码

  1. 代码能够正常运行。
  2. 尽可能少的 BUG(不可能没有BUG)。
  3. 可执行效率够高。
  4. 可读性要强。
  5. 可维护性高。
  6. 注释要清晰,能让人看得懂。
  7. 相应文档齐全。

2. 常用编程技巧

  1. 使用 assert 断言。
    • assert 的表达式如果为假则直接结束程序并报错,使用 assert 来判断指针是否指向 NULL。
  2. 尽量使用 const 修饰变量(包括变量和指针变量)。
  3. 养成良好的编码风格。
  4. 添加必要的注释。
  5. 避免编码的陷阱。

⒈const 修饰指针变量

  • const 可以修饰普通的变量,让变量的值无法被修改,从而变成常变量(本质任然是个变量)。

在这里插入图片描述

  • 同样的,const 也可以用来修饰指针变量。const 修饰指针有两种形式。

  • 对于指针变量来说,应该关注的有两点:

    1. 指针变量本身能不能改;
    2. 指针变量指向的那个变量能不能改。
  • const 放置的位置就决定了能不能修改这两种值。

1. const 放在 * 的左边

const int* p = &n;	//只要 const 放在 * 的左边,这两中写法就都一样。
int const* p = &n;	
  • 限制的是指针指向的内容,也就是限制了 *p,让指针指向的那个变量的值无法被修改。
  • 但是指针变量是可以修改的,指针可以指向其他变量。

在这里插入图片描述

2. const 放在 * 的右边

int* const p = &n;
  • 限制的是指针变量本身,在 p 已经指向了 n 之后,p 就不能再被修改为指向其他变量了。
  • 但是可以通过指针变量修改指向的内容。

在这里插入图片描述

  • 当在 * 的两边都加上 const 之后,p 就只能指向 n,并且*p 也不能改变 n 的值了。

在这里插入图片描述

⒉良好代码示范

模式实现 strcpy

#include <stdio.h>
#include <assert.h>//我只想改变 str1,不想改变 str2 ,const 保证 src 指针指向的 str2 数组内的值不会一不小心被修改
char* my_strcpy(char* dest, const char* src)
{assert(dest && src);			//当传过来的两个指针为 NULL 时,直接结束程序并报错char* ret = dest;				//保存目的地首元素的地址,一会还要传回去while (*dest++ = *src++)		//直到 *src = \0,然后由于是后置++,再将 \0 也赋值给 dest 为止{;}return ret;						//返回 dest 的起始地址
}	int main()
{char str1[20] = "***************";char str2[]   = "hello word!";printf("%s\n", my_strcpy(str1, str2));return 0;
}

在这里插入图片描述

模拟实现 strlen

#include <stdio.h>
#include <assert.h>size_t my_strlen(const char* str)	//防止原数组中得内容不小心被修改
{assert(str);					//判断传过来的指针的有效性 (!= NULL)const char* end = str;			//标识字符串末尾while (*end++);					//当 end 指向 \0 时退出循环return (end - str - 1);			//指针 - 指针得到同一块空间的两个地址之间的元素个数//-1 是因为后置 ++ 的副作用,要把 \0 的那一个元素去掉
}int main()
{char str[] = "hello word!";printf("%zd\n", my_strlen(str));return 0;
}

在这里插入图片描述

Ⅵ 编程中常见的错误

1. 编译型错误

  • 一般为语法错误
  • 这类错误直接查看错误提示信息(双击),解决问题,或者凭借经验就可以搞定。

2. 链接型错误

  • 一般为未包含头文件符号名(函数名、变量名)不存在或者拼写错误
  • 看错误提示信息,主要在代码中找到错误信息中的标识符,然后定位问题所在。

3. 运行时错误

  • 一般为程序运行起来时发现的错误
  • 只能借助调试定位到问题所在,这种问题最难解决。

相关文章:

【C语言初阶(19)】实用的 VS 调试技巧

文章目录 Ⅰ 调试的介绍Ⅱ 常用调试快捷键Ⅲ 调试的时候查看程序当前信息⒈查看临时变量的值⒉查看内存信息⒊查看调用堆栈⒋查看汇编信息⒌查看寄存器信息 Ⅳ 观察形参指针指向的数组Ⅴ 易于调试的代码该如何编写⒈const 修饰指针变量⒉良好代码示范 Ⅵ 编程中常见的错误 Ⅰ 调…...

虚拟机之间配置免密登录

目录 一、配置主机名映射 二、虚拟机配置SSH免密登录 三、验证 一、配置主机名映射 即修改/etc/hosts文件&#xff0c;将几台服务器和主机名进行映射。 注意每台服务器都要进行同样的配置。这样在各自服务器下&#xff0c;我们就可以通过主机名访问对应的ip地址了。 当然&…...

【contenteditable属性将元素改为可编辑状态】

元素添加contenteditable属性之后点击即可进入编辑状态 像这种只修改一条属性不必再打开弹框进行编辑&#xff0c;使用contenteditable会很方便 添加失焦、回车、获焦事件 如 <p :contenteditable"item.contenteditable || false"keydown.enter"key($event…...

Android 第三方库CalendarView

Android 第三方库CalendarView 根据需求和库的使用方式&#xff0c;自己弄了一个合适自己的日历&#xff0c;仅记录下&#xff0c;方便下次弄其他样式的日历。地址 需求&#xff1a; 只显示当月的数据 默认的月视图有矩形的线 选中的天数也要有选中的矩形框 今天的item需要…...

钉钉群消息推送

1. 添加钉钉群机器人 PC端登录&#xff08;当前版本手机端无法进行推送关键词设置&#xff09;&#xff0c;群设置--> 机器人 --> webhook进行安全设置复制webhook对应的url 2. 群消息推送 钉钉群消息支持纯文本和markdown类型 2.1 调用示例源码 import com.alibaba.…...

css clip-path 属性介绍

circle() – 圆 语法&#xff1a;circle( [<shape-radius>]? [at <position>]? ) shape-radius 圆的半径 position 圆的中心点位置 使用方法&#xff1a; clip-path: circle(); // 以元素的中心点为圆的中心点&#xff0c;最小宽度一半为圆的半径。clip-path: c…...

Python之pyinstaller打包exe填坑总结

一、起因 编写了一个提取图片中文字的python脚本&#xff0c;想传给同事使用&#xff0c;但是同事电脑上没有任何python环境&#xff0c;更没有安装python库&#xff0c;因此想到通过pyinstaller打包成exe程序传给同事使用&#xff0c;于是开始了不断地挖坑填坑之旅 import p…...

Form Generator 表单JSON数据储存以及JSON回显表单

一、form-generator是什么?✨ ⭐️ 🌟 form-generator的作者是这样介绍的:Element UI表单设计及代码生成器,可将生成的代码直接运行在基于Element的vue项目中;也可导出JSON表单,使用配套的解析器将JSON解析成真实的表单。 但目前它提供的组件并不能满足我们在项目中的…...

Python - OpenCV识别条形码、二维码(已封装,拿来即用)

此代码可识别条形码和二维码&#xff0c;已封装好&#xff0c;拿来即用&#xff1a; import cv2 import pyzbar.pyzbar as pyzbar import numpy from PIL import Image, ImageDraw, ImageFontclass CodeScan():def __init__(self):super(CodeScan, self).__init__()def decode…...

Python如何快速实现爬取网页?

首先我们对要编写的爬虫程序进行简单地分析&#xff0c;该程序可分为以下三个部分&#xff1a; 拼接 url 地址发送请求将照片保存至本地 明确逻辑后&#xff0c;我们就可以正式编写爬虫程序了。 导入所需模块 本节内容使用 urllib 库来编写爬虫&#xff0c;下面导入程序所用…...

怎么才能远程控制笔记本电脑?

为什么选择AnyViewer远程控制软件&#xff1f; 为什么AnyViewer是远程控制笔记本电脑软件的首选&#xff1f;以下是选择AnyViewer成为笔记本电脑远程控制软件的主要因素。 跨平台能力 AnyViewer作为一款跨平台远程控制软件&#xff0c;不仅可以用于从一台Windows电…...

【3】C++实现多进程、多线程

系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 TODO:写完再整理 文章目录 系列文章目录前言一、同步与互斥1、【thread】同步并发的方法(1)创建、终止、等待、分离线程的方法1.创建线程形式1:使用一个循环执行的函数创建一个线程形式2:…...

Linux用户权限信息、chmod以及chown命令

权限修改 权限信息chmod命令chown命令 权限信息 在Linux系统中&#xff0c;每个文件和目录都包含了权限信息&#xff0c;用于控制对其的访问权限。 文件权限&#xff1a;Linux系统中的文件权限由三组权限表示&#xff0c;分别是所有者权限、组权限和其他用户权限。 所有者权…...

利用vscode--sftp,将本地项目/文件上传到远程服务器中详细教程

1、首先在 vscode 中下载 sftp&#xff1a; 2、然后在 vscode 中打开本地将要上传的项目或文件&#xff1a; 3、安装完后&#xff0c;使用快捷键 ctrlshiftP 打开指令窗口&#xff0c;输入 sftp:config &#xff0c;回车&#xff0c;在当前目录中会自动生成 .vscode 文件夹及 s…...

java List和数组相互转换的方法总结

Java中&#xff0c;可以通过以下方法将List转换为数组&#xff1a; List<String> list new ArrayList<>(); String[] array list.toArray(new String[0]);在这个例子中&#xff0c;我们将一个String类型的List转换为String类型的数组。需要注意的是&#xff0c;…...

【音频分离】demucs V3的环境搭建及训练(window)

文章目录 一、环境搭建&#xff08;1&#xff09;新建虚拟环境&#xff0c;并进入&#xff08;2&#xff09;安装pyTorch&#xff08;3&#xff09;进入代码文件夹&#xff0c;批量安装包&#xff08;4&#xff09;安装其他需要的包 二、数据集准备&#xff08;1&#xff09;下…...

JAVA环境变量配置(windows)

windows配置环境变量&#xff08;大小写不区分&#xff09;&#xff1a; 新建JAVA_HOME&#xff1a;jdk的根目录 D:\Java\jdk1.8.0_71Path&#xff08;必须&#xff09;%JAVA_HOME%\bin新建&#xff08;类路径&#xff09;CLASSPATH: .;D:\Java\jdk1.8.0_71\lib(或者.;%JAVA_HO…...

爬虫教程1_Xpath 入门教程

Xpath 入门教程 在编写爬虫程序的过程中提取信息是非常重要的环节&#xff0c;但是有时使用正则表达式无法匹配到想要的信息&#xff0c;或者书写起来非常麻烦&#xff0c;此时就需要用另外一种数据解析方法&#xff0c;也就是本节要介绍的 Xpath 表达式。 Xpath表达式 XPath…...

Python爬虫教程篇+图形化整理数据(数学建模可用)

一、首先我们先看要求 1.写一个爬虫程序 2、爬取目标网站数据&#xff0c;关键项不能少于5项。 3、存储数据到数据库&#xff0c;可以进行增删改查操作。 4、扩展&#xff1a;将库中数据进行可视化展示。 二、操作步骤&#xff1a; 首先我们根据要求找到一个适合自己的网…...

数字安全观察·数据安全分析方向

政策形势方面&#xff0c;全球均在加快制定并完善数字经济与数据安全相关政策法规。国际方面&#xff0c;欧盟、美国、英国、印度、俄罗斯等国家持续完善数据安全方面的法律政策&#xff0c;并且尤其关注数据跨境传输方面的问题。同时世界各国都着力关注人工智能数据安全风险&a…...

Kubernetes系列-配置存储 ConfigMap Secret

1 ConfigMap介绍 1.1 概述 在部署应用程序时&#xff0c;我们都会涉及到应用的配置&#xff0c;在容器中&#xff0c;如Docker容器中&#xff0c;如果将配置文件打入容器镜像&#xff0c;这种行为等同于写死配置&#xff0c;每次修改完配置&#xff0c;镜像就得重新构建。当然…...

bacnet ddc控制器如何通过485口转发Modbus协议控制modbus执行设备

要将BACnet DDC控制器通过485口转发Modbus协议控制Modbus执行设备&#xff0c;可以按照以下步骤进行&#xff1a; 确定Modbus执行设备的通信参数&#xff1a;包括串口波特率、数据位、停止位和校验位等参数。确保BACnet DDC控制器的485口通信设置与Modbus执行设备一致。 在BAC…...

构建易于运维的 AI 训练平台:存储选型与最佳实践

伴随着公司业务的发展&#xff0c;数据量持续增长&#xff0c;存储平台面临新的挑战&#xff1a;大图片的高吞吐、超分辨率场景下数千万小文件的 IOPS 问题、运维复杂等问题。除了这些技术难题&#xff0c;我们基础团队的人员也比较紧张&#xff0c;负责存储层运维的仅有 1 名同…...

前期自学Java的基础部分总结(二)

一. 抽象类 1.1 抽象类的概述 在java中&#xff0c;一个没有方法体的方法应该定义为抽象方法&#xff0c;而类中如果有抽象方法&#xff0c;该类必须被定义为抽象类 1.2 抽象类的特点 抽象类和抽象方法必须使用abstract关键字修饰 publice abstract class 类名{};public…...

Altova MissionKit 2023Crack

Altova MissionKit 2023Crack MissionKit是一套面向信息架构师和应用程序开发人员的企业级XML、JSON、SQL和UML工具的软件开发套件。MissionKit包括Altova XMLSpy、MapForce、StyleVision和其他市场领先的产品&#xff0c;用于构建当今的真实世界软件解决方案。 使用MissionKit…...

Linux CentOS上快速安装Docker并运行服务

在 CentOS 上快速安装 Docker&#xff0c;可以按照以下步骤进行&#xff1a; 1. 更新系统&#xff1a; sudo yum update 2. 安装 Docker&#xff1a; sudo yum install docker 3. 启动 Docker 服务&#xff1a; sudo systemctl start docker 4. 设置 Docker 开机自启动&…...

TCP三次握手与四次断开

TCP三次握手机制 三次握手是指建立一个TCP连接时&#xff0c;需要客户端和服务器总共发送3个包。进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。 1、客户端发送建立TCP连接的请求报文&#xff0c;其…...

关于前端与APP录音相关的笔记

文章目录 一、前言二、内容组成1、权限获取2、针对设备兼容3、内容类型转换4、传输存储 三、拓展内容自动播放部分 一、前言 主要针对前端适配录音能力的简要记录&#xff0c;针对默认的wav及其可能需要转换到特定的mp3之类格式以适配需求的问题。&#xff08;这类通常是兼容tt…...

【Java】SpringBoot项目整合FreeMarker加快页面访问速度

文章目录 什么是FreeMarker&#xff1f;它的优点有那些&#xff1f;使用方式 什么是FreeMarker&#xff1f; Freemarker是一个模板引擎技术&#xff0c;它可以将数据和模板结合起来生成最终的输出。它是一种用于生成文本输出&#xff08;如HTML、XML、JSON等&#xff09;的通用…...

conda环境下安装opencv-python包

conda环境下安装opencv-python包 一、#查看环境 conda info --env# conda environments: # base D:\ProgramData\Anaconda3二、激活base环境 进入conda环境 conda init cmd.exe conda activate base三、根据版本号&#xff0c;下载对应的 python-opencv…...