- 締切済み
動的なメモリ管理(複数の使用済みのメモリブロックの解放)
氏名をmalloc()した配列に格納後,氏名アドレスと生年月日を組み合わせた構造体をさらにmallocし,そのアドレスをポインタ配列に登録していく。生年月日は,YYYYMMDD形式でキーボード入力されたデータを数値変換してlong型の構造体メンバーに格納する。 下記のプログラムでどこで使用済みのメモリブロックを解放すればよいか教えてください。お願いします。 #include <stdio.h> #include <string.h> #include <stdlib.h> #define DEBUG 0 /* debug mode 0:off 1:on */ #define BUFFERSIZE 11 #define MAX_PERSON 10 #define MAX_CHARS 10 #define BBUFFERSIZE 8 // YYYYMMDD typedef struct { char *name; //氏名 long birth; // 生年月日 YYYYMMDD }PERSON; int main(void){ char str[BUFFERSIZE]; /*氏名一時保存の配列,*/ char *st; //氏名保存配列 PERSON *person[MAX_PERSON]; /*構造体のアドレスを保存する配列*/ PERSON per[MAX_PERSON];//構造体保存配列 char bir[BBUFFERSIZE]; int count; int i; int j; int l; //文字列の長さ int top_index = 0; int bot_index; int day; int mon; int num ; int ch; char *tmp; printf("*** 入力された氏名をソートし、表示します ***\n"); printf("*** 最大入力件数10件(1文字目'0'で入力終了) ***\n"); putchar('\n'); for (i = 0; i < MAX_PERSON ; i++) { printf("氏名入力(10文字まで有効) > "); //氏名をmalloc()した配列に格納 fgets(str, BUFFERSIZE, stdin); l = strlen(str); if (str[l-1] == '\n'){ str[l-1] = '\0'; } else { while ( getchar() != '\n'){ } } if (str[0] == '0'){ break; } st = (char*)malloc(sizeof(char) * (strlen(str)+1)); strcpy(st,str);//\0も含まれてコピー printf("累計 : %d\n", i+1); //氏名アドレスと生年月日を組み合わせた構造体をmalloc() //そのアドレスをポインタ配列に登録 per[i].name = st; //生年月日入力 printf( "生年月日入力(YYYYMMDD) > " ); while(1){ l = 0; while ((ch = getchar()) != '\n' && ch != EOF) { if (l < 8) { bir[l] = ch; } l++; } num = 0; //数値に変換してlong型の構造体のメンバに保存 for ( j = 0; j < 8; j++){ num = num * 10 + (bir[j] - '0'); } printf("num : %d\n",num); per[i].birth = num; break; } person[i] = (PERSON*)malloc(sizeof(per[i])); person[i] = &per[i]; } count = i; printf("データ表示\n"); for (i = 0 ;i < count ; i++ ){ printf("%d : %s\n", i+1, person[i]->name); printf("%08d\n", person[i]->birth); } return 0; }
- みんなの回答 (2)
- 専門家の回答
みんなの回答
- Oh-Orange
- ベストアンサー率63% (854/1345)
★うーん。『動的なメモリ管理』と同じような質問だね。 ・基本的に malloc で動的確保したデータは必要なくなったときに解放します。 person 構造体を main() 関数の最後にある『データ表示』で使っていますので、 その後に解放する仕組みを記述します。要するに『動的なメモリ管理』の回答と 同じです。return する前に記述します。 ・それで解放するときに person 構造体の name データを先にメモリ解放します。 その後、person 構造体のメモリを解放します。 その他: ・main() 関数が長すぎます。 大きく、データ入力部、メモリ確保部、データ表示部、メモリ解放部の4つに分けて 記述しましょう。分けるときは関数を作って分けます。 データ入力部…data_input() メモリ確保部…data_malloc() データ表示部…data_print() メモリ解放部…data_free() こんな感じで名前を付けて処理を分けます。 そして main() 関数で呼び出します。 int main(void) { /* 宣言部(変数,構造体など) */ PERSON *person[ MAX_PERSON ]; PERSON input; int n; /* 10件分のデータ入力部 */ for ( n = MAX_PERSON ; data_input(&input,n) ; n-- ){ /* data_malloc() 関数を使ってメモリ確保部を記述 */ } /* データの表示部 */ data_print(); ←この関数1つで表示させる /* データの解放部 */ data_free( person ); ←この関数1つで解放させる return( 0 ); } ・上記の main() 関数を参考にサブ関数に分けて記述してみて下さい。 main() 関数はあまり長くしない方が見やすいですよ。 関数の戻り値や引数の並びを考えて作り直すことをお勧めします。 試行錯誤でまずは4つのサブ関数を作って main() 関数で呼び出すように書き換えて下さい。 最後に: ・質問のどこでメモリブロックを解放するかは、確保したデータを利用しなくなったら そのとき、速やかに解放します。今回のプログラムでは main() しか使われていないため もし、記述するとすれば main() の最後の return(0) する前に解放ルーチンを記述します。 ・main() 関数の場合はプログラムの終了と同時にメモリが自動的に解放されますから明示的に free() 関数で解放しなくても良いです。ただ、malloc、free のお勉強と思いますので対で 確保→データ処理、データ表示→解放というステップでデータが不必要になったときに解放 すれば良い。 ・以上。参考に!
- asuncion
- ベストアンサー率33% (2127/6289)
確保した領域にアクセスしないことが確定した時点です。 今回の場合、return 0; の直前でありましょう。 もっとも、free()で明示的に解放しなくても、 プログラムの終了時に自動的に解放する、という話もあります。