以下是一些来自真实stackoverflow问题的片段:
table *temp = malloc(sizeof(table)); temp = cursor->next;
char students[][50] = { "Alan", "Bob", "Charles", "James", "Peter" }; char (*heapStudents)[50] = malloc(sizeof(students)); heapStudents = students;
t = (struct carinfo_t *)malloc(sizeof(struct carinfo_t)); t = carbase;
char *str = (char *)malloc(20 * sizeof(char)); str = "This is a string";
struct node_t *temps = malloc(sizeof(struct node_t *)); temps = src;
正如你所看到的,有一个清晰的模式。
p = malloc(sizeof(something));
p = something_else;
有什么问题吗?安全吗?有些人评论说"这不是指针在代码中的工作方式",但是它们实际上是什么意思呢?
有什么问题吗?
是的,有。在每种情况下都存在内存泄漏。此外,其中一些代码片段可能会做错误的事情(即,除了内存泄漏之外,程序给出了错误的答案,或者只是崩溃)。
为了理解内存泄漏,让我们回顾一下c中的赋值操作。
在简单赋值(=)中,右操作数[…]]替换存储在左操作数指定对象中的值。
简单来说,左操作数忘记了它之前保存的值,开始保存其他值。
现在让我们回忆一下,指针是一个值,指向一些数据(一个对象,或一块内存)。
在这些语句中被复制和遗忘的值是什么?
p = malloc(sizeof(something));
// p stores the value returned by malloc, which is a pointer to
// a block of memory. note that this value is the only pointer in
// existence that points to that block of memory.
p = something_else;
// p forgets that it was storing a pointer to a block of memory
// returned by malloc, and now stores a different pointer,
// presumably pointing to another block of memory.
// the old pointer is now lost forever. there is no other pointer
// that points to the same block.
这就是内存泄漏的定义。
注意内存块本身不会以任何方式、形状或形式被触摸或修改。只有指针被修改。
是指针和指向数据之间的混淆导致了这个错误。似乎人们在错误的印象下进行操作,p = malloc(...)
为数据分配空间,p = something_else
将数据分配到刚刚分配的空间。这确实不是指针的工作方式。这两条语句都只赋值指针,不触及指向数据。
正确的做法是什么?
这取决于"this"是什么,也就是说,取决于你需要什么。没有万能的配方。在某些情况下,你只是想复制一个指针。去掉malloc
行,直接使用第二个赋值:
p = something_else; // no malloc here, just pointer assignment
在其他情况下,您需要将something_else
指向的数据复制到malloc
返回的新内存块中,现在由p
指向(与something_else
本身相反,这是一个指针):
p = malloc(sizeof(*p)); // note how sizeof is used here.
copy_data (p, something_else); // always prefer this over sizeof(some_type)
当然,在c中没有copy_data
这样的东西,这是你需要自己提供的东西,或者使用标准函数之一。例如,如果您需要复制一个字符串:
p = malloc(strlen(something_else) + 1); // note no sizeof here. the size is dynamic
strcpy(p, something_else); // also note +1 for the null terminator
// these two lines can be replaced by p = strdup(something_else);
// strdup is a function that has recently entered the C standard, but it was
// supported by all major compilers since the dawn of time
如果你需要shallow-copyastruct
:
p = malloc(sizeof(*p));
memcpy(p, something_else, sizeof(*p));
// or, if both p and something_else are declared
// as pointers to struct something
*p = *something_else;
// if the struct contains pointers, this is probably not what you want