malloc 用于 C 中的结构和指针
Posted
技术标签:
【中文标题】malloc 用于 C 中的结构和指针【英文标题】:malloc for struct and pointer in C 【发布时间】:2013-01-23 23:06:21 【问题描述】:假设我想定义一个表示向量长度及其值的结构:
struct Vector
double* x;
int n;
;
现在,假设我想定义一个向量 y 并为其分配内存。
struct Vector *y = (struct Vector*)malloc(sizeof(struct Vector));
我在互联网上的搜索显示我应该为 x 单独分配内存。
y->x = (double*)malloc(10*sizeof(double));
但是,我似乎为y->x分配了两次内存,一次为y分配内存,另一次为y->x分配内存,这似乎是浪费内存。 如果让我知道编译器的真正作用以及正确的方法是什么,我们将不胜感激 初始化 y 和 y->x。
提前致谢。
【问题讨论】:
正如paxdiablo 所指出的,请不要在C 中转换malloc()
的返回值。我永远不明白为什么每个人都觉得有必要这样做。 :(
@unwind,也许他们是升级到 C 的老 C++ 程序员 :-)
@unwind 在 C 代码上使用 Nvidia 的 nvcc 编译器时,如果我不强制转换 malloc 的结果,则会引发错误。
@Nubcake 根据this link,这可能是因为 nvcc 在 C++ 模式下运行底层编译器,因为它们的 CUDA 接口是 C++。在 C 中,您不会因此而收到错误。在 C++ 中 void *
不会自动转换为其他指针,并且需要强制转换(或者,当然不要在 C++ 中使用 malloc()
)。
@unwind 是的,我后来发现了这个 :) 只是想说明一种情况,如果你没有转换结果,那么它会抛出一个错误。
【参考方案1】:
当你malloc(sizeof(struct_name))
时,它会自动为结构的完整大小分配内存,你不需要 malloc 里面的每个元素。
使用-fsanitize=address
标志检查您如何使用程序内存。
【讨论】:
错了。 x 只是一个指针,您必须为 x 指向的值分配内存。阅读其他答案以获取更多详细信息。 (例如:***.com/a/14768280/5441253)【参考方案2】:不,您没有为y->x
分配内存两次。
相反,您正在为结构(包括一个指针)分配内存加上该指针指向的东西。
这样想:
1 2
+-----+ +------+
y------>| x------>| *x |
| n | +------+
+-----+
所以您实际上需要两个分配(1
和 2
)来存储所有内容。
此外,您的类型应该是struct Vector *y
,因为它是一个指针,并且您永远不应该在 C 中转换来自 malloc
的返回值,因为它可以隐藏您不想隐藏的某些问题 - C 完全能够隐式将void*
返回值转换为任何其他指针。
当然,您可能希望封装这些向量的创建,以便更轻松地管理它们,例如:
struct Vector
double *data; // no place for x and n in readable code :-)
size_t size;
;
struct Vector *newVector (size_t sz)
// Try to allocate vector structure.
struct Vector *retVal = malloc (sizeof (struct Vector));
if (retVal == NULL)
return NULL;
// Try to allocate vector data, free structure if fail.
retVal->data = malloc (sz * sizeof (double));
if (retVal->data == NULL)
free (retVal);
return NULL;
// Set size and return.
retVal->size = sz;
return retVal;
void delVector (struct Vector *vector)
// Can safely assume vector is NULL or fully built.
if (vector != NULL)
free (vector->data);
free (vector);
通过这样封装创建,您可以确保向量要么完全构建,要么根本不构建——它们不可能半构建。它还允许您在将来完全更改底层数据结构而不会影响客户端(例如,如果您想让它们成为稀疏数组以牺牲空间换取速度)。
【讨论】:
为我的 ASCII 艺术技能而颤抖 :-) 非常感谢。真的很有帮助。 在if(retval == NULL)中,retval应该是retVal【参考方案3】:几点
struct Vector y = (struct Vector*)malloc(sizeof(struct Vector));
错误
它应该是struct Vector *y = (struct Vector*)malloc(sizeof(struct Vector));
,因为y
持有指向struct Vector
的指针。
1st malloc()
只分配足够的内存来保存 Vector 结构(指向 double + int 的指针)
第二个malloc()
实际上分配内存来容纳10个double。
【讨论】:
【参考方案4】:原则上你已经做对了。对于你想要的,你需要两个malloc()
s。
只是一些cmets:
struct Vector y = (struct Vector*)malloc(sizeof(struct Vector));
y->x = (double*)malloc(10*sizeof(double));
应该是
struct Vector *y = malloc(sizeof *y); /* Note the pointer */
y->x = calloc(10, sizeof *y->x);
在第一行中,您为 Vector 对象分配内存。 malloc()
返回一个指向已分配内存的指针,因此 y 必须是 Vector 指针。在第二行中,您为 10 个双精度数组分配内存。
在 C 语言中,您不需要显式强制转换,而编写 sizeof *y
而不是 sizeof(struct Vector)
更利于类型安全,此外,它还可以节省键入时间。
你可以重新排列你的结构并像这样做一个malloc()
:
struct Vector
int n;
double x[];
;
struct Vector *y = malloc(sizeof *y + 10 * sizeof(double));
【讨论】:
“节省打字”从来都不是编程决策的有效论据。使用 *y 的真正原因是出于安全考虑,确保为相应变量分配所需的空间。 @Lundin 我已经更新了我的答案,但对我来说,“类型安全”的论点几乎与写作if(NULL == foo)
@Lundin 写作sizeof *y
可以帮助你对抗错误,比如当你的意思是sizeof(Matrix)
时写作sizeof(Vector)
。你经常犯这样的错误吗?当你这样做时,你能多快找到并修复它们?我同意它提高了类型安全性,并且我确实在自己的代码中编写了 sizeof *y
,但它几乎就像编写 if(NULL == foo)
一样偏执,以防止在 ==
上出现拼写错误。
@Wernsey,为什么struct Vector *y = malloc(sizeof *y);
与struct Vector *y = malloc(sizeof(struct Vector));
相同?*y
是否以某种方式取消对 Vector 类型的引用?
@ShmuelKamensky 它们在功能上是等效的。 y
是指向 struct Vector
的指针,所以 sizeof *y
表示“y 指向的大小”,所以 sizeof struct Vector
。【参考方案5】:
您实际上可以在一个 malloc 中通过同时分配 Vector 和数组来执行此操作。例如:
struct Vector y = (struct Vector*)malloc(sizeof(struct Vector) + 10*sizeof(double));
y->x = (double*)((char*)y + sizeof(struct Vector));
y->n = 10;
这会分配 Vector 'y',然后使 y->x 指向 Vector 结构之后立即分配的额外数据(但在同一内存块中)。
如果需要调整向量的大小,您应该按照推荐的方式使用两个分配。然后可以调整内部 y->x 数组的大小,同时保持向量结构 'y' 完整。
【讨论】:
你为什么要专门输入 cast y to char ?为什么不 (double*)y + sizeof(struct Vector)? sizeof 以字节为单位返回结构体大小,并且指针算术“+”运算符将添加到“y”指针是 sizeof(y) 的倍数。如果我们像你上面那样做,y 将增加 sizeof(double)*sizeof(struct),这太多了。将 y 转换为 char 让我们将 y 增加 sizeof(char)*sizeof(struct) = 1*sizeof(struct) 不要这样做。它不能确保y->x
正确对齐以容纳double
。如果不是,您有未定义的行为。【参考方案6】:
首先 malloc 为 struct 分配内存,包括 x 的内存(指向 double 的指针)。第二个 malloc 为 x 指向的 double 值分配内存。
【讨论】:
【参考方案7】:第一次为Vector
分配内存,这意味着变量x
,n
。
但是x
还没有指出任何有用的东西。
这就是为什么也需要第二次分配。
【讨论】:
【参考方案8】:当您为struct Vector
分配内存时,您只需为指针x
分配内存,即用于空间,其中包含地址的值将被放置。因此,您不会为 y.x
将引用的块分配内存。
【讨论】:
以上是关于malloc 用于 C 中的结构和指针的主要内容,如果未能解决你的问题,请参考以下文章