[英]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], tok
) strcpy(args[0], tok
while (tok != NULL)
{
args[i] = tok = strtok(NULL, " ");
不要直接分配給args[i]
因為那樣會覆蓋指向已分配內存的指針。 而是分配給tok
,然后分配給strcpy(args[i], tok
) strcpy(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.