为什么在另一个函数中释放内存malloc()会导致崩溃?

为什么在另一个函数中释放内存malloc()会导致崩溃?,c,linked-list,malloc,free,C,Linked List,Malloc,Free,我有一个结构和函数的链接列表,可以从中添加、删除和创建数据。现在,当我试图释放在create函数中分配的()数据时,问题就出现了。如果我删除了代码中释放内存的部分,但没有释放内存,那么程序就可以正常运行 结构: typedef struct carinfo_t { char * brand; char * model; int year; float value; struct carinfo_t * next; } carinfo_t; 创建要添加到列

我有一个结构和函数的链接列表,可以从中添加、删除和创建数据。现在,当我试图释放在create函数中分配的()数据时,问题就出现了。如果我删除了代码中释放内存的部分,但没有释放内存,那么程序就可以正常运行

结构:

typedef struct carinfo_t
{
    char * brand;
    char * model;
    int year;
    float value;
    struct carinfo_t * next;
} carinfo_t;
创建要添加到列表中的项目的函数:

struct carinfo_t *createCarinfo(char *brand, char *model, int year, float value)
{
    carinfo_t *newInfo = (carinfo_t *) malloc (sizeof(newInfo));
    newInfo->brand = malloc (sizeof(brand));
    newInfo->model = malloc (sizeof(model));

    if (!newInfo)
    {
        printf("createCarinfo: error: no space left\n");
    }
    else
    {
        strcpy(newInfo->brand, brand);
        strcpy(newInfo->model, model);
        newInfo->year = year;
        newInfo->value = value;
        newInfo->next = NULL;
    }
    return newInfo;
}
自由功能:

void freeCarinfo(struct carinfo_t *carinfo)
{
    if(carinfo->brand != 0)
    {
        free(carinfo->brand);
        carinfo->brand = 0;
    }
    if(carinfo->model != 0)
    {
        free(carinfo->model);
        carinfo->model = 0;
    }
    if(carinfo != 0)
    {
       free(carinfo);
       carinfo = 0;
    }
}
freeCarinfo()由我的removeCarinfo()函数调用,该函数基本上确保当我删除所查找的项目时,队列中的所有项目都正确匹配

我现在想做的是能够释放我给程序的内存

carinfo_t *newInfo = (carinfo_t *) malloc (sizeof(newInfo));
newInfo->brand = malloc (sizeof(brand));
newInfo->model = malloc (sizeof(model));

查看
sizeof()
运算符的返回值。我想你会发现你分配了足够的字节来存储指针,而不是结构或字符本身
sizeof()
这样做很棘手

malloc()
实现很可能会为内部管理分配一些额外的字节。如果分配的内存太少,并且开始在这些内部结构上进行写操作,那么就完全进入了未定义的行为领域,这表明当您尝试
free()
该块时,因为
free()
可能会使用该数据


编辑:有关惯用的解决方案和@David Bowling的讨论,请参见下面的讨论,我将其推迟至:
carinfo\u t*newInfo=malloc(sizeof*newInfo)

首先,在为数据分配空间时,您犯了一个常见错误:

newInfo->brand = malloc (sizeof(brand));
这将分配足够的空间来存储指向
char
的指针,而不是数据本身。然后尝试将数据复制到其中:

strcpy(newInfo->brand, brand);
这可能会写入比您为其创建的空间还多的数据

您需要为整个字符串以及
\0
字符串结束标记创建足够的空间:

newInfo->brand = malloc (strlen(brand) + 1);
你也会在某个地方想要这个:

#include <string.h>
您可能需要的是:

carinfo_t *newInfo = malloc (sizeof(carinfo_t));
或者更好:

carinfo_t *newInfo = malloc (sizeof(*newInfo));

总之,这里有很多错误,这就是为什么你觉得它如此令人沮丧。重新阅读指针和动态分配,并根据所学内容重新审视代码。

sizeof(brand)
并没有达到预期效果
brand
是一个指针,因此可以得到指针的大小,4或8。
newInfo=malloc(sizeof(newInfo))已损坏
newInfo
是一个指针。要获取“字符串”的长度,请使用
strlen()
。还要注意,C字符串总是需要比其最大长度多一个字节。这是为了存储字符串的结束标记,即
0
-terminator。学会使用
sizeof
是一个运算符,而不是宏或函数。因此,括号
()
不是它的一部分,在将它应用于变量时也不需要它。
sizeof
不是宏。
sizeof
的棘手之处在于它既不是宏也不是函数,而是一个通常在编译时产生结果的运算符,但有时会在运行时对其求值,并且通常(但并非总是)不会对其操作数求值。括号不是
sizeof
运算符的一部分,而是操作数的一部分,操作数是一个表达式,可以是括号类型。你有OP遇到的问题的本质,有一个惯用的解决方案:
carinfo\u t*newInfo=malloc(sizeof*newInfo)。谢谢,@David Bowling,感谢你的启发。多年来,我一直在努力解决sizeof的棘手问题,确保只向它传递类型,这意味着代码将无法适应类型的变化,例如指针变量的变化,当我忘记在这两个地方更新类型时,会引入错误。当你这样写的时候,它看起来是不言而喻的,但我以前从未见过。这个习惯用法很有用,因为当类型在程序生命周期中发生变化时,只有左边的类型需要更新。因此,在程序维护中不容易出错,在初始编码中也不容易出错,因为程序员不必处理类型。请注意,这里的
*newInfo
表达式不是由
sizeof
计算的,而是由
*newInfo
表达式的类型来确定大小。@melpomene感谢您为我丢失了该转换!非常感谢。我以前试过使用strlen(),但还是犯了同样的错误。可能是因为我不知道我没有为newInfo正确分配数据。再次感谢,不客气。你的方向绝对正确。你的目标是艰难的,但非常值得去做。继续走,你会到达那里的!将指针与值
0
的整数常量进行比较与将指针与值
NULL
进行比较的含义完全相同。两者都是与空指针常量的比较。如果其中一个被认为比另一个更传统,那么肯定会使用
0
。另一方面,有一个很好的论据表明,出于文体的考虑,我更倾向于使用
NULL
。@JohnBollinger是的,当我写这篇文章时,我意识到
NULL
0
不一样,但在编辑它的过程中丢失了这一点。谢谢你。就我而言,如果K&rv1在指针比较中使用
NULL
(和),很难说
0
更传统。我们是否应该在“对
0
上的指针使用
NULL
是当前最佳实践”这一点上妥协?
carinfo_t *newInfo = malloc (sizeof(*newInfo));