c语言数组指针小例子,快速上手系列-C语言之指针篇(二)数组与指针

本文探讨了一维和二维指针数组的概念,以及它们与字符串、数组元素指针的区别。通过实例展示了如何操作和理解多维数组在内存中的分布,并强调了多维数组在处理多班级学号问题上的优势。同时,讲解了如何通过指针操作二维数组及其元素。
摘要由CSDN通过智能技术生成

之前说过,数组的元素可以是任意的,包括指针类型,并且指针数组也具有广泛的应用。

指针数组:

一个普通的数组可以存储普通数据,若存储的不是普通数据而是地址,即其元素均为指针类型数据;那么这个数组就称为指针数组。

一维指针数组的定义:

类型名 *数组名[数组长度]; 如:int *p[5];

例如定义一个指针数组,用于存放其他地址:

int a[4] = {1, 2, 3, 4};int *p[4] = { &a[0], &a[1], &a[2], &a[3] };

说明:[]的优先级要比*优先级高,所以这里p本质上是一个数组,只不过这数组的每一个元素都是地址(也就是存放别人的地址),那这地址应该是什么类型的地址呢?这就要看指针数组的类型了,比如本例指针数组的类型是int,那么他就能存放整型变量的地址。那p为什么又能存放 & a[0], & a[1], & a[2], & a[3]呢?因为对于int型数组,其中的元素也是int类型的变量,所以两者的类型一样当然可以存储呢。

再来看看指针数组与字符串的联系:

char *p[2]={“Hello”,“World”};p[0] = “Hello”;p[1] = “World”;

注意:

不要以为数组中存放的是字符串,它存放的是字符串首地址,这一点一定要注意。此时的 “hello”“word”存放在文字常量区,而p[0],p[1]存放的只是“hello”“word”的首地址(这字符串中第0个元素的起始地址)。如果想打印p[0]和p[1],可以通printf("p[0] = %s, p[1] = %s\n", p[0], p[1]);来打印结果;

再来看一个错误的用法:

int str[1024];

str = "hello"; //错误

说明:我们说过数组名代表是该数组的第一个元素的起始地址,且str是一个常量。虽然"hello"代表是该字符串的首地址,但也不能向一个常量str赋值吧。所以上面赋值代码是错误的,那是不是str就必须在定义的时候初始化呢?当然不是,可以使用符串的拷贝函数-strcpy函数来赋值,它会将一个字符串拷贝到指定的地址空间中去(不过这空间必须是合法的),而str代表的就是这个合法地址空间的起始地址。

数组指针:

数组指针就是一个指向数组的指针。这里需要注意一点,如:int a[10] ; int *p=a; 其中p是一个普通的指针变量,是一个指向数组a的第0个元素起始地址的指针变量, 而不是数组指针。

数组指针的定义形式为:类型名 (*数组名)[数组长度]; 如: int (*p)[5];

说到数组指针,还得说说数组元素指针,先看看数组指针与数组元素指针的区别:

数组在内存中的起始地址称为数组的指针数组元素在内存中的起始地址称为数组元素的指针注:在一个数组中,只有一个数组指针,它的步长是整个数组。而数组元素的指针则是多个,因为数组中的每个元素都有一个起始地址(数组元素的指针),而它的步长只是数组元素类型的长度。但值得注意的是一个数组的指针与它的第1个元素的起始地址( 数组元素的指针 )在数值上是相等的。举例说明:

750c116d7b6bf9f076a467aff5b0ccf7.png

说明:通过上面的例子可以看出,数组指针p和数组元素的指针*p(这里*p可以看成是(*p)+0,即第0个数组元素的指针)在数值上是相等的(他们的地址都为0x0105F8AC),但是,他俩的概念是不相同的,一个是数组指针,一个是数组元素指针,我们说过,数组指针的步长是整个数组,而数组元素指针的步长是数组元素类型的长度,上面例子正好验证了这一点,数组指针p地址为0X0105F8AC,p+1后地址为0X0105F8C0,两者相差20字节,正好是数组a的长度(数组a有5个元素,每个元素都为4字节的int型,总长度为20字节),即数组指针的步长是整个数组;再来看看数组元素指针*p,其地址为0X0105F8AC,(*p)+1后地址为0X0105F8B0,两者相差4字节,即数组元素指针的步长为数组元素类型的长度。

多维数组元素与指针

不管是一维还是多维的数组,在内存上实际分布始终是一维且连续的。多维数组用指针的方式表述起来稍稍有点复杂,既然操作起来比较复杂,也不是很容易理解,那用二维数组有什么用呢,来举个例子就明白了:

为了统计一个班级30个人的学号,很显然,我们会定义一个长度为30的一维数组,int student_no[30], 那么,student_no[0], student_no[1]...就是每个人的学号。那如果还要统计另一个班的30个人的学号,这时还是用一维数组,这时该一维数组的长度就不再是30了,而是60了,当然你也可以用两个长度为30的数组来表示,没问题,但是,万一要统计全校100个班级学生的学号呢,定义100个数组?这种方式显然不可取。再来说说刚才定义的60个元素的数组,对于第一个班学生的学号,可以使用student_no[i](其中i<30)来访问,第二个班级的可以用student_no[30+i](其中i<30),班级多了操作起来还是有点小复杂,同样不可取,这时,多维数组可以为解决这样一个问题提供帮助。

下面来简单看看二维数组:

int a[2]; //不过这时我们让a纵向分布:

7d8f5683c7b30e13840f156ff54bc52f.png

int b[3]; //此时b横向分布:

eba25fca8d936841b6abe3c023549cb2.png

int a[2][3]; 对于二维数组,我们从一整行去看,也可以看成一维的:

dd94ae057c4fe400e4d7c8a74a83bae7.png

那么单独去看某一行,也可以看成一个一维数组:

81ad4a1cb8e4e55b654967dd7e988a59.png

这里只是为了方便理解,要知道,不管是一维还是多维的数组,在内存上实际分布始终是一维且连续的。

3e1b6ef5110643ae34545a795ab159ee.png

对于int a[2][3]中的a+i和*(a+i)详解:

a+i为指向某一行的起始地址,只是行的上下移动,a+1的跨度是一行。*(a+i):这里需要注意,此时的*不是取值,而是将行指针变为指向某一行的第0个元素的起始地址的列指针:

5e6113f39b420945b780d7b3aa25b4cb.png

注意:a+1和*(a+1)在数值上是一个值,但是类型不一样,前者是一行的起始地址,而后者是某一行的第0个元素的起始地址。

f6f7a0c9034c4039ac7da2b7224c6ad6.png

如何让指针指向a[1][1]?首先让行指针指向第二行a+1,其次将指向第二行的行指针变成指向第二行的第0个元素的起始地址的列指针*(a+1),再次让列指针指向第1个元素的起始地址*(a+1)+1。如果取该地址的值 *(*(a+1)+1 ) == a[1][1]。

23eef8605bcd499635e13c6e530f9fa8.png

以实际例子来看看用指针的方式来表示二维数组:

14d24d6a7e2d49fea4ea2768b3349108.png

理解一些东西不难,表达出来貌似就不是那么回事儿了,写起来还是相当繁琐的,指针与数组暂时就写这么多,后续写写字符串与指针,函数与指针相关内容。

f20101b02c75f7560729e4f1a88d1ac9.png

举报/反馈

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值