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

数组和指针的关系

在 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.xdnf.cn/news/16936.html

相关文章:

  • 从0搭建YOLO目标检测系统:实战项目+完整流程+界面开发(附源码)
  • 疯狂星期四文案网第28天运营日记
  • zookeeper持久化和恢复原理
  • 锻造企业级数字基座 - 从生死线到增长引擎的全景蓝图
  • 【设计模式】5.代理模式
  • VUE2 学习笔记16 插槽、Vuex
  • Python特性工厂函数详解:优雅管理属性验证
  • 昇思学习营-开发版-模型开发与适配
  • 【鸿蒙高级】
  • AI Competitor Intelligence Agent Team
  • 36. 有一个高 100%的 div,里面有一个高 100px 的 div,剩下一个自动填满
  • HiveMQ核心架构思维导图2024.9(Community Edition)
  • VBA 64位API声明语句第012讲
  • 实现游戏排行榜
  • Spring Boot 的事务注解 @Transactional 失效的几种情况
  • 从马武寨穿越关山
  • K8S部署ELK(五):集成Kibana实现日志可视化
  • [硬件电路-144]:模拟电路 - 开关电源与线性稳压电源常见的性能指标对比
  • Android设备认证体系深度解析:GMS/CTS/GTS/VTS/STS核心差异与认证逻辑
  • 【连接器专题】连接器做为固定连接介质的三种分类
  • 问题集000
  • Go语言常量
  • CAP 理论笔记
  • 前端开发(HTML,CSS,VUE,JS)从入门到精通!第四天(DOM编程和AJAX异步交互)
  • Mysql深入学习:InnoDB执行引擎篇
  • K8S几种常见CNI深入比较
  • Vue+SpringBoot+langchain4j实战案例:实现AI消息问答 及 Markdown打字机渲染效果
  • C语言与数据结构:从基础到实战
  • 基于 Spring Boot + Vue 实现人脸采集功能全流程
  • 大模型智能体(Agent)技术全景:架构演进、协作范式与应用前沿