C释放数组和元素失败,同时释放两次



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

最新更新