c语言 一维数组指针数组指针数组

99ANYc3cd6
预计阅读时长 19 分钟
位置: 首页 C语言 正文

核心比喻:一个图书馆

想象一下图书馆:

c语言 一维数组指针数组指针数组
(图片来源网络,侵删)
  • 一维数组:就是一排连续的书架,每一本书(元素)都放在一个固定的位置,它们紧挨着,编号是连续的(0, 1, 2...),你不能把一个书架上的书和另一个书架上的书混在一起,它们是整体的一部分。
  • 指针数组:就是一排书架,但每个书架上只放了一本书的索引卡片(指针),这些卡片指向图书馆里任意位置的书(可以是连续的,也可以是分散的),书架本身是连续的,但它们指向的内容是离散的。
  • 数组指针:就像一个移动的、可伸缩的“书架车”,这个书架车本身就是一个指针,它指向一整排连续的书架(一个数组),你可以推着这个书架车在图书馆里移动,让它指向不同的书排。

一维数组

这是最基础的概念。

  • 定义:一组类型相同的元素的集合,这些元素在内存中连续存储
  • 本质:一个整体,包含多个连续的元素。
  • 关键点
    • sizeof(数组名) 得到的是整个数组所占的总字节数。
    • &数组名 得到的是整个数组的起始地址。
    • 数组名 在大多数情况下(除了作为 sizeof& 的操作数)会退化为指向其第一个元素的指针。

代码示例

#include <stdio.h>
int main() {
    // 定义一个一维数组,包含5个int类型的元素
    int arr[5] = {10, 20, 30, 40, 50};
    // 1. 数组名 'arr' 在这里会退化,等同于 &arr[0]
    printf("arr 的地址: %p\n", (void*)arr);
    printf("&arr[0] 的地址: %p\n", (void*)&arr[0]);
    // 2. sizeof(数组名) 计算整个数组的大小
    printf("sizeof(arr): %zu bytes\n", sizeof(arr)); // 5 * sizeof(int) = 20 bytes
    // 3. &数组名 得到的是整个数组的地址
    printf("&arr 的地址: %p\n", (void*)&arr);
    printf("arr + 1 的地址: %p\n", (void*)(arr + 1)); // 地址 + 4 (一个int的大小)
    printf("&arr + 1 的地址: %p\n", (void*)(&arr + 1)); // 地址 + 20 (整个数组的大小)
    return 0;
}

内存模型

+-----------+-----------+-----------+-----------+-----------+
|  arr[0]   |  arr[1]   |  arr[2]   |  arr[3]   |  arr[4]   |
| (value 10)| (value 20)| (value 30)| (value 40)| (value 50)|
+-----------+-----------+-----------+-----------+-----------+
     ^
     |
   arr  (指向第一个元素的指针)

指针数组

从名字看,“指针的数组”,它是一个数组

  • 定义:一个数组,其每个元素都是一个指针
  • 本质:一个数组,存储的是指针。
  • 关键点
    • 它是一个数组,sizeof(指针数组名) 得到的是整个数组所占的总字节数(即 指针个数 * sizeof(指针类型))。
    • 它的元素可以指向不同类型的内存地址(通常是同类型,但技术上可以不同)。
    • 常用于处理多个字符串(字符串字面量本质上是字符指针)。

代码示例

#include <stdio.h>
int main() {
    // 定义一个指针数组,包含3个int*类型的元素
    int *ptr_arr[3];
    int a = 100;
    int b = 200;
    int c = 300;
    // 让指针数组的每个元素指向一个整型变量
    ptr_arr[0] = &a;
    ptr_arr[1] = &b;
    ptr_arr[2] = &c;
    // 访问指针数组中的指针,再解引用获取值
    printf("Value via ptr_arr[0]: %d\n", *ptr_arr[0]); // 100
    printf("Value via ptr_arr[1]: %d\n", *ptr_arr[1]); // 200
    // 遍历指针数组
    for (int i = 0; i < 3; i++) {
        printf("ptr_arr[%d] points to value: %d\n", i, *ptr_arr[i]);
    }
    // sizeof 计算的是整个指针数组的大小
    // 3 * sizeof(int*) = 3 * 8 = 24 (在64位系统上)
    printf("sizeof(ptr_arr): %zu bytes\n", sizeof(ptr_arr));
    return 0;
}

内存模型

c语言 一维数组指针数组指针数组
(图片来源网络,侵删)
      +-------+       +-------+       +-------+
      |  &a   |       |  &b   |       |  &c   |
      +-------+       +-------+       +-------+
          ^               ^               ^
          |               |               |
