プログラミング入門2 第12回 データ型 関数のプロトタイプ宣言 動的な記憶域確保 芝浦工業大学情報工学科 青木 義満 データ型 データ型 整数型,文字型,浮動小数点数,倍精度型 データ型 意味 整数型 整数を表現する 文字型 文字を表現する 浮動小数点数 実数を表現する 倍精度型 精度の高い浮動小数点数を表現する C言語で扱うことのできるデータ型 プログラミング入門2 2 各データが扱える数値範囲 変数を用意する際,目的にあった(扱うデータの値の取りうる範囲,必要と される精度)データ型を以下から選択して使用 データ型 ビット長 扱える数値の範囲 short 16 -32768 ~ +32767 int 32 -2147483648 ~ 2147483648 long 32 -2147483648 ~ 2147483648 unsigned short 16 0 ~ 65535 unsigned int 32 0 ~ 4294967295 unsigned long 32 0 ~ 4294967295 unsigned (符号なし) → 0と正の数のみ扱える char 8 (-128 ~ 127) unsigned char 8 (0 ~ 255) float 32 3.4 x 10-38 ~ 3.4 x 10+38 double 64 1.7 x 10-308 ~1.7 x 10+308 ※実際のデータサイズは,処理系によって異なる(特にint) プログラミング入門2 3 各データ型の変換指定子 標準入出力のための変換指定子 指定子 意味 %d(%ld) 整数の10進数として出力 (longの場合,%ld) %u (%lu) 整数の符号なし10進数として出力 (unsigned longの場合,%lu) %f 浮動小数点表示(float, double共通) %c 1文字を出力 %s 文字列を出力 %p ポインタの値(アドレス)を出力 ※scanfの場合,float は%f, double は %lf で読み込み プログラミング入門2 4 データ型の値の範囲を出力 ソースファイル名: data.c 各データ型の値の取りうる範囲を出力 #include <stdio.h> #include <limits.h> 各データ型の値の範囲が定義(#define)されている int main(void) { printf("char : %d to %d\n", CHAR_MIN, CHAR_MAX); printf("unsigned char : %d to %d\n", 0, UCHAR_MAX); printf("short : %d to %d\n", SHRT_MIN, SHRT_MAX); printf("int : %d to %d\n", INT_MIN, INT_MAX); printf("long : %ld to %ld\n", LONG_MIN, LONG_MAX); printf("unsigned short : %u to %u\n", 0, USHRT_MAX); printf("unsigned int : %u to %u\n", 0, UINT_MAX); printf("unsigned long int: %lu to %lu\n", 0, ULONG_MAX); return(0); } プログラミング入門2 5 データ型のサイズ(バイト数)を表示 ソースファイル名: datasize.c 各データ型の大きさ(サイズ)を表示 #include <stdio.h> int main(void) { printf("sizeof(char) = %u\n", sizeof(char) ); printf("sizeof(short) = %u\n", sizeof(short) ); printf("sizeof(int) = %u\n", sizeof(int) ); printf("sizeof(long) = %u\n", sizeof(long) ); printf("sizeof(float) = %u\n", sizeof(float) ); printf("sizeof(double) = %u\n", sizeof(double) ); return(0); } sizeof( データ型 ) → データ型の大きさ(byte数) プログラミング入門2 ※p.180に詳しい解説 6 関数のプロトタイプ宣言 プログラムの冒頭に,使用する関数の仕様を先に宣言しておく → 関数のプロトタイプ宣言 #include <stdio.h> int main(void) { int x, y, z; x = 5; y = 10; z = func( x, y ); printf( "x+y = %d\n", z); 定義されていない(not defined)とエラー! return(0); } int func(int x, int y) { return (x+y) ; } 関数をmain関数の後に定義すると… プログラミング入門2 7 関数のプロトタイプ宣言 #include <stdio.h> int func(int x, int y); 変数の型のみプログラムの冒頭に記述 (どんな引数を何個受け取り,どんな値を返すのか) int main(void) { int x, y, z; 関数のプロトタイプ宣言 (書く習慣をつけておいた方が良い) x = 5; y = 10; z = func( x, y ); printf( "x+y = %d\n", z); return(0); } int func(int x, int y) { return (x+y) ; } プログラミング入門2 8 動的記憶域確保の必要性 これまでのプログラム 配列の要素数は固定 あらかじめ大きめの配列を確保しておく #defineマクロで、要素数を定数として宣言し、その値を変更す ることで対応 → 静的な配列(記憶域)の確保 問題に応じて、適切なサイズの配列(記憶域)を確保す る方法は? メモリの節約 プログラムの柔軟性向上 動的な記憶域確保の必要性! プログラミング入門2 9 calloc関数 : 記憶域の確保 必要になったら記憶域を動的(ダイナミック)に確保し、 不要になったら解放する機能を提供 ヘッダ #include <stdlib.h> 形式 void *calloc(size_t n, size_t size ); 解説 大きさがsizeであるn個のオブジェクト(記憶域)の領域を確保す る。 返却値 領域確保に成功した場合は、その領域の先頭へのポインタを返 し、失敗した場合は、空ポインタ(NULL)を返す。 プログラミング入門2 10 Callc関数による記憶域の確保(1) ソースファイル名:calloc1.c 整数1個分の記憶域を動的に確保 #include <stdio.h> #include <stdlib.h> stdlib.hのインクルードを忘れずに! int main(void) { int *p; p = (int *)calloc( 1, sizeof(int) ); /*整数を1個分動的に確保*/ if( p == NULL ) puts(“記憶域の確保に失敗しました"); else { *p = 15; printf("*p = %d\n", *p ); } return(0); } プログラミング入門2 11 Calloc関数の動作イメージ Calloc関数による記憶域の動的な確保 p = (int *)calloc( 1, sizeof(int) ); int型ポインタ変数を用意 500番地 *p sizeof( int ) p p Intのデータ1個を動的に確保 プログラミング入門2 12 void へのポインタ (void *)calloc(size_t n, size_t size ); p = (int *)calloc( 1, sizeof(int) ); Calloc関数の返却値 → void * 型 (voidへのポインタ型) 動的確保の対象: int, char, double, 構造体 など、様々なオブジェクト ・ 特定の型へのポインタを返す使用 → × ・ 融通の利く万能なポインタ void * → ○ プログラムでは、確保する変数の型に合わせて、(void *)型のポインタを 任意のポインタ型にキャスト ※上の例では、int * 型 プログラミング入門2 13 free関数 : 記憶域の解放 動的に確保した記憶域は、不要になった時点で必ず解放 ヘッダ #include <stdlib.h> 形式 void free( void *p ); 解説 Pが指す領域を開放する。但しpがNULLであれば何も 行わない。 プログラミング入門2 14 記憶域の解放 ソースファイル:calloc2.c 記憶域の解放 記憶域解放 #include <stdio.h> #include <stdlib.h> free(p); int main(void) { int *p; p = (int *)calloc( 1, sizeof(int) ); /*整数を1個分動的に確保*/ if( p == NULL ) puts(“記憶域の確保に失敗しました"); else { *p = 15; printf("*p = %d\n", *p ); free(p); /* 確保していた領域を解放 */ } p = (int *)calloc( 1, sizeof(int) ); 記憶域確保 return(0); } プログラミング入門2 15 確保した領域への値の書き込み ソースファイル名:calloc3.c 記憶域を1個動的に確保し、キーボードから値を読込み #include <stdio.h> #include <stdlib.h> int main(void) { int *p; p = (int *)calloc( 1, sizeof(int) ); /*整数を1個分動的に確保*/ if( p == NULL ) puts(“記憶域の確保に失敗しました"); else { printf(“整数を入力して下さい:”); scanf(“%d”, p); printf("*p = %d\n", *p ); } return(0); } プログラミング入門2 16 1次元配列の動的確保 配列宣言の例 int x[10]; ※もしくは、#defineで宣言した定数 配列の要素数は定数式でなければならない → 要素数を変数とすることは不可能 → 開発時に要素数を決定する必要 配列の動的確保 → 実行時に要素数を決定! 実行時に、扱うデータのサイズによって最適な配列を用 意することが可能 プログラミング入門2 17 1次元配列の確保 ソースファイル名:calloc4.c int型の配列を動的に確保 #include <stdio.h> #include <stdlib.h> p[0] int main(void) { int no; /* 配列の要素数 */ int i; int *p; sizeof(int) * 5 printf(“確保する配列の要素数:”); scanf(“%d”, &no); p = (int *)calloc( no, sizeof(int) ); p[1] p[2] p[3] p[4] /*整数を1個分動的に確保*/ if( p == NULL ) puts(“記憶域の確保に失敗しました"); else { for(i=0; i < no; i++) p[i] = i; for(i=0; i< no; i++) printf(“p[%d] = %d¥n”, i, p[i] ); free(p); } return(0); p あたかも int p[5]; と宣言された配列が存在する かのように処理できる! } プログラミング入門2 18 realloc : 確保した領域の大きさの変更 allocで確保した記憶域の大きさを必要に応じて変更 ヘッダ #include <stdlib.h> 形式 void *realloc( void *ptr, size_t size ); *ptr : 大きさを変更したい領域へのポインタ size: 新しい大きさ 解説 ptrが指す記憶域の大きさをsizeバイトに変更する。変 更前後の小さい方までのオブジェクトの内容は変わら ない。 プログラミング入門2 19 記憶域の大きさを変更 ソースファイル名:calloc5.c 確保した記憶域の大きさを途中で変更 printf("Before----\n"); for(i=0;i<no;i++) printf("p[%d] = %d\n", i, p[i]); printf("Input new array size : "); scanf("%d", &no2); #include <stdio.h> #include <stdlib.h> int main(void) { int no, no2; int i; int *p; int *temp; temp = (int *)realloc(p, no2 * sizeof(int) ); 領域サイズの変更 if(temp==NULL) puts("Cannot allocate memory.\n"); else{ p = temp; for(i=no; i < no2; i++) p[i] = i; printf("After----\n"); for(i=0;i<no2;i++) printf("p[%d] = %d\n", i, p[i]); } free(p); 領域の解放 printf("Input size: "); scanf("%d", &no); p = (int *)calloc(no, sizeof(int)); 1回目の領域確保 if(p==NULL) puts("Cannot allocate memory.\n"); else { for(i=0;i<no;i++) p[i] = i; } return(0); } プログラミング入門2 20 reallocの動作イメージ p p[0] p[1] p[2] p[3] p[4] 要素数はno ←0 ←1 ←2 ←3 ←4 p p[0] p[1] p[2] realloc関数 新たに確保 した領域 ※realloc関数で確保済みの領域の大きさを変更する際には、 realloc関数の返却値が、空ポインタでないことを確認! プログラミング入門2 p[3] p[4] p[5] p[6] p[7] ←5 ←6 ←7 要素数はn2 21 二次元配列の動的確保(1) ソースファイル名:calloc6.c height行3列の2次元配列を確保(行数固定) #include <stdio.h> #include <stdlib.h> int main(void) { int height; int (*p)[3]; int i, j; 要素型がintで要素数が3の配列へのポインタ printf("Gyou :"); scanf("%d", &height); p = (int (*)[3])calloc(height * 3, sizeof(int)); } if(p==NULL) puts("Cannot allocate memory.\n"); else{ for(i=0;i<height;i++) for(j=0;j<3;j++) p[i][j]=0; for(i=0;i<height;i++) for(j=0;j<3;j++) printf("p[%d][%d] = %d\n", i, j, p[i][j]); free(p); } return(0); プログラミング入門2 22 2次元配列の動的確保 イメージ p[0][0] p[0] p[0][1] p[0][2] p[1][0] p[1] p[1][1] p[1][2] 4(height) * 3 * sizeof(int) p[2][0] p[2] p[2][1] p[2][2] p[3][0] p[3] p[3][1] p[3][2] ※n次元配列を動的に確保する際は、最高位のn次元の 要素数のみが可変。それ以外の次元の要素数は定数でなければならない プログラミング入門2 23 二次元配列の動的確保(2) 上級者向け ソースファイル名:calloc7.c ダブルポインタを用いた2次元配列の動的確保(行数列数共に可変) #include <stdio.h> #include <stdlib.h> int main(void) { int height, width; int i,j; int **p; for(i=0;i<height;i++) for(j=0;j<width;j++) p[i][j]=0; for(i=0;i<height;i++) for(j=0;j<width;j++) printf("p[%d][%d]=%d\n", i, j, p[i][j]); Free: for(i=0;i<height;i++) free(p[i]); free(p); } return(0); printf("Gyou: "); scanf("%d", &height); printf("Retsu: "); scanf("%d", &width); p= (int **)calloc(height, sizeof(int *)); if(p==NULL) printf("Cannot allocate memory.\n"); else{ for(i=0;i<height;i++) p[i]=NULL; for(i=0;i<height;i++){ p[i]=(int *)calloc(width, sizeof(int)); if(p[i]==NULL){ puts("Cannot allocate memory.\n"); goto Free; } } } プログラミング入門2 24 演習課題 構造体配列の動的確保(kadai11-1.c) 以下のpoint構造体について、 プログラム中で扱える点の数を可変にしたい。 実行時にキーボードから点の数を入力し、それにより動的に 構造体の配列を確保するプログラムを作成せよ。 確保後、全ての座標値を0.0で初期化し、その結果を表示せよ。 最後に確保した領域を解放するのを忘れずに! typedef struct { double x; double y; } point; プログラミング入門2 25 演習課題 2次元配列の動的確保(kadai11-2.c) N x 3の行列を動的に確保し、2つの行列の和を表示するプ ログラムを作成せよ。 課題提出方法 ・ソースファイル2つをメール添付にて ・期限: 12/24(月)13:00まで ・題目: pro2-11 学籍番号 苗字 プログラミング入門2 26
© Copyright 2024 ExpyDoc