vs 调试

news2024/12/18 20:05:15

常用:

调试->窗口->

                      断点

                      监视

                      自动窗口

                      局部变量

                      调用堆栈

                      内存

                      反汇编(也可以右键,转到反汇编)

                      寄存器

快捷键:

F5:启用调试,经常用来跳到下一个断点处

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

F10逐过程,通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句。

F11逐语句,就是每次都执行一条语句,但这个快捷键可以使我们的执行逻辑进入函数内部(这是最常用的)

Crtl+F5:开始执行不调试

一些调试的实例:
实例1:

实现代码:求1!+2!+3!+……+n!

所以正确的代码就应该是

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
int main()
{
	int i = 0;
	int n = 0;
	scanf("%d", &n);
	int sum = 0;
	int ret = 1;
	for (i = 1;i <= n;i++)
	{
		ret = 1;
		int j = 0;
		for (j = 1;j <= i;j++)//计算i!
		{
			ret *= j;//经过调试我们可以发现ret的值会在程序进行中改变,而我们希望每次计算n!的时候ret初始化为1,所以应该在函数内部定义ret
		}
		sum += ret;//i从1到n的阶乘相加
	}
	printf("%d\n", sum);
	return 0;
}

 实例2:
研究程序死循环的原因

我们观察程序,分析为什么会死循环打印hello world

(以上结果演示是在vs编译器的x86环境下,不同编译器,预留空间不同)

在调试过程中我们可以发现arr[12]的值始终是和i的值相等的,那么这是为什么呢,可能是他们占了同一块内存空间,我们将他们的地址取出观察发现确实占的是同一块内存空间,等i自增到12是,将arr[12]这块空间赋值为10,在重复,i永远不可能大于12,所以死循环打印hello world。

原因:局部数据在栈区中存放,而栈区内存的使用习惯是先使用高地址处的空间,在使用低地址处的空间。但是数组地址随着下标的增长是由低到高变化的。所以如果i和arr之间有适当的空间,那么利用数组的越界操作就有可能会覆盖到i,导致死循环出现。

(这类题目,在《C陷阱和缺陷》书籍中提到)

如果是release版本的话,就会对上面的代码,做出适当的优化,打印结果在这题中会打印出12个hello world。

  • DeBug通常称为调试版本,它包含调试信息,并且不做任何优化,便于程序员运行调试程序。
  • Release版本称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好的使用(也是测试人员测试的版本)

如何写出好的代码

  • 代码运行正常
  • bug很少
  • 效率高
  • 可读性高
  • 可维护性高
  • 注释清晰
  • 文档齐全

常见技巧

  • 尽量使用assert
  • 尽量使用conse
  • 养成良好的编码风格
  • 添加必要的注释
  • 避免编码的陷阱

例:模拟实现strcpy函数

 我们可以初步写一个这样的代码,但是这个代码还有许多地方可以优化

void my_strcpy(char*dest, char*src)//destination目标空间,source源数据
{
	while (*src != '\0')
	{
		*dest = *src;
		src++;
		dest++;
	}
	*dest = *src;//将\0,也拷贝过来
}

int main()
{
	char arr1[20];
	char arr2[] = "hello world";
	//strcpy再拷贝字符串的时候会把\0也拷进去,这边便于识别字符长度
	my_strcpy(arr1, arr2);//用一个strcpy函数实现将arr2里面的数据拷贝到arr1中
	return 0;
}

比如函数部分可以写为

void my_strcpy(char* dest, char* src)//destination目标空间,source源数据
{
	while (*dest++ = *src++)
	{
		;
	}
	
}

\0的ASCII码值是数字0,所以我们可以指将将其放在判断里面,后置++,先赋值后++,当判断是\0的时候再自增一次,就是想当于将\0的值也赋进去。

我们也可以将代码进一步优化,使用assert和const

#include<assert.h>
void my_strcpy(char* dest, const char* src)//destination目标空间,source源数据//加const src的值不能被改变,避免出现拷反的情况
{
	//断言(如果assert为假就报错,需要包含assert.h的头文件)
	assert(src != NULL);// 空指针不能直接使用,传参是不能对空指针进行解引用
	assert(dest != NULL);
	while (*dest++ = *src++)
	{
		;
	}
	
}

assert函数,表示断言如果assert为假,编译器就会报错,并能定位到错的位置,使用时需要包含assert.h的头文件。

const表示常变量,这个值不能被直接修改,但是我们可以通过他的地址找到这个数对其进行修改,如:

const修饰指针变量分为两种情况

  1. const放在*左边(如const int* p或者int const *p)意思是:p指向的对象不能通过p来改变了,但是p变量本身的值是可以改变的。
  2. const放在*右边(int* const p)意思是:p指向的对象是可以通过p来改变的,但是不能修改p变量本身的值
  3. 若两边都放(const int* const p)意思是:p指向的对象和p变量本身都不可通过p来改变。 

但是我们发现在库函数里,strcpy的返回值类型是char*,这是为什么呢?

是为了实现链式访问,strcpy函数返回的是目标空间的起始地址。

我们可以将代码进一步完善:

