プログラミング入門2 第11回 情報工学科 篠埜 功 今日の内容 • malloc, callocによる動的な領域確保について 動的な記憶域確保 静的(static)な記憶域確保 • これまでの方法 – 配列の要素数は固定。 – あらかじめ大きめの配列を確保しておく必要が あった。 • 今回紹介する方法 動的(dynamic)な記憶域確保 – 問題に応じて、適切なサイズの配列(記憶域)を 確保するには、プログラムの実行時に確保を行 う必要がある。 – 余分なメモリの使用を避けることができる。 静的(static) --- プログラムのコンパイル時 動的(dynamic) --- プログラムの実行時 ヒープ領域(heap) • プログラムからはヒープ領域(heap)を用いることがで きる。 • ヒープ領域を使うには、mallocあるいはcallocという ライブラリ関数で領域を確保する。使い終わったら、 freeというライブラリ関数で解放する。解放すること により、それ以降のmallocあるいはcallocで再利用 可能になる。 (注意)ここでいうヒープ領域は、データ構造の授 業で習う木構造のヒープとは関係がない。 calloc関数 • ヒープ領域から実行時に記憶域を確保する。 • calloc関数を使うためにはstdlib.hをインクルードする必 要がある。 • 返り値はvoidへのポインタ型(実際に使う型にキャスト して使用する) • 引数は、データ型のサイズ(第2引数)と、その個数(第 1引数)。 • データ型のサイズは、sizeof (型式) で取得できる。 ヘッダ #include <stdlib.h> 形式 void * calloc (size_t n, size_t size); 解説 大きさがsizeであるn個のオブジェクトの領域を確保する。 返り値 領域確保に成功した場合は、その領域の先頭へのポインタを返 し、失敗した場合は、空ポインタ(NULL)を返す。 例(打ち込んで確認) #include <stdio.h> #include <stdlib.h> int main(void) { int *p; int型1個分の記憶域をヒープ p = (int *) calloc (1, sizeof (int)); 領域から割り当てる if( p == NULL ) printf (“記憶域の確保に失敗しました。\n"); else { *p = 15; printf ("*p = %d\n", *p ); } return 0; } 解説 • calloc関数による記憶域の動的な確保 int * p; p = (int *) calloc (1, sizeof (int) ); int型ポインタ変数を宣言 int * p; calloc関数呼び出し時に領域が確保され、 その先頭へのポインタがpに代入される。 p = (int *) calloc (1, sizeof (int) ); 500番地 p p sizeof演算子 sizeof演算子は、型式を引数にとる。評価結果は、その型 のサイズである。 構文 sizeof (型式) 意味 sizeof (t) の評価結果はtのサイズである 型式は、int, double, char等の基本型、int [3]等の 配列型、struct {int px; int py} 等の構造体型、int * 等のポインタ型、 typedefで定義した型名などであ る。詳しくは教科書あるいは規格書を参照。 例(打ち込んで確認) #include <stdio.h> typedef struct { int x; int y; } point; int main (void) { printf ("int: %d\n", sizeof(int)); printf ("int[3] : %d\n", sizeof(int[3])); printf ("struct {int x; int y;} : %d\n", sizeof(struct {int x; int y;})); printf ("point: %d\n", sizeof(point)); printf ("point *: %d\n", sizeof(point *)); return 0; } void へのポインタ calloc関数の返り値の型はvoid *である。 p = (int *) calloc (1, sizeof (int) ); calloc関数の返り値 → void * 型 (voidへのポインタ型) int, char, double, 構造体 など、さまざまな型のための領 域を確保する際にcalloc関数が用いられるので、void *型 で返している。 使うときには、calloc関数の返り値を実際に使うポインタ 型にキャストしてから使用する。 上の例では、int * 型にキャストしている。 free関数 : 記憶域の解放 • 動的に確保した記憶域は、不要になった時点 でfree関数を呼び出して解放する。それに よって、それ以降のcallocやmallocの呼び出し で再利用可能な状態になる。 ヘッダ #include <stdlib.h> 形式 void free( void *p ); 解説 pが指す領域を開放する。但しpがNULLであれば何 も行わない。 例(打ち込んで確認) #include <stdio.h> #include <stdlib.h> int main(void) { int *p; p = (int *)calloc( 1, sizeof(int) ); if (p == NULL) printf ("記憶域の確保に失敗しました。\n"); else { *p = 15; printf("*p = %d\n", *p ); free(p); } return 0; } 記憶域解放 free(p); p = (int *)calloc( 1, sizeof(int) ); 記憶域確保 確保した領域へ値を書き込む例(打ち込んで確認) #include <stdio.h> #include <stdlib.h> int main(void) { int * p; p = (int *) calloc (1, sizeof(int)); if(p == NULL) printf ("記憶域の確保に失敗しました。\n"); else { printf ("整数を入力して下さい:"); scanf ("%d", p); printf ("*p = %d\n", *p); } return 0; } 1次元配列の動的確保 • 配列宣言の例 int x[10]; 配列の要素数は定数式でなければならない。 要素数を変数とすることは1990年のISO規格 では許されていない。 (注)1999年のISO規格(C99)では許されている。 実行時に領域を確保することにより、適切な長 さの配列を用いることができる。 例(打ち込んで確認) #include <stdio.h> #include <stdlib.h> int main (void) { int no, i=0; int * p; printf("確保する配列の要素数:"); scanf("%d", &no); p = (int *) calloc (no, sizeof (int)); if (p == NULL) printf ("記憶域の確保に失敗しました。\n"); else { while (i < no) { p[i] = i; i=i+1; } i = 0; while ( i < no ) { printf("p[%d] = %d\n", i, p[i] ); i = i + 1; } /* 続き */ free (p); } return 0; } p[0] sizeof(int) * 5 p[1] p[2] p[3] p[4] p あたかも int p[5]; と宣言された配列が存在する かのようになる。 今日の課題1 • キーボードから数を入力として受け取り、その 個数分のint型データをキーボードから受け取 り、それらの最大値を画面に出力するプログ ラムをcallocを用いて書け。 今日の課題2 受験者N人(Nは実行時にキーボードから入力)の氏名およ び数学、英語の2科目の試験の点数をキーボードから入力 し、氏名、各科目の点数、合計点を一覧表にして表示した い。これを行うプログラムを、callocを用いて書け。 各受験者の氏名と点数を入力する部分、合計点を計算す る部分、一覧表示をする部分は、別々の関数として定義し、 それらをmain関数から呼び出す形でプログラムを記述せよ。 (実行例) [sasano@oli001 11kai]$ ./a.out 人数を入力してください: 2 氏名: 芝浦太郎 数学: 90 英語: 90 氏名: 芝浦次郎 数学: 100 英語: 100 氏名 数学 英語 合計 芝浦太郎 90 90 180 芝浦次郎 100 100 200 構造体配列の動的確保(pointでの例) (0) point構造体を定義 (1) point構造体へのポインタ型の変数pを宣言しておく。 point *p; (2) Nにscanfで配列の要素数を入れる。 (3) p = (point *) calloc (N, sizeof (point)); で必要な領域を確保し、その先頭ア ドレスをpに代入 (4) pを使って、確保した領域内の各要素にアクセス。 p[0], p[1] などが領域内の各構造体を表す。(*p, *(p + 1), 等でもよい) p[0].x, p[0].y, p[1].x, …などが、領域の中に確保された各構造体のメン バーを表すことになる。 p -> x, p -> y, (p+1)-> x 等、アローを使った表記でもよい。 typedef struct { double x; double y; } point; チャレンジ課題 • 課題2の表示を、合計点の高い順に行えるよ うにせよ。
© Copyright 2024 ExpyDoc