- ベストアンサー
メモリ2(ポインタ編)
#include "stdafx.h" #include <ctype.h> #include <string.h> #include <stdlib.h> int check(int a[100], int n); typedef struct { char *number; char *class_type; char *name; char *subject; } my; int main(int argc, char* argv[]) { FILE *fp; int field = 0, line = 0; char buf[1000], *str; char bufG[1111]; int i, len; my *o; if((fp=fopen("test3.csv","r"))==NULL){ printf("ファイルが開けません"); } while(fgets(buf,1000,fp) !=NULL){ str=buf; len = strlen(buf); o = (my *) calloc(len + 1, sizeof(my *)); while(*str != '\0'){ if(*str != ','){ for(i = 0; *str != ',' && *str != '\0' ; i++){ if(*str == '\n'){ } else{ bufG[i] = *str; } str++; } bufG[i] = '\0'; switch(field){ case 0: o[line].number = bufG; break; case 1: o[line].class_type = bufG; break; case 2: o]line].name = bufG; break; case 3: o[line].subject = bufG; } field++; } else{ str++; } } line++; field = 0; } fclose(fp); return 0; } 固定なのがいけないといわれたのでこのように 変更しました。もちろん上手く動かないわけですが 原因を教えて下さい。 ちなみにエラーはo[0].numberが国語とかになってたり ちゃんとアクセスができません。
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
必要最低限のメモリを確保し、メモリがある限り何行あっても動くのを作ってみた。 #include <stdio.h> #include <ctype.h> #include <string.h> #include <stdlib.h> typedef struct { char *number; char *class_type; char *name; char *subject; } my,*pmy; /*すべての行とリストを開放する*/ void FreeAll(pmy Data,int Max) { int i; pmy p; if(!Data) return; p = Data; for (i = 0;i < Max;i++) { if(p->number) free(p->number);/*行データ開放*/ p++; } free(Data);/*リスト本体開放*/ } /*1行分読んで、1行分のメモリを確保し、読んだ項目データをリストに加える 成功なら1を EOFなら0を エラーが出たなら-1を返す*/ int ReadLine(FILE *fp,pmy DataPtr) { char buf[1000],*p; if(!fgets(buf,1000,fp)) return 0; if(buf[strlen(buf)-1] != '\n') {/*末尾が改行じゃないなら、まだ行が続いてる*/ printf("行が長過ぎます。"); return -1; } else { buf[strlen(buf)-1] = '\0';/*改行を取り除く*/ } p = malloc(strlen(buf) + 1);/*\0分を含めて確保*/ if(!p) { printf("メモリが足りません。"); return -1; } strcpy(p,buf);/*\0までコピー*/ DataPtr->number = strtok(p,",");/*カンマで区切る*/ DataPtr->class_type = strtok(NULL,",");/*カンマで区切る*/ DataPtr->name = strtok(NULL,",");/*カンマで区切る*/ DataPtr->subject = strtok(NULL,",");/*カンマで区切る*/ if(!DataPtr->class_type || !DataPtr->name || !DataPtr->subject) {/*カンマで4項目に区切れない*/ printf("項目が足りません。"); return -1; } return 1; } int main(void) { FILE *fp; int AllocSize,MaxSize,LineNumber,Status,Count; pmy Data,tmpData; /*ここから、読み込み処理*/ fp=fopen("test3.csv","rt"); if(!fp) { printf("ファイルが開けません"); return 256; /*エラーが出たらそれ以上処理を続けない*/ } AllocSize = 0; Data = NULL; LineNumber = 0; while(!feof(fp)) { if(LineNumber >= AllocSize) {/*確保済み件数より多いなら拡張する*/ AllocSize += 100;/*足りなくなったら100件増やす*/ tmpData = (pmy)realloc(Data,sizeof(my) * AllocSize); if(!tmpData) { printf("メモリが足りません"); fclose(fp); FreeAll(Data,AllocSize); return 257; /*エラーが出たらそれ以上処理を続けない*/ } else { Data = tmpData; for(Count = LineNumber;Count < AllocSize;Count++) { Data[Count].number = NULL;/*拡張した未使用のデータはNULLにしておく*/ } } } Status = ReadLine(fp,&Data[LineNumber]); if(Status) LineNumber++; if(Status == -1) { printf("%d行目でエラーが発生しました",LineNumber); fclose(fp); FreeAll(Data,AllocSize); return 258; /*エラーが出たらそれ以上処理を続けない*/ } } fclose(fp); /*MaxSizeに何件読んだかを保持しておく*/ MaxSize = LineNumber; /*読み込み処理、ここまで*/ /*ここから、メインルーチン*/ for(Count = 0;Count < MaxSize;Count++) { printf("番号:%s\n",Data[Count].number); printf("クラス:%s\n",Data[Count].class_type); printf("名前:%s\n",Data[Count].name); printf("教科:%s\n",Data[Count].subject); } /*ここから、終了処理*/ FreeAll(Data,AllocSize); /*終了処理、ここまで*/ return 0; }
その他の回答 (5)
- Tacosan
- ベストアンサー率23% (3656/15482)
「1行読み込むごとに要素を増やしていく」なら realloc するかリンクリストにするくらいだと思う. 以下個人的に気になったことをいくつか: ・ここって calloc を使わないとダメなの? 素直に malloc でいいような気がするんだけど.... ・sizeof のオペランドに型名を入れるのはなんかいや. ・C だと T * と void * は相互に変換可能なのでキャストはなくてもいい>#4.
- phoenix343
- ベストアンサー率15% (296/1946)
#3です 補足ですが callocが返す戻り値はvoid*ですのでキャストする必要があります つまり char *p; p = (char*)calloc(100, sizeof(char)); // '\0'を含め100バイト分確保 という風にしないといけないですね また o = (my *) calloc(len + 1, sizeof(my *)); ですが このlenって一行の文字列の長さですよね 構造体myの長さじゃないですよね? 私でしたら o = (my *)calloc(100, sizeof(my)); という感じでまず100件分確保し、100件を越えるようでしたら 再確保してそこにコピーするようにしますよ?
補足
これから製品を作っていく場合無駄なメモリはとらないようにする とのことでそれじゃダメなようです。20バイトとかしかなかったら80バイト無駄ですから。一行の長さ=構造体の長さだとおもってましたが カンマ省いていましたね。
- phoenix343
- ベストアンサー率15% (296/1946)
http://willcom.okwave.jp/qa5084764.html http://willcom.okwave.jp/qa5087031.html 同じような質問はいったんシメてほしいですねえ。 とりあえず例をいくつか挙げます。 char data[100]; strcpy(data, "sample"); はできますが char *p; strcpy(p, "sample"); はできません。なぜならchar *p;とはただのアドレスを示すもので 実際に格納する文字(char)の配列を確保しているわけではないからです。 この宣言に限らず my *data;とか'*'を使っている宣言はすべて 実体はないと認識してください。 char data[5]; strcpy(data, "sample"); これもダメです('\0'も含めると7文字になるので当然ダメ) char *p; p = calloc(100, sizeof(char)); // '\0'を含め100バイト分確保 strcpy(p, "sample"); これはOK char *p; p = calloc(5, sizeof(char)); // '\0'を含め5バイト分確保 strcpy(p, "sample"); これはNG (7バイト分必要だから) char *p; p = strdup("sample"); // 文字列を複製する。 これはOK(指定した文字列の長さ分メモリを確保して、そこにコピーするから) あと、calloc、strdupなどを使ってメモリを確保した場合は必ずfree関数で解放しましょう。
- trapezium
- ベストアンサー率62% (276/442)
それにcalloc()の位置も悪いです。このデータ構造でやるならば、ループの前に適当な件数でmalloc()し、ループ内で現在のデータ件数がmalloc()した件数を超えたら、realloc()するようにするか、リスト構造にするかでしょう。 また、o[line].number = bufG;などとしてるのはだめです。ここもstrdup()、要はbufGの文字数分malloc()してstrcpy()する関数にでも置き換えないと、bufGは次のループで上書きされるし、なによりbufGはローカル変数。
- asuncion
- ベストアンサー率33% (2127/6289)
>o = (my *) calloc(len + 1, sizeof(my *)); my型「の実体」を所定の数だけ確保して、 その先頭アドレスをo(もっと適切な名前の方がいいと思います)に 格納したいのですよね? だとすると、 sizeof(my *) は、ひじょうにまずいです。
補足
ありがとうございました。