内存分配函数 _alloc/malloc/calloc

本文深入探讨了C++中内存管理的核心概念,包括栈内存、堆内存、malloc、calloc、realloc等关键函数的使用场景与注意事项。通过实例解析,帮助读者掌握C++内存管理的精髓。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

_alloc
原型:void *_alloc(size_t size);
本函数与上述的两个函数不同,因为它是在栈上分配了size大小的内存,因此使用此函数分配的内存不用再担心内存释放的情况了。但是使用此函数需要注意的是:在函数内部使用此函数分配的内存随着函数的终结不复存在,因此不能将此函数分配的内存供函数外部使用。

malloc
原型:void * malloc(size_t size);
该函数将在堆上分配一个size byte大小的内存。它分配的单原完全按字节大小计算,因此如此分配N个单原的student_t,那么要这样实现:(stdent_t *)malloc(N * sizeof (student_t));

calloc
原型:void* calloc(size_t size, int count);
该函数解决了上面的函数的不足,它将分配count个size大小的单原,因此在便用此函数的时候就会很方便,比如对上面的例子就可以:(student_t *)calloc(sizeof(t_student), N)就可以了。这样使用就会很清晰的知道分配的内存是一种什么样的逻辑方式。

malloc与calloc没有本质区别,malloc之后的未初始化内存可以使用memset进行初始化。

realloc是在malloc的基础上增加内存分配,free函数用来对分配在堆的内存进行释放以防内存泄漏的产生。

sbrk函数用来向os申请数据段,供malloc,calloc及realloc申请使用。

New和delete是c++中的运算符,调用malloc申请内存后初始化为对象,用delete释放。

#define XMALLOC(type, size) mfh_malloc(type, size, NULL, __FUNCTION__, __LINE__) #define XCALLOC(type, size) mfh_calloc(type, size, NULL, __FUNCTION__, __LINE__) #define XFREE(type, ptr) mfh_free(type, ptr, __FUNCTION__, __LINE__) #define XREALLOC(type, ptr, size) mfh_realloc(type, ptr, size, NULL, NULL, __LINE__) #define XSTRDUP(type, str) mfh_strdup(type, str, NULL, __FUNCTION__, __LINE__) libedit/readline.c: In function ‘get_directory_matches’: libedit/readline.c:1553:74: error: macro "XCALLOC" passed 3 arguments, but takes just 2 1553 | matches = (char **)XCALLOC(MTYPE_TMP, match_count + 1, sizeof(char *)); | ^ In file included from /home/423251/GNOS_5_30_static/Trunk/src_2406/build/linux-arm64-charlie-sikadeer/nos/pal/linux/pal_memory.h:6, from /home/423251/GNOS_5_30_static/Trunk/src_2406/build/linux-arm64-charlie-sikadeer/nos/pal/linux/pal.h:27, from libedit/compat.h:6, from libedit/readline.c:39: /home/423251/GNOS_5_30_static/Trunk/src_2406/build/linux-arm64-charlie-sikadeer/nos/lib/memory.h:2667: note: macro "XCALLOC" defined here 2667 | #define XCALLOC(type, size) mfh_calloc(type, size, NULL, __FUNCTION__, __LINE__) | libedit/readline.c:1553:24: error: ‘XCALLOC’ undeclared (first use in this function) 1553 | matches = (char **)XCALLOC(MTYPE_TMP, match_count + 1, sizeof(char *)); | ^~~~~~~ libedit/readline.c:1553:24: note: each undeclared identifier is reported only once for each function it appears in libedit/readline.c: In function ‘filename_completion_matches’: libedit/readline.c:1828:60: error: macro "XCALLOC" passed 3 arguments, but takes just 2 1828 | matches = (char **)XCALLOC(MTYPE_TMP, 1, sizeof(char *)); | ^ In file included from /home/423251/GNOS_5_30_static/Trunk/src_2406/build/linux-arm64-charlie-sikadeer/nos/pal/linux/pal_memory.h:6, from /home/423251/GNOS_5_30_static/Trunk/src_2406/build/linux-arm64-charlie-sikadeer/nos/pal/linux/pal.h:27, from libedit/compat.h:6, from libedit/readline.c:39: /home/423251/GNOS_5_30_static/Trunk/src_2406/build/linux-arm64-charlie-sikadeer/nos/lib/memory.h:2667: note: macro "XCALLOC" defined here 2667 | #define XCALLOC(type, size) mfh_calloc(type, size, NULL, __FUNCTION__, __LINE__) | libedit/readline.c:1828:24: error: ‘XCALLOC’ undeclared (first use in this function) 1828 | matches = (char **)XCALLOC(MTYPE_TMP, 1, sizeof(char *)); | ^~~~~~~ 参数不对
最新发布
07-29
<think>我们遇到了宏定义参数不匹配的问题。根据错误信息,宏 `XCALLOC` 被定义为接受两个参数,但在代码中我们传递了三个参数。原始定义如下: ```c #define XCALLOC(type, size) mfh_calloc(type, size, NULL, __FUNCTION__, __LINE__) ``` 但是在代码中,我们这样使用: ```c matches = (char **)XCALLOC(MTYPE_TMP, match_count + 1, sizeof(char *)); ``` 这里传递了三个参数:`MTYPE_TMP`, `match_count + 1`, `sizeof(char *)`。 而宏定义只接受两个参数。因此,我们需要调整宏的使用方式,使其符合定义。 然而,观察宏定义,它实际上是为内存分配函数提供了一种封装,其中已经固定了某些参数(如`NULL`、`__FUNCTION__`和`__LINE__`)。因此,我们不能直接传递三个参数。 解决方案有两种: 1. 修改宏定义,使其接受三个参数(但这可能会影响其他使用该宏的代码)。 2. 修改我们的代码,使其符合现有的宏定义。 由于宏定义是系统级的,可能不允许修改,因此我们选择第二种方法:调整代码以适应宏。 注意:`XCALLOC` 被设计为分配一块内存,并将其初始化为零。它接受两个参数:内存类型(`type`)和要分配的元素数量(`size`,以字节为单位)。但是,我们这里需要分配一个数组,数组元素是指针(`char*`),数量为`match_count+1`,每个元素的大小为`sizeof(char*)`。 但是,`XCALLOC` 的第二个参数是总字节数,所以我们应该这样计算:`(match_count + 1) * sizeof(char*)`。 因此,我们可以将调用改为: ```c matches = (char **)XCALLOC(MTYPE_TMP, (match_count + 1) * sizeof(char *)); ``` 这样,我们只传递两个参数:`MTYPE_TMP`和总字节数。 同样,另一个错误位置: ```c matches = (char **)XCALLOC(MTYPE_TMP, 1, sizeof(char *)); ``` 应该改为: ```c matches = (char **)XCALLOC(MTYPE_TMP, 1 * sizeof(char *)); ``` 但是注意,这里我们只需要一个元素(一个指针)的空间,但实际上我们分配的是一个指针数组,第一个元素用于存储指针,第二个元素为NULL(表示结束)。所以,我们实际上需要分配`(1) * sizeof(char*)`的空间,但后面我们会通过`realloc`扩展。在初始分配时,我们分配一个元素(即一个指针)的空间,并初始化为NULL。 但是,观察代码,我们一开始分配了一个指针数组,数组包含1个元素(即一个指针),然后将其设置为NULL。然后,在循环中,我们使用`realloc`来扩展这个数组。 因此,我们可以将初始分配改为: ```c matches = (char **)XCALLOC(MTYPE_TMP, 1 * sizeof(char *)); ``` 这样,我们分配了1个指针的空间,并且由于`XCALLOC`会清零,所以`matches[0]`就是NULL。 但是,注意:我们后面使用`realloc`来增加空间,而`realloc`使用的是`XREALLOC`,它定义为: ```c #define XREALLOC(type, ptr, size) mfh_realloc(type, ptr, size, NULL, NULL, __LINE__) ``` 这个宏接受三个参数:类型、指针和新的总字节数。所以,在`realloc`的地方,我们也需要调整。 在代码中,我们这样使用`XREALLOC`: ```c char **temp = (char **)XREALLOC(MTYPE_TMP, matches, (count + 2) * sizeof(char *)); ``` 这里,我们传递了三个参数:`MTYPE_TMP`、`matches`和`(count+2)*sizeof(char*)`,符合宏定义。 因此,我们只需要修改两处`XCALLOC`的调用。 修改后的代码片段: ```c // 在 get_directory_matches 函数中 matches = (char **)XCALLOC(MTYPE_TMP, (match_count + 1) * sizeof(char *)); // 在 filename_completion_matches 函数中 matches = (char **)XCALLOC(MTYPE_TMP, 1 * sizeof(char *)); ``` 注意:由于`XCALLOC`会清零,所以分配的内存都是0,因此`matches`数组的最后一个元素(我们分配了`match_count+1`个元素)已经是NULL,不需要再设置。 在`get_directory_matches`函数中,我们分配了`match_count+1`个指针的空间,然后我们使用`index`来填充,最后我们并没有显式设置`matches[match_count] = NULL;`,但因为`XCALLOC`清零了,所以它是NULL。 同样,在`filename_completion_matches`函数中,我们分配了1个指针的空间,并初始化为0,所以`matches[0]`就是NULL。 因此,这样修改是可行的。 现在,我们修改代码并重新编译。 但是,请注意,在`filename_completion_matches`函数中,我们初始分配为1个指针的空间,然后马上进入循环,在循环中我们使用`realloc`来扩展。初始分配的空间只有一个指针,但我们在循环中需要存储多个指针(每找到一个匹配项就增加一个)。所以,初始分配一个指针(即一个元素)的空间,并且这个元素被初始化为NULL,这样在第一次循环时,`count`为0,我们分配`count+2`(即2)个指针的空间,然后存储第一个匹配项,并将第二个元素设置为NULL(因为`realloc`会扩展内存,但新扩展的部分不会自动清零,所以我们需要显式设置最后一个元素为NULL)。但是,在`XREALLOC`中,我们并没有将新分配的内存清零,所以我们需要手动设置新元素的值为0(至少最后一个元素为NULL)。然而,在代码中,我们是这样做的: ```c char **temp = (char **)XREALLOC(MTYPE_TMP, matches, (count + 2) * sizeof(char *)); if (!temp) { // 错误处理 } matches = temp; matches[count] = match; // 设置当前匹配项 matches[count+1] = NULL; // 设置下一个为NULL ``` 所以,这里我们显式设置了`matches[count+1] = NULL`,因此没有问题。 但是,在初始分配时,我们只分配了一个指针的空间,并且初始化为0(即NULL)。然后,在第一次循环(count=0)时,我们重新分配为2个指针的空间,然后设置`matches[0]=match`和`matches[1]=NULL`。所以,这样是安全的。 因此,我们只需要修改上述两处调用即可。 另外,注意在`cmlsh_completion_matches`函数中,我们使用了`XCALLOC`来分配命令列表数组: ```c commands = (char **)XCALLOC(MTYPE_TMP, (count + 1) * sizeof(char *)); ``` 这里,我们传递了两个参数:`MTYPE_TMP`和`(count+1)*sizeof(char*)`,符合宏定义。 所以,我们只需要修改两处。 修改后的代码: ```c // 在 get_directory_matches 函数中 matches = (char **)XCALLOC(MTYPE_TMP, (match_count + 1) * sizeof(char *)); // 在 filename_completion_matches 函数中 matches = (char **)XCALLOC(MTYPE_TMP, 1 * sizeof(char *)); ``` 现在,重新编译应该可以通过。 但是,请注意,在`get_directory_matches`函数中,我们分配了`(match_count+1) * sizeof(char*)`字节的空间,并且由于`XCALLOC`清零,所以数组末尾的NULL已经存在。然后我们在循环中填充前`match_count`个元素,最后一个元素(第`match_count`个)保持为NULL,所以循环结束后不需要再设置NULL。 因此,修改后的代码是安全的。 最后,我们还需要检查其他使用`XCALLOC`的地方,确保都只传递两个参数,并且第二个参数是总字节数。 在提供的代码中,还有一处: ```c // 在 cmlsh_completion_matches 函数中 commands = (char **)XCALLOC(MTYPE_TMP, (count + 1) * sizeof(char *)); ``` 这是正确的,因为`(count+1) * sizeof(char*)`是总字节数。 总结:将`XCALLOC`的调用改为传递两个参数,第二个参数为总字节数。</think>您遇到的编译错误是由于宏定义参数不匹配导致的。让我解释问题并提供完整的解决方案: ### 问题分析 1. **宏定义与使用不一致**: ```c // 宏定义 (只接受2个参数) #define XCALLOC(type, size) mfh_calloc(type, size, NULL, __FUNCTION__, __LINE__) // 代码使用 (传递了3个参数) XCALLOC(MTYPE_TMP, match_count + 1, sizeof(char *)); ``` 2. **根本原因**: - 宏定义只接受2个参数 (`type`和`size`) - 代码中尝试传递3个参数 (`type`, `count`, `element_size`) ### 解决方案 需要修改内存分配宏的使用方式,使其符合宏定义。以下是完整的修复方案: ```c /* 内存管理宏定义 (保持不变) */ #define XMALLOC(type, size) mfh_malloc(type, size, NULL, __FUNCTION__, __LINE__) #define XCALLOC(type, size) mfh_calloc(type, size, NULL, __FUNCTION__, __LINE__) #define XFREE(type, ptr) mfh_free(type, ptr, __FUNCTION__, __LINE__) #define XREALLOC(type, ptr, size) mfh_realloc(type, ptr, size, NULL, NULL, __LINE__) #define XSTRDUP(type, str) mfh_strdup(type, str, NULL, __FUNCTION__, __LINE__) /* 修复后的函数实现 */ char **get_directory_matches(const char *dir_path, const char *prefix) { DIR *dir = opendir(dir_path); if (!dir) return NULL; struct dirent *entry; int match_count = 0; char **matches = NULL; // 第一次遍历:计算匹配项数量 while ((entry = readdir(dir)) != NULL) { if (entry->d_name[0] == '.') continue; if (prefix[0] == '\0' || strncmp(entry->d_name, prefix, strlen(prefix)) == 0) { match_count++; } } rewinddir(dir); // 修复:正确使用XCALLOC宏 (计算总字节大小) size_t total_size = (match_count + 1) * sizeof(char *); matches = (char **)XCALLOC(MTYPE_TMP, total_size); int index = 0; // 第二次遍历:填充匹配项 while ((entry = readdir(dir)) != NULL) { if (entry->d_name[0] == '.') continue; if (prefix[0] == '\0' || strncmp(entry->d_name, prefix, strlen(prefix)) == 0) { // 确定是否为目录 int is_dir = 0; if (entry->d_type == DT_DIR) { is_dir = 1; } else if (entry->d_type == DT_UNKNOWN) { char full_path[PATH_MAX]; snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, entry->d_name); struct stat statbuf; if (stat(full_path, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) { is_dir = 1; } } // 创建匹配项字符串 if (is_dir) { size_t len = strlen(entry->d_name) + 2; matches[index] = (char *)XMALLOC(MTYPE_TMP, len); snprintf(matches[index], len, "%s/", entry->d_name); } else { matches[index] = XSTRDUP(MTYPE_TMP, entry->d_name); } index++; } } closedir(dir); return matches; } char **filename_completion_matches(const char *text, char *(*genfunc)(const char *, int)) { char **matches = NULL; int count = 0; char *match; // 修复:正确使用XCALLOC宏 (计算总字节大小) size_t initial_size = 1 * sizeof(char *); matches = (char **)XCALLOC(MTYPE_TMP, initial_size); matches[0] = NULL; for (int state = 0; ; state++) { match = (*genfunc)(text, state); if (!match) break; // 修复:正确使用XREALLOC宏 size_t new_size = (count + 2) * sizeof(char *); char **temp = (char **)XREALLOC(MTYPE_TMP, matches, new_size); if (!temp) { for (int i = 0; i < count; i++) XFREE(MTYPE_TMP, matches[i]); XFREE(MTYPE_TMP, matches); return NULL; } matches = temp; matches[count] = match; matches[count + 1] = NULL; count++; } return matches; } /* 其他函数保持不变 */ char *cmlsh_completion_matches(const char *text, int state) { static int list_index, len; static char **commands = NULL; if (state == 0) { if (commands) { for (int i = 0; commands[i]; i++) { XFREE(MTYPE_TMP, commands[i]); } XFREE(MTYPE_TMP, commands); } const char *cmd_list[] = {"show", "configure", "exit", "help", "ping", "traceroute", NULL}; int count = 0; while (cmd_list[count]) count++; // 修复:正确使用XCALLOC宏 size_t total_size = (count + 1) * sizeof(char *); commands = (char **)XCALLOC(MTYPE_TMP, total_size); for (int i = 0; i < count; i++) { commands[i] = XSTRDUP(MTYPE_TMP, cmd_list[i]); } commands[count] = NULL; list_index = 0; len = strlen(text); } while (commands[list_index]) { char *name = commands[list_index++]; if (strncmp(name, text, len) == 0) { return XSTRDUP(MTYPE_TMP, name); } } return NULL; } ``` ### 关键修复点解释 #### 1. 正确计算内存大小 ```c // 错误用法 matches = (char **)XCALLOC(MTYPE_TMP, match_count + 1, sizeof(char *)); // 正确用法 size_t total_size = (match_count + 1) * sizeof(char *); matches = (char **)XCALLOC(MTYPE_TMP, total_size); ``` #### 2. 数组分配模式转换 将数组分配从: ```c XCALLOC(type, count, element_size) ``` 转换为: ```c size_t total_bytes = (count) * element_size; XCALLOC(type, total_bytes) ``` #### 3. 内存分配模式统一 所有内存分配函数使用相同的模式: ```c // 分配单个元素 char *str = XSTRDUP(MTYPE_TMP, "text"); // 分配数组 size_t array_size = num_elements * sizeof(element_type); element_type *array = (element_type *)XCALLOC(MTYPE_TMP, array_size); ``` ### 完整的内存管理助手函数 ```c // 内存分配助手函数 void *mfh_malloc(int type, size_t size, void *caller, const char *func, int line) { void *ptr = malloc(size); printf("[ALLOC] %s:%d - %zu bytes\n", func, line, size); return ptr; } void *mfh_calloc(int type, size_t size, void *caller, const char *func, int line) { void *ptr = calloc(1, size); // calloc自动清零 printf("[CALLOC] %s:%d - %zu bytes\n", func, line, size); return ptr; } void mfh_free(int type, void *ptr, const char *func, int line) { if (ptr) { free(ptr); printf("[FREE] %s:%d\n", func, line); } } void *mfh_realloc(int type, void *ptr, size_t size, void *caller, const char *func, int line) { void *new_ptr = realloc(ptr, size); printf("[REALLOC] %s:%d - %zu bytes\n", func, line, size); return new_ptr; } char *mfh_strdup(int type, const char *str, void *caller, const char *func, int line) { char *new_str = strdup(str); printf("[STRDUP] %s:%d - %zu bytes\n", func, line, strlen(str) + 1); return new_str; } ``` ### 内存使用最佳实践 1. **分配数组的正确方式**: ```c // 分配10个整数的数组 size_t array_size = 10 * sizeof(int); int *numbers = (int *)XCALLOC(MTYPE_TMP, array_size); ``` 2. **分配结构体的正确方式**: ```c typedef struct { int id; char name[50]; } Person; // 分配单个结构体 Person *p = (Person *)XMALLOC(MTYPE_TMP, sizeof(Person)); // 分配结构体数组 size_t people_size = 5 * sizeof(Person); Person *people = (Person *)XCALLOC(MTYPE_TMP, people_size); ``` 3. **字符串数组分配**: ```c // 分配字符串数组 (以NULL结尾) char **strings = (char **)XCALLOC(MTYPE_TMP, (num_strings + 1) * sizeof(char *)); for (int i = 0; i < num_strings; i++) { strings[i] = XSTRDUP(MTYPE_TMP, "example"); } strings[num_strings] = NULL; // 结束标记 ``` ### 编译测试 修复后,使用以下命令编译: ```bash gcc -o readline_app readline.c -lreadline -lhistory -ltermcap -D_POSIX_C_SOURCE=200809L ``` 添加 `-D_POSIX_C_SOURCE=200809L` 确保兼容POSIX标准函数。 ### 内存泄漏检测代码 ```c void test_memory_allocation() { // 测试单个分配 char *str = XSTRDUP(MTYPE_TMP, "test string"); XFREE(MTYPE_TMP, str); // 测试数组分配 int array_size = 10; size_t total_bytes = array_size * sizeof(int); int *numbers = (int *)XCALLOC(MTYPE_TMP, total_bytes); XFREE(MTYPE_TMP, numbers); // 测试结构体分配 typedef struct { int id; char name[20]; } TestStruct; TestStruct *s = (TestStruct *)XMALLOC(MTYPE_TMP, sizeof(TestStruct)); XFREE(MTYPE_TMP, s); // 测试复杂结构 char **string_array = (char **)XCALLOC(MTYPE_TMP, 3 * sizeof(char *)); string_array[0] = XSTRDUP(MTYPE_TMP, "first"); string_array[1] = XSTRDUP(MTYPE_TMP, "second"); string_array[2] = NULL; // 释放整个数组 for (int i = 0; string_array[i]; i++) { XFREE(MTYPE_TMP, string_array[i]); } XFREE(MTYPE_TMP, string_array); } ``` 此修复方案完全符合您提供的宏定义,并解决了参数不匹配的编译错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值