C释放数组和元素失败,双重免费

时间:2015-12-14 19:19:13

标签: c arrays regex memory-management memory-leaks

我是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函数从字符串中提取正则表达式并将它们存储到一个动态分配的字符串数组中,称为&#34;匹配&#34;并从函数返回此信息。这很有效。

我的问题是我现在想要释放与字符串数组相关联的内存,这是free_regex_memory()函数的用武之地。我遍历数组,释放与每个元素关联的内存在matches数组中然后我尝试释放数组本身。我可以做其中一个,要么释放数组,要么释放它的元素。然而,尝试两者(如上面的代码中)给我的错误&#34;双重免费或腐败&#34; (如上面代码中的评论所示)。

那是什么给出的?我看到的所有其他SO问题都提到需要释放malloced数组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("%.*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);

2 个答案:

答案 0 :(得分:2)

你有:

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++]);
}

答案 1 :(得分:1)

更多建议 -

来自维基百科:

  

malloc预留的内存未初始化,可能包含以前使用和丢弃的数据残留

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