• ベストアンサー

構造体の動的メモリについて

#include <stdio.h> #include <stdlib.h> #include <string.h> #define NUM 10 /*生徒数*/ typedef struct data { int num; /*従業員番号*/ char name[16]; /*名前*/ int jap; /*国語の点数*/ int math; /*数学の点数*/ }data; int main(void) { data test[NUM]; /*生徒のデータ*/ FILE *fp; /*ファイル操作用*/ int i; /*配列インデックス*/ int count; /*データ分割用*/ char s[100]; /*データ読み込み用*/ char *token; /*データ分割用*/ char *data[6]; /*分割データ保存用*/ fp = fopen ("data1.txt","r");        for (i=0; i<NUM; i++){ fgets (s, sizeof(s), fp); /*dataファイルから1行読み込み*/ token = strtok(s, ","); /*読み込んだデータを","で分割する*/ count=0; while (token != NULL){ data[count] = token; /*分割したデータを配列へ入れる*/ token = strtok(NULL,","); count++; } test[i].num = atoi(data[0]);       strcpy (test[i].name, data[1]); test[i].jap = atoi(data[2]); test[i].math = atoi(data[3]); } fclose(fp);       } このプログラムを構造体へのポインタの配列で管理するように変えたいのですが、どのように変更すればいいのでしょうか。 条件として、個人データを格納するメモリ領域とポインタの配列のメモリ領域は動的に確保します。 初心者でよくわからないので詳しく教えていただけると助かります。よろしくお願いします。

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

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

こんにちわ。 data * datap, * p; datap = (data *)malloc(sizeof(data) * NUM); /* メモリ確保 */ p = datap; /* 先頭ポインタ取得 */ for(i = 0; i < NUM; i++) { ・・・ p->num = atoi(data[0]); strcpy (p->name, data[1]); p->jap = atoi(data[2]); p->math = atoi(data[3]); p++; } で、いけるんじゃないですか? 構造体のポインタの配列を、わざわざ使う必要も無いと思います。 NUMが可変の場合(ファイル行数によって変わる)、ファイルをまず最後まで読み込み、行数を取得した後で その行数 * sizeof(data)で、mallocすれば、余計なメモリを確保せずに済みます。 これが最善の方法かは、知りません(汗)

その他の回答 (1)

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.1

ポインタの配列を動的に確保しようと思ったら、配列のサイズを確保する前に知る必要があるので、例えば生徒数を読み込むような変更をする必要があると思います。 逆に #define NUM 10 のように固定になっているなら、動的にポインタの配列を確保する必要はなくて、あらかじめ確保すればいいと思います。 さて、配列のサイズが決まれば data **配列 = calloc(size, sizeof(data*)) のように(あるいは、mallocを使って)確保すればいいです。 それぞれの個人データは、読込の度に 配列[counter++]=malloc(sizeof(data)); のようにして確保してそのポインタを配列に格納すればよいです。

