当前位置: 首页 > news >正文

数组和指针的关系

在 C 语言中,​指针和数组有着非常紧密的联系,但它们本质上是 ​不同的概念。理解它们的关系是掌握 C 语言内存操作的关键。下面我会从多个角度帮你梳理 ​指针和数组的直接联系,并解释它们的异同点。

1. 数组和指针的本质区别

概念本质存储方式能否修改指向典型用途
数组(Array)​一组 ​连续存储的同类型数据在栈或静态区分配固定大小的内存❌ 不能整体修改(数组名是常量指针)存储固定数量的数据
指针(Pointer)​一个 ​变量,存储内存地址可以指向任意内存位置(栈、堆、静态区)✅ 可以修改指向(指向不同地址)动态内存操作、函数传参

关键区别​:

  • 数组名 arr 在大多数情况下会退化为指向首元素的指针(&arr[0]),但它本身不是指针变量​(不能重新赋值,如 arr = &x 是错误的)。
  • 指针是一个变量,可以存储任意地址,并且可以修改指向​(如 int *p = &x; p = &y;)。

2. 数组和指针的直接联系

​(1) 数组名在大多数情况下退化为指针(指向首元素)​

int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;  // 等价于 int *p = &arr[0];
  • ​**arr​ 的类型是 int[5](数组),但在表达式里(如赋值给指针时),它会 ​退化为 int*(指向 arr[0] 的指针)​**。
  • ​**arr 和 &arr[0] 是等价的**,都表示数组首元素的地址。

​(2) 数组名 arr 和 &arr 的区别

表达式类型含义
arrint*(退化)指向 ​首元素 arr[0] 的指针
&arrint (*)[5]指向 ​整个数组 arr 的指针​(类型是 int[5] 的指针)
arr + 1移动 ​1 个 int 大小(4 字节)​指向 arr[1]
&arr + 1移动 ​整个数组大小(5 * 4 = 20 字节)​指向 arr 的下一个数组(如果有的话)

示例​:

int arr[5] = {1, 2, 3, 4, 5};
printf("%p\n", arr);     // 数组首元素地址(等价于 &arr[0])
printf("%p\n", &arr);    // 整个数组的地址(值和 arr 相同,但类型不同)
printf("%p\n", arr + 1); // 指向 arr[1](地址 + 4 字节)
printf("%p\n", &arr + 1); // 指向 arr 的下一个位置(地址 + 20 字节)

输出​:

0x7ffd12345670  (arr)
0x7ffd12345670  (&arr,值相同)
0x7ffd12345674  (arr + 1,+4 字节)
0x7ffd12345684  (&arr + 1,+20 字节)

结论​:

  • arr 和 &arr 的 ​值相同​(都是数组的起始地址),但 ​类型不同​:
    • arr 是 int*(指向 int)。
    • &arr 是 int (*)[5](指向 int[5] 数组)。
  • arr + 1 和 &arr + 1 的 ​步长不同​:
    • arr + 1 移动 ​1 个 int 大小(4 字节)​
    • &arr + 1 移动 ​整个数组大小(5 * 4 = 20 字节)​

​(3) 数组访问方式 vs 指针访问方式

数组方式
int arr[3] = {10, 20, 30};
printf("%d\n", arr[1]);  // 20(数组下标访问)
指针方式
int *p = arr;
printf("%d\n", *(p + 1));  // 20(指针偏移访问)

等价关系​:

  • arr[i] 等价于 *(arr + i)
  • p[i] 等价于 *(p + i)

结论​:

  • 数组下标访问 arr[i] 底层就是指针偏移 *(arr + i)
  • 指针可以像数组一样使用 [] 运算符​(因为 [] 本质是指针算术)。

​(4) 函数传参时数组退化为指针

