数组指针的推演与理解

数组指针一般用于函数传参,其他基本很少遇到,其概念相对繁琐,本文将对数组指针做一个从头到尾的透彻分析,如果以后印象模糊了,再回来看看。

#include <stdio.h>
#include <stdlib.h>
 
int main(int argc, char *argv[])
{
	int num;
	printf("sizeof(int) = %d\t\tsizeof(num) = %d\n", 
		sizeof(int), sizeof(num));
	// sizeof(int) == sizeof(num)
	int arr[3] = { 1, 2, 3 };
	printf("sizeof(int[3]) = %d\tsizeof(arr) = %d\n", 
		sizeof(int[3]), sizeof(arr));
	// int arr[3] == int[3] arr 将 int[3] 看作是一种类型
	// 同上num变量的例子,类型的大小与构造出来的变量大小是一样的
	printf("%p %p\n", arr, (&arr) + 1);
	// 将arr看作一个指向数组整体地址的变量
	// 对数组整体加一相当于偏移了整个数组所占用总字节大小的内存单位
	// 很少有情况会这样用一维数组,感觉没什么用
	printf("%p %p\n", arr, arr + 1);
	// 不带间接引用运算符的情况下,将arr看作指向数组首元素地址的变量
	// 对首元素加一相当于偏移了(int)类型大小的字节到第二个元素
	printf("%d %d\n", arr[0], *(arr + 0));
	// 第一种不用多说,下标访问
	// 第二种通过上面的解释可以知道
	// 相当于将指向数组首元素的指针变量向后偏移了0个(int)类型大小的字节数
	// 偏移后依然是个指向地址的指针变量,所以要用*(间接引用运算符)获取该地址中存放的内容
	// 结论:arr[i] == *(arr + i)
 
	int array[3][4] = { 1 ,2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2 };
	// 1、二维数组中[]运算符优先级最高,所以先运算下面的array[3]
	// 2、int array[3] 是一个一维数组
	// 3、int array[3] 可以间接的理解为 int[3] array
	// 4、而 int array[3][4] 则间接的可以理解为 int[4] array[3]
	// 5、意味着 array[3] 中每一个数据类型,都是 int[4] 类型的
	printf("%d--%d\n", array[1][1], (*(array + 1))[1]);
	// 第一种不用多说,正常的下标访问
	// 第二种通过一维数组的结论得出 array[i] == *(array + i)
	// 相当于array向后偏移了1个单位,然后使用*间接引用地址中存放的数据
	// 所以把 array[1][1] 替换为 *(array + 1)[1]
	printf("%d--%d\n", array[1][1], *(*(array + 1) + 1));
	// 再向下推理,*(array + 1)[1] == *(*(array + 1) + 1)
	// 相当于把*(array + 1)向后偏移了1个单位,然后使用*间接引用地址中存放的数据
 
	/*【数组指针】*/
	int oneArray[] = {1, 2, 3, 4, 5};
	// 当不给出一维数组元素个数的时候
	// 编译器会根据输入的元素个数决定数组长度
	// 也就是一维数组的列数,而一维数组的行数已经确定,只有一行。
 
	int twoArray[][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2 };
	// 二维数组同理,无需给出数据的行数
	// 只给出数据的列数,元素总数除以列数就得出了行数
	// 12 / 4 = 3,所以我们无需指定行数
 
	// 思考设计函数的时候,如何传递二维数组?
	// 函数传递一维数组时,可使用 arr[] 或者 *arr 作为形参
	// 经过推演,int a[5] 这个数组中 a == &a[0],a[0]是一个int类型的数值,对其使用&运算符就变成了 int*
	// 同理,int twoArray[3][4] == int[4] twoArray[3]
	// twoArray = &twoArray[0],则twoArray是一个int[4]类型的变量,对其使用&运算符就变成了 int[4]*
	// 所以如果函数的形参可以设置为 int[4] *twoArray
	// 但是这样写编译不通过,因为语言不通过。
	// 像int *p、double *p 这些写法代表是一个int类型的指针、浮点型类型的指针
	// 而 int[4] *twoArray 我们则称他为 “数组指针”,因为前面是一个经过拆解的int类型的一维数组
	// 上面我们理解一维数组 int oneArray[i] == int[i] oneArray
	// 同理,我们可以推理出 int *twoArray[4] == int[4] *twoArray
	// 这样编译通过了,但是因为[]运算符的优先级比*高,所以我们要给他加个括号
	// 最后变成了 int (*twoArray)[4]
 
	system("pause");
	return 0;

}

 

发表评论