あなたが尋ねる:
マロックされた文字列でstrtokを使用することについて知っておくべきことはありますか?
知っておくべきことがたくさんあります。まず、文字列を処理するときに文字列を変更し、区切り文字が見つかった場所にstrtok()
null()を挿入します。'\0'
これは、割り当てられたメモリの問題ではありません(変更可能です!)。定数文字列をに渡そうとすると問題になりますstrtok()
。
free()
第二に、あなたはあなたがするのと同じくらい多くの呼び出しをしなければなりませんmalloc()
(calloc()
しかしrealloc()
、カウントを台無しにする可能性があります)。
私のコードには(一般的に)
char* line=getline();
Parse(dest,line);
free(line);
保持するスペースを割り当てない限り、の呼び出し後に構造体(より正確には、構造体内の行へのポインター)をParse()
使用することはできません。リリースによって割り当てられたスペースと、その後のポインターの使用により、未定義の動作が発生します。未定義の動作には、「動作しているように見えるが、偶然にのみ」というオプションが含まれていることに注意してください。dest
dest
free()
free()
getline()
ここで、getline()はchar *をマロックされたメモリに返す関数であり、Parse(dest、line)はオンラインで解析を行い、結果をdest(他の情報から部分的に以前に入力されたもの)に格納する関数です。
Parse()はstrtok()をオンラインで可変回数呼び出し、いくつかの検証を行います。各トークン(strtok()によって返されるものへのポインター)は、私がいくつ持っているかがわかるまで、キューに入れられます。
strtok()
によって返されるポインタはすべて、によって割り当てられたスペースの単一のチャンクへのポインタであることに注意してくださいgetline()
。追加のメモリ割り当てについては説明していません。
次に、それらはdestのmallocされたchar**にコピーされます。
これは、ポインタをからポインタの配列にコピーするように聞こえますstrtok()
が、それらのポインタが指しているデータのコピーには注意を払っていません。
これで、free(line)とdestのchar * []の各部分を解放する関数は、どちらもvalgrindに次のように表示されます。
"Address 0x5179450 is 8 bytes inside a block of size 38 free'd"
または同様のもの。
free()
の' char *[]
'部分の最初の部分には、dest
おそらくへのポインタがあるline
ため、メモリのブロック全体が解放されます。の部分での後続のすべての解放は、dest
によって返されないアドレスを解放しようとしてmalloc()
おり、それvalgrind
を通知しようとしています。の最初のポインタがすでにそのスペースを解放しているfree(line)
ため、操作は失敗します。free()
dest
コードをリファクタリングして[...]それらのコピーを保存することを検討しています。
提案されたリファクタリングはおそらく賢明です。他の人がすでに述べた機能strdup()
は、きちんとそして確実に仕事をします。
リファクタリング後も行を解放する必要がありますが、によって返されるポインターは解放されないことに注意してくださいstrtok()
。これらは、(によって識別される)によって管理されるスペースへの単なるポインタでline
あり、を解放するとすべて解放されますline
。
strdup()
個別に割り当てられた( 'd)文字列のそれぞれと、を介してアクセスされる文字ポインタの配列を解放する必要があることに注意してくださいdest
。
または、を呼び出した直後に回線を解放しないでくださいParse()
。dest
割り当てられたポインター()を記録し、ポインターのline
配列を解放するときにそれを解放します。ただし、によって返されたポインタはまだ解放されませんstrtok()
。