C语言问题求解?

#include<stdio.h>structdata{charstr[8];intarr[2];};intmain(void){structdatad={"",-3,7... #include <stdio.h>

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;
}
展开
 我来答
X_earth
2021-02-07 · TA获得超过248个赞
知道小有建树答主
回答量:204
采纳率:73%
帮助的人:60.3万
展开全部

这个问题涉及到内存分布,在这里我假设你的电脑采用小端格式存储数据(小端格式存储不了解的话先百度下)。

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

arongustc
科技发烧友

2021-02-06 · 智能家居/数码/手机/智能家电产品都懂点
知道大有可为答主
回答量:2.3万
采纳率:66%
帮助的人:5500万
展开全部
简单的说:由于你的代码是非标准方法访问变量,导致结果非常不确定,没有固定答案,不同编译器结果不一样

你这样是故意内存访问越界来计算么?为什么要研究这个呢?因为这样做非常明显的违背软件工程的
问题是这个答案是没有标准答案的,因为编译器会对结构内的内存布局稍微做调整,不同编译器和不同编译条件导致的布局都不一样,没法给你确保arr值得准确性
所以我建议是至少不要现在研究这个,等你学的深入了对内存布局及编译器优化有深刻了解在研究这个。对于初学者而言,养成良好的编程习惯很重要,这种东西还是不对的
更多追问追答
追问
非常感谢你的回答,练习指针操作时想到的,经过验证答案是唯一的
追答
str后面的8写成7试试, 你换几种编译器试试,还有vc的pack指令试试看看,
你测试的种类还不够多,不知道编译器控制内存布局的手段
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式