多维数组、数组在内存中的存储顺序、指向数组的指针的解释与声明

目录

    • 指针和多维数组
      • 1. 多维数组
      • 2.数组在内存中的存储顺序:
      • 3.多维数组初始化
      • 4.指针和多维数组的关系
        • 从数组的角度:
        • 从指针的角度:
      • 5.指向数组的指针
      • 6.如何声明指向整形数组的指针
      • 7.如何声明一个有10个指针的数组,其中的指针是指向整型数
      • 8.如何声明一个指向函数的指针,该函数有一个整型参数并返回一个整型数(函数指针)
      • 9.如何声明一个有10个指针的数组,其中的指针指向一个函数,该函数有一个整型参数并返回一个整型数

指针和多维数组

1. 多维数组

如果,某个数组的维数不止一个,这样的数组被称为多维数组。

举例:

int  one;
int  onearray[2];
int  twoarray[6][2];
int  threarray[3][6][2];

多维数组、数组在内存中的存储顺序、指向数组的指针的解释与声明_第1张图片
四种数据类型的结构如上图,他们在内存中存储的顺序也是按照上图排序存储的。
多维数组、数组在内存中的存储顺序、指向数组的指针的解释与声明_第2张图片

2.数组在内存中的存储顺序:

如上图,数组中的元素是顺序存储的,多维数组的存储顺序是按照最右边的下表先变化的原则,称为行主续。
举例:

threarray[3][6][2]

存储顺序为:

0,1. 0,1. 0,1. 0,1. 0,1. 0,1.
0,1. 0,1. 0,1. 0,1. 0,1. 0,1.
0,1. 0,1. 0,1. 0,1. 0,1. 0,1.

其中0和1为下表序号。

3.多维数组初始化

二维数组:

int  twoarray[6][2];
twoarray[6][2] = 
{
	 {0,0},
	 {0,0},
	 {0,0},
	 {0,0},
	 {0,0},
	 {0,0},
};

三维数组:

threarray[3][6][2] = 
{
	{  {0,0},{0,0},{0,0},{0,0},{0,0},{0,0}  },
	{  {0,0},{0,0},{0,0},{0,0},{0,0},{0,0}  },
	{  {0,0},{0,0},{0,0},{0,0},{0,0},{0,0}  }
};

4.指针和多维数组的关系

指针和数组并不是相等的!牢记,在后面的博客中解释。

一维数组名的值是一个指针常量,它的类型是“指向数组元素类型的指针”,它指向数组的第一元素。多维数组也是类似的原理。

对于二维数组:

int  twoarray[6][2];
twoarray[6][2] = 
{
	 {0,0},
	 {0,0},
	 {0,0},
	 {0,0},
	 {0,0},
	 {0,0},
};

从数组的角度:

它是一个内含int数组的 数组,即它的第一维的元素实际上是另外一个数组。
twoarray的首元素是一个内含两个int值的数组,所以twoarray该数组名是这个内含两个int值的数组的 地址。

在这里插入图片描述

从指针的角度:

twoarray是该数组首元素的地址,它的值是指向它第一个元素的指针, 所以,twoarray(该数组名)是一个 指向
一个包含两个整形元素的数组的 指针。

&twoarray[0] 是区该二维数组首元素的地址, 所以,twoarray 和 &twoarray[0]的值应该是相同的!

twoarray[0]本身是 一个内含两个int类型值的数组,twoarray[0]是一个内含两个int类型值的数组的数组名。
因为数组名就是该数组首元素的地址,所以, twoarray[0]和&twoarray[0][0]的值应该是相同的!

由于这个整数twoarray[0][0]所在的数组twoarray[0]
和内含两个整数的数组twoarray[0]所在的数组twoarray都开始于同一个地址,所以twoarray[0]和twoarray值应该是相同的。

但是,注意twoarray[0]是一个内含两个整数的数组,所以它实际一个占用了一个int大小对象的地址。 twoarray是一个内含了6个
其中每个包含两个整形元素的数组 的数组,所以它是一个占用了2个int大小对象的地址!

当指针或地址加1,其值会增加对应类型大小的值,所以,twoarray+1和twoarray[0]+1得到的结果是不同的!
多维数组、数组在内存中的存储顺序、指向数组的指针的解释与声明_第3张图片
多维数组、数组在内存中的存储顺序、指向数组的指针的解释与声明_第4张图片

问题:地址怎么区分出占用了一个int大小还是2个int大小的?

总结:
对于以上二维数组,该数组的首元素是一个内含两个int值的数组。
twoarray[0]、twoarray[1]、…twoarray[5]本身是一个内含两个整数的数组;
所以twoarray[0]是 一个内含两个整数的数组的 首地址。
下表引用实际上只是间接访问表达式的一种伪装形式,在多维数组中也是如此。

举例:

int mul_array[3][5];
mul_array[1][3]

访问的元素如图:红框中,按内存排序和按行排序分别标出。

多维数组、数组在内存中的存储顺序、指向数组的指针的解释与声明_第5张图片

mul_array的类型是“指向包含5个整形元素数组的指针”,他的值是
如图:
多维数组、数组在内存中的存储顺序、指向数组的指针的解释与声明_第6张图片

mul_array + 1也是“指向包含10个整形元素数组的指针”,但他指向的是mul_array的下一行。
“+1” 的值是根据 “包含10个整形元素数组的长度”进行调整, 所以,表达式 *(mul_array + 1) 事实上表示了一个包含10个整形元素的子数组。

5.指向数组的指针

int  array[10];
int*  array_p  =  array;//正确

int  mul_array[3][10];
int*  mul_array_p  =  mul_array;//错误

第一个声明是合法的,它为一个整形数组分配内存,并把 array_p声明为一个指向整形的指针。

第二个声明是非法的,声明创建了多维数组 mul_array,创建了一个指向整形的指针mul_array_p,但对它的初始化是不正确的,因为mul_array不是一个指向整形的指针,而是一个指向整形数组的指针。

6.如何声明指向整形数组的指针

int*p)[10];

下标的优先级高于间接访问,但是由于括号的存在,先执行的是间接访问,所以p是一个指针。接下来执行的是下标引用,所以p指向某种类型的数组,根据int可知,p是指向一个整形的数组,数组的每个元素都是整数。

所以在刚才的例子中,应该定义如下:

int  mul_array[3][10];
int* mul_array_p)[10]  =  mul_array;//正确

7.如何声明一个有10个指针的数组,其中的指针是指向整型数

int* (p[10]);
int* p[10];

“[]”操作符的优先级高于 “*”操作符,所以括号也可以省略。

8.如何声明一个指向函数的指针,该函数有一个整型参数并返回一个整型数(函数指针)

int (*pfun)(int);

9.如何声明一个有10个指针的数组,其中的指针指向一个函数,该函数有一个整型参数并返回一个整型数

int (*pfun[10])(int);
int (*(pfun[10]))(int);

你可能感兴趣的:(①C语言基础,c++,c语言,单片机,软件开发,嵌入式)