<c语言>数组与指针

<c语言>数组与指针


一、数组

(1)数组是什么

关于数组是什么
首先 我们需要知道:
通俗易懂的来说 数组是一个能够存放数据的一个工具吧
他的存储空间十分特殊,是一种连续存放的物理空间结构,
因此我们可以快速的访问其中的数据以此来运算
至于为什么能够快速访问,
这涉及到cpu的结构 他包含缓存,
而缓存是一次性能够读好几个字节(至于几个取决于你的cpu的位数)
(缓存相关知识涉及到计算机硬件知识,这里给大家点到为止)
因此数组有助于计算机在内存中快速读写数据。

(2)怎么定义数组(输入,输出)

我们以c语言为例 给大家举例一个整形数组的定义

int arr[10];//在这里 int 是数组的类型 可以根据实际情况调整
            //而arr是数组名,也可以根据实际情况来自己取名
            //而[10]的意思是这个数组最多可以存放十个元素,具体元素个数也可以根据自己来调整

到了输入,我们需要利用循环结构来利用scanf函数来输入,以下为代码举例

int i;
for(i=0;i<10,i++)//为什么i从0开始,是因为数组的首元素并不是arr[1]而是arr[0],所以需要从0开始
				//此外,我们需要注意判断输入的次数来避免内存越界(输入过多)了
				//并且这里用while或者用for循环并没有明确的规定,可以根据自己的实际情况来使用
{
	scanf("%d",&arr[i]);//其中&arr[i]可以写成arr+i,具体原因详见本章第四节 指针与数组的关系
}

比如说输入一个10个整形的数组1,2,3,4,5,6,7,8,9,10
那么他在内存空间是这样存放的一维数组的物理空间
其中黄色区域为未开辟空间,一旦输入过多,就会出现内存越界
以下是输出代码片段(接着输入的片段为基础)

for(i=0;i<10;i++)
{
	printf("%d",arr[i]);//这里arr[i]可以换成*(arr+i),原因也是详见本文“指针与数组的关系”
}

(3)二维数组(输入,输出)

我们可以用一维数组的思维来认识二维数组
在这里我们需要注意的是,二维数组指的是思维上的二维,但物理结构仍然属于是一维连续排放的
所以在处理内存问题的时候,注意不要被他的名称误导了

int arr[2][5];//在这里 int 是数组的类型 可以根据实际情况调整
            	//而arr是数组名,也可以根据实际情况来自己取名
            	//而[2][5]的意思是这个数组最多可以存放2*5也就是10个元素,具体元素个数也可以根据自己来调整

比如说输入一个10个整形的二维数组1,2,3,4,5,6,7,8,9,10
对于二维数组的输入比较特殊,需要用到嵌套循环来进行输入和输出

int i,j;
for(i=0;i<2;i++)
{
	for(j=0;j<5;j++)
	{
		scanf("%d",&arr[i][j]);
	}
}

如图是二维数组的下标及其位置,
其中每一个a[]都是这一个二维数组的子数组的名称
而子数组名本身也是一个地址
二维数组下标及其位置
以下是输出代码片段(接着输入的片段为基础)

for(i=0;i<2;i++)
{
	for(j=0;j<5;i++)
	{
		printf("%d",arr[i][j]);//这里arr[i]可以换成*(*(arr+i)+j),原因也是详见本文“指针与数组的关系”
	}
	printf("\n");//以二维形式打印,如果不需要,去掉这行代码即可
}

二、指针

(1)指针是什么

在c语言中 指针就是地址的别称,似乎指针这玩意被大家吹嘘的很难很烧脑,其实大家抛开那些繁杂的名词来看,也不算太难
指针实际上就是地址
地址是啥
这里我们可以把内存比喻成一个酒店
他有好多个房子 有好多个门牌号
而房子对应的是每一个字节
门牌号对应的是地址
我们可以通过一个门牌号去找到那个房间
也就是在内存中,每一个字节都有一个专属的地址,想要去访问那个地址,
我们就可以通过门牌号去访问那个地址,去使用或者改写他

补充的是 指针在32位机器中占4个字节 64位中占8个字节

(2)野指针

野指针 顾名思义 是野的指针 在这里我们可以理解为野狗(会乱咬人,不安全)
野指针是指那种地址指向内存中无效空间或者并未开辟空间的指针,一旦访问这个指针。
会造成严重报错。
在这里插入图片描述

(3)怎么定义指针

这里我们以c语言定义一个整形指针为例

int *p=NULL;//其中 int* 是类型,代表他是一个整形指针 ;p是指针的名字,可以根据你的实际情况来调整
			//至于int *p=NULL,是属于指针的初始化,把指针置空,避免野指针的出现

这里我们要注意如果需要给指针赋值的时候,需要注意类型的一个对应,比如说指针不能赋值一个常数 ,一级指针最好不要赋值二级指针(部分编译器报错)
这里我们需要注意的是,指针的类型与他所指向的那个空间所存储的数据有关系
这有什么影响呢
比如
以上方定义为例,我们定义了一个整形指针,而整形的大小是4个字节
如果这个时候我们指针p不为空,我们对p进行以下操作