#include<stdio.h>
#include<assert.h>
//模拟实现strcpy函数

char* my_strcpy(char* dest, const char* src)//destination目标空间,source源数据//加const src的值不能被改变,避免出现拷反的情况
{
	//断言(如果assert为假就报错,需要包含assert.h的头文件)
	char* ret = dest;//在程序运行过程中dest的地址已经发生了改变,所以我们可以向将他的起始地址存起来。之后我们使用这个数据的时候就可以通过起始地址找到它
	assert(src != NULL);// 空指针不能直接使用,传参是不能对空指针进行解引用
	assert(dest != NULL);
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}

int main()
{
	char arr1[20];
	char arr2[] = "hello world";
	//strcpy再拷贝字符串的时候会把\0也拷进去,这边便于识别字符长度
	printf("%s\n",my_strcpy(arr1, arr2));//用一个strcpy函数实现将arr2里面的数据拷贝到arr1中
	return 0;
}

(《高质量C/C++编程》一书中最后章节试卷有关strlcpy模拟实现的项目 )

注意:

  1. 分析参数的设计(命名,类型),返回值类型的设计
  2. 野指针,空指针的危害
  3. assert的使用
  4. const的使用
  5. 注释的添加

模拟一个strlen函数:

#include<stdio.h>
#include<assert.h>
//模拟实现strlen函数
int my_strlen(const char* str)
{
	int count = 0;
	assert(str != NULL);//这里也可以直接写str
	while (*str != '\0')//这里也可以直接写*str
	{
		str++;
		count++;
	}

	return count;
}
int main()
{
	char arr[] = "hello world";
	printf("%d\n", my_strlen(arr));
	return 0;
}

 变成常见错误:

  • 编译型错误

(看错误提示信息,双击)

  • 链接型错误 

(一般是标示符名不存在,或者拼写错误,可以用 ctrl+F查看文本)

  • 运行时错误 

借助调试,一步步分析。 

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

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

相关文章

从构想到实现:EasyOne 多模态 AI 产品开发历程

在人工智能技术飞速发展的今天&#xff0c;智能产品和服务已经从单一的应用向多模态智能系统进化。随着大语言模型、计算机视觉、语音识别等领域的突破&#xff0c;开发集成多种 AI 技术的平台变得日益重要。为此&#xff0c;我们开发了 EasyOne&#xff0c;一个全新的 AI 多模…

游戏引擎学习第43天

仓库 https://gitee.com/mrxiao_com/2d_game 介绍运动方程 今天我们将更进一步&#xff0c;探索运动方程&#xff0c;了解真实世界中的物理&#xff0c;并调整它们&#xff0c;以创建一种让玩家感觉愉悦的控制体验。这并不是在做一个完美的物理模拟&#xff0c;而是找到最有趣…

【已解决】启动此实时调试器时未使用必需的安全权限。要调试该进程,必须以管理员身份运行此实时调试器。是否调试该进程?

【已解决】启动此实时调试器时未使用必需的安全权限。要调试该进程&#xff0c;必须以管理员身份运行此实时调试器。是否调试该进程? 目录一、前言二、具体原因三、解决方法 目录 报错截图 一、前言 进行应用程序开发时&#xff0c;需要对w3wp进行附加调试等场景&#xff…

idea无法识别文件,如何把floder文件恢复成model

前景&#xff1a; 昨天&#xff0c;我在之前的A1214模块包下新增了一个demo类&#xff0c;然后又新建了一个A1216模块&#xff0c;写了算法题&#xff0c;后面打算用git提交&#xff0c;发现之前的A1214模块下的demo类和新建的模块源文件都已经被追踪了&#xff0c;都是绿色的&…

2024三掌柜赠书活动第三十六期:深度学习高手笔记系列

目录 前言 理解深度学习基础 数据预处理技巧 关于《深度学习高手笔记》 编辑推荐 内容简介 作者简介 图书目录 媒体评论 《深度学习高手笔记》全书速览 结束语 前言 不用多讲&#xff0c;近两年的技术圈关于AI相关的技术讨论层出不穷&#xff0c;而深度学习作为人工…

【技术干货】移动SDK安全风险及应对策略

移动SDK&#xff08;软件开发工具包&#xff09;已经成为应用开发中不可或缺的一部分。通过SDK&#xff0c;开发者能够快速集成分析、广告调度、音视频处理、社交功能和用户身份验证等常见功能&#xff0c;而无需从零开始构建。这不仅能节省时间和资源&#xff0c;还能提高开发…

【一文概述】常见的几种内外网数据交换方案介绍

一、内外网数据交换的核心需求 内外网数据交换的需求核心在于“安全、效率、合规”&#xff0c;而应用场景的多样性使得不同企业需要定制化的解决方案。通过结合业务特性和安全等级要求&#xff0c;企业能够选择适合的技术方案来实现高效、安全的内外网数据交换。 1、数据安全…

【Linux 篇】Docker 容器星河与镜像灯塔:Linux 系统下解锁应用部署奇幻征程

