字符指针,指针数组,数组指针

字符指针

常见的一种用法

首先大家有没有遇见过字符指针这样一种写法

这种写法是通过指针变量p来输出字符串,而当我们执行这样一个程序时会呈现出这样的结果

我们来深入了解一下这个代码

1.首先p作为一个char类型的指针变量只能存放一个char类型变量的地址。

2.其次“abcdef”作为一个字符串,我们可以把它当作一个简单的表示式,任何一个表达式都会有两种属性(值属性和类型属性),此时就会把首字符的地址当作其值属性,所以在后面的赋值操作时就会把‘a’的地址赋值给变量p。

3.最后通过printf()来得到打印字符串的效果:

能形成这样的结果主要还是因为printf()函数的作用

它在满足两个条件下:1.输出格式为%s

                                    2.提供(该字符串的)起始地址

就会从起始位置的地址开始向后打印直到遇见'\0'

如果你还是心存质疑,我们再来看下面这个代码

这里分别输出p里面所存放的的地址和”abcdef“的地址(其实就是其中a的地址),两者是相同的关系

关于常量字符串的特殊“机制”

接下来我们简单认识一下常量字符串(不能被修改)和只读数据区(静态内存里面的一个区域,用于存放常量字符串,只能用来读,不能被修改里面的值)的概念

上面代码中的”abcdef“就是存放在常量字符区的常量字符串。(本篇不做过多解释) 

当如果定义两个char类型的变量,并且同时指向相同的一个常量字符串,那么请思考这两个变量里面所存放的地址相同吗?

答案是相同

在这个只读数据区里面,由于里面的所有内容不能被修改,那么内存还有必要存两份相同的数据吗?所有像这种常量字符串,内存只会存一份。

再来看接下来的这段代码

在这里我们创建的是两个独立的数组,每个数组都被0,1,2,3初始化了本身,所以为了存放这些数组元素,arr1和arr2数组就会分别在内存中开辟出一块空间来存放各自的元素,每个数组都拥有自己独立的空间,所以这里的他们的地址是不同的。(其它类型的数组同理)

这里有本人画的一个简易图解

指针数组和数组指针

指针数组

在了解这种类型的数组之前,先来对之前我们学过的数组做一个拆解

int  arr[6];我们可以将他拆成三个部分:数组元素类型(int),数组名(arr)和元素个数(6)。

其它类型的数组同理

怎么理解指针数组

指针数组顾名思义就是存放指针的数组,数组内的每个元素都是指针:

拿int* arr[6]这个指针数组举例:数组元素类型为(int*),数组名为(arr),元素个数为6。这就是一个存放整型指针的数组;同理char* arr1[6];就是存放字符指针的数组......

 无意间形成的"二维数组"?

对于指针数组正常的用法我们就不过多解释了,直接来看不寻常的:

我们先来看下面这个代码

首先数组名正常情况下代表数组首元素的地址(有两种例外,如果不知道,百度就可以搜到),我们创建了一个用来存放整形指针的数组p,元素个数为3.

这里的arr1就代表arr1首元素的地址,也就是一个整形类型的指针,所以可以作为p数组里面的元素内存中就可以想象成这样

在这种情况下,就无意识的创建了一个与二维数组非常相似的一维数组

既然创建了这么一个”二维数组“,我们就来了解一下怎么使用它(这无非就是要掌握每个元素的表达方式)

对于p数组来说,p[0]代表的就是该数组的第一个元素也就是arr1的首元素的地址,p[0]+1就是arr1的第二个元素的地址,那么对它进行解引用操作*(p[0]+1),此时它的值如果用%d的形式打印出来就是2

当然并不只有这一种表现方法:在我们学习指针的时候,应该学过这样的用法  *(pa+i)等价于pa[i]

那么我们这里就可以把p[0]当作pa,就有了这种写法p[0][1];至此,是不是更加感觉p就是一个二维数组了,但其实他不是

数组指针

认识数组指针

我们很容易理解:有指向整形的指针,指向字符的指针等等。

那么数组指针就是指向数组的指针,而int (*p)[5]就是一个简单的数组指针

本人有一个如何判断的方法:对于int *p[5]和int(*p)[5]

int *p[5]:在这里p先与[5]结合,已经得出他是一个数组,int*代表每个元素的类型。所以是一个指针数组。

int(*p)[5]:p先与*结合,已经得出他是一个指针,int [5]代表改指针指向的对象(一个元素个数为5,类型为int的数组)。所以是一个数组指针。(如果你已经有了java数组的知识,那么这里会更容易理解)(这里的*不是解引用,而是为了告诉你p是一个指针)

另外有一点注意:[]里面必须写入数组元素,不能省略,否则系统会将它当作[0]

如何用数组指针遍历整个数组(一般不会用数组指针干这种事)

注意:我们并不经常这样使用,写在这里只是让你知道确实存在这种用法,后面会介绍常见用法

p指向数组,*p相当于数组名,而数组名又相当于首元素地址,所以*p就是首元素的地址,所以使用*(*p+i)就可以遍历真个数组

我们再来看下面这种用法

这种用法是不是比上面那种简单多了,当然不要因此觉得数组指针很没用了。

当我们将其至少用到二维甚至三维数组上的时候,才能体会到他的强大

数组指针的常见用法(作用于多维数组中)

对于一个二维数组:把每一行当作一个元素,所以二维数组的首元素就是他的第一行,因此它的数组名就是他的第一行。

arr传给函数的就是第一行(作为一个一维数组)的地址,那么函数接收时就需要用一个能指向一维数组的指针p

p指向的就是第一行,p+1就指向的是第二行,以此类推。所以*(p+i)就指的是每个一维数组的数组名(想一想数组指针最简单的用法 int arr[2]={0,1};int (*p)[2]=&arr;之后的*p指的arr这个数组名)

如果你感觉这样写太麻烦,可以用p[i][j]来代替*(*(p + i) + j)两者是等价的

小方法

不管是指针数组还是数组指针,去掉名字,其实就是所代表的类型

如int(*p)[5]:p的类型是int(*)[5]

int *p[5]:p的类型是int *[5]

当然你千万不要用int(*)[5] p;这样的形式来定义p,因为语法不支持。我这么说只是方便你理解

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奈奈朵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值