我是C的新手,正在尝试使用regex库。到目前为止,我已经成功地构建了一个regex匹配数组(字符串数组),并试图释放这样做时使用的内存
#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("%.*sn", 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函数从字符串中提取regex,并将它们存储到一个动态分配的字符串数组中,称为"matches",然后从函数中返回。这很有效。
我的问题是,我现在想释放与字符串数组相关联的内存,这就是free_regex_memory()函数的作用所在。我循环遍历数组,释放与matches数组中每个元素相关的内存,然后尝试释放数组本身。我可以做一个或另一个,要么释放数组,要么释放它的元素。然而,尝试同时执行这两种操作(如上面的代码中所示)会导致错误"双重自由或损坏"(如上面代码中的注释所示)。
那是什么呢?我看到的所有其他SO问题都提到需要释放mallocated数组AND元素来正确释放内存,但我似乎做不到。我缺少什么?
作为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);
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("%.*sn", 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);
您有:
int i = 0; while (matches_array[i] != NULL) { free(&matches_array[i]); }
- 您正在释放
matches_array[i]
的地址。我不相信这是故意的 - 你永远不会递增
i
您需要与此等效的代码(可以选择使用for
循环):
int i = 0;
while (matches_array[i] != NULL) {
free(matches_array[i++]);
}
更多建议-
来自维基百科:
malloc留出的内存没有初始化,可能包含cruft:以前使用和丢弃的数据的残余
当使用malloc()时,在分配内存块后清除它:
char **matches = (char **) malloc(sizeof(char *) * reg_limit);
memset( (char *)matches, 0, sizeof(char *) * reg_limit );
不要依赖matches_array指针的硬端,使用您分配的限制:
void free_regex_memory( char **matches_array, int reg_limit )
{
int i = 0;
for (i = 0; i < reg_limit; i++)
{
if ( matches_array[i] != NULL )
free( matches_array[i] ); // initial problem
}
free(matches_array);
}
从Main:调用
int main()
{
char **matches;
int i =0;
/////////////////
free_regex_memory( matches, reg_limit );
return 0;
}