数组指针与指针数组
核心定义与语法的区别
数组指针(指向数组的指针)
- 定义:数组指针是一个指针变量,它指向一个固定长度的数组.
- 语法:
类型(*指针名)[数组长度] - 示例:
int (*ptr)[5]; 表示 ptr 是一个指针,指向包含 5 个 int 的数组。 - 关键特征:
- 指针指向数组的
首地址,解引用后得到整个数组。 - 指针的步长为 数组长度 × 单个元素大小。
- 指针指向数组的
指针数组(数组存储指针)
- 定义:指针数组是一个数组,其元素均为指针变量。
- 语法:
类型* 数组名[数组长度] - 示例:
int* ptr_arr[5]表示:ptr_arr是一个包含5个int*类型元素的数组。 - 关键特征:
- 数组元素是指针,可指向不同的内存地址(如不同的变量、数组或动态内存)。
- 本质是普通数组,遵循数组的访问规则(通过下标访问指针元素)。
内存布局对比
1.数组指针:(以int (*ptr)[3]为例)
- 指向对象:一维数组:
int arr[3] = {1,2,3}; - 内存示意图:
arr: ┌───┬───┬───┐
│ 1 │ 2 │ 3 │
└───┴───┴───┘
地址:0x1000 0x1004 0x1008
ptr: ────────────────► arr (0x1000)
-
指针运算:
ptr + 1偏移3 * sizeof(int) = 12字节(指向 arr 之后的下一个数组)。2.指针数组(以
int* ptr_arr[2]为例) -
存储的内容:指针数组存储多个指针,每个指针指向独立的内存区域。
-
内存示意图:
ptr_arr: ┌─────────┬─────────┐ │ 0x2000 │ 0x3000 │ (假设分别指向 arr1 和 arr2) └─────────┴─────────┘ 地址:0x4000 0x4004 arr1: ┌───┐ arr2: ┌───┐ │ 1 │ │ 4 │ └───┘ └───┘ 0x2000 0x3000 -
访问方式:
ptr_arr[0]得到0x2000(指向arr1),*ptr_arr[0]解引用得到 1。
典型示例对比:
1.数组指针示例:处理二维数组
#include <stdio.h>
int main()
{
// 二维数组(2行3列)
int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
// 数组指针指向二维数组的行(列数必须与数组一致)
int (*row_ptr)[3] = arr; // 等价于 int (*row_ptr)[3] = &arr[0];
// 访问第一行第二列元素
printf("第一行第二列:%d\n", (*row_ptr)[1]); // 输出 2
// 指针移动到第二行
row_ptr++;
printf("第二行第一列:%d\n", (*row_ptr)[0]); // 输出 4
return 0;
}
- 关键点:二维数组名
arr隐式转换为数组指针int (*)[3],指向首行。
2.指针数组示例:管理多个动态数组
#include<stdio.h>
int main()
{
//指针数组:存储3个指向int 数组的指针
int* ptr_arr[3];
//动态分布三个一维数组
ptr_arr[0] = (int*)malloc(sizeof(int));
ptr_arr[1] = (int*)malloc(2 * sizeof(int));
ptr_arr[2] = (int*)malloc(3 * sizeof(int));
// 赋值
*ptr_arr[0] = 10;
ptr_arr[1][0] = 20; ptr_arr[1][1] = 21;
ptr_arr[2][0] = 30; ptr_arr[2][1] = 31; ptr_arr[2][2] = 32;
// 访问
printf("第一个数组元素:%d\n", *ptr_arr[0]); // 10
printf("第二个数组元素:%d\n", ptr_arr[1][1]); // 21
// 释放内存
for (int i = 0; i < 3; i++)
{
free(ptr_arr[i]);
}
return 0;
}
维度
数组指针
指针数组
本质
指针(指向一个固定大小的数组)
数组(元素为指针类型)
语法核心
(*) 优先(先声明为指针)
[] 优先(先声明为数组)
定义示例
int (ptr)[5];
int ptr[5];
内存占用
占一个指针的大小(如 8 字节,64 位)
占 n × 指针大小(如 5×8=40 字节)
典型用途
二维数组行操作、固定列数的数组传递
动态数组管理、字符串数组、指针集合
初始化方式
指向已有数组(如 ptr = &arr;)
逐个初始化指针元素(如 ptr[i] = &var;)
访问元素
通过 (*ptr)[i] 或 ptr[i][j] 访问
通过 ptr[i] 访问指针指向的值
常见场景
函数参数传递二维数组(列数固定)
存储多个动态分配的内存地址
经典应用场景
1. 数组指针:
1.处理多维数组:当需要指针遍历或多维数组时
//ptr 直接指向二维数组的行,偏移量为 3*sizeof(int),无需额外转换,可直接通过 ptr[i][j] 访问元素
#include <stdio.h>
int main()
{
int arr[2][3] = {{1,2,3}, {4,5,6}};
int (*ptr)[3] = arr; // 指向第一行(类型为int(*)[3])
// 遍历数组
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
printf("%d ", ptr[i][j]); // 等价于*(*(ptr+i)+j)
}
printf("\n");
}
return 0;
}
int arr[2][3] = {{1,2,3},{4,5,6}};
int (*ptr)[3] = arr //指向第一行
printf("%d\n",ptr[1][2]); //输出6
2.动态分配二维数组(连续内存)
//优势:内存连续,缓存命中率高释放简单,只需一次 free
#include <stdio.h>
#include <stdlib.h>
int main()
{
int rows = 3, cols = 4;
int (*matrix)[cols] = malloc(rows * sizeof(*matrix));
// 初始化
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
matrix[i][j] = i * cols + j;
// 释放内存
free(matrix); // 一次释放全部内存
return 0;
}
3.函数参数传递多维数组
//注意:函数参数中 ,int (*arr)[3] 必须指定列数,等价于 int arr[][3],但指针形式更清晰
#include <stdio.h>
// 计算二维数组的和(必须指定列数)
int sum(int (*arr)[3], int rows)
{
int total = 0;
for (int i = 0; i < rows; i++)
for (int j = 0; j < 3; j++)
total += arr[i][j];
return total;
}
int main()
{
int arr[2][3] = {{1,2,3}, {4,5,6}};
printf("Sum: %d\n", sum(arr, 2)); // 输出21
return 0;
}
// 函数声明:处理二维数组(列数固定为3)
// 参数说明:
// - int (*arr)[3]:数组指针,指向包含3个int的一维数组(即二维数组的行)
// - rows:二维数组的行数
void process_2d_array(int (*arr)[3], int rows)
{
// 外层循环:遍历每一行(i表示行号)
for (int i = 0; i < rows; i++)
{
// 内层循环:遍历当前行的每一列(j表示列号,列数固定为3)
for (int j = 0; j < 3; j++)
{
// 访问二维数组元素并乘以2
// 等价于:(*(arr + i))[j] *= 2;
// 解析:
// - arr + i:指向第i行(数组指针偏移i行,每行3个int)
// - *(arr + i):解引用得到第i行的一维数组(类型为int[3])
// - [j]:访问该行的第j个元素
arr[i][j] *= 2;
}
}
}
int main()
{
// 定义二维数组:2行3列
int arr[2][3] =
{
{1, 2, 3}, // 第0行
{4, 5, 6} // 第1行
};
// 调用函数处理二维数组
// 传递数组名arr时,会隐式转换为数组指针int (*)[3](指向首行)
process_2d_array(arr, 2);
// 若需要验证结果,可添加打印代码:
// for (int i = 0; i < 2; i++)
{
// for (int j = 0; j < 3; j++)
{
// printf("%d ", arr[i][j]);
// }
// }
return 0;
}
// 2 4 6 8 10 12
2.指针数组:
1.动态二维数组(非连续内存)
#include <stdio.h>
#include <stdlib.h>
int main()
{
int rows = 3, cols = 4;
int* matrix[rows]; // 创建指针数组
// 为每行分配内存(每行可不同长度)
for (int i = 0; i < rows; i++)
{
matrix[i] = malloc(cols * sizeof(int));
}
// 初始化
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
matrix[i][j] = i * cols + j;
// 释放内存(必须逐行释放)
for (int i = 0; i < rows; i++)
{
free(matrix[i]);
}
return 0;
}
//matrix[0] → [0, 1, 2, 3]
//matrix[1] → [4, 5, 6, 7]
//matrix[2] → [8, 9, 10, 11]
//优势:每行可独立分配不同长度,适合不规则数组
2.指向独立内存块
#include <stdio.h>
int main()
{
int a = 10, b = 20, c = 30;
int* ptr[3] = {&a, &b, &c}; // 每个指针指向不同变量
for (int i = 0; i < 3; i++)
{
printf("%d ", *ptr[i]); // 输出: 10 20 30
}
return 0;
}
3.字符串数组
#include <stdio.h>
int main()
{
char* names[3] =
{
"Alice", // 指向字符串常量的指针
"Bob",
"Charlie"
};
for (int i = 0; i < 3; i++)
{
printf("Name %d: %s\n", i, names[i]);
}
return 0;
}
//本质:names 是一个包含3个 char* 的数组,每个指针指向一个字符串常量
字符串数组(存储字符串指针)
#include <string.h> // 提供strcpy等字符串处理函数
int main()
{
// 指针数组:存储多个字符串常量的地址
// 每个字符串常量存储在只读内存区,str_arr存储它们的首地址
char* str_arr[] = {"apple", "banana", "cherry"};
// 遍历指针数组,输出每个字符串
for (int i = 0; i < 3; i++)
{
printf("字符串 %d: %s\n", i+1, str_arr[i]);
// str_arr[i] 是第i个字符串的首地址,%s自动解析字符串直到'\0'
}
// 动态创建指针数组(在堆区分配内存)
char** dyn_str_arr = (char**)malloc(2 * sizeof(char*));
// 分配2个指针的空间,dyn_str_arr指向该内存块
// 为第一个指针分配内存并复制字符串
dyn_str_arr[0] = (char*)malloc(5 * sizeof(char)); // 分配5字节(含'\0')
strcpy(dyn_str_arr[0], "test"); // 复制"test"到分配的内存中
// 注意:代码未释放内存(存在内存泄漏)
// 正确做法应在return前添加:
free(dyn_str_arr[0]);
free(dyn_str_arr);
return 0;
}
//字符串 1: apple
//字符串 2: banana
//字符串 3: cherry
-
静态字符串数组
str_arr-
str_arr ┌─────────┬─────────┬─────────┐ │ 0x1000 │ 0x1006 │ 0x1013 │ (字符串常量地址) └─────────┴─────────┴─────────┘ ↓ ↓ ↓ "apple\0" "banana\0" "cherry\0" 0x1000 0x1006 0x1013 (只读内存区) -
str_arr是栈上的指针数组,每个元素指向一个字符串常量。
-
-
动态指针数组
dyn_str_arr-
dyn_str_arr ───► ┌─────────┬─────────┐ (堆区:2个指针) │ 0x2000 │ NULL │ └─────────┴─────────┘ ↓ ┌─────────────┐ (堆区:5字节) │ t e s t \0 │ └─────────────┘ 0x2000 -
dyn_str_arr指向堆区的指针数组 -
dyn_str_arr[0]指向另一段堆内存,存储 “test”
-
-
动态内存分配
-
char** ptr = (char**)malloc(n * sizeof(char*)); // 分配指针数组 ptr[i] = (char*)malloc(len * sizeof(char)); // 为每个指针分配字符串空间
总结:
处理固定列数的二维数组 |数组指针 |保持行列逻辑,高效传递二维数组
管理动态或变长数组 |指针数组 |灵活分配内存,每个指针可独立操作
存储字符串集合 | 指针数组 |字符串本质是 char*,适合用指针数组管理
按行操作二维数组 |数组指针 |直接操作行数据,符合内存布局特性
| 内存布局 | 连续存储整个多维数组 | 存储多个指针,每个指针可能指向不同内存区域 |
|---|---|---|
| 指针类型 | ptr 是一个指针,类型为 int(*)[n] | ptr 是数组,类型为 int*[n] |
| 偏移量 | ptr + 1 跳过 n*sizeof(int) 字节 | ptr + 1 跳过 sizeof(int*) 字节 |
| 初始化 | int arr[2][3]; int (*ptr)[3] = arr; | int* ptr[3] = {malloc(4), malloc(4), malloc(4)}; |
| 访问方式 | ptr[i][j] 直接访问 | ptr[i][j] 通过指针间接访问 |
| 内存释放 | 一次 free(ptr) | 需逐个释放每个指针:for(i) free(ptr[i]) |
| 典型场景 | 规则矩阵运算、高效遍历 | 不规则数组、动态长度数组、字符串数组 |
常见错误与注意事项
错误1:混淆指针类型
int arr[2][3];
int (*ptr)[3] = arr; // 正确:ptr指向第一行
int* ptr2 = arr; // 错误:类型不匹配(int* 与 int(*)[3])
错误2:错误释放内存
int rows = 3, cols = 4;
int* matrix[rows];
for (int i = 0; i < rows; i++)
{
matrix[i] = malloc(cols * sizeof(int));
}
free(matrix); // 错误!只释放了指针数组,未释放每行内存
// 正确做法:
for (int i = 0; i < rows; i++)
{
free(matrix[i]);
}
1100

被折叠的 条评论
为什么被折叠?



