【问题标题】:Should I free char* initialized using string-literals?我应该释放使用字符串文字初始化的 char* 吗?
【发布时间】:2012-03-19 06:16:47
【问题描述】:

当使用字符串文字初始化char* 变量时,我应该释放它们吗?对我来说,语法会让我假设它们只是堆栈分配的,但这个例子告诉我,它们不是。

#include <stdlib.h>
#include <stdio.h>

static char* globalBuffer;

typedef struct Container {
    char* buffer;
} Container;

Container* Container_new(char* buffer) {
    Container* container = malloc(sizeof(Container));
    container->buffer    = buffer;
    globalBuffer         = buffer;
    return container;
}

void Container_print(Container* container) {
    if (container->buffer != NULL) {
        printf("%s", container->buffer);
        printf("\n");
    }
    else {
        printf("Container contains a NULL-buffer.");
    }
}

Container* stage() {
    Container* container = Container_new("Test-string.");
    Container_print(container);
    return container;
}

int main() {
    Container* container = stage();
    Container_print(container);

    free(container);
    Container_print(container); // I know, this results in undefined behaviour

    printf(globalBuffer);
    printf("\n");

    return 0;
}

我得到以下输出:

C:\Users\niklas\Desktop>gcc char_test.c

C:\Users\niklas\Desktop>a.exe
Test-string.
Test-string.
­6>
Test-string.

C:\Users\niklas\Desktop>

因此,使用字符串文字初始化的 char* 仍然存在,即使它超出了范围。

那么,我的问题是,我应该释放这样的char* 指针吗?这是正确的main() 吗?

int main() {
    Container* container = stage();
    Container_print(container);

    free(container->buffer);    // NEW
    free(container);
    Container_print(container);

    printf(globalBuffer);
    printf("\n");

    return 0;
}

【问题讨论】:

  • 顺便说一句 - 如果您的 printf(globalBuffer)printf(container-&gt;buffer); 包含 % 字符,它们会给您 jip。
  • 有时一些元推理会有所帮助:你真的相信像字符串文字这样的基本概念只有在伴随着清理代码的情况下才能正确使用?肯定不是。
  • 不,你不能那样做。您只能将 free() 用于使用 malloc()、calloc() 或 realloc() 动态分配的内存。
  • 为了澄清,字符串文字也没有分配在堆栈上。它们是静态分配的,这意味着它们被烘焙到程序数据中并在程序加载时加载到内存中。所有指向字符串的指针都是指向程序数据中该位置的指针。它们既不是堆栈也不是堆。如果它们是在堆栈上分配的,那么您将无法安全地从函数中返回它们。

标签: c memory memory-management


【解决方案1】:

你永远不会free()记忆你没有malloc()ed。

编译器实现字符串文字的方式与您无关:这是一个实现细节。您可以free() 指向您使用malloc() 分配的内存的指针,并且只能使用这些指针,否则您会冒着系统生命周期的风险。

理想情况下,malloc() 调用和 free() 调用应该出现在同一个“设计级别”(例如,在同一个模块的同一个实现文件中),并且它们应该完美匹配:每个 @ 一个 free() 987654328@。但这并不总是可能的。

(请注意,某些库会分配内存块,返回指向这些块的指针,并指示您释放它们。在这种情况下,您可以释放这些指针,但从创建图书馆的人。)

【讨论】:

  • 现在我查了一下,它看起来根本不像是标准的一部分。它在 POSIX 中。
  • @Mysticial 以及为什么我每次看到它时都说“不要使用strdup
  • 好吧,如果你要抱怨strdup,你也可以抱怨callocrealloc...
  • 如果库向您提供指针并告诉您在不再需要它们时释放它们是不好的设计......处理释放由库分配的内存的正确方法是什么?
  • @SzerémiAttila :库应该为您提供一个函数调用来释放它分配的内存。这确保调用正确的函数来释放指针(取决于使用的运行时和库的链接方式,malloc()free() 在库内部或外部可能不同)
【解决方案2】:

字符串字面量的存储方式使其在程序的生命周期内都可用;如果你写

char *ptr = "This is a test";

写入ptr 的所有内容都是字符串文字"This is a test"地址。即使ptr 变量超出范围,字符串文字仍然存在于它自己的内存部分中,这与malloc 使用的部分相同(至少,不在逻辑层)。请注意,同一字符串文字的多个实例可能解析到同一个位置; IOW,给定的

char *p0 = "This is a test";
char *p1 = "This is a test";

p0p1 可能都包含相同的地址(是否多次出现的字符串文字是否映射到同一位置取决于编译器)。

当您拨打Container_new 时,您所做的只是将地址 复制到container-&gt;bufferglobalBuffer;两者最终都指向独立于它们中的任何一个而存在的同一事物。 free-ing container 不会影响container-&gt;buffer 指向的字符串文字,所以printf(globalBuffer); 仍然显示"Test-string."

总之,你应该打电话

free(container->buffer);

对于这个特定的程序,因为您没有将malloccallocrealloc 调用的结果分配给它。

如果,OTOH,你把Container_new写成

Container* Container_new(char* buffer) 
{
  Container* container = malloc(sizeof(Container));
  container->buffer    = malloc(strlen(buffer) + 1);  // Allocate memory to 
  if (container->buffer)                              // store a *new* instance
  {                                                   // of the input string. 
    strcpy(container->buffer, buffer);                // This will need to be 
  }                                                   // freed before freeing
  globalBuffer         = buffer;                      // the container
  return container;
}

那么你需要在释放container之前释放container-&gt;buffer

【讨论】:

  • 哇,很好的答案,非常感谢!
猜你喜欢
  • 1970-01-01
  • 2010-09-29
  • 1970-01-01
  • 2015-03-22
  • 1970-01-01
  • 2015-08-12
  • 2023-03-25
  • 1970-01-01
相关资源
最近更新 更多