释放记忆,全部?

时间:2011-09-21 09:38:49

标签: c

也许是一个糟糕的主题,但鉴于以下代码,我是否也需要free(player->name)

#include <stdio.h>

struct Player
{
       char *name;
       int level;       
};

int main()
{
    struct Player *player;
    player->name = malloc(sizeof(player->name)*256);
    player->name = "John";

    printf(player->name);

    free(player);

    printf("\n\n\n");
    system("PAUSE");
    return 0;
}

5 个答案:

答案 0 :(得分:15)

哦,小伙子,从哪里开始?你真的需要一本好书。叹。让我们从main()的顶部开始:


struct Player *player;

定义了指向struct Player的指针,但它没有初始化它。因此它具有或多或少的随机值,指向存储器中的某处。此

player->name = malloc(sizeof(player->name)*256);

现在将malloc()获得的一块内存的地址写入该随机位置的部分内容。通过未初始化的指针写入内存会调用未定义的行为。之后,所有赌注都已关闭。无需进一步了解您的计划。你不幸的是,你不小心写入了你的进程所拥有的一块内存,所以它不会立即崩溃,让你意识到这个问题。

有两种方法可以改善这种状况。要么坚持指针并让它指向为Player对象分配的一块内存。你可以致电malloc(sizeof(Player)来获得它 或者只使用本地的自动(也就是基于堆栈的)对象:

struct Player player;

编译器将生成代码以在堆栈上为其分配内存并自动释放它。这是最简单的,当然应该是你的默认值。


但是,您的代码存在更多问题。

player->name = malloc(sizeof(player->name)*256);

在堆上分配连续内存以存储256个指向字符的指针,并分配第一个指针的地址(char*的地址,因此为char**)至player->name(a char*)。坦率地说,我很惊讶甚至编译,但后来我更习惯于C ++更严格的类型执行。无论如何,你可能想要的是为256个字符分配内存:

player->name = malloc(sizeof(char)*256);

(根据定义,sizeof(char)1,您通常会将其视为malloc(256)。)
但是,还有更多:为什么256?如果我将字符串传递1000个字符怎么办?不,简单地为更长的字符串分配空间不是解决这个问题的方法,因为我可以将它传递给更长的字符串。所以 1)修复了最大字符串长度(只需将Player::name声明为该长度的char数组,而不是char*)并强制执行此限制在您的代码中,或 2)在运行时动态查找所需的长度,并准确分配所需的内存(字符串长度加1,终止'\0' char)。

但它变得更糟。此

player->name = "John";

然后将字符串文字的地址分配给player->name,覆盖malloc()在您存储的唯一变量中分配的内存地址,使您丢失并泄漏内存。 /> 但是字符串在C中不是一等公民,所以你不能分配它们。它们是字符数组,按惯例终止为'\0'。要复制它们,您必须逐个字符地复制它们,或者最好是通过调用strcpy()来复制它们。

为了增加对伤害的侮辱,你后来尝试释放字符串文字所在的记忆

free(player);
因此很可能严重扰乱堆管理器的数据结构。同样,你似乎不幸的是不会导致立即崩溃,但代码看似按预期工作是未定义行为表现自己的最糟糕可能性之一。如果以前所有赌注都没有被淘汰,他们现在就会完全失败。


我很抱歉,如果这听起来有点谴责,那真的不是那种意思,但你肯定并且认真地搞砸了这个。总结一下:

  1. 你需要一本好的C ++书。马上。 Here是C程序员在Stack Overflow上汇编的好书。 (我是一名C ++程序员,所以我不会评论他们的判断,但K&amp; R肯定是一个不错的选择。)

  2. 您应该立即初始化所有指针,使用现有有效对象的地址,或者使用分配用于保存正确类型对象的内存块的地址,或使用NULL(您可以在以后轻松查看)。特别是,您不得尝试读取或写入尚未分配(在堆上动态或在堆栈上自动分配)的内存。

  3. 您需要free()通过恰好调用malloc() 一次获得的所有内存。

  4. 您不得尝试free()任何其他记忆。


  5. 我确信该代码还有更多内容,但我会在这里停下来。 我是否提到你需要一本好的C书?因为你这样做了。

答案 1 :(得分:0)

player不需要被释放,因为它永远不会malloc',它只是一个本地堆栈变量。确实需要释放player->name,因为它是动态分配的。

int main()
{
    // Declares local variable which is a pointer to a Player struct
    // but doesn't actually point to a Player because it wasn't initialised
    struct Player *player;

    // Allocates space for name (in an odd way...)
    player->name = malloc(sizeof(player->name)*256);

    // At this point, player->name is a pointer to a dynamically allocated array of size 256*4

    // Replaces the name field of player with a string literal
    player->name = "John";


    // At this point, the pointer returned by malloc is essentially lost...
    printf(player->name);

    // ?!?!
    free(player);

    printf("\n\n\n");
    system("PAUSE");
    return 0;
}

我想你想做这样的事情:

int main() {
  struct Player player;
  player.name = malloc( 256 );
  // Populate the allocated memory somehow...

  printf("%s", player.name);
  free(player.name);
}

答案 2 :(得分:0)

您必须free() malloc()所有内容,并且必须malloc()在编译时未分配的所有内容。

所以:

您必须使用malloc player并且必须免费player->name

答案 3 :(得分:0)

好的,所以你的变量播放器是一个你没有初始化的指针,因此指向一个随机的内存位置。

首先需要为player分配内容player->name,然后为播放器&gt;名称分配内容。

分配有malloc()的任何内存都需要使用free()释放。

查看thisthis

答案 4 :(得分:0)

这是糟糕的代码。为什么?首先,为player-&gt; name分配内存。 malloc返回指向已分配内存的指针。在下一步中,您将丢失此指针值,因为重新分配player-&gt; name以指向静态“John”字符串。也许你想使用strdup或sprintf函数?

同样最大的错误是使用未初始化的指针指向播放器结构。试着想象它可以指向随机内存位置。所以在malloc的帮助下为你的结构分配内存是个好主意。或者不要使用指针来构造并使用真实的结构变量。