C语言中,指针数组和数组指针有啥区别

指针数组和数组指针是C语言中两个容易混淆但完全不同的概念,它们在声明方式、内存结构和用途上都有显著区别。

1. 定义与本质区别

类型

本质

声明形式

指针数组

数组元素都是指针的数组

int *arr[10];

数组指针

指向整个数组的指针

int (*ptr)[10];

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值