• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:C言語 ポインタ型引数の呼び出しについて2)

C言語のポインタ型引数の呼び出しについて

このQ&Aのポイント
  • C言語のポインタ型引数の呼び出しについての処理速度向上の検証方法について質問です。
  • 私はVB6でCSVを処理しているのですが、処理速度が遅いためC言語に変更してみたいと思っています。
  • strtokを使って処理するとデータが正しく取得できないため、他の方法を探しています。メモリリークの問題も解決したいです。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

> strdupの後メモリを開放しているつもりなのですが問題あるのでしょうか? 関係ないところをstrdupで確保したメモリ領域だと思ってfreeさせてますね。 GetCSV関数の中でif ((*pBuf = strpbrk(q,",")) != 0) *(*pBuf)++ = 0;という箇所がありますが、これによってsplit関数の*strBuffの値が書き換えられています。つまり、これが行われたあとにfree(*strBuff);してもメモリアロケータが知らないポインタをfreeしてほしいと申請しているわけなので、strdupで作られた領域はfreeされません。 正常にfreeしたいならstrdupしてからGetCSV関数を呼ぶまでの間に*strBuffのコピーをとっておく必要があります。 しかし、freeできるようになってもさらに問題があります。 ary[...]の指している値はstrdupしたメモリ領域を指しているので、strdupした領域をfreeしてしまうとaryの指している領域が無意味になってしまいます。多くの場合はメモリがすぐに再利用されないので問題に気づかないかもしれませんが、これはのちのちに見つけにくいバグになります。 そもそも、メモリの確保や開放をどこかの関数で勝手にやるとバグの温床になります。確保したところで開放するというのはよいとは思いますが、確保したメモリ領域を呼び出し元が使う場合はこの実装を避けた方がよいでしょう。つまり、splitの呼び元でstrdupしてからsplitの引数として渡す方がよいでしょう。 そうすると、例えばこんなプログラムになるでしょうか。 /* * CAUTION: May change the argument 's'. */ int split(char *ary[], const int ary_nelms, char *s) { int len = 0; for (len = 0; len < ary_nelms; len++) { if ((ary[len] = GetCSV(&s)) == NULL) break; } return len; } int main(void) { char str[] = "a,b,c,,e", *tmp, *ary[BUF_SIZE]; int i, len; tmp = strdup(str); len = split(ary, BUF_SIZE, tmp); for (i = 0; i < len; i++) printf("%s\n", ary[i]); free(tmp); return 0; } あるいは、もし、splitの引数が質問で示された形に決まっているとしたら、こんな感じで作るでしょうか。この場合、aryのサイズが小さすぎるとメモリを破壊しますし、split二度呼び出すと前回のsplitの結果が失われ、無意味なものになってしまいます。 static char *csv_string = NULL; int split(char *ary[], char *s) { int len, lsize; char *csv_buff; if (csv_string != NULL) free(csv_string); csv_string = csv_buff = strdup(s); lsize = strlen(s); for (len = 0; len < lsize; len++) { if ((ary[len] = GetCSV(&csv_buff)) == NULL) break; } return len; } 自分だったら可能な限り前者の実装にしますね。

rai_4000
質問者

お礼

回答ありがとうございます。 丁寧な説明を記述いただいた上、ロジックまで記述いただきありがとうございました。 始めの案で処理したところメモリリークはしなくなりました。 大変助かりました、どうもありがとうございました。

その他の回答 (2)

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.3

> VB6でCSVをリードして処理しているのですが、処理速度が遅いため > I/OをしているところをCに変更して処理速度 その目的なら、まずはVBの方のプログラムを見直す方が効果的だと思います。 特に、質問にあるようなメモリの確保と解放を繰り返すようなものだと、 大きな効果は期待できません (メモリの確保と解放は比較的時間のかかる処理です) 例えば ・VB6にsplitという関数があります。CSVの各要素の分解するのに有効です。 http://jeanne.wankuma.com/tips/vb6/string/split.html ・変数を全部Variant型にしてたりしませんか?

rai_4000
質問者

お礼

回答ありがとうございます。 Variant型にはしていないのですが、VBの方も無駄な処理がないか調べて見ます。 貴重なご意見ありがとうございました。

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.1

>char*strBuff[BUF_SIZE]; ポインターの配列を定義していて、 >*strBuff = strdup(s); >lsize = strlen(*strBuff); >free(*strBuff); その配列の先頭要素だけをさわっている理由を教えてください。

rai_4000
質問者

お礼

ご指摘ありがとうございます。 色々試しているうちに意味のないロジックになっていました。 以後気をつけます。

関連するQ&A

専門家に質問してみよう