当前位置: 首页 > 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.lryc.cn/news/608999.html

相关文章:

  • 【LeetCode刷题指南】--二叉树的后序遍历,二叉树遍历
  • VUE父级路由没有内容的解决方案
  • Python自动化测试框架:Unittest 断言
  • 数据结构中使用到的C语言
  • elk快速部署、集成、调优
  • [硬件电路-143]:模拟电路 - 开关电源与线性稳压电源的详细比较
  • mybatis-plus从入门到入土(四):持久层接口之BaseMapper和选装件
  • MySQL极简安装挑战
  • nmon使用教程
  • sqli-labs:Less-23关卡详细解析
  • 基于Python实现生产者—消费者分布式消息队列:构建高可用异步通信系统
  • cpy相关函数区分
  • Ollama模型库模型下载慢完美解决(全平台)
  • 设计模式 - 组合模式:用树形结构处理对象之间的复杂关系
  • 新手向:Python制作贪吃蛇游戏(Pygame)
  • FLUX.1 Krea - 告别“AI味”,感受超自然细节,黑森林最新开源文生图模型 支持50系显卡 一键整合包下载
  • 控制建模matlab练习08:根轨迹
  • js--2048小游戏
  • 【openlayers框架学习】十:openlayers中控件的使用
  • Ubuntu系统VScode实现opencv(c++)视频的处理与保存
  • C语言与数据结构:从基础到实战
  • 解决飞书文档中PDF文档禁止下载的问题
  • Linux 环境下 Docker 安装与简单使用指南
  • ubuntu syslog中appindicator报错解决
  • 扩散模型(一)——综述
  • Rust: 获取 MAC 地址方法大全
  • 【MySQL进阶】------MySQL程序
  • 机器学习第三课之逻辑回归(三)LogisticRegression
  • 2025H1具身智能产业十大数据
  • Python训练营打卡 Day27