什么时候应该在C中使用malloc,什么时候不使用?

ran*_*its 91 c memory memory-management

我理解malloc()是如何工作的.我的问题是,我会看到这样的事情:

#define A_MEGABYTE (1024 * 1024)

char *some_memory;
size_t size_to_allocate = A_MEGABYTE;
some_memory = (char *)malloc(size_to_allocate);
sprintf(some_memory, "Hello World");
printf("%s\n", some_memory);
free(some_memory);
Run Code Online (Sandbox Code Playgroud)

为简洁起见,我省略了错误检查.我的问题是,你不能通过初始化指向内存中某些静态存储的指针来做到这一点吗?也许:

char *some_memory = "Hello World";
Run Code Online (Sandbox Code Playgroud)

在什么时候你真的需要自己分配内存而不是声明/初始化你需要保留的值?

cod*_*ict 130

char *some_memory = "Hello World";
Run Code Online (Sandbox Code Playgroud)

正在创建一个指向字符串常量的指针.这意味着字符串"Hello World"将位于内存的只读部分中,您只需指向它.您可以将该字符串用作只读.您无法对其进行更改.例:

some_memory[0] = 'h';
Run Code Online (Sandbox Code Playgroud)

是在惹麻烦.

另一方面

some_memory = (char *)malloc(size_to_allocate);
Run Code Online (Sandbox Code Playgroud)

将char数组(变量)和some_memory指向分配的内存.现在这个数组都是读写的.你现在可以这样做:

some_memory[0] = 'h';
Run Code Online (Sandbox Code Playgroud)

并且数组内容更改为"hello World"

  • 你是对的.你可以做到这一点.使用malloc()时,内存是在运行时动态分配的,因此您无需在编译时修复数组大小,也可以使用realloc()进行增长或缩小.执行以下操作时,不能执行以下任何操作:char some_memory [] ="你好"; 即使你可以改变数组的内容,它的大小也是固定的.因此根据您的需要,您可以使用以下三个选项之一:1)指向char const的指针2)动态分配数组3)固定大小,编译时分配数组. (18认同)
  • 只是为了澄清,尽管我喜欢这个答案(我确实给你+1),你可以通过使用一个字符数组来做同样的没有malloc().类似于:char some_memory [] ="你好"; some_memory [0] ='W'; 也会工作. (17认同)

R S*_*hko 37

对于这个确切的例子,malloc几乎没用.

需要malloc的主要原因是,您的数据必须具有与代码范围不同的生命周期.您的代码在一个例程中调用malloc,将指针存储在某处并最终在不同的例程中调用free.

第二个原因是C无法知道堆栈上是否有足够的空间用于分配.如果您的代码需要100%健壮,那么使用malloc会更安全,因为您的代码可以知道分配失败并处理它.

  • 内存生命周期以及何时以及如何解除分配的相关问题是许多常见库和软件组件的重要问题.它们通常有一个记录良好的规则:"如果你将一个指针传递给*this*我的一个例程,你需要对它进行malloc.它会跟踪它,并在我完成时释放它它." 令人讨厌的错误的常见来源是将指向静态分配的内存的指针传递给这样的库.当库试图释放()它时,程序崩溃.我最近花了很多时间修复一个像别人写的那样的bug. (4认同)

mor*_*itz 16

与静态声明(如hello world示例)相比,malloc是在运行时分配,重新分配和释放内存的绝佳工具,它们在编译时处理,因此无法更改大小.

因此,当您处理任意大小的数据(如读取文件内容或处理套接字)并且您不知道要处理的数据的长度时,Malloc始终是有用的.

当然,在像你给出的一个简单的例子中,malloc不是神奇的"正确工作的正确工具",但对于更复杂的情况(例如在运行时创建任意大小的数组),它是唯一的方法走.


ada*_*603 7

如果您不知道需要使用的内存的确切大小,则需要动态分配(malloc).一个示例可能是用户在您的应用程序中打开文件.您需要将文件的内容读入内存,但当然您不会提前知道文件的大小,因为用户在运行时会在现场选择文件.所以基本上你需要malloc提前知道你正在使用的数据的大小.至少这是使用的主要原因之一malloc.在您的示例中,您已经知道编译时的大小(并且您不想修改它)的简单字符串,动态分配它没有多大意义.


稍微偏离主题,但是......你必须非常小心,不要在使用时造成内存泄漏malloc.考虑以下代码:

int do_something() {
    uint8_t* someMemory = (uint8_t*)malloc(1024);

    // Do some stuff

    if ( /* some error occured */ ) return -1;

    // Do some other stuff

    free(someMemory);
    return result;
}
Run Code Online (Sandbox Code Playgroud)

你看到这段代码出了什么问题吗?malloc和之间有条件返回语句free.一开始看起来似乎还可以,但请想一想.如果出现错误,您将返回而不释放您分配的内存.这是内存泄漏的常见原因.

当然这是一个非常简单的例子,在这里很容易看到错误,但想象一下几百行代码乱七八糟的指针,mallocs,frees和各种错误处理.事情真的很快就会变得非常混乱.这是在适用的情况下我更喜欢现代C++而不是C的原因之一,但这是一个完整的主题.

因此,无论何时使用malloc,都要确保尽可能地记忆free.


eph*_*ent 6

char *some_memory = "Hello World";
sprintf(some_memory, "Goodbye...");
Run Code Online (Sandbox Code Playgroud)

是非法的,字符串文字是const.

这将在堆栈上或全局分配一个12字节的char数组(取决于它声明的位置).

char some_memory[] = "Hello World";
Run Code Online (Sandbox Code Playgroud)

如果要为进一步操作留出空间,可以指定数组的大小应该更大.(但请不要在堆栈上放1MB.)

#define LINE_LEN 80

char some_memory[LINE_LEN] = "Hello World";
strcpy(some_memory, "Goodbye, sad world...");
printf("%s\n", some_memory);
Run Code Online (Sandbox Code Playgroud)


Mar*_*ins 5

需要分配内存的一个原因是,如果要在运行时修改它.在这种情况下,可以使用堆栈上的malloc或缓冲区.将"Hello World"分配给指针的简单示例定义了"通常"在运行时无法修改的内存.