news 2026/5/1 6:12:41

数组退化成指针的几种情况

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
数组退化成指针的几种情况

一.什么是“数组退化成指针”?

在许多情况下,数组名会退化为指针,即原本代表数组的变量,变成了指向数组第一个元素的指针。这意味着数组名并不总是一个指向整个数组的指针,而是指向数组第一个元素的指针

二.举例

1.作为函数参数传递时

在函数参数中,数组总是退化为指针。这是因为函数参数的大小是固定的,而数组的大小在编译时并不确定。

#include <stdio.h> void foo(int arr[]) { printf("%zu\n", sizeof(arr)); // 输出指针的大小(4 或 8 字节) } int main() { int arr[10]; foo(arr); }

结果:sizeof(arr) 输出的是 指针的大小(4 或 8 字节,取决于32/64位平台)

分析:传递数组时,arr退化为指针sizeof(arr)返回的是指针的大小,而不是数组的大小。

void foo(int arr[ ]) 等价于void foo(int *arr)

2.作为函数参数的引用时

即使你使用引用(C++ 中)或者指针(C / C++ 中)传递数组,数组名依然会退化成指针。

#include <iostream> void foo(int* arr) { std::cout << sizeof(arr) << std::endl; // 输出指针大小 } int main() { int arr[10]; foo(arr); // 数组退化为指针 }

分析:arr作为参数传递给foo时,退化为指针,即传递给函数的是指向arr[0]的指针。

foo(arr)等价于foo(&a[0]);

3.用作sizeof表达式时

sizeof返回的是数组类型的大小,然而如果在数组名后加上 0,它会退化为指针类型,只看指针类型的大小。

#include <stdio.h> int main() { int arr[10]; printf("%zu\n", sizeof(arr)); // 数组的大小(40字节,假设 int 为4字节) printf("%zu\n", sizeof(arr+0)); // 指针的大小(4 或 8 字节) }

分析:

  • arr:在sizeof(arr)中,arr是一个数组,返回的是数组的总大小10 * sizeof(int))。

  • arr+0:在sizeof(arr+0)中,arr退化为指针(int*),sizeof返回的是指针的大小

4.在指针运算中

数组名在指针运算中始终退化为指针,因为数组名本质上是指向数组第一个元素的指针。

#include <stdio.h> int main() { int arr[5] = {1, 2, 3, 4, 5}; int *ptr = arr; // 数组退化为指针 printf("%d\n", *(ptr + 2)); // 输出 arr[2] 的值 3 }

分析:

  • arr被赋值给ptr,实际上是指针赋值,这时候arr退化为指向arr[0]的指针。

  • *(ptr + 2)实际上等价于arr[2]

5.作为函数返回值时(C++)

在 C++ 中,数组返回值也会退化为指针。如果你尝试返回整个数组,编译器会报错,但返回一个指向数组的指针是合法的。

#include <iostream> int* foo() { static int arr[3] = {1, 2, 3}; return arr; // 返回指向数组的指针 } int main() { int* ptr = foo(); std::cout << ptr[1] << std::endl; // 输出 2 }

分析:

  • 由于arr是一个局部数组,返回其指针是合法的(arr退化为指向arr[0]的指针)。

  • 注意:数组名退化为指针,因此你得到的是指向数组首元素的指针。

6.数组作为运算中的操作数时

在许多情况下,数组名也会自动退化为指针,尤其是作为运算的操作数时。

#include <stdio.h> int main() { int arr[3] = {1, 2, 3}; printf("%d\n", *(arr + 1)); // 输出 2 }

分析:

  • 这里arr退化为指向arr[0]的指针,arr + 1就是指向arr[1]的指针,*(arr + 1)解引用它,得到 2。

三、总结 & 避免数组传参退化的方法

数组在传参时默认会退化为指向首元素的指针,但这是由形参类型决定的,如果形参不是“数组引用”或“指向数组的指针”,则实参数组一定会发生数组到指针的转换也就是所谓的退化

简单说:只有当形参显式表示“整个数组类型”时,退化才不会发生。

那什么是形参为“数组引用”或“指向数组的指针”??

1.指向数组的指针(C / C++)

void foo(int (*arr)[10]);
int a[10]; foo(&a);
  • 实参传的是&a,类型匹配int (*)[10],没有退化

2.数组引用(C++)

void foo(int (&arr)[10]);
int a[10]; foo(a);
  • arr是数组引用,数组身份被完整保留没有退化

情况是否退化
foo(arr)✅ 实参处发生转换
void foo(int arr[])
void foo(int *arr)
void foo(int (*arr)[N])
void foo(int (&arr)[N])
sizeof(arr)
&arr

数组名在函数调用中作为形参时,普通写法一定会退化,只有参数代表整个数组类型,它才能接收整个数组否则都是接收的单个元素,正确不退化的形参写法:void foo( int (* arr )[10] )

写法指向
int *p单个 int
int (*p)[10]整个 int[10]
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/28 18:11:05

java 判断string[]中是否有a

在 Java 中判断字符串数组是否包含特定字符串&#xff0c;有几种常见方法&#xff1a;方法1&#xff1a;使用 Arrays.asList() 和 contains()import java.util.Arrays;String[] array {"a", "b", "c"}; boolean containsA Arrays.asList(array…

作者头像 李华
网站建设 2026/5/1 5:30:24

如何实现 “右移”的智能监控,快速定位和恢复线上事故?

一、核心理念:从“被动响应”到“主动预警” 传统监控停留在“故障发生-告警-人工处理”,而智能“右移”强调生产环境的事前预防、事中定位、事后自愈。 二、智能监控体系分层设计 1. 数据采集层 多维度埋点: 应用层:日志(结构化/非结构化)、链路追踪(Trace)、关键业…

作者头像 李华
网站建设 2026/4/30 18:01:27

Flutter 自定义 Widget 开发:从基础绘制到复杂交互

Flutter 自定义 Widget 开发&#xff1a;从基础绘制到复杂交互 在 Flutter 开发中&#xff0c;系统提供的 Widget 虽能满足大部分基础需求&#xff0c;但在实现个性化 UI 或复杂交互逻辑时&#xff0c;自定义 Widget 成为核心技能。本文将从基础的绘制原理出发&#xff0c;逐步…

作者头像 李华
网站建设 2026/4/25 3:06:40

Flutter 路由进阶:命名路由、动态路由与路由守卫实现

Flutter 路由进阶&#xff1a;命名路由、动态路由与路由守卫实现 路由是 Flutter 应用中页面跳转与导航的核心机制&#xff0c;负责管理页面之间的跳转逻辑、参数传递与状态维护。基础路由&#xff08;如 Navigator.push、Navigator.pop&#xff09;虽能满足简单场景需求&…

作者头像 李华
网站建设 2026/4/18 0:13:29

7大核心功能重构:绝区零自动化解决方案的技术突破与实践指南

7大核心功能重构&#xff1a;绝区零自动化解决方案的技术突破与实践指南 【免费下载链接】ZenlessZoneZero-OneDragon 绝区零 一条龙 | 全自动 | 自动闪避 | 自动每日 | 自动空洞 | 支持手柄 项目地址: https://gitcode.com/gh_mirrors/ze/ZenlessZoneZero-OneDragon 绝…

作者头像 李华
网站建设 2026/4/19 17:24:08

四步重塑小米AI音箱:从语音助手到全屋智能中枢的进化之路

四步重塑小米AI音箱&#xff1a;从语音助手到全屋智能中枢的进化之路 【免费下载链接】mi-gpt &#x1f3e0; 将小爱音箱接入 ChatGPT 和豆包&#xff0c;改造成你的专属语音助手。 项目地址: https://gitcode.com/GitHub_Trending/mi/mi-gpt 你是否曾经对着家里的智能音…

作者头像 李华