void printArray(int arr[], int size) {  // 实际上 arr 是 int*for (int i = 0; i < size; i++) {printf("%d ", arr[i]);  // 等价于 *(arr + i)}
}int main() {int myArr[3] = {1, 2, 3};printArray(myArr, 3);  // 数组名退化为指针return 0;
}

关键点​:

  • ​**函数参数中的 int arr[] 实际上等价于 int *arr**​(编译器不会把数组完整传进去,而是传首地址)。
  • 所以 ​在函数内部无法通过 sizeof(arr) 获取数组大小​(只能得到指针大小,通常是 4 或 8 字节)。

3. 指针和数组的常见操作对比

操作数组方式指针方式
访问第 i 个元素arr[i]*(p + i) 或 p[i]
遍历数组for (int i = 0; i < n; i++) { arr[i]; }for (int *p = arr; p < arr + n; p++) { *p; }
函数传参void func(int arr[])(实际是 int*void func(int *p)
获取首地址arr 或 &arr[0]p(指针本身)
获取数组大小sizeof(arr) / sizeof(arr[0])(仅限数组定义处)❌ 无法直接获取(只能手动传大小)

4. 总结

​(1) 指针和数组的联系

✅ ​数组名在大多数情况下会退化为指向首元素的指针​(如 arr → &arr[0])。
✅ ​数组访问 arr[i] 底层就是指针算术 *(arr + i)
✅ ​指针可以像数组一样使用 [] 运算符​(如 p[i])。
✅ ​函数传参时,数组会退化为指针​(无法在函数内获取数组真实大小)。

​(2) 指针和数组的区别

❌ ​数组名不是指针变量​(不能重新赋值,如 arr = &x 是错误的)。
❌ ​**arr 和 &arr 类型不同​(arr 是 int*&arr 是 int (*)[n])。
❌ ​
数组在栈/静态区分配固定大小,指针可以指向任意内存(堆、栈、静态区)​**。

​(3) 关键结论

  • 数组名 arr 在大多数情况下可以当作指针使用,但它本质不是指针变量
  • 指针更灵活,可以指向任意内存,而数组名是固定的
  • 函数传参时,数组会退化为指针,所以无法在函数内获取数组真实大小​(必须额外传 size 参数)。

http://www.dtcms.com/a/313433.html

相关文章:

  • 操作系统——读者写者问题
  • KNX协议介绍
  • Nvidia Orin + RealSense D435i 与3D地图实现导航
  • Ubuntu系统VScode实现opencv(c++)视频的处理与保存
  • [硬件电路-129]:模拟电路 - 继电器的工作原理、关键指标、常用芯片与管脚定义
  • SpringAI的使用
  • Socket编程——TCP协议
  • 从一到无穷大 #51:突破阿姆达尔定律:COZ因果剖析与串行优化八法
  • Java学习第一百零一部分——网关(Gateway)
  • java测试题(ssm框架)
  • 02.Redis 安装
  • MPLS 静态LSP
  • TV电视版软件集合分享
  • 深入理解Java并发编程:原理、实战与最佳实践
  • Redis 7 中的 Set 和 Zset 使用
  • 基于transformer的目标检测——匈牙利匹配算法
  • 深入解析HashMap:原理与性能优化
  • Vim编辑器详解:从入门到高效使用
  • 从零开始的CAD|CAE开发: LBM源码实现分享
  • 编程语言分类
  • JAVAEE--5.多线程之常见的锁策略
  • AI Competitor Intelligence Agent Team
  • 【openlayers框架学习】七:绘制线要素以及点击画线功能
  • 力扣热题100----------141.环形链表
  • 基于BiLSTM+CRF实现NER
  • 【机器人】VLN-R1 微调 | 增强训练 | 连续导航
  • Web3合约ABI,合约地址生成部署调用及创建,连接钱包,基础交易流程
  • ARPO:让LLM智能体更高效探索
  • 【Linux网络编程基础--socket地址API】
  • 多 4G 通讯模组共存时的干扰问题深度解析与解决方案