C语言数组与sizeof()技术疑问:内存、实现及源码查询
C数组与sizeof相关问题解答
问题背景与代码示例
#include <stdio.h> char array1[3] = { 0,0,0 }; char array2[4] = { 0,0,0,0 }; char* a1 = array1; char* a2 = array2; int main(void) { printf("Array 1 Memory: %p\n", a1); printf("Array 2 Memory: %p\n\n", a2); //Array 1 set values and display addresses. printf("array1 = ["); for (int i = 0; i < 5; i++) { array1[i] = i; printf("%d, ", array1[i]); } printf("\n"); for (int i = 0; i < 4; i++) { printf("array1[%d] memory location: %p\n",i, a1 + i); } printf("size of array1 = %d\n", sizeof(array1)); printf("]\n"); //Array 2 display values and addresses printf("array2 = ["); for (int i = 0; i < 4; i++) { printf("%d, ", array2[i]); } printf("\n"); for (int i = 0; i < 4; i++) { printf("array2[%d] memory location: %p\n", i, a2 + i); } printf("size of array2 = %d\n", sizeof(array2)); printf("]\n"); printf("array2[-1] = %d\n", array2[-1]); return 0; }
运行输出
Array 1 Memory: 005CA4F4 Array 2 Memory: 005CA4F8 array1 = [0, 1, 2, 3, 4, array1[0] memory location: 005CA4F4 array1[1] memory location: 005CA4F5 array1[2] memory location: 005CA4F6 array1[3] memory location: 005CA4F7 size of array1 = 3 ] array2 = [4, 0, 0, 0, array2[0] memory location: 005CA4F8 array2[1] memory location: 005CA4F9 array2[2] memory location: 005CA4FA array2[3] memory location: 005CA4FB size of array2 = 4 ] array2[-1] = 3
疑问解答
1. 越界赋值后sizeof(array1)仍返回3的原因
sizeof是编译期运算符,它的值完全由数组的声明类型决定,和运行时的内存操作无关。当你声明char array1[3]时,编译器在编译阶段就已经确定了这个数组的大小是3字节,后续运行时哪怕你越界写入了额外的内存,也不会改变编译器对数组类型的认知——数组的大小信息是编译时的类型元数据,不会存储在运行时的内存中。另外,数组越界写入属于C语言中的未定义行为,可能会破坏其他变量的内存,绝对不要这么做。
2. sizeof的定义与实现逻辑
sizeof不是普通函数,而是C语言标准规定的运算符,所以不会在stdio.h或其他头文件里有函数声明。它的行为由C标准(如C11、C17)明确:
- 对于基本数据类型(如
int、char),返回该类型的字节数; - 对于数组类型,返回数组总字节数(元素个数 × 单个元素字节数);
- 对于指针类型,返回当前平台下指针的字节数(比如32位系统是4,64位是8)。
编译器在编译阶段就会计算sizeof表达式的值:对于静态数组、常量类型,直接替换为对应的常量数值;对于动态类型(如变长数组),则会生成运行时计算的代码。想了解具体实现,可以看GCC、Clang等开源编译器的源码,它们在前端语法分析阶段就会处理sizeof表达式。
3. C编译器源码与数组创建机制
常见的开源C编译器有GCC、Clang/LLVM,你可以直接获取它们的源码来研究。以char array[3]为例:
- 如果是全局数组,编译器会在程序的数据段预留3个
char大小的连续内存空间;如果是函数内的局部数组,则会在栈上分配空间。 - 数组的大小是编译期确定的类型信息,不会存储在运行时内存中。编译器只会在编译阶段用这个大小做静态检查(比如开启
-Wall警告时,越界访问会被提示),但运行时没有任何机制维护数组的大小,所以越界访问不会被自动拦截。
内容的提问来源于stack exchange,提问作者ryanc
相关产品推荐
相关产品推荐

