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

我了解 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);

为了简洁起见,我省略了错误检查。我的问题是,不能通过初始化指向内存中某个静态存储的指针来完成上述操作吗?也许:

char *some_memory = "Hello World";

在什么时候,您实际上需要自己分配内存,而不是声明/初始化需要保留的值?

76234 次浏览

One reason when it is necessary to allocate the memory is if you want to modify it at runtime. In that case, a malloc or a buffer on the stack can be used. The simple example of assigning "Hello World" to a pointer defines memory that "typically" cannot be modified at runtime.

For that exact example, malloc is of little use.

The primary reason malloc is needed is when you have data that must have a lifetime that is different from code scope. Your code calls malloc in one routine, stores the pointer somewhere and eventually calls free in a different routine.

A secondary reason is that C has no way of knowing whether there is enough space left on the stack for an allocation. If your code needs to be 100% robust, it is safer to use malloc because then your code can know the allocation failed and handle it.

char *some_memory = "Hello World";
sprintf(some_memory, "Goodbye...");

is illegal, string literals are const.

This will allocate a 12-byte char array on the stack or globally (depending on where it's declared).

char some_memory[] = "Hello World";

If you want to leave room for further manipulation, you can specify that the array should be sized larger. (Please don't put 1MB on the stack, though.)

#define LINE_LEN 80


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

malloc is a wonderful tool for allocating, reallocating and freeing memory at runtime, compared to static declarations like your hello world example, which are processed at compile-time and thus cannot be changed in size.

Malloc is therefore always useful when you deal with arbitrary sized data, like reading file contents or dealing with sockets and you're not aware of the length of the data to process.

Of course, in a trivial example like the one you gave, malloc is not the magical "right tool for the right job", but for more complex cases ( creating an arbitrary sized array at runtime for example ), it is the only way to go.

char *some_memory = "Hello World";

is creating a pointer to a string constant. That means the string "Hello World" will be somewhere in the read-only part of the memory and you just have a pointer to it. You can use the string as read-only. You cannot make changes to it. Example:

some_memory[0] = 'h';

Is asking for trouble.

On the other hand

some_memory = (char *)malloc(size_to_allocate);

is allocating a char array ( a variable) and some_memory points to that allocated memory. Now this array is both read and write. You can now do:

some_memory[0] = 'h';

and the array contents change to "hello World"

If you don't know the exact size of the memory you need to use, you need dynamic allocation (malloc). An example might be when a user opens a file in your application. You will need to read the file's contents into memory, but of course you don't know the file's size in advance, since the user selects the file on the spot, at runtime. So basically you need malloc when you don't know the size of the data you're working with in advance. At least that's one of the main reasons for using malloc. In your example with a simple string that you already know the size of at compile time (plus you don't want to modify it), it doesn't make much sense to dynamically allocate that.


Slightly off-topic, but... you have to be very careful not to create memory leaks when using malloc. Consider this code:

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;
}

Do you see what's wrong with this code? There's a conditional return statement between malloc and free. It might seem okay at first, but think about it. If there's an error, you're going to return without freeing the memory you allocated. This is a common source of memory leaks.

Of course this is a very simple example, and it's very easy to see the mistake here, but imagine hundreds of lines of code littered with pointers, mallocs, frees, and all kinds of error handling. Things can get really messy really fast. This is one of the reasons I much prefer modern C++ over C in applicable cases, but that's a whole nother topic.

So whenever you use malloc, always make sure your memory is as likely to be freed as possible.