繁体   English   中英

在C中释放malloc字符串的二维数组失败

[英]Freeing a 2D array of malloc'd strings fails in C

我知道这是一个经常被问到的问题,但是我读了十多个封闭的问题,没有任何运气,因为我的解决方案似乎与其他人提出的解决方案相符。

我正在编写自己的Shell作为学习练习,并且这样做是在分配一个字符串数组作为程序调用的参数。 我的malloc如下完成,其中argcnt是给定的参数数量+ 2以匹配标准argv大小,并允许该数组以null终止,从而由execvp使用:

char ** args;
args = (char **) malloc(argcnt*sizeof(char *));
for(i = 0; i < argcnt; i++) {
    args[i] = (char *) malloc(80*sizeof(char));
    printf("Made %d\n", i);
}

然后,我释放相同的内存,如下所示:

for (i = 0; i < argcnt; i++) {
    free(args[i]);
    printf("Freed %d\n", i);
}
free(args);

该程序可以编译,但是在运行时无法释放argv [1]。 运行该程序然后调用ls -a -l的示例输出如下:

jack@ubuntu:~/myshell$ ./myshell 
[30/03 23:34] # ls -a -l
Argcnt: 4
Made 0
Made 1
Made 2
Made 3
Arg[0]: ls
Arg[1]: -a
Arg[2]: -l
Arg[3]: (null)
Freed 0
*** Error in `./myshell': free(): invalid pointer: 0x0000000001a84c43 ***
Aborted (core dumped)

在过去的两个小时中,我一直在努力解决这一问题,但无法找出问题出在哪里,因此非常感谢您对该问题有所了解。

编辑:当前打破我的程序的功能是:

void breakargs(char * cmd, char ** args) {
    char * tok = malloc(strlen(cmd)*sizeof(char)); //maximum token size is full cmd
    char * str = malloc(strlen(cmd)*sizeof(char));
    int i=1;
    strcpy(str, cmd); //maintains integrity of cmd

    args[0] = tok = strtok(str, " ");
    while (tok != NULL)
    {
        args[i] = tok = strtok(NULL, " ");
        i++;
    }
    args[i] = '\0';
    free(tok);
}

第2编辑:问题是我用strtok重新分配了由原始malloc生成的指针,从而丢失了原始指针引用。 此外,我对参数使用确定的字符串长度可能会导致问题。 解决方案是,仅当我知道需要存储在其中的字符串的长度时才使用malloc args [i],然后使用strcpy而不是像我一直在进行的直接分配将字符串移至该内存位置。 这样可以保持指针引用的完整性,并允许其正确释放。

问题不出在您显示的代码中。 它在您未显示的代码中。 在没有阅读完整的评论链的情况下,我怀疑您正在执行以下操作:

 args[0] = "ls";
 args[1] = "-a";
 args[2] = "-l";
 args[3] = NULL;

然后尝试释放args数组。 也许您的代码不是很公然,但是最终结果可能大致相同。 例如,您可能已经拆分了一条已读入缓冲区的命令行,并且可能会将指向缓冲区各部分的指针复制到args数组元素中。 更新:似乎是实际的问题。)

这使分配的内存消失了(您丢失了它-内存泄漏了),后来您试图释放未分配的内存( malloc()或它的一个朋友未返回的指针)。 第一个这样的free()通常是“可行的”,但是却完全弄乱了malloc()等人使用的控件,因此第二个free()失败了。 许多但不是全部现代系统都使用malloc()来检测许多此类滥用。

您需要以下代码:

strcpy(args[0], "ls");
strcpy(args[1], "-a");
strcpy(args[2], "-l");
free(args[3]);
args[3] = NULL;

请注意,为每个字符串分配80个字节是这些字符串的总超额分配。 太太,对于其他(更长)的论点也可能是完全不够的。 您应该像以前那样为args分配内存。 您可能应该根据相应参数包含的内容为各个元素分配内存。 您可能正在寻找一个名为strdup()的(POSIX,但不是Standard C)函数-它为字符串的副本分配了足够的空间,并将该字符串复制到分配的空间中。 或者,您可能根本不需要分配。

如果您的平台可用,则应使用valgrind来验证内存使用并确定滥用情况。

strtok将指针返回到最初传递给strtok的字符串中,无需为该指针分配空间。

当将strtok的返回值分配给指针变量时,将用新值覆盖该变量的指针值。 这意味着,如果该指针变量指向您已经分配的内存,则该内存将被“泄漏”,因为您不再有指向它的指针。

简而言之-如果您为指针变量分配内存,请不要为该指针变量分配其他值,除非您已经free了内存或将指针值放在其他位置。

breakArgs函数中,存在许多问题:

void breakargs(char * cmd, char ** args) {
    char * tok = malloc(strlen(cmd)*sizeof(char)); //maximum token size is full cmd

您不需要为tok分配内存,因为您将从strtok为其分配一个值

    char * str = malloc(strlen(cmd)*sizeof(char));
    int i=1;
    strcpy(str, cmd); //maintains integrity of cmd

    args[0] = tok = strtok(str, " ");

不要直接分配给args[0]因为那样会覆盖指向已分配内存的指针。 而是分配给tok ,然后分配给strcpy(args[0], tokstrcpy(args[0], tok

    while (tok != NULL)
    {
        args[i] = tok = strtok(NULL, " ");

不要直接分配给args[i]因为那样会覆盖指向已分配内存的指针。 而是分配给tok ,然后分配给strcpy(args[i], tokstrcpy(args[i], tok strcpy开始之前,还应该检查tok为NULL。

        i++;
    }
    args[i] = '\0';

不要直接分配给args [i],而是可以用strcpy(args[i], "")指示结尾,因此结尾处有一个空白字符串。

    free(tok);

不要在此处释放tok ,因为在此阶段tok应该为NULL,但是您确实需要free (str)

}

还要注意其他一些有关检查您处理的参数是否超过内存限制的注释(例如,每项80个字符)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM