• 締切済み

しつもんです

cygwinでc言語を使っています。同じディレクトリに na.txtというテキストファイルがあるとします。 そのファイルには 2,3,4,5,6 7,8,9,10,11 12,13,14,15,16 と5つずつカンマ区切りのデータが入力されているとします。このファイルのデータを読み込んで二次元配列に入れたいです。この例でいえば、5つのデータで3行あるので a[3][5]の配列が必要でそれにa[0][0]=2 a[0][1]=3, .... a[2][4]=16と入れていきたいです。 ただ、ファイルが何行あるのかわからないとします。つまりこの場合なら3行あるのですが、それはわからないとします。 たぶんファイルポインタを用意するんだと思うですがどうしてもよくわかりません。教えてください

みんなの回答

  • matsu-td
  • ベストアンサー率31% (5/16)
回答No.4

参考になるかどうか。。。 BLUEPIXYさんのおっしゃる「vectorみたいな機構」みたいなやつを書いてみました。main関数の中のforループ回数をいろいろと変えて試して見て下さい。 余談ですが、ここでの見栄えを良くするために、全角スペースを使っています。コピペする場合は注意して下さいね。 #include <stdio.h> #include <malloc.h> struct MyData {   MyData* prev;    // 前のアイテムへのポインタ   MyData* next;    // 次のアイテムへのポインタ   int   data;    // データ }; /// /// 引数itemで指定されたアイテムの次に、 /// 新しいアイテムを追加します。 /// MyData* AddItem(MyData* item, int data) {   // メモリを確保する   MyData* pItem = (MyData*)malloc(sizeof(MyData));   // アイテムが指定されている場合   if(item != NULL)   {     // 次のアイテムとして、今新しく追加されたアイテムをセット     item->next = pItem;   }   // メモリが正常に確保できなかった場合   if(pItem == NULL)   {     // ここで抜ける     return NULL;   }   // 新しく追加されたアイテムのプロパティを設定   pItem->prev = item;   // 前のアイテムへのポインタ   pItem->next = NULL;   // 次のアイテムへのポインタ   pItem->data = data;   // データ   // 新しく追加されたアイテムのポインタを返す   return pItem; } /// /// 全てのアイテムを削除します。 /// void DeleteAll(MyData* pFirst) {   while(pFirst)   {     // 次のアイテムへのポインタを取得     MyData* pNext = pFirst->next;     // アドレスをデバッグ出力     printf("free(%p)\n",pFirst);     // メモリを解放     free(pFirst);     // ポインタを次のアイテムに更新     pFirst = pNext;   } } /// /// メイン関数 /// void main() {   int i;   MyData* pCurrent = NULL;   MyData* pFirst = NULL; /// /// リストの作成 ///   // 100回ループ(回数は変更可)   for(i = 0; i < 100; i++)   {     // データとしてiの値を持つアイテムを追加する     pCurrent = AddItem(pCurrent, i);     // 最初のアイテムのポインタが初期化されてない場合     // (1回目のみ)     if(pFirst == NULL)     {       // 最初のアイテムのポインタを保存       pFirst = pCurrent;     }     // データ追加に失敗した場合     if(pCurrent == NULL)     {       // ループを抜ける       break;     }   } /// /// リストの内容の確認 ///   // 最初のアイテムのポインタを取得   pCurrent = pFirst;   do   {     // アイテムの内容をデバッグ出力     printf("[%p] data = %d\n",pCurrent, pCurrent->data);     // 次のアイテムのポインタを取得     pCurrent = pCurrent->next;   } while(pCurrent); /// /// リストの削除 ///   // 全てのアイテムを削除(メモリ解放)   DeleteAll(pFirst); }

すると、全ての回答が全文表示されます。
  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.3

#2>正直なにをいっているのか理解できないです #2の方針でのプログラムのサンプルを作ってみました。 あんまり、参考にならないところもあるかもしれません。^^; ------------------------------------------------------------------ #include <stdio.h> #include <string.h> #include <stdlib.h> int countComma(const char *str){ int count=0; const char *pos; for(pos=str;NULL!=(pos=strchr(pos, ','));pos++){ count++; } return count; } int main(void){ FILE *fp; char buff[64]; char *p; int count=0; int (*a)[5], *wk; int i,j; fp=fopen("na.txt","r");//カンマで区切られた1行に5個のデータがあるファイル while(NULL!=(fgets(buff,64,fp))){ count+=countComma(buff)+1;//コンマがn個あるときデータはn+1個 } // printf("データ数:%d\n",count); if(NULL==(a=(int (*)[5])calloc(count/5, sizeof(int [5])))){ printf("メモリが確保できません\n"); return -1; } rewind(fp); wk=(int*)a; while(NULL!=(fgets(buff,64,fp))){ p=buff; while(1){ *wk++=atoi(p); if(NULL==(p=strchr(p, ','))) break; p++; } } fclose(fp); for(i=0;i<count/5;i++){ for(j=0;j<5;j++) printf("a[%d][%d]=%d ",i,j,a[i][j]); printf("\n"); } return 0; }

すると、全ての回答が全文表示されます。
  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.2

2次元配列をあらかじめ余分をみて確保するのではなく、動的に確保したいということでしょうか? C言語では、動的に2次元配列を確保するような宣言ができないので、 callocとかを使ってメモリを確保し、そのポインタを使って配列アクセスみたいな形になるかと思います。 その時の確保するサイズが判らないので、 いったん、ファイルを読み出して、必要な要素の数を数えて それで確保し 2回目の読み出しで、実際に値をセットするようなことをすればいいかと思います。 2度読みするのでムダみたいですがしょうがないです。 C++でいうvectorみたいな機構(実行時にメモリの確保や拡張を自動的にやってくれるようなの)を実装すると楽ですが、そういうのが必要なのかどうかは、処理する人の考え次第。

benzousandazoyo
質問者

補足

すいません、正直なにをいっているのか理解できないです。どうしてもこれらを格納するためのプログラムがわからないのです。

すると、全ての回答が全文表示されます。
  • yyamagu
  • ベストアンサー率40% (21/52)
回答No.1

配列を使う方法もいろいろありますが、こういう場合、配列は使わないのが普通です。 リスト構造を覚えたほうがよいですよ。

参考URL:
http://www005.upp.so-net.ne.jp/h-masuda/cl/CAlgo/list02.html
benzousandazoyo
質問者

補足

リスト構造を大学でならったんですが、よくわからないです、、、、。

すると、全ての回答が全文表示されます。

関連するQ&A