【掲示板ご利用上の注意】

 ※題名は具体的に!
 ※学校の課題の丸投げ禁止!
 ※ソースの添付は「HTML変換ツール」で字下げ!
 ※返信の引用は最小限に!
 ※環境(OSとコンパイラ)や症状は具体的に詳しく!
 ※マルチポスト(多重投稿)は謹んで!

 詳しくはこちら



 本当はこんなに大きく書きたくはないのですが、なかなか守っていただけなくて…。
 守ってくださいね。お願いします。(by管理人)

C言語ソース⇒HTML形式ツール   掲示板2こちら


管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.19845

動的メモリ管理
投稿者---ぷらすぷらむ(2005/02/11 14:44:07)


はじめまして。
いまCSVファイルのデータを分割して取得するプログラムを作成しています。(環境:windowsXP/VC++ 6.0)
CSVファイルのデータ
11,22,33,44,55,66,77,88,99,00,12,34,56,78,90[CRLF]
を取得して","ごとに分割したいのですが、データ長およびデータ数が不定なため、メモリを動的に確保して処理するように考えました。

処理としては、
1データを、動的にメモリを確保したdataに格納する。
2データの","をNULLに置き換える
3同時に各要素の先頭アドレスを管理変数dtadminに格納していく
(データ数が不定なため、管理変数dtadminもメモリを動的に確保する)
4データを処理する際は管理変数dtadminを利用してデータにアクセスする
を考えました。

プログラムを作成して実行すると、以下の問題が発生し、解決できません。
・分割したデータにゴミ(不定値)が入る(→デバッガにより確認)
11 22 33 44 55 66 77 ゴミ 88 99 00 12 34 56 78 ゴミ 90
・分割したデータを数値に変換しようとするとプログラムが強制終了する

アドバイスお願いします。

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>

int main()
{
  int i, idata;
  char seps[] = ",";
  char* rtnchr;
  FILE  *fp;

  char* data;
  int  dtsize;
  char**  dtadmin;
  int  dtadmnum;

  fp = fopen("data.csv", "r");

  // メモリ領域を動的に確保
  dtsize = 100;
  data = malloc(dtsize);
  dtadmnum = 20;
  dtadmin = malloc(dtadmnum);

  // データを取得、データを分割する
  rtnchr = fgets(data, dtsize, fp);
  fclose(fp);

  *dtadmin = data;  // 先頭アドレスをセット
  dtadmin++;
  *dtadmin = strtok(data, seps);  // トークン切出し
  while(NULL != *dtadmin) {
    dtadmin++;
    *dtadmin = strtok(NULL, seps);
  }

  // データを数値に変換
  *dtadmin = data;
  for (i = 0 ; *dtadmin != NULL; i++, dtadmin++) {
    idata = atoi(*dtadmin);
  }

  free(data);
  free(dtadmin);

  return(0);
}



この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:動的メモリ管理 19846 南野骨茶 2005/02/11 16:11:41
<子記事> Re:動的メモリ管理 19848 しっぽ 2005/02/11 16:34:42


No.19846

Re:動的メモリ管理
投稿者---南野骨茶(2005/02/11 16:11:41)


>・分割したデータにゴミ(不定値)が入る(→デバッガにより確認)
>11 22 33 44 55 66 77 ゴミ 88 99 00 12 34 56 78 ゴミ 90

malloc()に渡している100や20という値の意味合いがよくわかりません。
が、ゴミが入っているのが20バイトごとのようですので、何か関係は
あるのでしょう。

また、fopen()やmalloc()に失敗した場合のことも考えましょう。
そうする方が、より堅牢なプログラムになります。



この投稿にコメントする

削除パスワード

No.19848

Re:動的メモリ管理
投稿者---しっぽ(2005/02/11 16:34:42)


下記の2点は重症です。

(1)
char **dtadmin;
dtadmin = malloc(dtadmnum);

(2)
dtadmin++;
free(dtadmin);


>はじめまして。
>いまCSVファイルのデータを分割して取得するプログラムを作成しています。(環境:windowsXP/VC++ 6.0)
>CSVファイルのデータ
>11,22,33,44,55,66,77,88,99,00,12,34,56,78,90[CRLF]
>を取得して","ごとに分割したいのですが、データ長およびデータ数が不定なため、メモリを動的に確保して処理するように考えました。
>
>処理としては、
>1データを、動的にメモリを確保したdataに格納する。
>2データの","をNULLに置き換える
>3同時に各要素の先頭アドレスを管理変数dtadminに格納していく
>(データ数が不定なため、管理変数dtadminもメモリを動的に確保する)
>4データを処理する際は管理変数dtadminを利用してデータにアクセスする
>を考えました。
>
>プログラムを作成して実行すると、以下の問題が発生し、解決できません。
>・分割したデータにゴミ(不定値)が入る(→デバッガにより確認)
>11 22 33 44 55 66 77 ゴミ 88 99 00 12 34 56 78 ゴミ 90
>・分割したデータを数値に変換しようとするとプログラムが強制終了する
>
>アドバイスお願いします。
>
><pre>#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>