+---------+---------+---------+---------+---------+
| ptr_arr[0] | ptr_arr[1] | ptr_arr[2] | ... (其他可能的内存)
+---------+---------+---------+---------+---------+
   (指针数组本身在内存中是连续的)

数组指针

从名字看,“指向数组的指针”,它是一个指针

  • 定义:一个指针,它指向一个完整的数组
  • 本质:一个指针,其指向的数据类型是一个数组。
  • 关键点
    • 它是一个指针,sizeof(数组指针名) 得到的是指针本身的大小(通常是 4 或 8 字节)。
    • 定义时必须明确它指向的数组的维度(即包含多少个元素)。
    • 语法上有点奇怪:int (*p)[N],括号是关键,它告诉编译器 p 是一个指针,而不是一个数组。

代码示例

#include <stdio.h>
int main() {
    int arr[5] = {10, 20, 30, 40, 50};
    // 定义一个数组指针 p,它指向一个包含5个int元素的数组
    // 语法:int (*p)[5]
    //       ^   ^
    //       |   +---- p指向的数组有5个int元素
    //       +-------- p是一个指针
    int (*p)[5] = &arr; // 注意,这里必须取 &arr,因为p指向的是整个数组
    // 1. *p 解引用后,就得到了它所指向的整个数组
    //    *p 和 arr 行为类似,会退化为其首元素地址
    printf("Value via *p: %d\n", (*p)[2]); // 30, 等同于 arr[2]
    // 2. p 是一个指针,sizeof(p) 得到的是指针的大小
    printf("sizeof(p): %zu bytes\n", sizeof(p)); // 8 bytes (64位系统)
    // 3. p + 1 的地址会跳过整个数组的大小
    printf("p's address: %p\n", (void*)p);
    printf("(p + 1)'s address: %p\n", (void*)(p + 1)); // 地址 + 5 * sizeof(int) = 20
    return 0;
}

内存模型

+-----------+-----------+-----------+-----------+-----------+
|  arr[0]   |  arr[1]   |  arr[2]   |  arr[3]   |  arr[4]   |
+-----------+-----------+-----------+-----------+-----------+
     ^
     |
   &arr  (整个数组的地址)
     ^
     |
     p  (数组指针,指向了 &arr)

核心区别与总结

特性 一维数组 (int arr[5]) 指针数组 (int *ptr_arr[3]) 数组指针 (int (*p)[5])
名称 数组 指针数组 数组指针
本质 一个数组,包含多个同类型元素 一个数组,其元素都是指针 一个指针,指向一个数组
定义语法 type name[size]; type *name[size]; type (*name)[size];
sizeof sizeof(name) -> 整个数组大小 sizeof(name) -> 整个指针数组大小 sizeof(name) -> 指针本身大小
&name &name -> 整个数组的地址 &name -> 指针数组的地址 &name -> 指针的地址
name + 1 name + 1 -> 指向下一个元素 name + 1 -> 指向下一个指针元素 p + 1 -> 指向下一个相同类型的数组
用途 存储一组连续的数据 存储多个指向不同内存地址的指针(如字符串) 指向并操作一个固定大小的多维数组行
记忆口诀 数组的元素 数组的元素是指针 指针指向的是数组

如何区分 int *p[5]int (*p)[5]

这是最经典的语法辨析题,关键在于运算符的优先级

  1. *`int p[5];`**

    c语言 一维数组指针数组指针数组
    (图片来源网络,侵删)
    • [] (数组下标运算符) 的优先级高于 (指针解引用运算符)。
    • int *p[5] 被解释为 int *(p[5])
    • 意思是:p 是一个包含5个元素的数组,这个数组的每个元素都是 int* (指向整型的指针)。
    • 指针数组
  2. *`int (p)[5];`**

    • 括号 的优先级最高。
    • int (*p)[5] 被解释为 p 是一个指针,这个指针指向 int[5] (一个包含5个整型的数组)。
    • 数组指针

简单记忆法: 和 [] 中间没有括号,[] 优先,p 是数组; 被 包围, 优先,p 是指针。

希望这个详细的解释和比喻能帮助你彻底理解这三个概念!

-- 展开阅读全文 --
头像
html5织梦模板免费下载
« 上一篇 2025-12-28
织梦UTF8模板如何转GBK?
下一篇 » 2025-12-28
取消
微信二维码
支付宝二维码

目录[+]