对数组指针的理解

一、一维数组

1.先定义一个一维数组

int a[4]={1,2,3,4};

(1)一维数组名a是个地址,地址类型为:int *

(2)一维数组名取地址&a是个地址,地址类型同:int (*p)[4], 也即&a指向含4个int元素的一维数组  此时&a类型即为一个数组指针

2.数组名是数组首元素的首地址

   a的值和&a[0]的值相同     但    意义不同

3.意义不同在哪里

先实现一串代码

#include <stdio.h>
#include <stdlib.h>
int main() {
	int a[3] = { 0 };
	printf("a   =%d\n", a );
	printf("a+1 =%d\n", a + 1);
	printf("&a+1=%d\n", &a + 1);
	system("pause");
	return 0;
}

运行结果:

“+1”就是偏移量问题:一个类型为T的指针的移动,是以sizeof(T)为移动单位

a+1:在数组首元素的首地址的基础上,偏移一个sizeof(a[0])单位。此处的类型T就是数组中的一个int型的首元素。

 &a+1:在数组的首地址的基础上,偏移一个sizeof(a)单位。此处的类型T就是数组中的一个含有3个int型元素的数组

4.a[0]和&a[0]

#include <stdio.h>
#include <stdlib.h>
int main() {
	int a[3] = { 0 };
	printf("a       =%d\n", a);
	printf("a+1     =%d\n", a + 1);
	printf("&a[0]+1 =%d\n", &a[0] + 1);
	printf("&a+1    =%d\n", &a + 1);
	printf("a[0]+1  =%d\n", a[0] + 1);
	system("pause");
	return 0;
}

运行结果:

可以看到&a[0]+1的值其实和a+1的值是相同的

而a[0]+1其实就是0+1=1

二、二维数组

1.定义一个二维数组

int b[3][4]={0};

此时二维数组可以看成是有3个成员的一维数组,每个一维数组有4个元素

2.解释

   (1)b[0]是个一维数组名,也是个地址,地址类型为:int *

(2)&b[0]是个地址,地址类型同:int (*p)[4], 也即&b[0]指向含4个int元素的一维数组

更进一步:

(3)b是个地址,地址类型同:int (*p)[4],也即b指向含4个int元素的一维数组

(4)&b是个地址,地址类型同:int (*p)[3][4],也即&b指向含3x4个int元素的2维数组

    *注意:尤其注意上面的(3),这条结论指出了:二维数组名实际上是一维数组的地址!

验证:

#include <stdio.h>
#include <stdlib.h>
int main() {
	int b[3][4] = { 0 };
	printf("b   =%d\n", b );
	printf("b+1 =%d\n", b + 1);
	printf("&b+1=%d\n", &b + 1);
	system("pause");
	return 0;
}

运行结果:

同上述一维数组a+1  &a+1 

3.其他

#include <stdio.h>
#include <stdlib.h>
int main() {
	int b[3][4] = { 0 };
	printf("b           =%d\n", b);
	printf("b+1         =%d\n", b + 1);
	printf("&b[0]+1     =%d\n", &b[0] + 1);
	printf("&b+1        =%d\n", &b + 1);
	printf("b[0]+1      =%d\n", b[0] + 1);
	printf("&b[0][0]+1  =%d\n", &b[0][0] + 1);
	system("pause");
	return 0;
}

运行结果:

b[0]+1就相当于一维数组中的a+1 只是偏移一个元素

&b[0][0]即相当于一维数组中&a[0]

三、总结

1.数组名,是指向它的第一个一级成员的指针

2. 数组名取地址,是指向整个数组的指针

//所谓一级成员,举个例子,int a[5],那么数组a的一级成员就是int型变量;int b[10][5],数组b的一级成员是int [5]的一维数组

3.数组名是数组首元素的首地址

--------------------- 

部分参考:
原文:https://blog.csdn.net/qq_31073871/article/details/80800858 
 

