malloc関数(strtok関数の自作版)につきまして分からないことがあります。
以下のプログラムにmallo関数がフリーする最適な位置を明示しなさいといわれました。
文字が分離した時にfreeすると助言されたのですが
いまいち理解できません・・・。
条件式の中で使用するともいわれていました。(おそらくif文・・・。)
色んな意見を参考にしたいので詳しい方助言のほうよろしくおねがいします。
なおプログラムはほかの箇所を変更したり、他の場所でもmalloc関数を使用することが認められています。
またfreeする場所はメイン関数ではなくあくまでもstrtok関数の中で宣言するようです。
よろしくお願いします。
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
main(){
char* s2 = ",/";
char* result;
char* r1;
char* r2;
char* r3;
char* r4;
result = strtok("//123//,45/,678,9/","/,");
r1 = strtok(NULL, s2);
r2 = strtok(NULL, s2);
r3 = strtok(NULL, s2);
r4 = strtok(NULL, s2);
printf("%s\n",result);
printf("%s\n",r1);
printf("%s\n",r2);
printf("%s\n",r3);
printf("%s\n",r4);
return;
}
char *strtok(char *s1, const char *s2)
{
int i,len;
char *str1, *str2 , *str3;
static char *tok ;
static char* mstr;
if(s1 != NULL) {
str1 = s1;
}
else {
str1 = tok;
}
str2 = str1 + strspn(str1, s2); /* strspnを利用 */
if (*str2 == '\0') {
return (NULL);
}
len = 1;
i = 0;
while(*(str2 + i) != '\0'){
len++;
i++;
}
mstr = (char*)malloc(sizeof(char)*len);
if(mstr == (NULL)) {
return 0;
}
i = 0;
while(*(str2 + i) != '\0'){
*(mstr + i) = *(str2 + i );
i++;
}
*(mstr + i ) = '\0';
str3 = mstr + strcspn(mstr, s2); /* strcspnを利用 */
if (*str3 != '\0'){
*str3 = '\0';
str3 = str3 + 1;
}
tok = str3;
return (mstr);
}
No.5ベストアンサー
- 回答日時:
簡単な問題です。
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する前にアクセスする
「アクセス違反」の心配も有りません。
安心して使えるのではないでしょうか?
No.7
- 回答日時:
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()内で正常動作を保ちつつ解放する手段は「ありません」。
No.6
- 回答日時:
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するしか
ありません。
No.4
- 回答日時:
「strtok()の自作」と言うからにはstring.hのstrtok()と置き換えてそのまま使えるのが前提だと思いますが、既に言われている通り標準関数のstrtok()は
・最初に与えた第一引数の文字列を破壊しながらトークン分割を行う(ので文字列リテラルを渡せるかどうかは環境依存、不可能な環境が圧倒的に多い)
・上記性質からstatic変数を内部に持っておけばmalloc()を使う必要はない、というか変に使うことで実装をややこしくしているだけ
です。
動作的にも、分割できない場合には本来「残りの全て」を返さなければならないところでNULLを返している(NULLが帰るのは「残りの文字列がない」場合)とか標準関数との互換がなく、free()の位置を考える以前の問題です。
で、このコードでfree()を追加するならmain()の中で、戻り値をfree()します。
free()は引数がNULLなら何もしないので、malloc()で確保済みのアドレスかNULLしか受け取らないこの実装で条件判断が要るかというと……?
No.3
- 回答日時:
最近、あちこちのプログラムQAで同じような質問があるのは学校の課題か何かだろうか?
http://soudan1.biglobe.ne.jp/qa5839814.html
の時も書いたが、ANSI準拠ならmallocは使用しない。
ANSI「風」でmallocを利用するとしても、returnでmallocで確保している領域を返している限り、freeできる個所はない。
それと
>いまいち理解できません・・・。
に対して助言。
まず、「自分で」ソースにコメントをふってみる。
頭だけでは理解できない部分も理解できる可能性がある。
そして、質問する際は「コメントを追記した」ソースを提示し「理解があっているか」も聞く。
No.2
- 回答日時:
そもそもC標準ライブラリのstrtok()関数は、
malloc()で確保した領域を返却する関数ではありません。
第1パラメータに指定された文字列領域を区切り記号で区切られた
文字列に分割する関数であり、malloc()は使わずに実現します。
したがって、free()も不要です。
(参考ソース)
https://research.microsoft.com/en-us/um/redmond/ …
また、第1パラメータには文字列定数は指定できない仕様です。
http://sometime.minidns.net/programming/c/strtok …
の「strtok関数の特徴と注意事項」の解説も参考にしてください。
もし、本来のstrtok()と異なる仕様の関数を作りたいのなら、
関数名を変えて、その関数の仕様を説明して質問した方が
よいと思います。
(他人にアドバイスを求める時に混乱されないように)
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# バイナリファイルをコピーするのにかかる時間を測りたいのですが実行するとFatel error:gli 2 2022/11/03 01:10
- C言語・C++・C# c言語でユーザ関数を利用して入力された文字列を反転させるプログラムを作りたいです。 3 2023/01/29 19:47
- C言語・C++・C# C言語で再起関数とポインタを用いて文字列反転をする方法がわかりません。 4 2023/04/29 20:32
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# const char** p;のとき、free(p)でC4090エラーとなるのはなぜですか 3 2023/03/31 16:28
- 大学・短大 C言語線形リストの問題です 3 2022/12/22 00:45
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
newしないオブジェクトについて
-
スタック破壊の上手な見つけ方...
-
ヒープメモリの解放について
-
ヒープ領域の限界値設定
-
DLLのマルチスレッドの動作につ...
-
mallocで確保するメモリの領域...
-
アンマネージド関数でのメモリ...
-
プログラムが途中で強制終了し...
-
C言語の質問です。 以下の命令...
-
DLLで同じメモリ領域を参照する...
-
malloc でのメモリ取得状況の可...
-
x64環境で連続4GB以上のメモリ...
-
C++のnewで確保したメモリーの...
-
allocってなんですか?
-
freeで開放される範囲
-
dllを使用しVB側に文字列...
-
malloc呼び出し時のセグメンテ...
-
ヒープの実際の限界値は?
-
void*型のデータサイズ
-
大容量の静的な確保の限界値
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
allocってなんですか?
-
newしないオブジェクトについて
-
c言語のポインタへの文字列入力...
-
スタック破壊の上手な見つけ方...
-
ヒープメモリの解放について
-
C++のnewで確保したメモリーの...
-
指定したメモリアドレスの値の...
-
void*型のデータサイズ
-
配列の添え字の最大数とは?
-
DLLのマルチスレッドの動作につ...
-
malloc呼び出し時のセグメンテ...
-
Accessで、メモリを開放するタ...
-
HEAP に関すること
-
ヒープ領域の限界値設定
-
大容量の静的な確保の限界値
-
mallocで確保するメモリの領域...
-
64ビットと32ビットの違い
-
構造体でchar name[]と*nameの...
-
画像を読み込む配列の確保。
-
newでrealloc?
おすすめ情報