- ベストアンサー
malloc関数(strtok関数の自作版)についての質問
- malloc関数(strtok関数の自作版)について質問があります。
- malloc関数を適切な位置で使う方法を教えてください。
- strtok関数の中でのfreeの位置について助言をお願いします。
- みんなの回答 (7)
- 専門家の回答
質問者が選んだベストアンサー
簡単な問題です。 strtok()の中で確実にfreeできます! ちょっとした「脳トレ」です。 mallocの後半しか見ていないと、 「罠」にはまり、 mainでやるしかないとか思うようになります。 「static」がキーワードです。 staticがあれば、関数を抜けても前の値を保持します。 ポインタであれば、前に代入されたアドレスを保持します。 ですから strtok()の先頭でfreeすれば良い!! これが正解! 大丈夫か? 検討します。 まずfree(NULL)は安全である (何もしない) 事が保証されています。 staticなポインタはNULLで初期化されます。 つまり、最初の呼び出し時のfreeは無いのと同じ。 mallocで代入されます。 return でアドレスを返し関数を抜けますが staticなので mstrは割り当てられたアドレスを覚えています。 次回の呼び出しで再度(でたらめな値で)初期化される ことはありません。 これがstaticの付く/付かないの大きな差になります。 言わば、ここに「大ヒント」があるのです!!!!!! こうして2回目の呼び出しのfreeでは 前回の呼び出し時に割り当てられたアドレスが 無事freeに渡り、正しく解放されます。 free後はmallocまでmstrに一切アクセスしてませんので 問題ありません。 こうして2回目のmalloc時には既にmstrは解放済みであることが 分かるので再度mstrに割り当てても 「メモリーリーク」にならないことが分かります。 これを何度か繰り返します。 最終の呼び出しを検討する必要があります。 最終のstrtok呼び出しの条件はなにか? *str2 == '\0’ がその条件です。 与えられたトークンを最後まで切りだし完了した と言うことです。 この時はmallocせずに抜けています。 つまり、最終の呼び出しでmstrにmallocされて終了する メモリーリークについて全く心配ない事が分かります。 こうして全てのmallocの前にmstrが有効なアドレスを指しておらず、 最終回の呼び出しではmallocが回避され 全部のmallocされた領域が確実にfreeされることが分かります。 「メモリリーク」はありません。 また、freeしたメモリを再度mallocする前にアクセスする 「アクセス違反」の心配も有りません。 安心して使えるのではないでしょうか?
その他の回答 (6)
- D-Matsu
- ベストアンサー率45% (1080/2394)
main()の流れの方を見ればすぐにわかりますが、 > result = strtok("//123//,45/,678,9/","/,"); > r1 = strtok(NULL, s2); > r2 = strtok(NULL, s2); > r3 = strtok(NULL, s2); > r4 = strtok(NULL, s2); result,r1,r2,r3,r4「それぞれに」malloc()で確保しているのでstrtok()内でfree()してしまうとこの流れの終了後にr4以外の領域は解放済みになってしまいます。 つまり、strtok()内で正常動作を保ちつつ解放する手段は「ありません」。
- Lchan0211
- ベストアンサー率64% (239/371)
No.5さんの案通りにstrtok()の先頭でmstrをfreeした場合、 質問のmain関数の printf("%s\n",result); の実行時点でresultはfreeされていますから 「アクセス違反」となる可能性があります。 それだけでなく、この自作strtok()内のtok変数もmstrと同じ malloc領域をポイントしていますから、そこがfreeされた後、 str1 = tok; strspn(str1, s2); が実行されて「アクセス違反」となる可能性があります。 他の人が言われている通り、mallocで確保した領域を returnで渡したのなら、呼び出し元のmain関数でfreeするしか ありません。
- D-Matsu
- ベストアンサー率45% (1080/2394)
「strtok()の自作」と言うからにはstring.hのstrtok()と置き換えてそのまま使えるのが前提だと思いますが、既に言われている通り標準関数のstrtok()は ・最初に与えた第一引数の文字列を破壊しながらトークン分割を行う(ので文字列リテラルを渡せるかどうかは環境依存、不可能な環境が圧倒的に多い) ・上記性質からstatic変数を内部に持っておけばmalloc()を使う必要はない、というか変に使うことで実装をややこしくしているだけ です。 動作的にも、分割できない場合には本来「残りの全て」を返さなければならないところでNULLを返している(NULLが帰るのは「残りの文字列がない」場合)とか標準関数との互換がなく、free()の位置を考える以前の問題です。 で、このコードでfree()を追加するならmain()の中で、戻り値をfree()します。 free()は引数がNULLなら何もしないので、malloc()で確保済みのアドレスかNULLしか受け取らないこの実装で条件判断が要るかというと……?
- anicicle
- ベストアンサー率36% (129/356)
最近、あちこちのプログラムQAで同じような質問があるのは学校の課題か何かだろうか? http://soudan1.biglobe.ne.jp/qa5839814.html の時も書いたが、ANSI準拠ならmallocは使用しない。 ANSI「風」でmallocを利用するとしても、returnでmallocで確保している領域を返している限り、freeできる個所はない。 それと >いまいち理解できません・・・。 に対して助言。 まず、「自分で」ソースにコメントをふってみる。 頭だけでは理解できない部分も理解できる可能性がある。 そして、質問する際は「コメントを追記した」ソースを提示し「理解があっているか」も聞く。
- Lchan0211
- ベストアンサー率64% (239/371)
そもそもC標準ライブラリのstrtok()関数は、 malloc()で確保した領域を返却する関数ではありません。 第1パラメータに指定された文字列領域を区切り記号で区切られた 文字列に分割する関数であり、malloc()は使わずに実現します。 したがって、free()も不要です。 (参考ソース) https://research.microsoft.com/en-us/um/redmond/projects/invisible/src/crt/strtok.c.htm また、第1パラメータには文字列定数は指定できない仕様です。 http://sometime.minidns.net/programming/c/strtok_and_substring.html の「strtok関数の特徴と注意事項」の解説も参考にしてください。 もし、本来のstrtok()と異なる仕様の関数を作りたいのなら、 関数名を変えて、その関数の仕様を説明して質問した方が よいと思います。 (他人にアドバイスを求める時に混乱されないように)
- Tacosan
- ベストアンサー率23% (3656/15482)
この形だと, malloc した領域のアドレスを return で返してるから, strtok の中では free できないのでは?
お礼
丁寧なコメントありがとうございます!! ぜひ参考にさせていただきます!