関連するQ&A

  • C言語でファイルの内容を strtok関数 を使って数字と文字を分けて

    C言語でファイルの内容を strtok関数 を使って数字と文字を分けて配列に格納したいのですが、うまくできません。 どこが駄目なのかご指摘をお願いします! ファイル内容 20 田中 10 鈴木 #include <stdio.h> #include <string.h> #include <stdlib.h> int main(int argc,char *argv[]) { FILE *fp; char str[256]; char *tp; int i=0; int num[10]; char na[10]; fp=fopen(argv[1],"r"); while(fgets(str,sizeof str,fp)!=NULL); tp = strtok ( str, " " ); while(tp != NULL ) { num[i]=atoi(tp); tp = strtok( NULL," "); if ( tp != NULL ){ na[i]=*tp; } i++; } printf("%d\n%s",num[0],na[0]); printf("%d\n%s",num[1],na[1]); fclose(fp); return 0; }

  • C言語で、ファイルを読み込んで数字と名前に分けて配列に格納に関する質問

    C言語で、ファイルを読み込んで数字と名前に分けて配列に格納に関する質問です! ファイルを開いた後でエラーとなるのですが、何が足りないのでしょうか? ファイル内容 20 田中 10 鈴木 #include <stdio.h> #include <string.h> #include <stdlib.h> int main(int argc,char *argv[]) { FILE *fp; char str[256]; char *tp; int k,i=0; int num[10]; char na[10][20]; fp=fopen(argv[1],"r"); if(fp==NULL){ printf("ファイルを開けません\n"); return 1; }else{ printf("開けた\n"); } while(fgets(str,sizeof str,fp)!=NULL){ tp=strtok(str," "); num[i]=atoi(tp); tp=strtok(NULL," "); strcpy(na[i],tp); i++; } printf("%d\n%s\n",num[0],na[0]); printf("%d\n%s\n",num[1],na[1]); fclose(fp); return 0; }

  • 大規模データの処理について困っています

    掲題の通り、大規模データの処理で悩んでおります。 行ベクトル150万、列ベクトル14のCSVファイルを読み込もうとしているのですが、データ数が10万以上になるとVisual C++が勝手に動作を停止してしまいプログラムを実行することができません。 具体的には、CSVファイル上の4列目に記載されている都道府県名のデータを配列で取り、画面に表示しようと、次のようなプログラムを書いているのですが、 #include<stdio.h> #include<string.h> #include<stdlib.h> #define FNAME "data.csv" #define NUM 10000 int main(void) { FILE *fp; char buf[256]; char *p_token; char dat[14][100]; int n; int i; long int j; char *place[NUM][15]; place[NUM][15]=(char*)malloc(sizeof(char)*NUM); fp = fopen(FNAME,"r"); if (fp == NULL) { printf("ファイルをオープンできませんでした\n"); return 0; } for(j=0;j<=NUM;j++){ fgets(buf,256,fp) !=NULL; p_token = strtok(buf, ","); strcpy(dat[0],p_token); n=1; while(-1) { p_token = strtok(NULL,","); if(p_token == NULL) { break; } strcpy(dat[n],p_token); n++; } if(j!=0) { place[j-1][10]=dat[3]; printf("%s \n",place[j-1][10]); } } fclose(fp); free(place[NUM][15]); return 0; } NUMの数を10万以上にすると、実行してもプログラムが勝手に停止してしまいます。書籍もネットも大分読み漁ったのですが、処置がまったくわからず途方にくれています。 どなたかこうした処理に詳しい方、アドバイスをいただけないでしょうか。よろしくお願い申し上げます。 追記:(1)都道府県名を二次元配列で取っているのは、都道府県名が「大阪府」などと、CSVファイル上で日本語で記載されているからです。 (2)プログラムを実行する際にデータ数を10万以上にすると、CSVファイルをフォルダ内においていなくてもプログラムが停止します(ただしコンパイルエラーはでません)。つまり、メモリの確保に問題があるということになるのでしょうか?

  • 助けてください。困っています

    初めまして 課題でメイン関数(メインメニュー)から呼び出されるサブシステムの「かな氏名検索」を作っているのですが、 自分なりに頑張ってみたものの全くの初心者のため完全に行き詰ってしまい、どこが悪いのかもわからない状態です。 なので、皆さんに教えて頂きたいと思い、 お願いにまいりました。 100人分のデータから「ふりがな」を部分一致で検索して、一致した人のデータを表示させるもので、 探すデータ(社員データ)はカンマ区切りテキストで 社員番号 名前 ふりがな 郵便番号 住所 電話番号 生年月日 入社年月日 役職コード 所属コード 性別 の順に 0523,鈴木一郎,すずきいちろう,105-0000,東京都どこどこ, ,19830101,20090404,01,01,M のように入っています。空白部には半角スペースが入ってます。 現在の自分で作ったソースは #include <stdio.h> #include <string.h> #include "CFUNC.h" #include "display.h" #define NUM 200 typedef struct shain{ char id[5]; char name[21]; char hurigana[31]; char yubin[9]; char jusyo[101]; char tel[14]; int birth; int nyusya; char yakusyokucode[3]; char syozokucode[3]; char seibetsu[2]; }shain; int main(void) { int j; int i; int cnt = 0; shain data[100]; FILE *fp; char *token; char s[NUM]; char mes[25] = "該当する結果がありません"; char mes2[30] = "該当するメニューがありません"; char str[30]; fp = fopen("shain.txt","r"); if(fp==NULL){ printf("ファイルオープンに失敗しました。\n"); return 1; } for(i=0; i<100; ++i){ fgets(s,NUM-1,fp); token= strtok(s, ","); /* str1の分割(1回目) */ strcpy(data[i].id,token); token = strtok(NULL, ","); strcpy(data[i].name,token); token = strtok(NULL, ","); strcpy(data[i].hurigana,token); token = strtok(NULL, ","); strcpy(data[i].yubin,token); token = strtok(NULL, ","); strcpy(data[i].jusyo,token); token = strtok(NULL, ","); strcpy(data[i].tel,token); token = strtok(NULL, ","); data[i].birth =(int)token; token = strtok(NULL, ","); data[i].nyusya=(int)token; token = strtok(NULL, ","); strcpy(data[i].yakusyokucode,token); token = strtok(NULL, ","); strcpy(data[i].syozokucode,token); token = strtok(NULL, "\n"); strcpy(data[i].seibetsu,token); } cls(); /*検索画面*/ printf("*****************************************************\n"); printf("[かな氏名検索]\n"); printf("かなを入力してください:\n"); printf(" \n"); printf(" \n"); printf(" 0:メニューに戻る\n"); printf("*****************************************************\n"); printf("メッセージ:\n"); for(;;){ setLocate(24,3); scanf("%s",str); if(strcmp(str,"0")==0){ break; } for(i=0; i<100; ++i){ if(strncmp(str,data[i].hurigana,5)==0){ cnt++; if(cnt==1){ /*検索結果画面*/ printf("*****************************************************\n"); printf("[かな氏名検索結果]\n"); printf("社員番号 氏名  ふりがな  入社年度  所属  性別 役職\n"); printf(" %s  %s  %5s %d %s %s %s %s\n",  data[i].id,data[i].name,data[i].hurigana,data[i].nyusya,  data[i].syozokucode,data[i].seibetsu,data[i].yakusyokucode); } else{ printf(" %s  %s  %5s %d %s %s %s %s\n", data[i].id,data[i].name,data[i].hurigana,data[i].nyusya, data[i].syozokucode,data[i].seibetsu,data[i].yakusyokucode); } } //見たつからなかった時 if (cnt==0){ setLocate(12,8); printf("%s\n",mes); } //メッセージ setLocate(24,3); scanf("%s",str); setLocate(12,8); printf("%s\n",mes); } } printf("\n"); fclose(fp); return 0; } 所々変なところもあり見にくいと思いますが、 とりあえず単独で検索だけしっかり出来るようにしたいです。 検索は1回だけでなく、何回も出来るようにしたいです。 下手な文章のうえ長文でまことにすいませんが、よろしくお願いします。

  • 構造体配列

    いつもお世話になっています。 今日構造体配列を勉強した際に下の演習をしていたのですが、いまいち基礎的な関数や配列のことやコマンドライン引数のことが理解できていません。一応自分なりにプログラムを書いてみたのですが、エラーがでます。 どなたかアドバイス・ご指摘・解説・例などをおねがいいたします。 問題はコマンドライン引数で人数を指定し,人数分のデータを標準入力(キーボード)から構造体配列に入力し,標準出力(ディスプレイ)に出力するプログラムです。 #include<stdio.h> typedef struct{ char name[100]; int age; double height; double weight; } PERSONAL_DATA1; typedef struct{ int person[10]; }PERSONAL_DATA2; PERSONAL_DATA1 input_personal_data(int num); void output_personal_data(PERSONAL_DATA2 person[10],int num); int main(int argc, char *argv[]){ PERSONAL_DATA1 x; int num,i; char person[10]; if(argc != 2){ printf("Usage ./test number"); return 0; } num=atoi(argv[1]); for(i=0;i<10&&i<num;i++){ person[i]=input_personal_data(); output_personal_data(person,num); return 0; } } PERSONAL_DATA input_personal_data(void){ PERSONAL_DATA1 x; printf("name>"); scanf("%c" ,&x.name); printf("age>"); scanf("%d" ,&x.age); printf("height>"); scanf("%lf" ,&x.height); printf("weight>"); scanf("%lf" ,&x.weight); return x; } void output_personal_data(PERSONAL_DATA2 person[10],int num){ PERSONAL_DATA1 x; printf("name>>%s\n" ,x.name); printf("age>>%d\n" ,x.age); printf("height>>%lf[cm]\n" ,x.height); printf("weight>>%lf[kg]\n" ,x.weight); } またコマンドライン引数で指定したデータファイルAから入力した個人データ集合を構造体配列に取り込み,標準出力(ディスプレイ)と同じくコマンドライン引数で指定したデータファイルBへファイル出力に出力するプログラムというおまけの問題もあります。 こちらの問題のヒントもいただけませんか?

  • c言語で文書を読み込み、単語の出現頻度を教える

    c言語の課題で、与えられた文書を読み込んでその中にある単語の出現頻度を教えるプログラミングを作成しているのですが、うまくいきません。 どこが間違っているのでしょうか?? ファイルの中身は As sweet as coat , green , milk And everyone think coat になっており、求めたい回答は buffer[0]=As count=1 buffer[1]=sweet count=1 buffer[2]=as count=1 buffer[3]=coat count=2 buffer[4]=green count=1 buffer[5]=milk count=1 buffer[6]=And count=1 buffer[7]=everyone count=1 buffer[8]=think count=1 Number of words:9 にしたいのです。 プログラミングは #include<stdio.h> #include<stdlib.h> #include<string.h> #include<ctype.h> typedef struct token_checker{ char * token; int count; }TOKEN_CHECKER; int main(int argc,char* argv[]){ FILE * fp; char buffer[1024]; int numword=0; char * delimiter = " .,"; char * s; TOKEN_CHECKER *t; int j; int i = 0; int flag =0; int find = -1; t=(TOKEN_CHECKER*)malloc(sizeof(TOKEN_CHECKER)*24); if(argc != 2){ printf("Parameter error.\n"); exit(1); } if((fp=fopen(argv[1],"r"))==NULL){ printf("File open error.\n"); exit(1); } while( fgets(buffer,sizeof(buffer),fp)!=NULL){ buffer[ strlen(buffer)-1]='\0'; s = strtok(buffer,delimiter); if(s != NULL){ t[numword].token=s; for(i=0;i<=numword;i++){ if(strcmp(t[numword].token,t[i].token)==0){ t[i].count++ } } printf("buffer[%d]=%s count=%d\n",numword,t[numword].token,t[numword].count); numword++; } while((s=strtok(NULL,delimiter)) != NULL){ t[numword].token=s; for(i=0;i<=numword;i++){ t[numword].count=0; if(strcmp(t[numword].token,t[i].token)==0){ t[i].count++; } } printf("buffer[%d]=%s count=%d\n",numword,t[numword].token,t[numword].count); numword++; } } printf("Number of words:%d\n",numword); free(t); fclose(fp); exit(0); } になっており、実行すると buffer[0]=As count=1 buffer[1]=sweet count=1 buffer[2]=as count=1 buffer[3]=coat count=1 buffer[4]=green count=1 buffer[5]=milk count=1 buffer[6]=And count=1 buffer[7]=everyone count=1 buffer[8]=think count=1 buffer[9]=coat count=1 Number of words:9 となってしまい、coatがカウントされないのです。

  • C言語で半角スペースをデリミタとしたデータファイルを読み込むプログラム

    C言語で半角スペースをデリミタとしたデータファイルを読み込むプログラムを作っています. まず, データのレコード数とフィールドの数をカウントしてその後, double型の2次元配列に必要なメモリ領域をmalloc関数にて確保して, 2次元配列にデータを代入していくという処理をやらせています. とうプログラムをコンパイルして実行した所以下のようなエラーが出てどうやらFreeを2重にしてしまっていることがエラーログから分かるのですが, どこを修正していいかわかりません. どなたかお力を貸していただけないでしょうか? ■ソース■ #include<stdio.h> #include<string.h> #include<malloc.h> #define LINE_MAX_SIZE 5120 int main(void){ __road("test.dat"); } int road(char fname[100]){ __FILE *fp; __char line[LINE_MAX_SIZE]; __char *tp; __char *token=" "; __int rn=0; __int fn; __int i=0; __int j=0; __ __fp=fopen(fname,"r"); ____/* ____ check record number and field number ____*/ ____while(fgets(line,sizeof(line),fp)){ ______ ______tp=strtok(line,token); ______fn=0; ______while(tp!=NULL){ ________tp=strtok(NULL,token); ________fn++; ______} ______rn++; ____} ____//printf("rn=%d fn=%d\n",rn,fn); ____/* ______make 2 dimension array dynamically ____*/ ______double **data; ______ ______data=malloc(sizeof(double *)*rn); ______// then data have 2 pointer to double type ______for(j=0;j<fn;j++){ ________data[j]=malloc(sizeof(double)*fn); ______} ____ ____/* ____ insert data to array ____*/ ____i=j=0; ____while(fgets(line,sizeof(line),fp)){ ______j=0; ______tp=strtok(line,token); ______data[i][j]=atof(tp); ______while(tp!=NULL){ ________j++; ________tp=strtok(NULL,token); ________data[i][j]=atof(tp); ______} ______i++; ____} ____for(i=0;i<rn;i++){ ______for(j=0;j<fn;j++){ ________printf("%f ",data[i][j]); ______} ______printf("\n"); ____} ____/* ____/ free memory for data[][] ____*/ ____if(data){ ______for(j=0;j<fn;j++){ ________if(data[j]){ __________free(data[j]); ________} ______} ______free(data); ____} __fclose(fp); } /* int freeMem(){ } */

  • C言語 strtok

    失礼します。現在こちらでアドバイスを頂きfgetcを使用して配列に格納をすることができたのですが、CSVをカンマ区切りで格納したいのですが上手くいかず困っています。strtokを使用方法をドキュメントを読んでもうまく区切ったものを配列に入れる方法がわかりません 何卒よろしくお願いします。 ソースコード #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include<string.h> #define MAXITEM 1400 int split(char *str, const char *delim, char *outlist[]) { char *tk; int cnt = 0; tk = strtok(str, delim); while (tk != NULL && cnt < MAXITEM) { outlist[cnt++] = tk; tk = strtok(NULL, delim); } return cnt; } int main(void) { FILE *fp; char *fname = "testfile.csv"; char *tp; char *array[1400]; char *test[11][1400]; char c; int i = 0; int n,y; char *tp[1400]; fp = fopen(fname, "r"); if (fp == NULL) { printf("%sファイルが開けません¥n", fname); return -1; } while ((c = fgetc(fp)) != EOF) { array[i] = (char)c; i++; } tp = strtok(array, ","); puts(*tp); while (tp != NULL) { tp = strtok(NULL, ","); if (tp != NULL)puts(tp); } for (n = 0; n < 11; n++) { for (y = 0; y < 1400; y++) { test[n][y] = tp[y]; printf("%c", test[n][y]); } } fclose(fp); return 0; }

  • C言語を使って、ファイルの読み込みをして切り出して2次元配列に格納した

    C言語を使って、ファイルの読み込みをして切り出して2次元配列に格納したいのです。 1,2行目に配列の行の数と列の数が書かれ、3行目から改行とカンマ、スペースで区切られて配列が書かれているテキストを読み込んで2次元配列に格納する。 テキストの例) 4 3 1.1 1.2 1.3 1.4 1.5 2.1 2.2 2.3 2.4 2.5 3.1 3.2 3.3 4.4 3.5 というプログラムを書いています。色々と参考書やサイトを参考してとりあえずの形にはなったと思ったのですが、実行してもエラーが出ます。 どこまで動いているか調べたところ、一行ごとに読み出してそれを切り出して行くところでおかしな事をしてしまっているようですが、どう変えたらいいものか分かりません。 なので、その点のアドバイスと 大きさの分からないファイルから1,2行目を読み出すのはこれで変な動きをする恐れはないか の2点についてヒントでも構わないので、教えてください。 以下、書いたソースです(申し訳ないのですが、文字数の関係で一部省略しています。) #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[] ) { double ** mainhairetu; int size_x, size_y; /* size_x 行 size_y 列 */ int i,j,count=0,count2; int *cut,*temp2; double temp; char s2[] = " ,"; char gyou[10],*num; FILE *fil; while((fgets(gyou,10,fil)) !=NULL){ if(count == 0){ size_x=atoi(gyou); count++; }else if(count ==1){ size_y=atoi(gyou); count=count+1; }else{ break; } } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ここでmallocを使ってcutとmainhairetuの2つの配列を作っています。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ count=0; for (i = 0; i < size_y+2; i++) { mainhairetu[i][0] = atof( strtok( fgets(cut,50,fil),s2 ) ); for (j = 1; j < size_x; j++){ if(count <=1){ count++; break; }else{ mainhairetu[i][j] = atof( strtok( NULL,s2 ) ); } } } for(i=0;i<size_y;i++){ for(j=0;j<size_y;j++){ printf("%f",mainhairetu[i][j]); } printf("\n"); } return(0); }

  • CSVファイルの内容を構造体に格納したい(Unix使用)。

    こんにちは。私は30代の男性です。 「名前」「身長」「体重」が記載されたCSVファイルの内容を読み取って、構造体の「name」「height」「weight」に格納するプログラムを作っています。CSVの内容は A,175,80 B,167,89 C,155,45 ・ ・ ・ Z,188,70 だと仮定します。数値が読み取れているか、下記のように「tp = strtok(file_image, ",\n" );」の前後に「printf("%s\n", file_image);」を置いてみたら、strtok前では全て表示されるのに、strtok後では「ABC」しか表示されません。これでは全てのデータを構造体に格納できないので、困っています。 1.どのようにすれば、数字も取り出せる(読み取れる)でしょうか? 2.効率よく構造体に格納するには、どのようにしたらよいでしょうか? アドバイスを頂ければ幸いです。宜しくお願いいたします。 #include <stdio.h> #include <stdlib.h> #include <limits.h> #include <string.h> int main(int argc, char *argv[]) { FILE *fp = NULL; int rtn = 0; if ((fp = fopen(argv[1], "r")) == NULL) { printf("ファイルオープンに失敗しました。\n"); return 1; } if (argc != 2) { printf("ERROR: オプションの数に過不足があります。\n"); return 1; } rtn = change_csv(fp); return 0; } int change_csv(FILE *fp) { int i; int j; char file_image[256]; /* 読み込んだ先のメモリの領域 */ char *tp; for (i = 0; i <= 256; i++) { if (fgets(file_image, 256, fp) == NULL) { if (ferror(fp) != 0) { printf("ERROR: 読み込みに失敗しました。\n"); return 1; } } if (feof(fp) != 0) { break; } printf("%s\n", file_image); tp = strtok(file_image, ",\n" ); printf("%s\n", file_image); } fclose(fp); return 0; }

専門家に質問してみよう