文章目录 【Linux 篇】Docker 容器星河与镜像灯塔&#xff1a;Linux 系统下解锁应用部署奇幻征程前言一 、docker上部署mysql1. 拉取mysql镜像2. 创建容器3. 远程登录mysql 二 、docker上部署nginx1. 拉取nginx镜像2. 在dockerTar目录下 上传nginx.tar rz命令3. 创建nginx容器4…

Pytorch | 从零构建Vgg对CIFAR10进行分类

Pytorch | 从零构建Vgg对CIFAR10进行分类 CIFAR10数据集Vgg网络结构特点性能应用影响 Vgg结构代码详解结构代码代码详解特征提取层 _make_layers前向传播 forward 训练和测试训练代码train.py测试代码test.py训练过程和测试结果 代码汇总vgg.pytrain.pytest.py 前面文章我们构建…

实战 | 某院校小程序记录

更多大厂面试经验的视频分享看主页和专栏 目录&#xff1a; 前言&#xff1a; 渗透思路 1.绕过前端 2.信息泄露 3.爆破用户账号密码 4.信息泄露2 结束 前言&#xff1a; 遇到一个学校小程序的站点&#xff0c;只在前端登录口做了校验&#xff0c;后端没有任何校验&#x…

k8s kubernetes

文章目录 CGroupk8s运行时k8s组件k8s组件安装kubeadm命令kubectl命令k8s官网代码 CGroup 在 Linux 上&#xff0c;控制组&#xff08;CGroup&#xff09;用于限制分配给进程的资源。kubelet 和底层容器运行时都需要对接控制组来强制执行 为 Pod 和容器管理资源 并为诸如 CPU、…

uniapp中vuex(全局共享)的应用

一、Vuex概述 1.1 官方解释 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。 它采用集中式存储管理 应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化 - Vuex 也集成到 Vue 的官方调试工具 devtools extension&#xff0c;提供了诸…

React简单入门 - [Next.js项目] - 页面跳转、AntD组件、二级目录等

须知 1Next.js 官网(英文)Next.js by Vercel - The React Framework2Next.js 文档(中文)简介 | Next.js 中文文档3React官网(中文)https://react.docschina.org/learn4Ant Design组件总览组件总览 - Ant Design5tailwindcss类名大全 官网英Justify Content - TailwindCS…

【十进制整数转换为其他进制数——短除形式的贪心算法】

之前写过一篇用贪心算法计算十进制转换二进制的方法&#xff0c;详见&#xff1a;用贪心算法计算十进制数转二进制数&#xff08;整数部分&#xff09;_短除法求二进制-CSDN博客 经过一段时间的研究&#xff0c;本人又发现两个规律&#xff1a; 1、不仅仅十进制整数转二进制可…

企业内训|阅读行业产品运营实战训练营-某运营商数字娱乐公司

近日&#xff0c;TsingtaoAI公司为某运营商旗下数字娱乐公司组织的“阅读行业产品运营实战训练营”在杭州落下帷幕。此次训练营由TsingtaoAI资深互联网产品专家程靖主持。该公司的业务骨干——来自内容、市场、业务、产品与技术等跨部门核心岗位、拥有8-10年实战经验的中坚力量…

pinctrl子系统学习笔记

一、背景 cpu的gpio引脚可以复用成多个功能&#xff0c;如可以配置成I2C或者普通GPIO模式。配置方式一般是通过写引脚复用的配置寄存器&#xff0c;但是不同芯片厂商配置寄存器格式内容各不相同&#xff0c;设置引脚复用无法做到通用且自由的配置&#xff0c;只能在启动初始化…

免费开源了一个图床工具 github-spring-boot-starter

文章目录 第一步&#xff0c;新建一个SpringBoot项目第二步&#xff0c;在pom文件里面引入jar包第三步&#xff0c;配置你的github信息github.authorization1、进入github官网&#xff0c;登录账号&#xff0c;点击头像&#xff0c;选择setting2、选择[Developer Settings](htt…

JVM系列之内存区域

每日禅语 有一位年轻和尚&#xff0c;一心求道&#xff0c;多年苦修参禅&#xff0c;但一直没有开悟。有一天&#xff0c;他打听到深山中有一古寺&#xff0c;住持和尚修炼圆通&#xff0c;是得道高僧。于是&#xff0c;年轻和尚打点行装&#xff0c;跋山涉水&#xff0c;千辛万…

自动驾驶AVM环视算法--python版本的俯视碗型投影模式

c语言版本和算法原理的可以查看本人的其他文档。《自动驾驶AVM环视算法--3D碗型投影模式的exe测试工具》本文档进用于展示部分代码的视线&#xff0c;获取方式网盘自行获取&#xff08;非免费介意勿下载&#xff09;&#xff1a;链接: https://pan.baidu.com/s/1STjUd87_5wDk_C…

【并发容器】源码级ConcurrentHashMap详解(java78)

1. ConcurrentHashMap 为什么要使用ConcurrentHashmap 在多线程的情况下&#xff0c;使用HashMap是线程不安全的。另外可以使用Hashtable&#xff0c;其是线程安全的&#xff0c;但是Hashtable的运行效率很低&#xff0c;之所以效率低下主要是因为其实现使用了synchronized关…