簡體   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