![](/img/trans.png)
[英]How would I go about freeing this malloc in order to prevent any memory leaks when using valgrind
[英]Valgrind - Memory Leaks When Duplicating/Freeing Arrays
我在弄亂分配和釋放內存以獲取更多信息。 下面,我從命令行( char **argv
)接收字符串參數,並嘗試將它們作為大寫字符串復制到另一個malloc數組中:
static char **duplicateArgs(int argc, char **argv) {
if (argc <= 1) {
printf("%s\n", "No strings to duplicate.");
exit(1);
}
char **duplicate = (char**)malloc((argc + 1) * sizeof(char**));
int i = 1;
int j = 0;
int stringLength;
while (argv[i]) {
stringLength = strlen(argv[i]);
duplicate[i] = (char*)malloc(stringLength * sizeof(char) + 1);
for (j = 0; j < stringLength; j++) {
duplicate[i][j] = toupper(argv[i][j]);
}
duplicate[i][j]= '\0';
i++;
}
duplicate[i] = NULL;
return duplicate;
}
我也有釋放它們的功能:
static void freeDuplicateArgs(char **copy) {
int i = 0;
while (copy[i]) {
if (copy[i] != NULL){
free(copy[i]);
}
i++;
}
if (copy != NULL){
free(copy);
}
}
在main
函數中,我調用以下方法,將它們打印出來,然后釋放它們:
char **copy = duplicateArgs(argc, argv);
char **p = copy;
argv++;
p++;
while(*argv) {
printf("%s %s\n", *argv++, *p++);
}
freeDuplicateArgs(copy);
return 0;
輸出按預期工作,定期打印出字符串,然后大寫輸出。 但是,當我對Valgrind進行檢查時,會遇到以下麻煩:
==20867== Conditional jump or move depends on uninitialised value(s)
==20867== at 0x100000D1A: freeDuplicateArgs (part2.c:32)
==20867== by 0x100000E19: main (part2.c:57)
==20867==
==20867==
==20867== HEAP SUMMARY:
==20867== in use at exit: 62,847 bytes in 368 blocks
==20867== total heap usage: 520 allocs, 152 frees, 66,761 bytes allocated
==20867==
==20867== LEAK SUMMARY:
==20867== definitely lost: 8,639 bytes in 18 blocks
==20867== indirectly lost: 1,168 bytes in 5 blocks
==20867== possibly lost: 4,925 bytes in 68 blocks
==20867== still reachable: 48,115 bytes in 277 blocks
==20867== suppressed: 0 bytes in 0 blocks
如果編譯器沒有為我的freeDuplicates方法引發任何錯誤並且我的輸出正常,為什么會出現這樣的內存混亂情況?
編輯:我還應該提到我在OSX 10.8上-顯然Valgrind與此有關。
您的釋放代碼很有趣-並非完全錯誤,但也並非完全正確:
static void freeDuplicateArgs(char **copy) {
int i = 0;
while (copy[i]) {
if (copy[i] != NULL){
free(copy[i]);
}
i++;
}
if (copy != NULL){
free(copy);
}
}
您可以在釋放copy != NULL
之前測試copy != NULL
,但是一直以來都在使用它,因此該測試在那里很多余。 此外,您可以執行free(NULL)
而不會遇到問題。
然后我們看一下循環:
while (copy[i] != NULL)
{
if (copy[i] != NULL)
循環條件和if條件相同-同樣,您可以free(NULL)
。
您的while循環具有寫出的for循環結構。 您最好在以下方面做得更好:
static void freeDuplicateArgs(char **copy)
{
if (copy != NULL)
{
for (int i = 0; copy[i] != NULL; i++)
free(copy[i]);
free(copy);
}
}
copy != NULL
的測試可防止崩潰,並且僅在已知為非null時釋放它,這是(非常非常)小的優化。
我懷疑這是問題的直接起因(稍后我會在其余的代碼中看起來有點困難),但這是要考慮的問題。
你有:
static char **duplicateArgs(int argc, char **argv) {
if (argc <= 1) {
printf("%s\n", "No strings to duplicate.");
exit(1);
}
首先,可以在沒有用戶參數的情況下調用程序,但是它仍然具有argv[0]
,程序名稱和NULL指針。 您的代碼可能應該通過返回(char **)NULL
簡單地處理負值。 對於0參數,您將返回一個指向空指針的指針。 對於一個或多個參數,需要做的工作。
考慮這一行:
duplicate[i] = (char*)malloc(stringLength * sizeof(char) + 1);
您可能會考慮兩種情況: sizeof(char) == 1
和sizeof(char) > 1
(是的,請稍等-等待!)。 如果sizeof(char) == 1
,那么您不需要乘以它。 如果sizeof(char) > 1
,則說明您沒有分配足夠的空間。 表達式應為(stringLength + 1) * sizeof(char)
。 因此,編寫以下兩行之一:
duplicate[i] = (char*)malloc((stringLength + 1) * sizeof(char));
duplicate[i] = (char*)malloc(stringLength + 1);
我注意到C標准說定義為sizeof(char) == 1
,所以實際結果是相同的,但是如果您正在處理int
或其他sizeof(type)
數組,請在右側獲取與sizeof(type)
相乘的值這個地方可能很關鍵。
ISO / IEC 9899:2011§6.5.3.4中
sizeof
和_Alignof
運營商¶4當將
sizeof
應用於類型為char
,unsigned char
或signed char
(或其限定版本)的操作數時,結果為1。
以您的代碼幾乎與問題中的代碼相同:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char **duplicateArgs(int argc, char **argv)
{
if (argc <= 1) {
printf("%s\n", "No strings to duplicate.");
exit(1);
}
char **duplicate = (char**)malloc((argc + 1) * sizeof(char**));
int i = 0;
int j = 0;
int stringLength;
while (argv[i]) {
stringLength = strlen(argv[i]);
duplicate[i] = (char*)malloc(stringLength * sizeof(char) + 1);
for (j = 0; j < stringLength; j++) {
duplicate[i][j] = toupper(argv[i][j]);
}
duplicate[i][j]= '\0';
i++;
}
duplicate[i] = NULL;
return duplicate;
}
static void freeDuplicateArgs(char **copy)
{
int i = 0;
while (copy[i]) {
if (copy[i] != NULL){
free(copy[i]);
}
i++;
}
if (copy != NULL){
free(copy);
}
}
int main(int argc, char **argv)
{
char **copy = duplicateArgs(argc, argv);
char **p = copy;
argv++;
p++;
while(*argv) {
printf("%s %s\n", *argv++, *p++);
}
freeDuplicateArgs(copy);
return 0;
}
(區別是在本工作代碼中為int i = 0;
而不是問題代碼中為int i = 1;
)
在valgrind
下運行時,這將獲得干凈的健康單:
$ gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition mlk.c -o mlk
$ valgrind ./mlk nuts oh hazelnuts
==582== Memcheck, a memory error detector
==582== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==582== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==582== Command: ./mlk nuts oh hazelnuts
==582==
nuts NUTS
oh OH
hazelnuts HAZELNUTS
==582==
==582== HEAP SUMMARY:
==582== in use at exit: 18,500 bytes in 33 blocks
==582== total heap usage: 38 allocs, 5 frees, 18,564 bytes allocated
==582==
==582== LEAK SUMMARY:
==582== definitely lost: 0 bytes in 0 blocks
==582== indirectly lost: 0 bytes in 0 blocks
==582== possibly lost: 0 bytes in 0 blocks
==582== still reachable: 18,500 bytes in 33 blocks
==582== suppressed: 0 bytes in 0 blocks
==582== Rerun with --leak-check=full to see details of leaked memory
==582==
==582== For counts of detected and suppressed errors, rerun with: -v
==582== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)
$
如您所見,沒有報告內存錯誤。 對於該機器,仍在使用的33個塊是“正常”的; 它們是由Mac OS XC運行時庫分配的。 我還沒有在Mac OS X 10.8系統上使用valgrind
進行比較。 我建議您嘗試在valgrind
下運行一個非常簡單的程序,看看它能告訴您什么:
int main(void) { return 0; }
這將是您系統的基准。 如果存在泄漏,則泄漏不是由您的代碼引起的,並且您將需要學習如何記錄抑制,以便您的程序不會因操作系統的違背行為而受到懲罰。
如果您在上面運行了簡單程序,發現它不會產生泄漏(或者泄漏從根本上變得越來越小),那么請嘗試一些更復雜的程序:
#include <stdlib.h>
int main(void)
{
void *vp = malloc(32);
free(vp);
return(0);
}
這樣可以確保將malloc()
拖入並使用,但顯然不會泄漏(它也可以正確處理malloc()
失敗!)。
valgrind
對Mac OS X 10.8的支持 Valgrind網站說:
2012年9月18日:valgrind-3.8.1,用於X86 / Linux,AMD64 / Linux,ARM / Linux,PPC32 / Linux,PPC64 / Linux,S390X / Linux,MIPS / Linux,ARM / Android(2.3.x及更高版本),提供X86 / Android(4.0和更高版本),X86 / Darwin和AMD64 / Darwin(Mac OS X 10.6和10.7,對10.8的支持有限)。
您所看到的可能是對Mac OS X 10.8的有限支持的一個方面。
我看到我需要為自己重建valgrind
(3.7.0不是最新的)。
我認為您永遠不會將freeDuplicateArgs
duplicate[0]
設置為任何值,所以當您在freeDuplicateArgs
使用copy[i]
時(從i = 0開始),您將不知道會發生什么。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.