第12章 関数と配列

第12章 関数と配列
1次元配列
2次元配列
配列を使って結果を返す
演習問題
レポート課題
9.4 配列変数とポインタ
(再掲)
C では、配列変数はポインタ変数
を用いてアクセスすることが多い
&a[0] は1000、 &a[1] は1004
int *a_p;
a_p = &a[0];
a_p は、整数型変数のアドレスが入る
ポインタ型変数で(1行目)、配列 a の
先頭の要素の番地を代入する(2行目)
1000
1004
1008
・
・
・
a[0]
a[1]
a[2]
a[3]
a[4]
a_p
1000
ポインタと配列変数との間の関係
a_p = &a[0]; は、
a_p = a; と書いても良い
ポインタ定数
上記の文で、
a_p には、配列 a の先頭の要素
a[0] の番地を代入するよ、
という意味。
図示すると、
1000
1004
1008
・
・
・
a[0]
a[1]
a[2]
a[3]
a[4]
a_p
a_p
1000
a[0]
1000
10.9 関数と配列
プログラム例 10.9.1
…
value = sum(count, &a[0]);
…
main で関数 sum を呼び
出す時、a の先頭アドレス
(ポインタ定数)を引数と
している
float sum(int n, float *x_p)
{
関数 sum の引数は、
int i;
配列の要素数 n とポインタ
float s;
s = 0.;
for (i = 0; i < n; i++) {
s += *x_p; x_p++;
a[0], a[1], ... の値が加算される。
}
ポインタ自体は、
return s;
}
&a[0], &a[1], … と変化する
10.9 関数と配列
プログラム例 10.9.1
float sum(int n, float *x_p)
{
int i;
float s;
s = 0.;
for (i = 0; i < n; i++) {
s += *x_p; x_p++;
}
return s;
}
s
x_p
0
&a[0]
i=0のループ終了時
a[0]
&a[1]
i=1のループ終了時
a[0]+a[1]
&a[2]
ループに入る時
i=2のループ終了時 a[0]+a[1]+a[2] &a[3]
・
・
・
・
・
・
・
・
・
10.9 関数と配列
プログラム例 10.9.1 の main の4行目
value = sum(count, &a[0]);
上記の文は、下のように書いても同様
(この方が一般的)
value = sum(count, a);
12.1 1次元配列
プログラム例 10.9.1 改
#include <stdio.h>
double sum(int n, double x[]);
*x_p のかわりに 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("総和 = %f\n", value);
return 0;
}
*x_p のかわりに x[]
double sum(int n, double x[])
{
int i; double s;
s = 0.;
for (i = 0; i < n; i++)
*x_p; x_p++ のかわりに x[i]
s += x[i];
return s;
}
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>
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次元配列
行の大きさは省略できるが、列の大きさは省略できない
x[3][3] → x[][3]
記憶領域→1次元的
a[m][n] の行列表現
1行目
2行目
a12
・・・
a21 a22
・・・
a11
・
・
・
m行目
・
・
・
am1 am2
a1n
a2n
・
・
・
・・・
a11
amn
1行目
a12
・
・
・
a1n
a21
・
・
・
折り返し場所の情
報は省略できない
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
#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");
}
}
呼び出し側の配列へデータを返す
プログラム例 10.10.2
c11 c12 c13
c21 c22 c23
c31 c32 c33
=
a11 a12 a13
a21 a22 a23
a31 a32 a33
=
a11+b11 a12+b12 a13+b13
a21+b21 a22+b22 a23+b23
a31+b31 a32+b32 a33+b33
+
b11 b12 b13
b21 b22 b23
b31 b32 b33
関数 sum: 配列 a と b から、上記のように新しい配列 c を計算。
配列 c (新しいデータ)を main に返すには?
呼び出し側の配列へデータを返す
プログラム例 10.10.2
…
sum(nr, nc, &a[0][0], &b[0][0], &c[0][0]);
…
sum の呼び出し前: 配列 c[i][j] は 未定
sum の呼び出し後: 配列 c[i][j] には a[i][j] + b[i][j] が入る
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++;
}
}
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])
{
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])
{
int i, j;
for (i = 0; i < NROW; i++) {
for (j = 0; j < NCOL; j++) {
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
(つづき)
void sum(int x[][N], int y[][N], int z[][N])
{
zi, j  xi, j
行列の和
???...???
}
void diff(int x[][N], int y[][N], int z[][N])
{
zi, j  xi, j
???...???
行列の差
}
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;
n
for (k = 0; k < ?; k++)
zi , j 
z[i][j] += ???????????????;
}
k 1
}
}
void disp_2D_array(int x[][N])
{
???...???
}
 yi, j
 yi, j
x
i,k
 yk , j
演習問題12.4
#include <stdio.h>
#define N 3
void sweep_out(double ????????);
void disp_2D_array(double ????????);
int main(void)
{
double a[N][N+1] = {{2,3,1,-1}, {3,1,2,7}, {1,2,3,6}};
disp_2D_array(?);
sweep_out(?);
disp_2D_array(?);
return 0;
}
掃出法
 2 3 1  1  1 0 0 x 

 

 3 1 2 7   0 1 0 y
 1 2 3 6  0 0 1 z

 

演習問題12.4
(つづき)
void sweep_out(double ????????)
{
int i, j, k; double w;
k行目の成分をその対角成分で割る
for (k = 0; k < N; k++) {
w = a[k][k];
for (j = 0; j <= N; j++) a[k][j] /= w;
for (i = 0; i < N; i++) {
if (i != k) {
w = a[i][k];
for (j = 0; j <= N; j++) a[i][j] -= w * a[k][j];
}
}
掃き出し操作
}
}
void disp_2D_array(double ????????)
{
???...???
}
第1回 レポート(必須) 課題



課題:教科書p.114の演習問題12.3 または 12.4
提出期限:2009年10月23日(金) 12:50
提出場所:ネットワーク実験室(1)の入口近くの箱
今回のレポートでは以下の項目をいれること。
1. 学籍番号、氏名
2. 問題番号
レポートのファイルは
3. ソースリスト
保存しておくこと
4. 実行結果
5. 感 想(5行以上)
レポートサンプルを参照のこと