<think>我们正在讨论指针数组数组指针。让我们先明确这两个概念的定义和区别。 根据引用[2]和[4]: - 指针数组:首先是一个数组数组中的每个元素都是指针。 - 数组指针:首先是一个指针,它指向一个数组(整个数组)。 引用[4]特别强调:数组指针存放的是整个一维数组的地址,而不是首元素的地址。 现在,我们详细分析: 1. 指针数组 (Array of Pointers) - 定义:`int *arr[10];` - 含义:这是一个包含10个元素的数组,每个元素都是一个指向整型的指针。 - 大小:由于是指针数组,所以数组的大小为元素个数乘以指针的大小。在32位系统中,指针占4字节,所以`sizeof(arr)=40`;在64位系统中,指针占8字节,所以`sizeof(arr)=80`。 - 赋值:可以将多个变量的地址赋给数组的元素,也可以将多个动态分配的内存地址赋给它。 示例(参考引用[5]): ```c int a = 1, b = 2, c = 3; int *ptrArr[3] = {&a, &b, &c}; // 指针数组 ``` 2. 数组指针 (Pointer to an Array) - 定义:`int (*ptr)[10];` - 含义:这是一个指针,它指向一个包含10个整型元素的数组。 - 注意:定义时括号不能省略,因为`[]`的优先级高于`*`,不加括号就变成了指针数组。 - 赋值:需要将一个整个数组的地址赋给它,即使用`&`操作符取整个数组的地址。 示例: ```c int arr[10] = {0}; int (*p)[10] = &arr; // 数组指针,指向整个数组 ``` 引用[4]特别指出:`p`存放的是整个一维数组的地址,而不是首元素的地址。虽然数组名`arr`和`&arr`的值相同(都是数组首地址),但它们的类型不同: - `arr`的类型是`int*`(指向数组首元素的指针) - `&arr`的类型是`int(*)[10]`(指向整个数组指针) 因此,当我们对数指针进行加减运算时,是以整个数组的长度为步长。例如: ```c int arr[10]; int (*p)[10] = &arr; p+1; // 将跳过整个数组(10个整数),即地址增加10*sizeof(int) ``` 3. 区别总结 | 特性 | 指针数组 | 数组指针 | |--------------|---------------------------|---------------------------| | 本质 | 数组 | 指针 | | 定义形式 | `int *arr[size];` | `int (*ptr)[size];` | | 存储内容 | 多个指针 | 一个指向数组指针 | | `sizeof`操作 | 数组总大小(元素数×指针大小) | 指针的大小(4或8字节) | | 步长 | 数组元素指针的大小 | 指向的整个数组的大小 | 4. 常见用法 - 指针数组:常用于字符串数组(如`char *strArr[]`),每个元素指向一个字符串。 - 数组指针:常用于二维数组的操作,因为二维数组名可以理解数组指针(指向第一行的一维数组)。 例如,处理二维数组: ```c int matrix[3][4]; int (*p)[4] = matrix; // 数组指针,指向一行(包含4个整数的数组) // 访问matrix[i][j]可以用 p[i][j] 或 *(*(p+i)+j) ``` 这里,`matrix`是二维数组名,它表示指向第一行(一个一维数组)的指针,所以可以赋给数组指针`p`(类型匹配)。 5. 容易混淆的地方 引用[4]提到一个疑问:`int *p, arr[10]; p = arr;` 和 `int (*pa)[10]; pa = &arr;` 的区别。 - 第一个:`p`是指向整型的指针,`arr`是数组名(退化为指向首元素的指针),所以`p`指向`arr[0]`。 - 第二个:`pa`是指向整个数组指针,`&arr`是整个数组的地址。 虽然它们指向的地址值相同,但类型不同,进行指针运算时结果不同: ```c p++; // 前进sizeof(int)字节 pa++; // 前进10*sizeof(int)字节 ``` 最后,引用[3]提到数组指针可以看作二级指针,但要注意:数组指针指向一个数组数组名本身就是一个指针),所以它相当于指向一个指针数组名),因此数组指针可以看作是二级指针。但是,它们并不完全等同,因为数组指针有确定的步长(整个数组的大小),而普通的二级指针的步长是一个指针的大小。 希望这个解释能帮助你理解指针数组数组指针的概念。如果还有疑问,可以参考相关引用或继续提问。 </think>### 指针数组数组指针的深入解析 #### 一、核心概念区分 | 类型 | 本质 | 声明形式 | 内存布局 | 步长计算 | |------------|---------------|------------------|------------------|------------------| | **指针数组** | 存放指针数组 | `int* arr[size]` | [指针1][指针2]... | `sizeof(指针)` | | **数组指针** | 指向数组指针 | `int (*ptr)[size]` | [数组首地址] | `size × sizeof(T)` | > 关键区别:指针数组是**容器**(存放指针),数组指针是**地址**(指向数组)[^2][^4] --- #### 二、指针数组(Array of Pointers) **本质**:存放指针数组,每个元素都是地址 **声明**:`数据类型* 数组名[大小]` **内存模型**: ```c int a=1, b=2, c=3; int* ptrArr[3] = {&a, &b, &c}; // 存储三个整型变量的地址 ``` ``` 内存布局: ptrArr[0] → 0x1000 [a=1] ptrArr[1] → 0x1004 [b=2] ptrArr[2] → 0x1008 [c=3] ``` **特性**: 1. `sizeof(ptrArr)` = 元素个数 × 指针大小 - 32位系统:`3×4=12字节` - 64位系统:`3×8=24字节`[^5] 2. 常用作字符串数组: ```c char* strArr[] = {"Apple", "Banana", "Cherry"}; // strArr[1][0] = 'B' ``` --- #### 三、数组指针(Pointer to Array) **本质**:指向整个数组指针(非首元素地址) **声明**:`数据类型 (*指针名)[大小]` **内存模型**: ```c int matrix[2][3] = {{1,2,3},{4,5,6}}; int (*ptr)[3] = matrix; // 指向包含3个整数的数组 ``` ``` 内存布局: ptr → 0x2000 [1][2][3] // 指向第一行 ptr+1 → 0x200C [4][5][6] // 跳过12字节(3×sizeof(int)) ``` **关键特性**: 1. **步长由数组大小决定**: $$ \text{步长} = \text{数组长度} \times \text{sizeof(元素类型)} $$ ```c ptr++; // 前进12字节(若int为4字节) ``` 2. 访问元素等价于: $$ \text{matrix[i][j]} \equiv \text{(*(ptr + i))[j]} \equiv \text{*(*(ptr + i) + j)} $$ 3. 与普通指针区别: ```c int arr[4]; int *p1 = arr; // 指向首元素(步长4字节) int (*p2)[4] = &arr; // 指向整个数组(步长16字节) ``` --- #### 四、典型应用场景 1. **指针数组用途** - 管理动态字符串集合 - 实现命令行参数`char* argv[]` - 创建非连续内存的数据结构 ```c // 动态创建锯齿数组 int *jagged[] = {malloc(3*sizeof(int)), malloc(5*sizeof(int))}; ``` 2. **数组指针用途** - 二维数组的行遍历 - 函数传递固定维度的多维数组 ```c void printMatrix(int (*mat)[3], int rows) { for(int i=0; i<rows; i++) for(int j=0; j<3; j++) printf("%d ", mat[i][j]); } ``` --- #### 五、常见误区解析 1. **声明优先级陷阱** - `int* a[4]`:指针数组(`[]`优先级高于`*`) - `int (*b)[4]`:数组指针(括号改变优先级)[^2] 2. **地址值相同但类型不同** ```c int arr[5]; printf("%p == %p\n", (void*)arr, (void*)&arr); // 输出相同地址值,但: // arr+1 → 前进4字节(int大小) // &arr+1 → 前进20字节(5×sizeof(int)) ``` 3. **`void*`的限制** ```c void *vp = malloc(100); // vp+1 // 错误!无法确定步长[^4] ``` --- ### 总结对比 | 特性 | 指针数组 | 数组指针 | |--------------|--------------------------|--------------------------| | **本质** | 存放地址的容器 | 指向数组实体的地址 | | **sizeof** | 数组总大小(元素数×指针大小) | 指针大小(4/8字节) | | **+1操作** | 移动到下一个指针元素 | 移动到下一个完整数组 | | **典型应用** | 字符串数组、命令行参数 | 多维数组处理、固定维度传递 | > 核心记忆点:指针数组是**数组**,数组指针是**指针**,类型声明决定操作语义[^3][^5] --- ### 相关问题 1. 如何在函数中传递动态二维数组并保持维度信息? 2. 指针数组在实现多态数据结构中有哪些优势? 3. 为什么`&arr`和`arr`的地址值相同但类型不同? 4. 如何用数组指针实现三维数组的遍历? 5. 指针数组与链表结构在内存管理上有何本质区别?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值