C语言中数组变量的存储机制(聚焦命名变量中的指针而非内存)
C数组与指针的核心差异:为什么sizeof有时有效有时失效
首先明确:C语言里的数组既不是普通指针,也不是带长度的宽指针。你的困惑来自C数组的特殊设计——数组退化,以及编译期与运行期的信息差异。
1. 数组变量的本质:编译期已知的连续内存块
当你写int arr[5];时,编译器会:
- 在栈或全局区分配一块能装下5个int的连续内存
- 给这块内存绑定名字
arr - 编译期就记住
arr的长度是5,所以sizeof(arr)会直接被替换成5 * sizeof(int)——这是编译期计算的常量,不需要运行时额外存储长度信息
这和Rust的[i32; 5]有相似性,但C的数组长度不是类型的一部分:你没法让函数参数明确是int arr[5](编译器会直接把它当成指针),而Rust的数组长度是类型的一部分,fn func(arr: [i32;5])是完全明确的。
2. 为什么数组看起来和指针像?——隐式退化
在绝大多数表达式场景下,数组名会自动转换为指向首元素的指针,比如:
int arr[5]; int *p = arr; // 等价于 int *p = &arr[0];
这种转换就是“数组退化”,也是你觉得char argv[][]和char **argv能互换的原因——但这只是语法相似,底层逻辑完全不同:
char argv[3][4]是一块连续的12个char的内存,argv[i][j]等价于*(argv + i*4 + j)char **argv是一个指针,指向多个独立的char*指针,每个指针又指向单独的char数组,argv[i][j]等价于*(*(argv + i) + j)
3. 函数传参后sizeof失效的原因:参数里的数组会完全退化为指针
C语言的函数参数中,数组类型会被直接解析为指针类型:
// 下面两个函数声明完全等价 void func(int arr[]); void func(int *arr);
所以当你把数组传给函数时,实际上只传了首元素的地址,函数内部拿到的是一个指针,sizeof(arr)自然取的是指针的大小(比如64位系统是8字节),而非数组的总大小。
这是C早期的设计选择——为避免拷贝大数组(当年内存资源紧张),默认传首地址。如果要在函数里获取数组长度,必须手动把长度作为参数传入,比如:
void func(int *arr, int len);
4. 关于“宽指针”的疑问
C语言没有原生的宽指针(带长度的指针),但你可以手动模拟——比如用结构体存储指针和长度,这其实就是Rust里&[T]切片的底层逻辑,但C没有原生支持这种类型,所有长度信息都需要手动管理。
内容的提问来源于stack exchange,提问作者Mindustry Logic Processor
相关产品推荐
相关产品推荐

