当前位置: 首页 > 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…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录

ASP.NET Core 是一个跨平台的开源框架&#xff0c;用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录&#xff0c;以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

JDK 17 新特性

#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持&#xff0c;不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的&#xff…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)

在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马&#xff08;服务器方面的&#xff09;的原理&#xff0c;连接&#xff0c;以及各种木马及连接工具的分享 文件木马&#xff1a;https://w…...

视觉slam十四讲实践部分记录——ch2、ch3

ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

jmeter聚合报告中参数详解

sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample&#xff08;样本数&#xff09; 表示测试中发送的请求数量&#xff0c;即测试执行了多少次请求。 单位&#xff0c;以个或者次数表示。 示例&#xff1a;…...

Chrome 浏览器前端与客户端双向通信实战

Chrome 前端&#xff08;即页面 JS / Web UI&#xff09;与客户端&#xff08;C 后端&#xff09;的交互机制&#xff0c;是 Chromium 架构中非常核心的一环。下面我将按常见场景&#xff0c;从通道、流程、技术栈几个角度做一套完整的分析&#xff0c;特别适合你这种在分析和改…...

【Veristand】Veristand环境安装教程-Linux RT / Windows

首先声明&#xff0c;此教程是针对Simulink编译模型并导入Veristand中编写的&#xff0c;同时需要注意的是老用户编译可能用的是Veristand Model Framework&#xff0c;那个是历史版本&#xff0c;且NI不会再维护&#xff0c;新版本编译支持为VeriStand Model Generation Suppo…...