0

0

C++ 数组名是常指针吗 C++数组衰变与指针区别解析【理论】

穿越時空

穿越時空

发布时间:2026-02-01 19:11:35

|

490人浏览过

|

来源于php中文网

原创

数组名不是指针,更非“常指针”;其类型为int[5],sizeof(arr)返回整个数组字节数,&arr类型为int(*)[5],与指针类型有本质区别。

c++ 数组名是常指针吗 c++数组衰变与指针区别解析【理论】

数组名不是指针,更不是“常指针”——但绝大多数时候它会自动变成 int* 类型的右值

这是最常被误传的结论。很多教材说“数组名是常量指针”,但它在 C++ 类型系统里根本就不是指针类型。证据很直接:sizeof(arr) 返回的是整个数组字节数,而 sizeof(p)pint*)永远是 8(64 位平台);对数组取地址:&arr 的类型是 int(*)[5](指向含 5 个 的数组),不是 int**。这些行为只有原生数组类型才能解释。

真正发生的是「数组衰变」(array decay):在绝大多数表达式语境中(如赋值、传参、算术运算),数组名会隐式转换为指向首元素的指针——而且是纯右值(prvalue),不能取地址、不可自增、不可赋值。它不是变量,也不占用存储空间。

  • int arr[5] = {1,2,3,4,5};arr 本身是类型 int[5]
  • int* p = arr; → 这里 arr 衰变为 int* 右值,再初始化 p
  • arr++; → 编译错误:lvalue required as increment operand(arr 不是左值)
  • &arr&arr[0] 地址数值相同,但类型不同、+1 偏移量不同

什么时候数组名不会衰变?——三个关键例外场景

理解衰变的“例外”,才能真正掌控数组类型。这三点直接影响模板推导、函数重载和 sizeof 行为:

  • sizeof(arr):返回 5 * sizeof(int),而非 sizeof(int*)
  • &arr:得到类型为 int(*)[5] 的指针,(&arr) + 1 指向内存中下一个“5元组”起始位置(偏移 5*sizeof(int)
  • 作为函数形参时用引用语法:void f(int (&a)[5]) —— 此时 a 是数组引用,不衰变,能保尺寸、可传入 sizeof

漏掉这些例外,写泛型代码或封装数组工具时就会意外丢失维度信息,比如把 std::array 当成裸数组用却得不到编译期长度。

立即学习C++免费学习笔记(深入)”;

讯飞绘文
讯飞绘文

讯飞绘文:免费AI写作/AI生成文章

下载

为什么 int* p = arr; 看起来像“数组名是指针”?——衰变 vs 显式声明的本质区别

这个赋值之所以成立,是因为编译器插入了隐式转换,不是因为 arr 本身就是指针。对比下面两行:

int arr[3] = {1,2,3};
int* p = arr;        // ✅ 合法:arr 衰变为 int* 右值,用于初始化 p
int* q = &arr;       // ❌ 错误:&arr 类型是 int(*)[3],不能隐式转为 int*

关键差异点:

  • p 是变量,可修改(p++p = &arr[2]);arr 本身不可修改、不可取地址(作为左值)
  • arr[2] 是语法糖,等价于 *((arr) + 2) —— 注意括号:先衰变,再指针加法
  • 传递给函数时,void f(int* x) 接收的是衰变后的指针,完全丢失数组长度;而 void f(int (&x)[5])template void f(int (&x)[N]) 才真正保留数组身份

实际踩坑:二维数组传参与 int (*)[N] 指针的必要性

当你写 void process(int mat[][4]),其实等价于 void process(int (*mat)[4]) —— 这里必须提供列数,因为编译器需要知道每行占多少字节来计算 mat+1 的偏移。如果只写 int** mat,你就失去了连续内存布局保证,也无法用 mat[i][j] 安全访问(除非手动分配成指针数组)。

  • 正确方式(栈上二维数组):int grid[3][4]; process(grid);,形参必须是 int (*m)[4]int m[][4]
  • 错误直觉:int** p = grid; → 编译失败:类型不匹配
  • 衰变只到“首元素”层级:二维数组 int a[2][3] 的首元素是 int[3],所以衰变成 int (*)[3],不是 int**

这种类型细节在对接 C 风格 API 或做高性能数值计算时无法绕过——以为“数组名就是指针”而强行用 int* 接收二维数组,轻则越界读写,重则静默 UB。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1503

2023.10.24

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

503

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

545

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

113

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

200

2025.08.29

go语言 注释编码
go语言 注释编码

本专题整合了go语言注释、注释规范等等内容,阅读专题下面的文章了解更多详细内容。

29

2026.01.31

go语言 math包
go语言 math包

本专题整合了go语言math包相关内容,阅读专题下面的文章了解更多详细内容。

17

2026.01.31

go语言输入函数
go语言输入函数

本专题整合了go语言输入相关教程内容,阅读专题下面的文章了解更多详细内容。

15

2026.01.31

golang 循环遍历
golang 循环遍历

本专题整合了golang循环遍历相关教程,阅读专题下面的文章了解更多详细内容。

3

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
CSS3 教程
CSS3 教程

共18课时 | 5.1万人学习

Sass 教程
Sass 教程

共14课时 | 0.8万人学习

Pandas 教程
Pandas 教程

共15课时 | 1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号