1.什么是指针数组和数组指针

顾名思义:指针数组是“存放指针的数组”,这个变量是一个数组,用指针修饰,数组中的每个元素都是指针。

数组指针是“指向数组的指针”,这个变量是一个指针,用数组修饰,这个指针存储着数组的首元素

2.指针数组和数组指针到底是什么

数组指针和指针数组在本质上的区别便是优先级关系,我们需要注意到底是指针的优先级高还是数组的优先级高,如果数组的优先级高是指针数组,如果指针的优先级高便是数组指针。

总结起来就是目的是谁,便让谁的优先级高就可以了。

在正式进入主题前,有一幅图需要先来了解一下

内存映像图内容权限
栈区函数中的普通变量可读可写
堆区动态申请的内存可读可写
静态变量区static修饰的变量可读可写
数据区用于初始化变量的常量只读
代码区代码指令只读

一般情况下,计算机有栈区到代码区是由高地址向低地址的,栈是向下增长,而堆是向上增长。

指针数组:

const char* arr[]={"hello","world","nihao"};//只能访问,不能修改//这里定义了一个指针数组arr,数组有三个元素,每个元素都是一个char*指针,每个指针保存着每个字符串首地址

在这里有一个注意点,由于[]的优先级高于*,所以char *arr[]char*(arr[])。

这个指针数组的大小是12字节:原因是在64位操作系统下,指针的大小是8字节,这里一共有3个指针,分别指向三个元素,故sizeof(p)=3*8=24

我这里使用的是64位操作系统,所以指针的大小是8.

数组指针:

int (*p)[4];//这里定义的是一个数组指针,指针存放着数组首元素的地址

为了便于理解,我们可以暂时将它写成int[](*p)。这样便可以很清楚的理解了。但是在实际编写的过程中,编译器不认识。

这里的大小便是4字节了,因为这个指针存储的是该数组首元素的地址

那么我们知道,数组名就是数组首元素的首地址,那两者有什么关系呢?

这里先定义一个数组arr

int arr[4];

这里的arr是指向首元素的地址,p也指向首元素的地址,但是 但是 但是 重要的事情说三遍

我们不能直接将arr赋给p,只能将arr整个的地址赋给p。(可以理解为arr是一维数组的首元素地址 , p是二维数组的首元素地址,如果把arr直接赋给p,则只赋值了二维数组的第一行)

我们给arr+1是数组第二个元素的地址,p+1是指向了下一行,我们可以理解为二维数组的行指针。在下一篇中会有对二维数组的介绍。

在这里我们可以明显的看到arr和p都指向首元素的地址,但是arr+1是指向第二个元素的地址(加了4字节),p+1是指向了第二行的地址(每一行是4*4=16个字节,加了16个字节)。而对arr解引用后是第一个元素,*(arr+1)解引用后是第二个元素。这里p已经指向了第一行,所以取[0]第一列后解引用是arr的第一个元素,而*(*p+1)则是指向了第一行第二列,即2。

*(*(p+i)+j)的意思是对第i行第j列的元素解引用。

而sizeof(arr)是整个数组的大小,sizeof(arr[0])是每个元素的大小,sizeof(p)是指针的大小 8个字节(前面很明显p=&arr)所以p是一个指针