指针数组和数组指针是C语言中两个容易混淆但完全不同的概念,它们在声明方式、内存结构和用途上都有显著区别。
1. 定义与本质区别
类型 | 本质 | 声明形式 |
指针数组 | 数组元素都是指针的数组 |
|
数组指针 | 指向整个数组的指针 |
|
2. 指针数组(Array of Pointers)
特点:
- 是一个数组,每个元素都是指针
- 元素可以指向不同类型的数据
- 常用于字符串数组或动态数据结构
示例:
#include <stdio.h>
int main()
{
// 指针数组:names是指针数组,数组里包含三个指针,每个指针指向一个字符串
char *names[3] = {"alice", "bob", "charlie"};
// 访问方式
for (int i = 0; i < 3; i++)
{
// names[i] 是字符串数组。
printf("name %d %s\n", i, names[i]);
}
return 0;
}
内存布局:
name 0 alice
name 1 bob
name 2 charlie
3. 数组指针(Pointer to Array)
特点:
- 是一个指针,指向整个数组
- 常用于处理多维数组
- 通过指针可以访问数组的所有元素
示例:
#include <stdio.h>
int main() {
int matrix[2][3] = {{1,2,3}, {4,5,6}};
// 数组指针:指向包含3个int的数组
int (*ptr)[3] = matrix;
// 访问方式
for(int i = 0; i < 2; i++) {
for(int j = 0; j < 3; j++) {
printf("%d ", ptr[i][j]); // 等价于matrix[i][j]
}
printf("\n");
}
return 0;
}
内存布局:
ptr → [1,2,3]
[4,5,6]
4. 关键区别对比
特性 | 指针数组 | 数组指针 |
本质 | 数组 | 指针 |
元素类型 | 指针 | 整个数组 |
内存占用 | 数组大小×指针大小 | 单个指针大小 |
增减操作 | 指针数组名不能++ | 数组指针可以++,跳过一个数组 |
常见用途 | 字符串数组、命令行参数 | 多维数组处理 |
5. 实际应用场景
指针数组的典型应用 - 命令行参数
int main(int argc, char *argv[]) {
// argv是指针数组,每个元素指向一个参数字符串
for(int i = 0; i < argc; i++) {
printf("参数%d: %s\n", i, argv[i]);
}
}
数组指针的典型应用 - 传递二维数组
#include <stdio.h>
void print_matrix(int (*mat)[3], int rows)
{
// 访问方式
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < 3; j++)
{
printf("%d ", mat[i][j]); // 等价于matrix[i][j]
}
printf("\n");
}
}
int main() {
int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};
print_matrix(matrix, 2);
}
6. 高级示例
指针数组的高级用法
// 动态创建指针数组
int **create_pointer_array(int rows, int cols) {
int **arr = malloc(rows * sizeof(int*));
for(int i = 0; i < rows; i++) {
arr[i] = malloc(cols * sizeof(int));
}
return arr;
}
数组指针处理三维数组
void process_3d_array(int (*arr)[2][3], int layers) {
for(int l = 0; l < layers; l++) {
for(int i = 0; i < 2; i++) {
for(int j = 0; j < 3; j++) {
printf("%d ", arr[l][i][j]);
}
}
}
}
int main() {
int arr3d[2][2][3] = {{{1,2,3},{4,5,6}}, {{7,8,9},{10,11,12}}};
process_3d_array(arr3d, 2);
}
7. 增减操作运算
指针数组的指针运算
int a = 1, b = 2, c = 3;
int *ptr_arr[] = {&a, &b, &c};
// ptr_arr + 1 移动sizeof(int*)字节
printf("%p -> %p\n", ptr_arr, ptr_arr + 1);
数组指针的指针运算
void array_pointer_add_one_demo()
{
// 数组指针
int arr[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
int(*arr_ptr)[4] = arr;
// arr_ptr+1,移动sizeof(int[4])个字节,通常为16个字节
// arr_ptr指向第0个数组,arr_ptr+1指向第1个数组
printf("%p --> %p \n", arr_ptr, arr_ptr + 1);
printf("%d --> %d \n", (*arr_ptr)[0], (*(arr_ptr + 1))[0]);
}
8. 记忆技巧
- 指针数组:先看
[]
,是数组,再看*
,元素是指针 → "数组里存指针" - 数组指针:先看
*
,是指针,再看[]
,指向数组 → "指针指向数组"
理解这两者的区别对处理复杂数据结构和多维数组非常重要!
9, 完整示例及输出
#include <stdio.h>
/*
指针数组示例。是一个数组,每个数组元素都是指针。
该示例中,元素是指向字符串的指针。指针数组常用于字符串数组。
*/
void pointer_array_demo1()
{
// 指针数组:names是指针数组,数组里包含三个指针,每个指针指向一个字符串
char *names[3] = {"alice", "bob", "charlie"};
// 访问方式
for (int i = 0; i < 3; i++)
{
// names[i] 是字符串数组。
printf("name %d %s\n", i, names[i]);
}
}
/*
数组指针示例。是一个指针,该指针指向一个数组。
*/
void array_pointer_demo1()
{
int rows = 2, cols = 3;
int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};
// 数组指针。该指针指向一个包含3个int的一维数组,
int(*ptr)[3] = matrix;
// 访问方式
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
printf("%d ", ptr[i][j]); // 等价于matrix[i][j]
}
printf("\n");
}
}
/*
数组指针示例2。将数组指针作为函数入参传递。
*/
void print_matrix(int (*mat)[3], int rows)
{
// 访问方式
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < 3; j++)
{
printf("%d ", mat[i][j]); // 等价于matrix[i][j]
}
printf("\n");
}
}
void array_pointer_demo2()
{
int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};
print_matrix(matrix, 2);
}
void pointer_array_add_one_demo()
{
// 指针数组,其中每个元素都是指针
int a = 1, b = 2, c = 3;
int *ptr_arr[] = {&a, &b, &c};
// ptr_arr + 1 移动 sizeof(int *)个字节
// ptr_arr[0]指向数组的首个指针元素地址,*(ptr_arr[0])指向该地址存储的值。
printf("%p --> %p\n", ptr_arr, ptr_arr + 1);
printf("%d --> %d\n", *(ptr_arr[0]), *(ptr_arr[1]));
}
void array_pointer_add_one_demo()
{
// 数组指针
int arr[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
int(*arr_ptr)[4] = arr;
// arr_ptr+1,移动sizeof(int[4])个字节,通常为16个字节
// arr_ptr指向第0个数组,arr_ptr+1指向第1个数组
printf("%p --> %p \n", arr_ptr, arr_ptr + 1);
printf("%d --> %d \n", (*arr_ptr)[0], (*(arr_ptr + 1))[0]);
}
// 指针数组和书数组指针示例
int main()
{
//指针数组示例。是一个数组,每个数组元素都是指针。
pointer_array_demo1();
//数组指针示例。是一个指针,该指针指向一个数组。
array_pointer_demo1();
// 数组指针示例2。将数组指针作为函数入参传递。
array_pointer_demo2();
// 指针数组加1
pointer_array_add_one_demo();
// 数组指针加1
array_pointer_add_one_demo();
return 0;
}
name 0 alice
name 1 bob
name 2 charlie
1 2 3
4 5 6
1 2 3
4 5 6
0x7ffee4d28330 --> 0x7ffee4d28338
1 --> 2
0x7ffee4d28320 --> 0x7ffee4d28330
1 --> 5