int main()
{
int i, idata;
char seps[] = ",";
char* rtnchr;
FILE *fp;

char* data;
int dtsize;
char** dtadmin;
int dtadmnum;

fp = fopen("data.csv", "r");

// メモリ領域を動的に確保
dtsize = 100;
data = malloc(dtsize);
dtadmnum = 20;
dtadmin = malloc(dtadmnum);

// データを取得、データを分割する
rtnchr = fgets(data, dtsize, fp);
fclose(fp);

*dtadmin = data; // 先頭アドレスをセット
dtadmin++;
*dtadmin = strtok(data, seps); // トークン切出し
while(NULL != *dtadmin) {
dtadmin++;
*dtadmin = strtok(NULL, seps);
}

// データを数値に変換
*dtadmin = data;
for (i = 0 ; *dtadmin != NULL; i++, dtadmin++) {
idata = atoi(*dtadmin);
}

free(data);
free(dtadmin);

return(0);
}
</pre>



この投稿にコメントする

削除パスワード

No.19885

Re:動的メモリ管理
投稿者---ぷらすぷらむ(2005/02/13 12:35:09)


ぷらすぷらむです。

アドバイスありがとうございます。
アドバイスをあまりよく理解することができず上手く利用することができませんでしたが、自分なりに調べて、以下のように修正してみました。(指摘してもらったエラー処理は、今回割愛しております)
しかし、どうしても問題を解決することができません。
もう少し考えてみます。

修正点
・dtadminのfree時に値が変わらないようにworkを追加して使用

問題点
・idataにほしい数値が入らない
ほしい数値:11 22 33 44 55 66 77 88 99 00 12 34 56 78 90
実際の数値: 0 0 0 33 44 55 66 77 88 99 00 12 34 56 78 90
・freeで失敗する(落ちる)
※データにゴミが入ることはなくなりましたが、なぜなくなったかは理解できていません。


#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>

int main()
{
  int i;
  int idata[50];
  char seps[] = ",";
  char* rtnchr;
  FILE  *fp;

  char* data;
  int  dtsize;
  char**  dtadmin;
  char**  work;
  int  dtadmnum;

  fp = fopen("data.csv", "r");

  // メモリ領域を動的に確保
  dtsize = 100;
  data = malloc(dtsize);
  dtadmnum = 20;
  dtadmin = malloc(dtadmnum);

  // データを取得、データを分割する
  rtnchr = fgets(data, dtsize, fp);
  fclose(fp);

  work = dtadmin;
  *work = data; // 先頭アドレスをセット
  work++;
  *work = strtok(data, seps); // トークン切出し
  while(NULL != *work) {
    work++;
    *work = strtok(NULL, seps);
  }

  // データを数値に変換
  work = dtadmin;
  for (i = 0 ; *work != NULL; i++) {
    idata[i] = atoi(*work);
    work++;
  }

  free(data);
  free(dtadmin);

  return(0);
}




この投稿にコメントする

削除パスワード

No.19886

Re:動的メモリ管理
投稿者---ぷらすぷらむ(2005/02/13 13:04:34)


ぷらすぷらむです。

自己レスです。

データ取得については以下※1を削除することで解決しました。(なぜかは考え中)
freeで失敗するのは、以下※2を20→100とすることで解決しました。
dataは実データを格納するため"100"とし、dtadminはNULL分割した実データの各カラムの先頭アドレスを格納するため"20"(カラム個数+α)でいいのかなと思ったのですが、違ったみたいです。

最終的には結果を取得することはできましたが、やりたいこととはちょっと違う気がしてなりません。なぜでしょう???

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>

int main()
{
  int i;
  int idata[50];
  char seps[] = ",";
  char* rtnchr;
  FILE  *fp;

  char* data;
  int  dtsize;
  char**  dtadmin;
  char**  work;
  int  dtadmnum;

  fp = fopen("data.csv", "r");

  // メモリ領域を動的に確保
  dtsize = 100;
  data = malloc(dtsize);
//<※2↓を修正>
  dtadmnum = 100;
  dtadmin = malloc(dtadmnum);

  // データを取得、データを分割する
  rtnchr = fgets(data, dtsize, fp);
  fclose(fp);

  work = dtadmin;
//<※1↓これを消した>
//  *work = data; // 先頭アドレスをセット
//  work++;
  *work = strtok(data, seps); // トークン切出し
  while(NULL != *work) {
    work++;
    *work = strtok(NULL, seps);
  }

  // データを数値に変換
  work = dtadmin;
  for (i = 0 ; *work != NULL; i++) {
    idata[i] = atoi(*work);
    work++;
  }

  free(data);
  free(dtadmin);

  return(0);
}



この投稿にコメントする

削除パスワード

No.19888

Re:動的メモリ管理
投稿者---あかま(2005/02/13 13:16:52)


>dataは実データを格納するため"100"とし、dtadminはNULL分割した実データの各カラムの先頭アドレスを格納するため"20"(カラム個数+α)でいいのかなと思ったのですが、違ったみたいです。
ポインタのサイズは大抵4バイト。
ポインタを20個欲しいなら、4*20で80バイト必要。

mallocを使うときは普通malloc(sizeof(型名)*個数);のような形で書きます。
この場合はmalloc(sizeof(char *)*20);


この投稿にコメントする

削除パスワード

No.19887

Re:動的メモリ管理
投稿者---しっぽ(2005/02/13 13:14:09)


私が指摘した(2)の問題は修正されているようです。
(1) については
dtadmin = malloc(dtadmnum * sizeof(char *));
にすべきだということです。




この投稿にコメントする

削除パスワード

No.19906

(解決)Re:動的メモリ管理
投稿者---ぷらすぷらむ(2005/02/14 09:01:34)


ぷらすぷらむです。

なるほど、領域を20個分取っていたつもりが、20/4=5個分しか取れていなかったわけですね。

皆さんありがとうございました。


この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