C语言int数组直接赋值给指针触发段错误的原因咨询
核心原因:两种声明的语义完全不同,不存在编译器识别错误
段错误的触发是编译器严格遵循C标准语义执行的结果,两种写法从变量类型到初始化逻辑没有共通之处:
- 数组声明
int arr[] = {1, 2, 3};
这是数组类型的专属初始化语法。编译器识别到声明类型为未指定长度的int数组时,会先根据初始化列表的元素个数计算所需连续内存大小(此处为3个int的长度),在栈上开辟对应空间后将1、2、3依次写入,再将数组名arr绑定到这块内存的起始位置。只有当arr被赋值给int*类型指针变量时,才会发生数组到首元素指针的退化。 - 指针声明
int *ptr = {1, 2, 3};
此处声明的变量类型是int*,属于单值标量类型(与普通int、char变量属同一类,并非数组)。C语言对标量类型使用大括号初始化时,仅会读取大括号内的第一个值作为变量初始值,后续多余的初始值编译器会直接抛出“初始值过多”的警告。
这段代码的实际执行逻辑是:将整数值1强制转换为int*类型,赋值给指针变量ptr——也就是说ptr中存储的内存地址是0x1,属于操作系统保留的低地址禁区,根本不在用户程序的可访问内存范围内。后续执行ptr[0]等价于访问地址0x1位置存储的int值,触发段错误是必然结果。
关键规则:初始化列表不会改变变量本身的类型,作用仅为给已经声明好类型的变量填充初始值。大括号不等于数组内存分配,只有当声明的变量本身是数组类型时,编译器才会执行连续内存分配的逻辑。
如果需要实现“指针直接指向存储了1、2、3的连续数组”的效果,必须显式通过复合字面量告知编译器开辟数组内存,合法写法如下:
int *ptr = (int[]){1, 2, 3}; printf("%d\n", ptr[0]); // 正常输出1,无段错误
该写法中(int[]){1,2,3}会显式指示编译器开辟3个int长度的连续栈空间,存入三个数值后将首地址赋值给ptr,和先定义arr数组再将arr赋值给ptr的底层逻辑完全一致。
内容的提问来源于stack exchange,提问作者viral_mutant
相关产品推荐
相关产品推荐

