C语言中&运算符作用于数组名时的数据类型差异相关疑问
C语言数组名与&运算符的类型行为底层说明
核心前置规则:数组名的退化机制
C语言中,数组名本身的原生类型是对应长度的数组类型,例如int array1[5]的原生类型是int [5],int array2[5][5]的原生类型是int [5][5]。仅当出现以下三种情况时,数组名不会自动转换为指向其首元素的指针(也就是常说的“数组退化”):
- 作为
sizeof运算符的操作数 - 作为
&运算符的操作数 - 是用于初始化字符数组的字符串字面值
问题1解答:array1与array2的类型差异本质
你观察到的类型差异,其实是数组在不同场景下是否触发退化的表现:
- 对
int array1[5]来说:- 赋值给
int *p1时,array1不属于上述三种例外场景,触发退化,转换为指向首元素(int类型)的指针,类型为int *,和p1类型匹配,因此编译正常。 - 作为
&的操作数时,array1不触发退化,保持int [5]的原生数组类型,&取该数组的地址,得到的类型是指向长度为5的int数组的指针,也就是int (*)[5],和int *类型不兼容,因此int *p2 = &array1编译报错。
- 赋值给
- 对
int array2[5][5]来说:- 它的首元素是
int [5]类型的一维数组,赋值给int (*q1)[5]时,array2触发退化,转换为指向首元素的指针,类型就是int (*)[5],和q1类型匹配,因此编译正常。 - 作为
&的操作数时,array2不触发退化,保持int [5][5]的原生二维数组类型,&取该二维数组的地址,得到的类型是指向长度为5*5的int二维数组的指针,也就是int (*)[5][5],和int (*)[5]类型不兼容,因此int (*q2)[5] = &array2编译报错。
- 它的首元素是
问题2解答:&运算符为什么会改变数组名的表现
本质上&并没有修改数组名的类型,而是阻止了数组名的退化行为:常规场景下数组名会隐式转成首元素指针,只有做&操作时,编译器会把数组名当做完整的数组类型处理,取到的地址是整个数组的地址,而非单个元素的地址。
注意:虽然
array1和&array1的数值地址完全相同(都指向数组的起始内存位置),但二者的指针步长完全不同:array1 + 1会偏移sizeof(int)个字节,而&array1 + 1会偏移sizeof(int[5])个字节,这个类型差异是为了保证指针运算的语义正确,并非无意义的语法规定。
内容的提问来源于stack exchange,提问作者Delisle
相关产品推荐
相关产品推荐

