コードを解放する
あなたの解放コードは興味深いものです—正確には間違っていませんが、実際には正しくありません。
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
解放する直前にテストしますが、ずっと使用しているので、テストは冗長です。その上、あなたは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の場合、nullポインタへのポインタを返します。そして、1つ以上の議論については、やるべきことがあります。
次の行を検討してください。
duplicate[i] = (char*)malloc(stringLength * sizeof(char) + 1);
あなたが考えるかもしれない2つのケースがあります:sizeof(char) == 1
そしてsizeof(char) > 1
(はい、待ってください—待ってください!)。の場合sizeof(char) == 1
、それを掛ける必要はありません。の場合sizeof(char) > 1
、十分なスペースを割り当てていません。式はである必要があります(stringLength + 1) * sizeof(char)
。したがって、次の2行のいずれかを記述します。
duplicate[i] = (char*)malloc((stringLength + 1) * sizeof(char));
duplicate[i] = (char*)malloc(stringLength + 1);
C標準では、sizeof(char) == 1
定義上、実際の結果は同じであると規定されていることに注意してください。ただし、配列などを扱っている場合は、適切な場所でint
乗算をsizeof(type)
行うことが重要になる可能性があります。
ISO / IEC 9899:2011§6.5.3.4sizeof
および_Alignof
演算子
¶4タイプ、、、または、
(またはその修飾バージョン)sizeof
を持つオペランドに適用されると、結果は1になります。char
unsigned char
signed char
Mac OSX10.7.5のValgrind
質問に書かれているとおりにコードを取得します。
#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ブロックは、このマシンでは「通常」です。それらはMacOSXCランタイムライブラリによって割り当てられます。valgrind
比較するMacOSX10.8システムを使用していません。で非常に単純なプログラムを実行してみて、valgrind
それが何を示しているかを確認することをお勧めします。
int main(void) { return 0; }
これがシステムのベースラインになります。リークがある場合、それはコードが原因ではありません。プログラムがO / Sの違反に対してペナルティを科されないように、抑制を記録する方法を学ぶ必要があります。
上記の単純なプログラムを実行してもリークが発生しない場合、またはリークが根本的に単純で小さい場合は、少し複雑なプログラムを試してください。
#include <stdlib.h>
int main(void)
{
void *vp = malloc(32);
free(vp);
return(0);
}
これにより、malloc()
がドラッグされて使用されることが保証されますが、明らかにリークすることはありません(また、malloc()
障害も正しく処理されます!)。
valgrind
Mac OSX10.8のサポート
ValgrindのWebサイトには次のように書かれています。
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 OSX10.8の限定的なサポートの側面かもしれません。
自分で再構築する必要があるようvalgrind
です(3.7.0は最新ではありません)。