C语言使用不同格式说明符访问数组的输出含义咨询
输出结果逐行解释
核心前提:C语言的
printf函数不会对传入参数的类型做校验,如果格式说明符和实际传入参数的类型不匹配,属于未定义行为,你看到的所有非预期输出都是该规则的体现,仅在你当前的Win10+MinGW 64位编译环境下生效,换环境输出可能完全不同,实际开发中严禁这类写法。
首先明确几个基础背景:
- C语言中数组名
y作为函数参数传递时,会自动退化为指向数组首元素的指针,类型为int*,数值等于数组的起始内存地址 &y是指向整个数组的指针,类型为int(*)[4],它的数值和y、&y[0]完全相等,都指向数组的起始位置- 64位环境下指针长度为8字节,
int类型长度为4字节,Windows系统采用小端字节序存储数据 - 操作系统的ASLR(地址空间布局随机化)机制会让程序每次运行时栈内存的地址发生变化,所以和地址相关的输出每次运行都不同
逐行输出解释:
- 第1条
printf(" 1 %d\n", y):%d要求传入int类型参数,实际传入的是指针值,运行时会取指针的低4字节按照int的规则解析输出,两次运行地址不同所以输出的整数值不同 - 第2条
printf(" 2 %s\n", y):%s要求传入字符串首地址(char*类型),会从传入地址开始逐个读取字节输出,直到遇到\0(ASCII值为0的字节)停止。你的数组首元素是12,小端存储的字节序列为0x0c 0x00 0x00 0x00,第一个字节是不可见的控制字符,第二个就是\0,所以输出内容几乎不可见,加上printf自带的换行,看起来就是两行空内容 - 第3条
printf(" 3 %f\n", y):%f要求传入double类型参数(float传参时会自动提升为double),且x86/64架构下浮点数参数和整数/指针参数使用不同的寄存器传递,此时printf读取的是浮点数寄存器中的残留值,你运行时刚好残留值为0,所以输出0.000000,该值是完全不确定的 - 第4条
printf(" 4 %p\n", y):%p是专门用于输出指针的格式说明符,这里会正确输出数组首元素的64位十六进制内存地址,每次运行地址变化所以输出不同 - 第5条
printf(" 5 %d\n", &y):&y的数值和y完全相等,所以运行逻辑和第1条完全一致,输出结果和第1条相同 - 第6条
printf(" 6 %p\n", &y):&y是合法的指针,用%p输出会得到正确的数组指针地址,数值和第4条一致 - 第7条
printf(" 7 %d\n", y[0]):格式说明符和参数类型完全匹配,正确输出数组第一个元素的值12,所以固定不变 - 第8条
printf(" 8 %p\n", y[0]):%p要求传入指针,实际传入的是int值12,运行时会把12按照地址的规则解析为十六进制输出,对应值为0xc,补全64位就是你看到的000000000000000c,固定不变 - 第9条
printf(" 9 %d\n", &y[0]):&y[0]就是数组首元素的地址,数值和y、&y一致,所以运行逻辑和第1条一致,输出相同结果 - 第10条
printf(" 10 %p\n", &y[0]):&y[0]是首元素的指针,用%p输出会得到正确的首元素地址,数值和第4、6条一致
内容的提问来源于stack exchange,提问作者user17328377
相关产品推荐
相关产品推荐

