C:数组指针与指针数组的详解


在 C/C++ 中,数组与指针是既相互关联又有区别的两个概念。当我们声明一个数组时,其数组的名字也是一个指针,该指针指向数组的第一个元素。

数组名的意义:

  1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
  2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
  3. 除此之外所有的数组名都表示首元素的地址。

arr&arr 分别是啥?

int main() {
    int arr[10] = {0};
    printf("arr = %p\n", arr);		// arr = 0x7ffee27d8460
    printf("&arr= %p\n", &arr);		// &arr= 0x7ffee27d8460
    printf("arr+1 = %p\n", arr+1);	// arr+1 = 0x7ffee27d8464
    printf("&arr+1= %p\n", &arr+1); // &arr+1= 0x7ffee27d8488
    return 0;
}

总结:

  • &arr 表示的是数组的地址,而不是数组首元素的地址。(细细体会一下)
  • 数组的地址+1,跳过整个数组的大小,所以 &arr+1 相对于 &arr 的差值是40.

数组指针与指针数组区别:

  • 指针数组: 首先它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身决定。它是“储存指针的数组”的简称。
  • 数组指针: 首先它是一个指针,它指向一个数组。在32 位系统下永远是占4 个字节,至于它指向的数组占多少字节,不知道。它是“指向数组的指针”的简称。

int (*p)[10] -----定义数组指针

这里有个有意思的话题值得探讨一下:平时我们定义指针不都是在指针类型后面加上指针变量名么?这个指针 p 的定义怎么不是按照这个语法来定义的呢?也许我们应该这样来定义p:

   int (*)[10] p;

int (*)[10]是指针类型,p 是指针变量。其实数组指针的原型确实就是这样子的,只不过为了方便与好看把指针变量p 前移了而已。

数组指针(也称行指针)

定义:

 int (*p)[n];//本质是一个指针

()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。

如要将二维数组赋给一指针,应这样赋值:

	int a[3][4];
	int (*p)[4];//该语句是定义一个数组指针,指向含4个元素的一维数组。
	p=a;        //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]
	p++;        //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]

所以数组指针也称指向一维数组的指针,亦称行指针。

指针数组

定义:

	int *p[n];//本质是一个数组

[]优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。

这里执行p+1是错误的,这样赋值也是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]…p[n-1],而且它们分别是指针变量可以用来存放变量地址。

但可以这样 *p=a; 这里 *p表示指针数组第一个元素的值,a的首地址的值。

比如:

	char arr[4]={"hello","world"};//这里的arr是一个指针数组,它里面有两个元素,每个元素都是一个指针类型。

如要将二维数组赋给一指针数组:

	int *p[3];
	int a[3][4];
	for(i=0;i<3;i++){
		p[i]=a[i];
	}
	//这里int *p[3] 表示一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2]

所以要分别赋值。

数组指针只是一个指针变量,似乎是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。
指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间。
还需要说明的一点就是,同时用来指向二维数组时,其引用和用数组名引用都是一样的。
比如要表示数组中i行j列一个元素:
*(p[i]+j)、 *( *(p+i)+j)、 *(p+i))[j]、p[i][j]

优先级:()>[]>*

知识点习题

  1. 64位系统中,**a[3][4],(**a)[3][4], *(*a)[3][4], *(*a[3])[4]等变量占用的内存空间为()?

在这里插入图片描述

int main() {
       int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
       int *ptr1 = (int *)(&aa + 1);
       int *ptr2 = (int *)(*(aa + 1));
       printf( "%d, %d", *(ptr1 - 1), *(ptr2 - 1));	// 10, 5
       return 0;
}

关于数组的面试题,在之前的博客中有所提及。欢迎大家练习,留言讨论!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值