我看到的代码如下所示。
typedef struct abc {
int a;
char b;
float c;
} abc;
int main()
{
abc *ab;
int *i;
i = (int*)malloc(sizeof(int));
*i = 0;
ab = (abc*) i;
return 0;
}
在倒数第二行ab = (abc*) i;
中,代码尝试做什么?
如果我们想设置ab->a
的值,那么为什么要这样做,而不是:
ab->a = (int)i;
如果ab = (abc*) i;
更新了ab->a
的值,那么其他两个结构成员如何在不对它们进行初始化的情况下进行初始化?
答案 0 :(得分:4)
那么其他两个结构成员如何在不对它们进行初始化的情况下进行初始化?
他们不会。
您将在ab->b
和ab->c
中获取垃圾值,因为i
不代表足够大小的内存块来表示abc
的实例。
ab->a
等于0,因为当您执行:*i = 0
时,您将值0
存储在i
指向的内存位置。当您使abc
指向与i
相同的内存位置时,没有对内存进行任何写入,您只是更改了数据的位置。
由于0
先前存储在i
指向的位置的4个字节中,并且因为int ab::a
恰好占用了4个字节,所以恰好是{1}}的第一个成员。 struct,ab->a
将等于0.
在内存中,相对于实例的位置,结构的排序如下:
____ ____ ____ ____ ____ ____ ____ ____ ____
| 00 | 01 | 02 | 03 | | 04 | | 05 | 06 | 07 | 08 |
|____|____|____|____| |____| |____|____|____|____|
int a char b float c
我希望这能解决问题。
注意强>
你真的不能保证结构完全打包,就像我在上面的表示中所做的那样。虽然顺序将被保留,但连续成员之间的空间并不总是0个内存地址单元。阅读Alignment。
答案 1 :(得分:3)
第ab = (abc*) i;
行正在将i
类型的指针变量int*
转换为类型abc*
,并将该赋值转换为指针变量ab
。这当然不是你想要在结构中初始化数据成员的方式,特别是因为只分配了int
的足够空间而且我们使用的结构占用的空间远远大于{ {1}}。
在一天结束时,这是合法的代码,但非常可怕。我甚至不确定您是否可以保证将数据成员int
存储在int a
指向的地址中。我想说这是依赖于实现的,但也许其他人可以为我解决这个问题。
答案 2 :(得分:2)
倒数第二行会导致从(int *)
转换为(abc *)
,并将结果分配给ab。它不是一个非常好的代码行,因为旧的指向类型的大小比新的指向类型小;尝试使用此转换的结果将是未定义的行为。将其保留为(int *)
,或者声明要转换为的前缀结构将是一个更好的主意。
*
中的abc *
表示该类型是“指向abc的指针”。 ab
在您告诉它指向一个abc
对象之前,它不会指向它。 ab = /* something */
指定ab
指向某事。在这个例子中,ab = malloc(sizeof *ab);
会有意义。
这很愚蠢:i = (int*)malloc(sizeof(int));
。您不需要转换malloc的返回值。唯一合理的理由是这段代码的作者忽略了#include <stdlib.h>
。我建议包括该库,而不是转换返回值。您可以随意忽略我的建议,但在阅读this page之前不要询问有关奇怪错误的任何问题。
答案 3 :(得分:1)
abc *ab;
ab是struct abc类型的指针;
int *i;
是指向malloc
使用*i = 0;
ab = (abc*) i;
此行将malloc分配的位置地址分配给ab。通过类型转换i
到(abc*)
,表明ab将用于读取struct abc
大小的内存块
ab = (abc*) i;
不为a分配值。要为u分配值,请执行ab->a = 5;
已存在的值是垃圾值(默认随机值)
答案 4 :(得分:-2)
ab = (abc*) i; updates the value of ab->a
如果我们看一下struct layout,int是int是第一个成员,所以它将初始化为0,所以ans是的!我尝试使用VC并将其初始化为0,但这很棘手,如果是struct,如果成员更改顺序,那么你就得到了垃圾!
还有内存泄漏,分配了malloc的内存永远不会释放!