简体   繁体   English

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

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

I know this is a question that has been asked quite frequently but I have read 10+ closed questions without any luck as my solution seems to match those proposed as solutions by others. 我知道这是一个经常被问到的问题,但是我读了十多个封闭的问题,没有任何运气,因为我的解决方案似乎与其他人提出的解决方案相符。

I am writing my own shell as a learning exercise and in doing so, I am malloc'ing an array of strings to serve as the arguments of a program call. 我正在编写自己的Shell作为学习练习,并且这样做是在分配一个字符串数组作为程序调用的参数。 My malloc is done as follows where argcnt is the number of arguments given + 2 to match the standard argv size and allow the array to be null terminated and thus used by execvp: 我的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);
}

I then free the same memory as follows: 然后,我释放相同的内存,如下所示:

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

The program compiles but fails at freeing argv[1] at runtime. 该程序可以编译,但是在运行时无法释放argv [1]。 The sample output of running the program and then calling ls -a -l is as follows: 运行该程序然后调用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)

I have been wrestling with this for the last 2 hours and can't work out what is wrong so some insight into the problem would be very much appreciated. 在过去的两个小时中,我一直在努力解决这一问题,但无法找出问题出在哪里,因此非常感谢您对该问题有所了解。

EDIT: The function currently breaking my program is: 编辑:当前打破我的程序的功能是:

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

2nd EDIT: The problem was my reassigning of the pointers made by my original malloc with strtok so that the original pointer reference was lost. 第2编辑:问题是我用strtok重新分配了由原始malloc生成的指针,从而丢失了原始指针引用。 Furthermore, my use of a definite string length for arguments could potentially lead to problems. 此外,我对参数使用确定的字符串长度可能会导致问题。 The solution was to only malloc args[i] when I knew the length of the string that needs to be stored there, and then move the string into that memory location using strcpy instead of direct assignment as I had been doing. 解决方案是,仅当我知道需要存储在其中的字符串的长度时才使用malloc args [i],然后使用strcpy而不是像我一直在进行的直接分配将字符串移至该内存位置。 This maintains the integrity of the pointer reference and allows it to be freed correctly. 这样可以保持指针引用的完整性,并允许其正确释放。

The problem isn't in the code you show; 问题不出在您显示的代码中。 it is in the code you don't show. 它在您未显示的代码中。 Without having read the complete comment chain, I suspect you're doing something similar to this: 在没有阅读完整的评论链的情况下,我怀疑您正在执行以下操作:

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

and then trying to free the args array. 然后尝试释放args数组。 Maybe your code was not quite so blatant, but the net result may be much the same. 也许您的代码不是很公然,但是最终结果可能大致相同。 For example, you could have split up a command line that was read into a buffer and might copy the pointers to sections of the buffer into the args array elements. 例如,您可能已经拆分了一条已读入缓冲区的命令行,并且可能会将指向缓冲区各部分的指针复制到args数组元素中。 ( Update: This seems to be the actual problem.) 更新:似乎是实际的问题。)

This has obliterated the allocated memory (you've lost it — you've leaked memory), and later you're trying to free unallocated memory (pointers that were not returned by malloc() or one of its friends). 这使分配的内存消失了(您丢失了它-内存泄漏了),后来您试图释放未分配的内存( malloc()或它的一个朋友未返回的指针)。 The first such free() often 'works', but completely messes up the controls used by malloc() et al so that the second free() fails. 第一个这样的free()通常是“可行的”,但是却完全弄乱了malloc()等人使用的控件,因此第二个free()失败了。 Many, but not all, modern systems sport a malloc() that detects many such abuses. 许多但不是全部现代系统都使用malloc()来检测许多此类滥用。

You need code more like: 您需要以下代码:

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

Note that allocating 80 bytes per string was a gross over-allocation for these strings. 请注意,为每个字符串分配80个字节是这些字符串的总超额分配。 OTOH, it could also be completely inadequate for other (longer) arguments. 太太,对于其他(更长)的论点也可能是完全不够的。 You should allocate the memory for args itself as you did; 您应该像以前那样为args分配内存。 you should probably allocate the memory for the individual elements according to what the corresponding argument contains. 您可能应该根据相应参数包含的内容为各个元素分配内存。 There's a (POSIX but not Standard C) function called strdup() that might be what you're looking for — it allocates enough space for a copy of a string and copies the string into the allocated space. 您可能正在寻找一个名为strdup()的(POSIX,但不是Standard C)函数-它为字符串的副本分配了足够的空间,并将该字符串复制到分配的空间中。 Alternatively, you might not need the allocations at all. 或者,您可能根本不需要分配。

If it is available for your platform, you should use valgrind to validate your memory use and identify your abuses. 如果您的平台可用,则应使用valgrind来验证内存使用并确定滥用情况。

strtok returns a pointer into the string that was initially passed to strtok , there is no need to allocate space for that pointer. strtok将指针返回到最初传递给strtok的字符串中,无需为该指针分配空间。

When you assign the return value of strtok to a pointer variable, you overwrite that variable's pointer value with the new value. 当将strtok的返回值分配给指针变量时,将用新值覆盖该变量的指针值。 This means, if that pointer variable points to memory you have already allocated, that memory will be "leaked" as you no longer have a pointer to it. 这意味着,如果该指针变量指向您已经分配的内存,则该内存将被“泄漏”,因为您不再有指向它的指针。

In short - if you allocate memory for a pointer variable, don't assign a different value to that pointer variable unless you have already free d the memory or put the pointer value somewhere else. 简而言之-如果您为指针变量分配内存,请不要为该指针变量分配其他值,除非您已经free了内存或将指针值放在其他位置。

In your breakArgs function there are a number of issues: breakArgs函数中,存在许多问题:

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

You don't need to allocate memory for tok as you will assigning it a value from strtok 您不需要为tok分配内存,因为您将从strtok为其分配一个值

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

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

Don't assign directly into args[0] as that will overwrite the pointer to the memory you already allocated. 不要直接分配给args[0]因为那样会覆盖指向已分配内存的指针。 Instead assign into tok , then strcpy(args[0], tok ); 而是分配给tok ,然后分配给strcpy(args[0], tokstrcpy(args[0], tok

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

Don't assign directly into args[i] as that will overwrite the pointer to the memory you already allocated. 不要直接分配给args[i]因为那样会覆盖指向已分配内存的指针。 Instead assign into tok , then strcpy(args[i], tok ); 而是分配给tok ,然后分配给strcpy(args[i], tokstrcpy(args[i], tok You should also check for tok being NULL before you strcpy from it. strcpy开始之前,还应该检查tok为NULL。

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

Don't assign directly into args[i], instead you could indicate the end by strcpy(args[i], "") so you have a blank string at the end. 不要直接分配给args [i],而是可以用strcpy(args[i], "")指示结尾,因此结尾处有一个空白字符串。

    free(tok);

Don't free tok here, as tok should be NULL by this stage, you do need to free (str) though. 不要在此处释放tok ,因为在此阶段tok应该为NULL,但是您确实需要free (str)

}

Also take note of some of the other comments about checking that the arguments you process don't exceed the limit you have put on the memory (eg 80 characters per item). 还要注意其他一些有关检查您处理的参数是否超过内存限制的注释(例如,每项80个字符)。

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

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