IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> c语言学习笔记-调试的艺术以及const在指针上的应用 -> 正文阅读

[C++知识库]c语言学习笔记-调试的艺术以及const在指针上的应用

目录

前言

一、从阶乘累和入手

二、越界访问的函数

?三、const在指针上的应用

总结


前言

在学习c语言的过程中,我发现了调试的重要性,也愈发感觉到在Visual Studio 下功能的强大,它能够让我们更好的找到出错的地方,并且也能够对代码进行进一步的优化,接下来,跟我一起来见识一下调试的魅力吧!(使用工具-Visual Studio 2022)

一、从阶乘累和入手

首先来上手一个1.0版本的代码:

//阶乘累和算法 1.0版本
int factorial_Tiredand(int n)
{
	int sum = 0;
	int ret = 1;
	for (int i = 0; i < n; i++)
	{
		for (int j = 1; j <= i + 1; j++)
		{
			ret *= j;
		}
		sum += ret;
	}
	return sum;
}

?从这里单纯的看的话其实很慢才会发现问题,所以在代码打出来的时候就测试几个自己能够口算的数来验算一下,看看是否正确。

?我们使用了3做测试,3!+2!+1!=9,可是实际上程序给我们的答案是15,错误了,与答案相差6,这个时候我们应该怎么做呢?这个时候不应该和程序死磕,死看代码,这个时候就要灵活的使用调试这个功能,ctrl+F10 F11 F5.....

?随后使用ctrl加F10打开调试,打开窗口中的监视,将局部变量名输入进去准备观察它们的变化,输入3后F11跳转至我们这个累和函数准备进行第一次循环:

?第一次十分正常,1!正确,累加也正确,继续

?这一次也十分正确:2!=2,累加之后1!+2! = 3。

?但是其实此时已经发现了ret似乎执行上一次之后没有发生变化,并没有还原成1,而调试是指向下次循环的,那么就有可能出了问题,继续。

果然出了问题,证明了我们的想法,3!=6才对,而此时是12,明显多乘了一个2,而这2的来源正是上次ret留存下来的2,所以,通过调试,我们就发现了ret每次算完一个数的阶乘之后没有回到初始位置而是继续乘了下去,所以经过修改我们就可以的得到2.0的版本。

//阶乘累和算法 2.0版本
int factorial_Tiredand(int n)
{
	int sum = 0;
	for (int i = 0; i < n; i++)
	{
		int ret = 1;
		for (int j = 1; j <= i + 1; j++)
		{
			ret *= j;
		}
		sum += ret;
	}
	return sum;
}

?我们将ret的创建直接放在累和的循环中,这样就能保证每次累加到下一个阶乘时会是从初始值1开始累乘的。

相反的,我们就可以思考得到另一个问题:既然是累乘之后相加,并且每次都是乘以上一次的结果,比如3!=2!*3,4!=3!*4,在算阶乘的时候同时相加岂不更妙?

于是乎,全新的3.0版本问世:

//阶乘累和算法 3.0版本
int factorial_Tiredand(int n)
{
	int sum = 0;
	int ret = 1;
	for (int i = 1; i <= n; i++)
	{
		ret *= i;
		sum += ret;
	}
	return sum;
}

相比前两个版本,没有出现误算,并且只用了一个循环,代码简洁明了,这正是状态十分的代码!健壮性强大!?

二、越界访问的函数

int main()
{
	int i = 0;
	int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	for (i = 0; i <= 12; i++)
	{
		arr[i] = 0;
		printf("hh\n");
	}
	return 0;
}

?首先,你来猜猜在Visual Studio 2022 x86环境下会是怎么样的一种情况呢?

测试一下,会发现竟然是无限循环啊!这是怎么一回事呢?你单单看代码能够将它给看破吗?看不破,你需要用到调试

如果不考虑越界访问的话(本身其实会报越界访问的错误的),乍一眼看hh应该被打印13次的,可是运行结果是无限循环,我们可以先想想其中的原因:

这个循环是由i的值来确定的,既然无限循环,证明了i永远不能超过12,可是i在++,除了for循环中的i++能控制i的值外,还有什么地方能够控制i的值呢?那么,只有一个地方了,就是循环体内的arr[i]出了问题,因为一直它就是被赋给0的,于是乎,我们调试一番便就可以发现问题的所在:

在调试到12之前都没有问题,知道当i = 12的时候,我们发现:

?

进行下一步之后:

?i和arr[12]同时变成0了,果然是这里出了毛病!,我们取地址一看:

?果然i和arr[12]是住在一间房子里面的(doge)!怪不得每次i到达12都被arr拖回0了,永远也到达不了13的那个结束循环的时候。

上面这种情况视环境而变:这里出现的情况就是在创建局部变量时,在栈区先创建高地址的空间,也就是i,随后创建低地址的空间arr,然后每次读取arr地址都会前进一步,而纯巧合的是arr[12]的空间刚好和i的空间重合了,所以才会出现这种情况,图解一下或许会更加清楚:

?三、const在指针上的应用

?const是可修饰常变量的,不可被改哦。
*注意const int* p只限制*p,不限制p,表示p指向的对象不能通过p来进行改变。但是p变量中的地址是可以改变的。
int *const p=这里就只限制p,不限制*p了。表示p的内容不能被改变,但是p指向的对象可以通过p来改变。
左定值右定向

总结

总之,调试这个功能是非常强大的,在找程序错误的时候有奇效!小萌新一枚,一起加油!

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-24 15:05:50  更:2022-02-24 15:05:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:39:10-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码