C语言基础

C语言基础,第1张

今天记录一个错误的程序,原因是这个程序可以引出几个小的知识点,有助于初学者更好学习C语言。


好了,直接看程序。


目录
    • 问题引出
    • 运行结果
    • 调试
    • 结论

问题引出
#include 

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("hehe\n");
	}

	return 0;
}

看了这段代码,大家觉得运行结果是什么呢?我认为对于这段代码,90%以上的初学者都能看出代码是有问题的,很明显定义的数组只有10个元素,而在for循环里面一直可以访问到第13个元素,这是一个数组越界问题,但是如果让你说出这段代码的运行结果,我相信很多初学者会感到无法预料,我第一次看到这段代码就是这个感觉。


运行结果

直接说结果:这段代码会陷入死循环。


很多人可能想不通为什么是这个结果(当然我指的是初学者)。


调试

接下来,我通过一个初学者的角度来分析一下这段代码,不想看这个可以直接跳转到结论。


第一步: 启动调试。


在VS编译器中,按F10进入调试,打开监视窗口,然后添加要监视的变量i和 arr,因为根据for循环中的条件,一直能访问到arr[12],因此把arr[10]、arr[11]、arr[12] 也添加到监视中。


如下图

第二步:开始调试,按F11一步步调试,调试过程中,我们能发现一个问题,i的值与arr[12]的值保持同步,当i=12时,如下图

第三步:分析。


我们发现,a[12] 被赋为0,i此时也变为了0,因此,无法跳出循环,这就是为什么程序运行结果为死循环的原因!

那么为什么会这样呢?这就引出了另一个知识点:数据存储,我们知道在内存中局部变量存储在栈区,i 和 arr就存在栈区。


下面需要明确两个知识点:

  1. 栈区的使用方式:先使用低地址空间,再使用高地址空间。


  2. 数组的存储方式:随着数组下标增长,地址由低到高变化。


结论

我们先定义i放入栈中,再定义数组arr放入i下方,arr的地址是低于i的,从低到高访问数组,一旦越界,就会访问到i的地址,arr[12]的地址与i一样,指的是同一块内存! 因此当循环到i=12时,arr[12] 被赋为0,也即i被赋为0,这样的话永远也跳不出循环!如下图所示。



这个时候肯定很多初学者(曾经的我)会有疑问:我没定义arr[12],为什么会访问到arr[12] ? 这就又引出另外一个小知识点:关于数组的定义。


我们需要知道 arr[i] 的含义,arr[i] <==>*(arr+i),所以arr[10] 这个数组也可以这样表示:10[arr]。


(但必须注意不能这样定义数组,可以这样访问) arr[12] 其实就是指:地址为(arr+12)的这块内存的值 。


C/C++对数组下标是不检查的,所以数组越界访问不会报错。


那么还有一个问题,i和数组arr在栈上的位置隔了两个整型空间,这是偶然还是必然?这个取决于编译器的内存分配方式,VC6.0编译器i和arr的地址是挨着的,VS空了两个整型,Linux下空了1个整型。


OK,就先写到这吧。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/562293.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-01
下一篇 2022-04-01

发表评论

登录后才能评论

评论列表(0条)

保存