C语言问题求解?
struct data
{
char str[8];
int arr[2];
};
int main(void)
{
struct data d = { "", -3, 769 };
scanf("%s", d.str);//这里输入1234abcdef
*((char*)(&d.str) + 13) = '\0';
*(d.arr) += *(d.arr + 1) + 3;
printf("%d\n", d.arr[0]);//输出什么?为什么?
*d.arr = 825373492;
d.arr[1] += 0xff;
printf("%s\n", d.str);//输出什么?为什么?
return 0;
} 展开
这个问题涉及到内存分布,在这里我假设你的电脑采用小端格式存储数据(小端格式存储不了解的话先百度下)。
1、首先可以列出第一个语句 struct data d = {"", -3, 769} 赋值后的内存分布,分布如下:
00 00 00 00 00 00 00 00 fd ff ff ff 01 03 00 00
从内存分布可知前8个0就是d.str,0xfffffffd代表d.arr[0] =-3,0x00000301代表d.arr[1]=769
注:默认从左往右的地址为从低到高,符合小端格式的设定
2、执行scanf("%s", d.str);//这里输入1234abcdef 语句后的内存分布如下:
31 32 33 34 61 62 63 64 65 66 00 ff 01 03 00 00
由于"1234abcdef"的长度10超过了a.str的大小8,那么后面的2字节就会被覆盖,从内存上看,从左往右的10个字节分别对应于"1234abcdef"的ascii码;那么为什么0x66('f')后面的字节为0了呢?那是因为字符串以'\0'结尾,所以这个字节也被覆盖了。
3、执行*((char*)(&d.str) + 13) = '\0';语句后内存分布如下:
31 32 33 34 61 62 63 64 65 66 00 ff 01 00 00 00
这个语句的含义是将从d.str地址开始后的第13个字节置为'\0’,也就是0x03->0x00;注意第13个字节的下标应该从0开始算。
4、执行*(d.arr) += *(d.arr + 1) + 3;语句
*(d.arr + 1)其实就是等于d.arr[1]的值,也就是0x00000001,也就是1,那么*(d.arr + 1) + 3就等于4;*(d.arr)其实就是a.drr[0]=0xff006665,加上4就等于0xff006669;那么经过计算后的内存分布就变为:
31 32 33 34 61 62 63 64 69 66 00 ff 01 00 00 00
5、printf("%d\n", d.arr[0]);输出什么?
从上面内存分布可以看到,d.arr[0]其实就是0xff006669,其二进制可以表示为:
1111 1111 0000 0000 0110 0110 0110 1001(高位在前表示)
最高位为1,代表为负数;由于计算机存储负数是用补补码存储的,所以这里需要将补码转换成原码,也就是是补码+1再除符号位每位取反就可以了。
补码加1:1111 1111 0000 0000 0110 0110 0110 1010
除符号位取反(原码):1000 0000 1111 1111 1001 1001 1001 0101
由于最高位为1表示负数:所以上面表示 -(0000 0000 1111 1111 1001 1001 1001 0101)=-16750999
所以:这句话输出 -16750999
6、执行*d.arr = 825373492;后的内存分布
将825373492用16进制可以表示为:0x31323334(高位在前);这语句其实是对d.addr[0]进行赋值,所以就会覆盖原来的0xff006669,覆盖后的内存分布为:
31 32 33 34 61 62 63 64 34 33 32 31 01 00 00 00
7、执行d.arr[1] += 0xff;后的内存分布
执行完上面所有步骤后d.arr[1] = 0x00000001; 那么执行完d.arr[1] = d.arr[1] + 0xff后就等于256,256的16进制表示为0x00000100;所以内存分布如下:
31 32 33 34 61 62 63 64 34 33 32 31 00 01 00 00
8、printf("%s\n", d.str);输出
从语句d.str的含义可知是打印从d.str地址开始的内容,直到遇到'\0'为止(与我们理解的打印d.str有一点偏差),也就是打印31 32 33 34 61 62 63 64 34 33 32 31 00;查询ascii码可知这就是字符串"1234abcd4321";所以最后打印1234abcd4321。
综上可知:程序最后输出:
-16750999
1234abcd4321
你这样是故意内存访问越界来计算么?为什么要研究这个呢?因为这样做非常明显的违背软件工程的
问题是这个答案是没有标准答案的,因为编译器会对结构内的内存布局稍微做调整,不同编译器和不同编译条件导致的布局都不一样,没法给你确保arr值得准确性
所以我建议是至少不要现在研究这个,等你学的深入了对内存布局及编译器优化有深刻了解在研究这个。对于初学者而言,养成良好的编程习惯很重要,这种东西还是不对的
非常感谢你的回答,练习指针操作时想到的,经过验证答案是唯一的
str后面的8写成7试试, 你换几种编译器试试,还有vc的pack指令试试看看,
你测试的种类还不够多,不知道编译器控制内存布局的手段