首页 > 解决方案 > 如何修复“realloc():无效指针”

问题描述

我正在尝试编写一个将文本文件转换为 CSV 文件的函数。输入文件有 3 行以空格分隔的条目。我必须找到一种将一行读入字符串并将输入文件中的三行转换为 CSV 文件中的三列的方法。

文件如下所示:

Jake Ali Maria
24 23 43
Montreal Johannesburg Sydney

我必须把它变成这样的东西:

Jake, 24, Montreal
...etc

我想我可以创建一个char **line变量来保存对三个单独char数组的三个引用,一个用于输入文件的三行中的每一行。即,我的目标是*(line+i)存储i+1文件的第 ' 行。

我想避免硬编码char数组大小,例如

char line1 [999]; 
fgets(line1, 999, file);

所以我写了一个while循环fgets,将一行的片段写入一个预定大小的小缓冲区数组,然后根据需要将内存存储为字符串,并strcat作为指向字符串的指针,其中是第一行,对于第二个等等。realloc*(line+i)i01

这是有问题的代码:

#include <stdio.h>
#include<stdlib.h>
#include<string.h>

#define CHUNK 10

char** getLines (const char * filename){
    FILE *file = fopen(filename, "rt");
    char **lines = (char ** ) calloc(3, sizeof(char*));
    char buffer[CHUNK];
    for(int i = 0; i < 3; i++){
        int lineLength = 0;
        int bufferLength = 0;
        *(lines+i) = NULL;
        do{
            fgets(buffer, CHUNK, file);
            buffLength = strlen(buffer);
            lineLength += buffLength;
            *(lines+i) = (char*) realloc(*(lines+i), (lineLength +1)*sizeof(char));
            strcat(*(lines+i), buffer);
        }while(bufferLength ==CHUNK-1);
    }
    puts(*(lines+0));
    puts(*(lines+1));
    puts(*(lines+2));

    fclose(file);
}

void load_and_convert(const char* filename){
    char ** lines = getLines(filename);
}

int main(){
    const char* filename = "demo.txt";
    load_and_convert(filename);
}

这仅适用于i=0. 但是,通过 GDB 进行此操作,我发现我收到了一个realloc(): invalid pointer错误。缓冲区加载正常,只有当我在 for 循环中调用 'realloc' 时i=1,当我到达第二行时它才会崩溃。

我设法在一个小示例中存储了我想要的字符串,以尝试查看发生了什么,但输入都在同一行。也许这与fgets从新行阅读有关?

我真的很感激这方面的帮助,我整天都被困住了。

非常感谢!

***编辑

我尝试按照建议使用calloc而不是malloc初始化变量**lines,但我仍然遇到同样的问题。我已将修改添加到我上传的原始代码中。

***编辑

删除文件并重新编译后,上面的方法现在似乎可以工作了。感谢大家帮助我!

标签: cdynamic-memory-allocationrealloc

解决方案


您分配line(这是一个用词不当,因为它不是单行),它是指向三个char*s 的指针。您永远不会初始化 s 的内容line(也就是说,您永远不会将这三个char*s 中的任何一个指向任何地方)。因此,当您这样做时realloc(*(line + i), ...),第一个参数是未初始化的垃圾。

要用于realloc进行初始内存分配,它的第一个参数必须是空指针。line您应该首先显式初始化to的每个元素NULL

此外,*(line+i) = (char *)realloc(*(line+i), ...)仍然很糟糕,因为如果realloc分配内存失败,它将返回一个空指针 clobber*(line + i)并泄漏旧指针。相反,您应该将其拆分为单独的步骤:

char* p = realloc(line[i], ...);
if (p == null) {
    // Handle failure somehow.
    exit(1);
} 
line[i] = p;

还有一些注意事项:

  • 在 C 中,您应该避免转换malloc/ realloc/的结果calloc。这不是必需的,因为 C 允许从void*其他指针类型进行隐式转换,而显式可能会掩盖您不小心省略的错误#include <stdlib.h>
  • sizeof(char)根据定义,是 1 个字节。
  • 在分配内存时,养成使用T* p = malloc(n * sizeof *p);而不是T* p = malloc(n * sizeof (T));. 这样,如果类型发生p了变化,如果您忽略更新malloc(or reallocor calloc) 调用,您就不会默默地分配错误的内存量。

推荐阅读