p++;

如果本来指针指向的地址为0x00000012
那么对他进行自加1以后 他的地址就变成了0x00000016
在这你观察到了什么?
没错,他对地址加1并不是地址数值上的加1
而是对地址加上‘1’个整形大小的数组
这就体现到了指针类型的重要性了
因为他的类型决定了这个指针+‘1’ 会导致加多少个字节的地址。
而这个多少取决于他的类型所占的空间。

(4)二级指针

二级指针 简单的来说 就是指针的指针(地址的地址)
每一个指针定义过后,内存都会为它开辟一块空间 ,而这一块空间肯定也会有地址
而这个地址,就是我们所说的二级指针

int **p=NULL;//其中 int** 是类型,代表他是一个二级整形指针 ;p是指针的名字,可以根据你的实际情况来调整
			//至于int *p=NULL,是属于指针的初始化,把指针置空,避免野指针的出现

讲到这 我相信大家也可以明白
还有三级 四级指针 但是实际运用很少运用到,大家可以类比来猜猜三级指针的定义

三、指针与数组的关系

(1)数组名

我们每次定义一个数组,他都会有一个数组名,就是你所定义的那个名称,而这个名称,实际上也是一个指针,是数组首元素也就是arr[0]的地址
所以对于二维数组,他的每一个子数组都有一个数组名,就是arr[],比如说上面的二维数组arr[2][5]
他就存在2个子数组,每个子数组是一个一维数组,每个一维数组的数组名分别是arr[0],arr[1];
了解了这里 我们就可以初步理解指针与数组的关系了

而学到这里,不禁好奇问一下,大家有没有想过为什么数组首元素的表示方法是arr[0]而不是
arr[1]呢
是外国人有毛病吗弄得这么麻烦
其实并不是
他之所以那样规定的原因是
数组名是首元素地址
所以arr指向的是arr[0]
那如果我对arr进行+1
那么我将得到arr[1]的地址
也就是说 arr+1是arr[1] 的地址

进一步的,我们可以推导出arr+i就是arr[i]的地址
但这只是一个地址
我们需要分清楚的是
是址还是值
在这里arr[i]是一个值,是一个数据
而arr+i是一个地址,我们需要对他进行解引用
也就是

*(arr+i);//这里我们可以把*理解为钥匙,可以打开房号房门看看里面的数据是什么

因此我们可以很容易的知道*(arr+i)等价与arr[i]
也可以得到&a[i]等价于arr+i;

更有意思的来了
根据以上的讲述,我们知道了*(arr+i)等价于arr[i];
(arr+i) 也等价于(i+arr)吧;(都是地址,加法交换律)
那*(i+arr)等价于i[arr]吧;
因此我们可以得到arr[i]等价于i[arr]
是不是觉得很惊讶
你可以自己去编译器实践试试,当你把以上所说的理解透彻以后,其实也没有那么大的惊讶

而二维数组本质上跟二级指针有莫大的关系(这里理解起来有点难度,建议慢慢理解消化)

我们可以知道,比如上面所说的数组arr[2][5]
他是一个装一维数组的数组,是不是很像我描述的二级指针,装指针的指针
从前半部分arr[2]可以看出,他装了两个一维数组,而每个数组有5个元素
那么arr[0][0]和arr[1][0]就分别是每一个一维数组的头,也就是他们的首元素
根据我以上可以知道前半部分arr[i]我们可以这样表示*(arr+i)其中括号里的是个二级指针
可以理解为套娃,酒店每一层楼都需要一把钥匙,进入了这一层楼还需要对应门牌号的钥匙

这里我们得到了第i+1行的地址,也就打开了那一层楼,而如果需要打开对应的房间,就需要额外一把钥匙,也就是*(*(arr+i)+j) 中间的括号是楼层,用( * )钥匙进入arr[i]然后在这一层走j步,走到arr[i][j]的地址,看到需要进入房间的门牌号,最后我们需要再用一把钥匙( * )得到里面的数组 arr[i][j];

总结

1.一维数组中&arr[i]是个地址,等价于arr+i
2.一维数组中arr[i]是个值,等价于*(arr+i)
3.二维数组中&arr[i][j]是个地址,等价于*(arr+i)+j(其中arr+i是个二级指针,打开了还是个指针)
4.二维数组中arr[i][j]是个值,等价于*(*(arr+i)+j)

四、其他有关数组的相关知识

1.指针数组(用来装指针的数组)
2.字符串(用来装字符的数组)
3.函数指针(指向函数的指针)
4.函数指针数组(用来装函数指针的数组)
好啦
本期学习就到这里了
大家如果想要深入学习以上其他相关知识的话可以自行去相关网站获取知识

本文就到这里啦,如果有哪里疏漏或者错误的地方,请各位帮忙纠错=v=
希望这个文章能让你收获

																			作者:@沐甄希
  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值