関数と配列とポインタ 1次元配列 2次元配列 配列を使って結果を返す 演習問題 第12章 関数と配列 関数と配列とポインタ 1次元配列 2次元配列 配列を使って結果を返す 演習問題
10.9 関数と配列 プログラム例 10.9.1 #include <stdio.h> 10.9 関数と配列 プログラム例 10.9.1 #include <stdio.h> double sum(int n, double *x_p); int main(void) { double a[5] = {1.56, 3.24, 5.24, 3.24, 6.23}; int count = 5; double value; value = sum(count, &a[0]); printf("&a[0]=%u, 総和 = %f\n", &a[0],value); return 0; } double sum(int n, double *x_p) … 参照呼び出し 関数sum を呼び出す時、配列a の 先頭アドレス(ポインタ定数)を渡す 関数sum の仮引数では、 配列はポインタでうけとる
関数と配列とポインタ C では、配列変数はポインタ変数 を用いてアクセスすることが多い 1.56 a[0] 1000 1008 1016 1024 1032 1040 a[0] 3.24 &a[0] は1000、&a[1] は1008、… a[1] 5.24 a[2] 3.24 … sum(count,&a[0]); //mainの中 double sum(int n, double *x_p) { } a[3] 6.23 a[4] 1000 x_p 関数の実引数にポインタ定数&a[0]を入れて呼ぶと、 その値が関数の仮引数x_pにコピーされる
10.9 関数と配列 プログラム例 10.9.1 main で関数sum を呼び出す時、 配列a の先頭アドレス(ポインタ … 定数)を渡す 10.9 関数と配列 プログラム例 10.9.1 main で関数sum を呼び出す時、 配列a の先頭アドレス(ポインタ 定数)を渡す … value = sum(count, &a[0]); double sum(int n, double *x_p) { int i; double s; printf("&x_p:%u,x_p:%u\n", &x_p,x_p); s = 0.; for (i = 0; i < n; i++) { s += *x_p; x_p++; } return s; 関数 sum の仮引数では、 配列はポインタで受け取る ポインタを介してa[0], a[1],… の 値を代入し、加算する。ポインタ自体は、 &a[0], &a[1],… と変化する
10.9 関数と配列 プログラム例 10.9.1 1000 a[0] 1008 a[1] 1016 a[2] 1024 a[3] 1032 a[4] 1040 . 1.56 3.24 5.24 6.23 double sum(int n, double *x_p) { int i; double s; s = 0.; for (i = 0; i < n; i++) { s += *x_p; x_p++; } return s; x_p i s 1040 5 19.51 1008 1000 1016 1024 1032 2 4 3 1 10.04 13.28 4.80 1.56 0.0
10.9 関数と配列 上記の文は、下のように書いても同様(この方が一般的) プログラム例 10.9.1 の main の4行目 10.9 関数と配列 プログラム例 10.9.1 の main の4行目 value = sum(count, &a[0]); 上記の文は、下のように書いても同様(この方が一般的) value = sum(count, a); 配列の場合、配列名 a がポインタ(正確にはポインタ定数)なので、 & をつけなくても「参照呼び出し」となる。 ポインタ定数 a と ポインタ変数 pの違い: p = a; は可能だが a = p; は不可
12.1 1次元配列 プログラム例 10.9.1 改 #include <stdio.h> 12.1 1次元配列 第12章の流儀 プログラム例 10.9.1 改 #include <stdio.h> double sum(int n, double x[]); int main(void) { double a[5] = {1.56, 3.24, 5.24, 3.24, 6.23}; int count = 5; double value; value = sum(count, a); printf("a:%u, 総和 = %f\n", a, value); return 0; } double sum(int n, double x[]) int i; double s; printf("&x:%u, x:%u\n", &x, x); s = 0.; for (i = 0; i < n; i++) s += x[i]; return s; *x_p のかわりに x[] *x_p のかわりに x[] *x_p; x_p++ のかわりに x[i]
12.1 1次元配列 プログラム例 12.1.1 #include <stdio.h> 12.1 1次元配列 プログラム例 12.1.1 #include <stdio.h> void disp_1D_array(int n, double x[]); int main(void) { double a[] = {3.24, 1.76, 5.32, 2.37, 4.33, 1.26}; int asize = 6; disp_1D_array(asize, a); return 0; } void disp_1D_array(int n, double x[]) int i; for (i = 0; i < n; i++) printf("%f\n", x[i]); 初期値があればサイズは省略可
10.10 関数と2次元配列 プログラム例 10.10.1 #include <stdio.h> 10.10 関数と2次元配列 プログラム例 10.10.1 #include <stdio.h> void disp_2D_array(int nrow, int ncol, double *a_p); int main(void) { int nrow = 3, ncol = 3; double a[3][3] = {{1.56, 3.24, 5.24}, {3.24, 6.23, 8.16}, {7.32, 2.86, 4.12}}; disp_2D_array(nrow, ncol, &a[0]); return 0; } void disp_2D_array(int nrow, int ncol, double *a_p) int i, j; for (i = 0; i < nrow; i++) { for (j = 0; j < ncol; j++) { printf(" %7.2f", *a_p); a_p++; printf("\n"); 内側の波カッコは人が読みやすくするため
12.2 2次元配列 行の大きさは省略できるが、列の大きさは省略できない a[3][3] → a[][3] 記憶領域→1次元的 12.2 2次元配列 行の大きさは省略できるが、列の大きさは省略できない a[3][3] → a[][3] 記憶領域→1次元的 a[m][n] の行列表現 a11 a12 ・ a1n a21 1行目 2行目 m行目 a11 a12 ・・・ a1n a21 a22 a2n ・ am1 am2 amn 1行目 折り返し場所の情報は省略できない
12.2 2次元配列 プログラム例 12.2.1 #include <stdio.h> 12.2 2次元配列 プログラム例 12.2.1 #include <stdio.h> void disp_2D_array(int n, double x[][3]); int main(void) { int nrow = 3; double a[3][3] = {{3.24, 1.76, 5.32}, {2.37, 4.33, 1.26}, {1.86, 1.86, 3.64}}; disp_2D_array(nrow, a); return 0; } void disp_2D_array(int n, double x[][3]) int i, j; for (i = 0; i < n; i++) { for (j = 0; j < 3; j++) { printf(" %7.2f", x[i][j]); printf("\n"); 列の大きさを指定する必要 列の大きさを指定する必要 引数で渡せない 3 という数字があちこちに散逸
12.2 2次元配列 プログラム例 12.2.2 2次元配列の1次元化(第2回)で 解決する方法もある 12.2 2次元配列 プログラム例 12.2.2 #include <stdio.h> #define NROW 3 #define NCOL 3 void disp_2D_array(double x[][NCOL]); int main(void) { double a[NROW][NCOL] = {{3.24, 1.76, 5.32}, {2.37, 4.33, 1.26}, {1.86, 1.86, 3.64}}; disp_2D_array(a); return 0; } void disp_2D_array(double x[][NCOL]) int i, j; for (i = 0; i < NROW; i++) { for (j = 0; j < NCOL; j++) { printf(" %7.2f", x[i][j]); printf("\n"); 行数、列数を集中管理 2次元配列の1次元化(第2回)で 解決する方法もある
呼び出し側の配列へデータを返す c11 c12 c13 c21 c22 c23 c31 c32 c33 a11 a12 a13 プログラム例 10.10.2 c11 c12 c13 c21 c22 c23 c31 c32 c33 a11 a12 a13 a21 a22 a23 a31 a32 a33 b11 b12 b13 b21 b22 b23 b31 b32 b33 = + a11+b11 a12+b12 a13+b13 a21+b21 a22+b22 a23+b23 a31+b31 a32+b32 a33+b33 = 関数 sum: 配列 a と b から、上記のように新しい配列 c を計算。 配列 c (新しいデータ)を main に返すには?
呼び出し側の配列へデータを返す プログラム例 10.10.2 … sum(nr, nc, &a[0][0], &b[0][0], &c[0][0]); void sum(int nrow, int ncol, float *a_p, float *b_p, float *c_p) { int i, j; for (i = 0; i < nrow; i++) for (j = 0; j < ncol; j++) { *c_p = *a_p + *b_p; a_p++; b_p++; c_p++; } sum の呼び出し前: 配列 c[i][j] は 未定 sum の呼び出し後: 配列 c[i][j] には a[i][j] + b[i][j] が入る
12.3 配列を使って結果を返す プログラム例 12.3.1 #include <stdio.h> #define NROW 3 12.3 配列を使って結果を返す プログラム例 12.3.1 #include <stdio.h> #define NROW 3 #define NCOL 3 void sum(int x[][NCOL], int y[][NCOL], int z[][NCOL]); void disp_2D_array(int u[][NCOL]); int main(void) { int a[NROW][NCOL] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; int b[NROW][NCOL] = {{11, 12, 13}, {14, 15, 16}, {17, 18, 19}}; int c[NROW][NCOL]; disp_2D_array(a); disp_2D_array(b); sum(a, b, c); disp_2D_array(c); return 0; }
12.3 配列を使って結果を返す void sum(int x[][NCOL], int y[][NCOL], int z[][NCOL]) 12.3 配列を使って結果を返す void sum(int x[][NCOL], int y[][NCOL], int z[][NCOL]) { int i, j; for (i = 0; i < NROW; i++) { for (j = 0; j < NCOL; j++) { z[i][j] = x[i][j] + y[i][j]; } void disp_2D_array(int u[][NCOL]) printf(" %10d", u[i][j]); printf("\n");
演習問題12.2 #include <stdio.h> #define NROW 3 #define NCOL 3 void sum_ave(double ?????????, double *s, double *av); int main(void) { double s, av; double a[NROW][NCOL] = {{3.24, 1.76, 5.32}, {2.37, 4.33, 1.26}, {1.86, 1.86, 3.64}}; sum_ave(??????????); printf("総和 = %7.2f, 平均 = %7.2f¥n", s, av); return 0; } void sum_ave(double ?????????, double *s, double *av) int i, j; *s = 0; for (i = 0; i < ????; i++) { for (j = 0; j < ????; j++) { *s += ???????; *av = ??????????????; 配列要素の数値の総和と 平均値を計算する関数 総和の計算 平均値の計算
演習問題12.3 #include <stdio.h> #define N 3 void sum(int x[][N], int y[][N], int z[][N]); void diff(int x[][N], int y[][N], int z[][N]); void prod(int x[][N], int y[][N], int z[][N]); void disp_2D_array(int x[][N]); int main(void) { int a[N][N] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; int b[N][N] = {{11, 12, 13}, {14, 15, 16}, {17, 18, 19}}; int c[N][N]; disp_2D_array(a); disp_2D_array(b); sum(???????); disp_2D_array(c); diff(???????); disp_2D_array(c); prod(???????); disp_2D_array(c); return 0; }
演習問題12.3 (つづき) 行列の和 行列の差 行列の積 演習問題12.3 (つづき) void sum(int x[][N], int y[][N], int z[][N]) { ???...??? } void diff(int x[][N], int y[][N], int z[][N]) void prod(int x[][N], int y[][N], int z[][N]) int i, j, k; for (i = 0; i < ?; i++) { for (j = 0; j < ?; j++) { z[i][j] = 0; for (k = 0; k < ?; k++) z[i][j] += ???????????????; void disp_2D_array(int x[][N]) 行列の和 行列の差 行列の積
本日のパズル 次のプログラムは何を出力するか #include <stdio.h> #define PRINTX(f,x) printf("%"#f"\n",x) main() { int x=1, y=1; if( y<0 ) if( y>0 ) x=3; else x=5; PRINTX(d,x); if( x=y ); x=3; } 1 2