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  |    +------+
        +-----+

所以您实际上需要两个分配(12)来存储所有内容。

此外,您的类型应该是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 中的结构和指针的主要内容,如果未能解决你的问题,请参考以下文章

结构体内结构体指针是,在函数中对结构体指针进行操作值会发生变化?

在 C 中使用指针的冒泡排序结构

C指针原理(20)-C指针基础

C结构指针从结构到结构数组

c语言中2个结构体的头指针相等,会不会把其中一个覆盖了

将指针值传递到c中的结构中