【问题标题】:Pointer within structure reallocs fine, but pointer to a pointer within structure fails to realloc with invalid pointer error结构内的指针重新分配很好,但指向结构内的指针的指针无法重新分配无效指针错误
【发布时间】:2013-01-29 11:50:46
【问题描述】:

在处理需要频繁分配内存的程序时,我遇到了无法解释的行为。我已经实施了一项工作,但我很好奇为什么我以前的实施没有奏效。情况如下:

指针的内存重新分配有效

这可能不是最佳实践(如果是,请告诉我)但我记得如果传入的指针为 NULL,realloc 可以分配新内存。下面是一个示例,我将文件数据读入临时缓冲区,然后为 *data 和 memcopy 内容分配适当的大小

我有这样的文件结构

typedef struct _my_file {
       int size;
       char *data;
}

然后内存重新分配和复制代码如下:

// cycle through decompressed file until end is reached
while ((read_size = gzread(fh, buf, sizeof(buf))) != 0 && read_size != -1) {
        // allocate/reallocate memory to fit newly read buffer
        if ((tmp_data = realloc(file->data, sizeof(char *)*(file->size+read_size))) == (char *)NULL) {
                printf("Memory reallocation error for requested size %d.\n", file->size+read_size);
                // if memory was previous allocated but realloc failed this time, free memory!
                if (file->size > 0)
                        free(file->data);
                return FH_REALLOC_ERROR;
        }
        // update pointer to potentially new address (man realloc)
        file->data = tmp_data;
        // copy data from temporary buffer
        memcpy(file->data + file->size, buf, read_size);

        // update total read file size
        file->size += read_size;
}

指针的内存重新分配失败

但是,这就是我感到困惑的地方。使用重新分配 NULL 指针将分配新内存的相同想法,我解析一个参数字符串,并为每个参数分配一个指向指针的指针,然后分配一个由该指针指向的指针指向一个指针。也许代码更容易解​​释:

这是结构:

typedef struct _arguments {
        unsigned short int options;    // options bitmap
        char **regexes;                // array of regexes
        unsigned int nregexes;         // number of regexes
        char *logmatch;                // log file match pattern
        unsigned int limit;            // log match limit
        char *argv0;                   // executable name
} arguments;

以及内存分配代码:

int i = 0;
int len;
char **tmp;
while (strcmp(argv[i+regindex], "-logs") != 0) {
        len = strlen(argv[i+regindex]);

        if((tmp = realloc(args->regexes, sizeof(char **)*(i+1))) == (char **)NULL) {
                printf("Cannot allocate memory for regex patterns array.\n");
                return -1;
        }
        args->regexes = tmp;
        tmp = NULL;

        if((args->regexes[i] = (char *)malloc(sizeof(char *)*(len+1))) == (char *)NULL) {
                printf("Cannot allocate memory for regex pattern.\n");
                return -1;
        }

        strcpy(args->regexes[i], argv[i+regindex]);

        i++;
}

当我编译并运行它时,我得到一个运行时错误“realloc: invalid pointer”

我一定遗漏了一些明显的东西,但是在尝试调试和在线搜索解决方案 5 个小时没有完成太多尝试之后,我只运行了两个循环,一个计算参数的数量并为其分配足够的空间,第二个循环为参数分配空间并对其进行 strcpys。

非常感谢对此行为的任何解释!我真的很想知道为什么。

【问题讨论】:

  • if ((tmp_data = realloc(file->data, sizeof(char *)*(file->size+read_size))) == (char *)NULL) {} 使 if ((tmp_data = realloc(file->data, file->size+read_size)) == NULL) {} 。您正在分配一个字符数组,而不是指针。你在结构 realloc 中犯了同样的错误。
  • 你确定args->regexes 是在realloc 调用之前初始化的吗?尝试打印printf("%p\n", ...)
  • if (file->size > 0) free(file->data); return FH_REALLOC_ERROR; 不设置 file->data 为 NULL 会泄漏内存,和上面提到的@cnicutar 一样。顺便说一句:它不会泄漏,但释放的内存可以被下一次迭代引用或“doule freed()”,如果有的话。
  • @wildplasser 感谢您指出这一点。部分代码工作正常有点惊讶。我还修复了“正则表达式解析代码(上面帖子中的第二个标题)”中的错误转换。 @cnicutar,绝对正确。显然我没有初始化指针。 args->regexes = NULL 已修复。还有@wildplassar,我不知道,谢谢你的提示。从现在开始,我也将在 free() 之后执行 '=NULL'。谢谢! (现在要弄清楚如何将其标记为已解决...作为用户,stackoverflow 的新手)

标签: c memory memory-management realloc


【解决方案1】:

第一个片段:

// cycle through decompressed file until end is reached
while (1) {
        char **tmp_data;
        read_size = gzread(fh, buf, sizeof buf);
        if (read_size <= 0) break;

        // allocate/reallocate memory to fit newly read buffer
        tmp_data = realloc(file->data, (file->size+read_size) * sizeof *tmp_data );
        if ( !tmp_data ) {
                printf("Memory reallocation error for requested size %d.\n"
                      , file->size+read_size);

                if (file->data) {
                        free(file->data)
                        file->data = NULL;
                        file->size = 0;
                }
                return FH_REALLOC_ERROR;
        }

        file->data = tmp_data;
        // copy data from temporary buffer
        memcpy(file->data + file->size, buf, read_size);

        // update total read file size
        file->size += read_size;
}

第二个片段:

unsigned i; // BTW this variable is already present as args->nregexes;

for(i =0; strcmp(argv[i+regindex], "-logs"); i++) {
        char **tmp;

        tmp = realloc(args->regexes, (i+1) * sizeof *tmp ); 
        if (!tmp) {
                printf("Cannot allocate memory for regex patterns array.\n");
                return -1;
        }
        args->regexes = tmp;

        args->regexes[i] = strdup( argv[i+regindex] ); 
        if ( !args->regexes[i] ) {
                printf("Cannot allocate memory for regex pattern.\n");
                return -1;
        }
...
return 0;
}

几点说明:

  • 语法ptr = malloc ( CNT * sizeof *ptr);sizeof(type) 变体更健壮。
  • strdup() 和你的 malloc+strcpy() 完全一样
  • for(;;) 循环比循环体末尾带有松散i++; 的while() 循环更不容易出错。 (它也清楚地表明循环条件永远不会被检查)
  • 对我来说if ( !ptr ) {}if (ptr != NULL) {} 更容易阅读
  • 演员不需要,有时甚至不需要。

【讨论】:

  • 感谢您的建议。我发现它们非常有用,从现在开始将使用 strdup。如果可以的话,我会投赞成票,但有一个盒子说我需要 15 次代表。你是对的,为什么不使用 nregexes 而不是创建另一个变量 i。将再次检查我的代码以进一步清理和优化。再次感谢您!
猜你喜欢
  • 2018-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-26
  • 2015-07-04
  • 1970-01-01
  • 2017-01-03
  • 2020-05-06
相关资源
最近更新 更多