配列の宣言 配列要素の初期値 配列の上限 メモリ領域 多次元配列 配列の応用 第6章 配 列 配列の宣言 配列要素の初期値 配列の上限 メモリ領域 多次元配列 配列の応用
配列の宣言 一般形 型宣言子 配列名[要素数]; 整数型 int a[10]; a[0]~a[9] 型宣言子 配列名[要素数]; 整数型 int a[10]; a[0]~a[9] unsigned int u[20]; u[0]~u[19] 浮動小数点数(実数)型 float f[101]; f[0]~f[100] double x[N+1]; x[0]~x[N] 符号付き整数 符号なし整数 単精度浮動小数点数 倍精度浮動小数点数 要素は必ず 0 から始まるため、最後の要素番号は(要素数-1)であることに注意
よくやるミス (ex6_2_1a.c) プログラム例 6.2.1改 #define N 10 int main(void) { #include <stdio.h> #define N 10 int main(void) { int i, x[N], n=N, total=0; double average; for (i=1; i<=n; i++) printf("x[%d]=% d\n", i, x[i]=i); for (i=1; i<=n; i++) total += x[i]; average = (double)total / n; printf("総 和=% d\n", total); printf("平均点=% .2f\n", average); return 0; } プログラム例 6.2.1改 コンパイルの前に N を 10 にすり替えてくれる
配列要素の初期値 int a[10] = {1, 2, 3, 4}; int b[10] = {0}; static int c[10]; double d[10] = {0}; static double e[10]; 残りは 0 で初期化 すべて 0 で初期化 静的変数は 0 で初期化される すべて 0.0 で初期化 静的変数は 0.0 で初期化される
配列要素の初期値 (ex6_3_1a.c) プログラム例 6.3.1改 #define N 10 int main(void) { #include <stdio.h> #define N 10 int main(void) { int i, x[N], n=N, total=0; double average; for (i = 0; i < n; i++) printf("x[%d]=% d\n", i, x[i]); for (i = 0; i < n; i++) total += x[i]; average = (double)total / n; printf("総 和=% d\n", total); printf("平均点=% .2f\n", average); return 0; } プログラム例 6.3.1改 初期値なしで宣言した場合(自動変数)
配列要素の初期値 (ex6_3_1b.c) プログラム例 6.3.1改2 #define N 10 int main(void) { #include <stdio.h> #define N 10 int main(void) { int i, x[N]={0}, n=N, total=0; double average; for (i = 0; i < n; i++) printf("x[%d]=% d\n", i, x[i]); for (i = 0; i < n; i++) total += x[i]; average = (double)total / n; printf("総 和=% d\n", total); printf("平均点=% .2f\n", average); return 0; } プログラム例 6.3.1改2 初期値 0 で宣言した場合(自動変数)
配列要素の初期値 (ex6_3_1c.c) プログラム例 6.3.1改3 #define N 10 int main(void) { #include <stdio.h> #define N 10 int main(void) { int i, n=N, total=0; static int x[N]; double average; for (i = 0; i < n; i++) printf("x[%d]=% d\n", i, x[i]); for (i = 0; i < n; i++) total += x[i]; average = (double)total / n; printf("総 和=% d\n", total); printf("平均点=% .2f\n", average); return 0; } プログラム例 6.3.1改3 static をつけて宣言した場合(静的変数) static によりすべて 0 に初期化される
配列の上限(自動変数の場合) プログラム例 6.6.3改 (ex6_6_3a.c) #include <stdio.h> #define N 200000 // <= 258522 int main(void) { int i, n=N; int x[N]; // stack size limit = 258522*4? long long sum=0; for (i=0; i < n; i++) x[i] = i+1; for (i=0; i < n; i++) sum += x[i]; printf("総 和=%lld\n", sum); return 0; } プログラム例 6.6.3改 (ex6_6_3a.c) 倍長精度整数型(64bit) long long 整数用書式修飾子
配列の上限(静的変数の場合) プログラム例 6.6.3改2 (ex6_6_3b.c) #include <stdio.h> #define N 200000000 // <= 499,107,120 int main(void) { int i, n=N; static int x[N]; // static limit = 499107120*4? long long sum=0; for (i=0; i < n; i++) x[i] = i+1; for (i=0; i < n; i++) sum += x[i]; printf("総 和=%lld\n", sum); return 0; } プログラム例 6.6.3改2 (ex6_6_3b.c) 倍長精度整数型(64bit) long long 整数用書式修飾子
配列の上限(大域変数の場合) プログラム例 6.6.3改3 (ex6_6_3c.c) #include <stdio.h> #define N 200000000 // <= 499107117 int x[N]; // static limit = 499107117*4? int main(void) { int i, n=N; long long sum=0; for (i=0; i < n; i++) x[i] = i+1; for (i=0; i < n; i++) sum += x[i]; printf("総 和=%lld\n", sum); return 0; } 倍長精度整数型(64bit) long long 整数用書式修飾子
メモリ領域 プログラム領域 プログラムコード 静的領域 静的変数、大域変数 ヒープ領域 動的確保(malloc) スタック領域 自動変数 プログラム領域 プログラムコード 静的領域 静的変数、大域変数 ヒープ領域 動的確保(malloc) スタック領域 自動変数 Windows XP(32 bit)の場合、1つのプログラムで使えるメモリは 2 GB まで? スタックより大、ヒープより小 データ領域 仮想メモリも使用可 比較的小さい
2次元配列の宣言 一般形 整数型 実数型 型宣言子 配列名[要素数][要素数]; int a[5][10]; 行 列 一般形 型宣言子 配列名[要素数][要素数]; 整数型 int a[5][10]; unsigned int u[10][20] 実数型 float f[100][10]; double x[M+1][N+1]; 5行10列 10行20列 a[0][0]~a[0][9] a[1][0]~a[1][9] … a[4][0]~a[4][9] u[0][0]~u[0][19] u[1][0]~u[1][19] … u[9][0]~u[9][19] f[0][0]~f[0][9] f[1][0]~f[1][9] … f[99][0]~f[99][9] x[0][0]~x[0][N] x[1][0]~x[1][N] … x[M][0]~x[M][N] 要素は必ず 0 から始まるため、おのおのの最後の要素番号は (要素数-1)であることに注意
2次元配列要素の初期値 int a[4][4] = {{1, 2, 3, 4},{ 5, 6, 7, 8}, {9,10,11,12},{13,14,15,16}}; int b[4][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16}; int c[][4] = {{1, 2, 3, 4}, 5, 6, 7, 8, 9,10,11,12,{13,14,15,16}}; int d[][] = {{1, 2, 3, 4},{ 5, 6, 7, 8}, 省略可 省略できない { }カッコだけでは折り返す場所の情報が伝わらない
2次元配列要素の初期値 行の大きさは省略できるが、列の大きさは省略できない a[4][4] → a[][4] 記憶領域→1次元的 a[m][n] の行列表現 a11 a12 ・ a1n a21 1行目 2行目 m行目 a11 a12 ・・・ a1n a21 a22 a2n ・ am1 am2 amn 1行目 折り返し場所の情報は省略できない
2次元配列要素の初期値 整数型 浮動小数点数型 int a[4][4] = {1, 2, 3, 4}; int b[4][4] = {0}; static int c[4][4]; 浮動小数点数型 double d[4][4] = {0}; static double e[4][4]; 残りは 0 で初期化 すべて 0 で初期化 静的変数は 0 で初期化される すべて 0.0 で初期化 静的変数は 0.0 で初期化される
2次元配列を用いた例(ex6_7_2a.c) プログラム例 6.7.2改 #include <stdio.h> #define N 4 int main(void) { int i, j, k=0, a[N][N]; for (i = 0; i < N; i++) for (j = 0; j < N; j++) a[i][j] = ++k; for (i = 0; i < N; i++) { for (j = 0; j < N; j++) printf("a[%d][%d]=%d\t", i, j, a[i][j]); printf("\n"); } return 0; プログラム例 6.7.2改 1~16の通し 番号を入力 2次元的に 表示
ex6.7.2a のPAD ex6.7.2a k ← 0 i = 0...N-1 j = 0...N-1 k ← k+1 a[i] ← k "a[%d][%d]=%d\t", i, j, a[i][j] "\n"
2次元配列の1次元化(ex6_7_2b.c) プログラム例 6.7.2改2 #include <stdio.h> #define N 4 #define IDX(i,j) ((i)*N+(j)) int main(void) { int i, j, a[N*N]; for (i = 0; i < N*N; i++) a[i] = i + 1; for (i = 0; i < N; i++) { for (j = 0; j < N; j++) printf("a[%d][%d]=%d\t", i, j, a[IDX(i,j)]); printf("\n"); } return 0; プログラム例 6.7.2改2 2次元→1次元変換用マクロ 1~16の通し 番号を入力 2次元的に 表示
x[L][M][0]~x[L][M][N] 3次元配列の宣言 段 行 列 一般形 型宣言子 配列名[要素数][要素数][要素数]; 整数型 int a[6][11][21]; 実数型 double x[L+1][M+1][N+1]; 6段11行21列 a[0][0][0]~a[0][0][20] a[0][1][0]~a[0][1][20] … … a[0][10][0]~a[0][10][20] a[5][0][0]~a[5][0][20] a[5][1][0]~a[5][1][20] … … a[5][10][0]~a[5][10][20] x[0][0][0]~x[0][0][N] x[0][1][0]~x[0][1][N] … … x[0][M][0]~x[0][M][N] x[L][0][0]~x[L][0][N] x[L][1][0]~x[L][1][N] … … x[L][M][0]~x[L][M][N] 要素は必ず 0 から始まるため、おのおのの最後の要素番号は (要素数-1)であることに注意
エラトステネスの篩(ふるい) 整数集合 A = {2, 3, ..., n} を考える。 整数 i = 2, 3, ..., n/2 について i∈A ならば i より大きい i の倍数を A から除いていく。 最後まで A に残ったものが n 以下の素数となる。 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 ……………………………………………………………………………………………… 769 773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997
エラトステネスの篩(ふるい) #include <stdio.h> #define N 1001 prime.c int main(void) { int i, j, k, a[N]; for (i = 2; i < N; i++) a[i] = 1; // 篩(a)の初期化 for (i = 2; i < N/2; i++) if (a[i]) { j = 2 * i; while (j < N) {a[j] = 0; j += i;} // iの倍数を除く } prime.c
k = 0; for (i = 2; i < N; i++) if (a[i]) { printf("%5d", i); if (++k % 15 == 0) printf("\n"); // 15個で改行 } if (k % 15 != 0) printf("\n"); return 0;
エラトステネスの篩(ふるい)のPAD 素数 i=2,...,N a[i] ← True j ← 2i a[i] i=2,...,N/2 j≦N a[j] ← False prime k ← 0 j ← j+i i の出力 a[i] i=2,...,N k ← k+1 改行 改行 k mod 15 ≠ 0 k mod 15 = 0 15個で改行
本日のパズル 次のプログラムは何を出力するか? #define PRINTX printf("%d\n",x) main() { int x=2, y, z; x *= 3 + 2; PRINTX; x *= y = z = 4; PRINTX; x = y == z; PRINTX; x == ( y = z ); PRINTX; } 1 2 3 4