在C

时间:2016-03-30 22:38:41

标签: c multidimensional-array memory-leaks malloc free

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

我正在编写自己的shell作为学习练习,并且在这样做时,我正在使用一个字符串数组作为程序调用的参数。我的malloc完成如下,其中argcnt是给定的参数数量+ 2以匹配标准的argv大小,并允许数组被空终止并因此被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);
}

第二次编辑:问题是我重新分配了我的原始malloc和strtok所做的指针,因此原始指针引用丢失了。此外,我使用明确的字符串长度进行参数可能会导致问题。当我知道需要存储在那里的字符串的长度时,解决方案只是malloc args [i],然后使用strcpy将字符串移动到该内存位置,而不是像我一直那样直接赋值。这样可以保持指针引用的完整性,并允许正确释放它。

2 个答案:

答案 0 :(得分:1)

问题不在你展示的代码中;它是在你不能展示的代码中。如果没有阅读完整的评论链,我怀疑你正在做类似的事情:

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

然后尝试释放args数组。也许你的代码并不那么明显,但最终结果可能大致相同。例如,您可以将已读取的命令行拆分为缓冲区,并可将指针复制到缓冲区的各个部分中的args数组元素。 (更新:seems是实际问题。)

这已经消除了分配的内存(你已经丢失了它 - 你已经泄露了内存),后来你试图释放未分配的内存({{1}未返回的指针或其中一位朋友)。第一个这样的malloc()通常会起作用,但会完全混淆free()等使用的控件,以便第二个malloc()失败。许多(但不是全部)现代系统都运行free()来检测许多此类滥用行为。

您需要的代码更像:

malloc()

请注意,为每个字符串分配80个字节是这些字符串的严重超额分配。 OTOH,它也可能完全不适合其他(更长)的论点。你应该像你一样为strcpy(args[0], "ls"); strcpy(args[1], "-a"); strcpy(args[2], "-l"); free(args[3]); args[3] = NULL; 本身分配内存;你应该根据相应的参数包含的内容为各个元素分配内存。有一个名为strdup()的(POSIX但不是标准C)函数可能是您正在寻找的函数 - 它为字符串的副本分配足够的空间并将字符串复制到分配的空间中。或者,您可能根本不需要分配。

如果适用于您的平台,则应使用valgrind验证您的内存使用情况并确定您的滥用行为。

答案 1 :(得分:1)

strtok返回指向最初传递给strtok的字符串的指针,不需要为该指针分配空间。

strtok的返回值赋给指针变量时,用新值覆盖该变量的指针值。这意味着,如果该指针变量指向您已经分配的内存,那么该内存将被泄露&#34;因为你不再有指向它的指针。

简而言之 - 如果为指针变量分配内存,则不要为该指针变量分配不同的值,除非您已经将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], tok);

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

不要直接分配到args[i],因为这会覆盖指向已分配内存的指针。而是分配到tok,然后strcpy(args[i], tok); 您还应该在tok之前检查strcpy是否为NULL。

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

不要直接分配到args [i],而是可以通过strcpy(args[i], "")指示结尾,以便最后有一个空字符串。

    free(tok);

不要在这里免费tok,因为tok在此阶段应为NULL,但您确实需要free (str)

}

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