【发布时间】:2015-12-14 19:19:13
【问题描述】:
我是 C 新手,正在尝试使用正则表达式库。到目前为止,我已经成功构建了一个正则表达式匹配数组(字符串数组),并且我正在尝试释放这样做时使用的内存。代码在这里:
#include "basic_curl.h"
//returns an array of strings
//the free_regex_memory should be called when regex results are no longer
//needed
char **regexme(char *_string, const char *reg_to_match, int reg_limit) {
regex_t preg;
size_t nmatch = 1;
regmatch_t pmatch[1];
int comp_ret;
int match;
int start;
int end = 0;
int match_len;
int i;
int string_offset = 0;
char **matches = (char **) malloc(sizeof(char *) * reg_limit);
for (i=0; i < reg_limit; i++) {
comp_ret = regcomp(&preg, reg_to_match, REG_ICASE|REG_EXTENDED);
match = regexec(&preg, &_string[string_offset], nmatch, pmatch, 0);
if (match == 1) {
puts("No more matches found, rest of the loop will be filled with NULLs");
break;
}
else if (match == 0 ) {
start = pmatch[0].rm_so;
end = pmatch[0].rm_eo;
string_offset += end;
match_len = end - start;
printf("%.*s\n", match_len, &_string[string_offset - match_len]);
//use malloc to find the length and use that instead of limiting array initially
//http://stackoverflow.com/questions/33003196/cant-copy-string-to-an-array-of-strings-in-c
matches[i] = malloc(sizeof(char) * (match_len + 1));
sprintf(matches[i], "%.*s" , match_len, &_string[string_offset - match_len]);
}
}
return matches;
}
int free_regex_memory(char **matches_array) {
int i = 0;
while (matches_array[i] != NULL) {
free(&matches_array[i]);
}
//why can't I do this after the above?
//I get a crash from the below line trying to free the array itself:
/*
*** Error in `/home/punk/ClionProjects/curl-ex/src/regmatch': double free or corruption (fasttop): 0x0000000000603010 ***
Program received signal SIGABRT, Aborted.
0x00007ffff7a4af79 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
*/
free(matches_array);
return 0;
}
int main() {
char **matches;
int i =0;
matches = regexme("0fff 1fc<a href=\"https://www.blahblahblah.com/whatever.php?xxx=r\" keaw 2eafa",
"(http|https)://[%/0-9a-zA-Z\\.\?=&#@:]*",
10);
//puts(matches[1]);
while (matches[i] != NULL) {
puts(matches[i]);
i++;
}
free_regex_memory(matches);
return 0;
}
基本上,上面的 regexme 函数从字符串中提取正则表达式并将它们存储到一个动态分配的字符串数组中,称为“matches”,然后从函数中返回它。这很好用。
我的问题是我现在想释放与字符串数组关联的内存,这就是 free_regex_memory() 函数的用武之地。我循环遍历数组,并释放与字符串中的每个元素关联的内存匹配数组,然后我尝试释放数组本身。我可以做一个或另一个,要么释放数组,要么释放它的元素。但是,尝试同时执行这两种操作(如上面的代码)会给我“双重释放或损坏”错误(如上面代码中的 cmets 所示)。
那是什么?我看到的所有其他 SO 问题都提到需要释放分配的数组和元素以正确释放内存,但我似乎不能这样做。我错过了什么?
顺便说一句,我是 C 的新手,我在这段代码中做了什么非常愚蠢或低效的事情吗?
编辑:这是我基于 cmets 和答案的新代码
#include "basic_curl.h"
//returns an array of strings
//the free_regex_memory should be called when regex results are no longer
//needed
char **regexme(char *_string, const char *reg_to_match, int reg_limit) {
regex_t preg;
size_t nmatch = 1;
regmatch_t pmatch[1];
int comp_ret;
int match;
int start;
int end = 0;
int match_len;
int i;
int string_offset = 0;
//char **matches = (char **) malloc(sizeof(char *) * reg_limit);
void **matches = malloc(sizeof(char *) * reg_limit);
for (i=0; i < reg_limit; i++) {
comp_ret = regcomp(&preg, reg_to_match, REG_ICASE|REG_EXTENDED);
match = regexec(&preg, &_string[string_offset], nmatch, pmatch, 0);
if (match == 1) {
puts("No more matches found, rest of the loop will be filled with NULLs");
break;
}
else if (match == 0 ) {
start = pmatch[0].rm_so;
end = pmatch[0].rm_eo;
string_offset += end;
match_len = end - start;
printf("%.*s\n", match_len, &_string[string_offset - match_len]);
//use malloc to find the length and use that instead of limiting array initially
//http://stackoverflow.com/questions/33003196/cant-copy-string-to-an-array-of-strings-in-c
matches[i] = malloc(sizeof(char) * (match_len + 1));
sprintf(matches[i], "%.*s" , match_len, &_string[string_offset - match_len]);
}
}
return matches;
}
int free_regex_memory(char **matches_array) {
int i = 0;
//fixed so that i'm no longer dereferencing the array element addresses and incrementing the pointer
while (matches_array[i] != NULL) {
free(matches_array[i]);
i++;
}
//this works now
free(matches_array);
return 0;
}
int main() {
char **matches;
int i =0;
matches = regexme("0fff 1fc<a href=\"https://www.blahblahblah.com/whatever.php?xxx=r\" keaw 2eafa",
"(http|https)://[%/0-9a-zA-Z\\.\?=&#@:]*",
10);
//puts(matches[1]);
while (matches[i] != NULL) {
puts(matches[i]);
i++;
}
free_regex_memory(matches);
return 0;
}
哦,这里是 basic_curl.h,以防有人想编译它:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <curl/curl.h>
#include <regex.h>
#include <sys/types.h>
struct MemWriteData {
size_t size;
char *memory;
};
static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userp);
char **regexme(char *_string, const char *reg_to_match, int reg_limit);
int free_regex_memory(char **matches_array);
【问题讨论】:
-
不应该
free(&matches_array[i]);是free(matches_array[i]);吗?当您使用i == 0执行此操作时,您正在执行您使用free(matches_array)尝试的操作 — 库标识的双重免费。 -
1) 一般规则:除非您真的知道自己在做什么,否则不要施放(有时施放,有时不施放,说明您不知道)。 2)不要在C中转换
malloc和朋友的结果。你没有数组,而是指向指针的指针。 4) 指针不是数组。 -
同意
matches_array[0]和matches_array是两个不同的地址,但这无关紧要,因为您将&matches_array[0]和matches_array传递给free(),它们是同一个地址。您真的不希望在对free的调用中使用&。我不得不不同意接受的答案,尽管我承认我没有正式编译和运行代码(部分原因是我没有basic_curl.h使其可编译)。 -
哦;我明白了——公认的答案是指出什么是错的,而不是显示什么是对的。那我就同意了。
-
@acnutch 请注意,在 C 中您应该始终检查您的返回值。但是,您的代码中似乎没有。特别是,对
malloc()的调用可能会因返回NULL而失败。如果发生这种情况并且您继续使用返回的NULL指针,您可能会发现 未定义的行为 包括从“工作”到“奇怪的错误”到它只是崩溃(在 任何点)。我强烈建议您考虑一些最小的错误处理。我对 curl API 不太熟悉,但我想您也没有处理它可能出现的错误。
标签: c arrays regex memory-management memory-leaks