プログラミング入門2プログラミング入門2
第第55回回配列配列
同じデータの集合を効率よく扱う同じデータの集合を効率よく扱う
芝浦工業大学情報工学科芝浦工業大学情報工学科 講師講師
青木青木 義満義満
2003/10/20 プログラミング入門2 2
今回の講義内容今回の講義内容
前回レポート
・学生の点数を入力 → 合計点,平均点を計算
・各学生の点数のデータは?
・学生を区別する方法:名前,学籍番号など
名前で呼ぶよりも,番号で呼ぶ方が便利例えば,野球選手の背番号,飛行機の座席番号
同じ型のデータの集合を効率良く扱うには?
配列 を使用!
2003/10/20 プログラミング入門2 3
配列の必要性は?配列の必要性は? (p.88)(p.88)ソースファイル名:List0501.c (p.88)3人の点数を読込み,合計点と平均点を表示
#include <stdio.h>
int main(void){
int aoki;int yanagisawa;int morishima;int sum = 0 ;double heikin = 0.0;
printf( “input score: ” );
printf( “no1: “ );scanf( “%d”, &aoki );printf( “no2: “ );scanf( “%d”, &yanagisawa );printf( “no3: “ );scanf( “%d”, &morishima );
#include <stdio.h>
int main(void){
int aoki;int yanagisawa;int morishima;int sum = 0 ;double heikin = 0.0;
printf( “input score: ” );
printf( “no1: “ );scanf( “%d”, &aoki );printf( “no2: “ );scanf( “%d”, &yanagisawa );printf( “no3: “ );scanf( “%d”, &morishima );
sum += aoki;sum += yanagisawa;sum += morishima;
heikin = (double)sum / 3 ;
printf( “Total : %d¥n”, sum )printf( “avg : %f¥n”, heikin );
return (0);}
キャスト
人数が100人になったら?人数が100人になったら?
2003/10/20 プログラミング入門2 4
配列の必要性配列の必要性
人数が100人に増えたら?
現在の知識だと・・・点数を格納する変数を100個用意100個分の変数に名前を付ける
→ 変数の名前を書くのが大変,ミスも多くなる!
同じ型の変数の集まりを“背番号”
を付けて管理する配列が便利
同じ型の変数の集まりを“背番号”
を付けて管理する配列が便利
2003/10/20 プログラミング入門2 5
配列配列の概念の概念
5人分の点数を格納するint型の変数を用意したい場合
整数 変数の宣言 整数型 配列の宣言
vc[4]vc[3]vc[2]vc[1]
int vc[5]; 宣言
型名 変数名
配列名 要素数vc[0]
型名 変数名
int vx; 宣言
VXintvc[0] ~vc[4]までの5個のint型変数vc[0] ~vc[4]までの5個のint型変数
一つ一つを,
配列の要素という
一つ一つを,
配列の要素という
2003/10/20 プログラミング入門2 6
配列の注意点配列の注意点
整数型 配列の宣言
要素数を5とすると・・
vc[0], vc[1], vc[2], vc[3], vc[4]
の5つのint型変数を利用できる!int vc[5]; 宣言
型名 変数名
要素数[ ]内の数字: 添え字
→ 背番号
vc[4]vc[3]vc[2]vc[1]vc[0]
注意!vc[5] という要素は存在しない!(配列は0から始まるため)
※浮動小数点(double)でも同様
2003/10/20 プログラミング入門2 7
配列使用のメリット配列使用のメリット ~~ 配列配列 とと forfor文文 ((p.90p.90))
ソースファイル名: list0502.c (p.90)配列の各要素に先頭から順に1,2,3,4,5を代入して表示
代入する値を少し変更しています
#include <stdio.h>
int main(void){
int vc[5];
vc[0] = 0;vc[1] = 1;vc[2] = 2;vc[3] = 3;vc[4] = 4;
printf("vc[0] = %d¥n", vc[0]);printf("vc[1] = %d¥n", vc[1]);printf("vc[2] = %d¥n", vc[2]);printf("vc[3] = %d¥n", vc[3]);printf("vc[4] = %d¥n", vc[4]);
return (0);}
#include <stdio.h>
int main(void){
int vc[5];
vc[0] = 0;vc[1] = 1;vc[2] = 2;vc[3] = 3;vc[4] = 4;
printf("vc[0] = %d¥n", vc[0]);printf("vc[1] = %d¥n", vc[1]);printf("vc[2] = %d¥n", vc[2]);printf("vc[3] = %d¥n", vc[3]);printf("vc[4] = %d¥n", vc[4]);
return (0);}
配列を使って変数名は簡潔になったが,もっと効率の良い方法は?
この部分が0~4まで順番に変化
先週の繰り返し文を使ってみては?
2003/10/20 プログラミング入門2 8
配列使用のメリット配列使用のメリット ~~ 配列配列 とと forfor文文 ((p.90p.90))ソースファイル名: list0503.c (p.90)配列の各要素に先頭から順に0,1,2,3,4 を代入して表示For文を使って簡潔に記述
代入する値を変更しています
#include <stdio.h>
int main(void){
int vc[5];int i;
for (i = 0; i < 5; i++)vc[i] = i;
for (i = 0; i < 5; i++)printf("vc[%d] = %d¥n", i, vc[i]);
return (0);}
#include <stdio.h>
int main(void){
int vc[5];int i;
for (i = 0; i < 5; i++)vc[i] = i;
for (i = 0; i < 5; i++)printf("vc[%d] = %d¥n", i, vc[i]);
return (0);}
?
?
2003/10/20 プログラミング入門2 9
配列使用のメリット配列使用のメリット ~~ 配列配列 とと forfor文文 ((p.90p.90))ソースファイル名: list0503.c (p.90)配列の各要素に先頭から順に0,1,2,3,4 を代入して表示For文を使って簡潔に記述
代入する値を変更しています
#include <stdio.h>
int main(void){
int vc[5];int i;
for (i = 0; i < 5; i++)vc[i] = i;
for (i = 0; i < 5; i++)printf("vc[%d] = %d¥n", i, vc[i]);
return (0);}
#include <stdio.h>
int main(void){
int vc[5];int i;
for (i = 0; i < 5; i++)vc[i] = i;
for (i = 0; i < 5; i++)printf("vc[%d] = %d¥n", i, vc[i]);
return (0);}
i=5, vc[5]にアクセスしようとすると,エラー!
配列とfor文を使った効率の良い記述!!
2003/10/20 プログラミング入門2 10
配列配列 とと forfor文文 ~~ 練習問題練習問題
List0503.cを変更して,配列の各要素に先頭から順に4,3,2,1,0を代入して表示せよ。
#include <stdio.h>
int main(void){
int vc[5];int i;
for (i = 0; i < 5; i++)vc[i] = i;
for (i = 0; i < 5; i++)printf("vc[%d] = %d¥n", i, vc[i]);
return (0);}
#include <stdio.h>
int main(void){
int vc[5];int i;
for (i = 0; i < 5; i++)vc[i] = i;
for (i = 0; i < 5; i++)printf("vc[%d] = %d¥n", i, vc[i]);
return (0);}
?
?
?
2003/10/20 プログラミング入門2 11
配列配列 とと forfor文文 ~~ 練習問題練習問題
List0503.cを変更して,配列の各要素に先頭から順に4,3,2,1,0を代入して表示せよ。
#include <stdio.h>
int main(void){
int vc[5];int i;
for (i = 0; i < 5; i++)vc[i] = 4 - i;
for (i = 0; i < 5; i++)printf("vc[%d] = %d¥n", i, vc[i]);
return (0);}
#include <stdio.h>
int main(void){
int vc[5];int i;
for (i = 0; i < 5; i++)vc[i] = 4 - i;
for (i = 0; i < 5; i++)printf("vc[%d] = %d¥n", i, vc[i]);
return (0);}
2003/10/20 プログラミング入門2 12
配列の初期化配列の初期化 ((p.92p.92))
変数の宣言と初期化(先週登場)
int vx = 0;
配列の宣言と各要素の初期化(先週登場)
{1, 2, 3, 4, 5};int vc[5] =
vc[4]vc[3]vc[2]vc[1]vc[0]1 →
2→3→4→5→
初期化子の数が足りない場合
{1, 2, 3};int vc[5] =
{1, 2, 3, 0, 0};int vc[5] =
初期化子の足りない要素は0で初期化される!初期化子の足りない要素は0で初期化される!
2003/10/20 プログラミング入門2 13
配列の初期化配列の初期化 ((p.92p.92))
ソースファイル名:list0505.c配列の要素を初期化する
#include <stdio.h>
int main(void){
int vc[5] = { 1, 2, 3, 4, 5 };int i;
for (i = 0; i < 5; i++)vc[i] = i;
for (i = 0; i < 5; i++)printf("vc[%d] = %d¥n", i, vc[i]);
return (0);}
#include <stdio.h>
int main(void){
int vc[5] = { 1, 2, 3, 4, 5 };int i;
for (i = 0; i < 5; i++)vc[i] = i;
for (i = 0; i < 5; i++)printf("vc[%d] = %d¥n", i, vc[i]);
return (0);}
初期化子の個数,値を変えてみる
2003/10/20 プログラミング入門2 14
配列の初期化における注意配列の初期化における注意
初期化子の数が配列の要素数を超えると・・・・
{ 1, 2, 3, 4, 5, 6 };int vc[5] =
vc[4]vc[3]vc[2]vc[1]vc[0]1 →
2→3→4→5→
初期化子の代入
int vc[3]; 6→
配列のサイズをオーバー!vc[3] = {1, 2, 3};
Error !!
2003/10/20 プログラミング入門2 15
配列のコピー配列のコピー ((p.93p.93))2つ配列を用意し,片方のデータをもう一方の配列にコピー
ソースファイル名: list0506.c
#include <stdio.h>
int main(void){
int i;int va[5] = { 10, 20, 30 };int vb[5];
for (i = 0; i < 5; i++)vb[i] = va[i];
for (i = 0; i < 5; i++)printf(“va:%3d, vb:%3d¥n", va[i], vb[i]);
return (0);}
#include <stdio.h>
int main(void){
int i;int va[5] = { 10, 20, 30 };int vb[5];
for (i = 0; i < 5; i++)vb[i] = va[i];
for (i = 0; i < 5; i++)printf(“va:%3d, vb:%3d¥n", va[i], vb[i]);
return (0);}
va[i]の値をvb[i]へ代入
2003/10/20 プログラミング入門2 16
配列のコピー配列のコピー 注意点注意点 ((p.93p.93))
va[5], vb[5] と2つの配列は要素数も同じだし,もっと簡単に次のように代入できないの?
vb = va ;
for (i = 0; i < 5; i++)vb[i] = va[i];
面倒でも,1つ1つ代入していく
重要重要
代入演算子によって,配列を代入することはできない代入演算子によって,配列を代入することはできない
2003/10/20 プログラミング入門2 17
配列の要素に値を読み込む(配列の要素に値を読み込む(scanfscanf)) p.94p.94
ソースファイル名:list0507.c5人分の点数を読込み,値を表示するプログラム
#include <stdio.h>
int main(void){
int i;int vx[5];
for (i = 0; i < 5; i++) {printf("vx[%d]:", i);scanf("%d", &vx[i]);
}
for (i = 0; i < 5; i++)printf("vx[%d]=%d¥n", i, vx[i]);
return (0);}
#include <stdio.h>
int main(void){
int i;int vx[5];
for (i = 0; i < 5; i++) {printf("vx[%d]:", i);scanf("%d", &vx[i]);
}
for (i = 0; i < 5; i++)printf("vx[%d]=%d¥n", i, vx[i]);
return (0);}
&vx[i]
vx[i]も一つのint型の変数だから,いつもどおりその前に&をつければOK
2003/10/20 プログラミング入門2 18
練習問題練習問題
前回のレポート(5人分の点数を読込み,合計と平均を計算)を配列(例えば,int score[5])とfor文を用いて実現せよ。
#include <stdio.h>
int main(void){
int i;int score[5];int sum = 0;
puts(“input score ");for (i = 0; i < 5; i++) {
printf( “no%d:", i + 1);scanf("%d", &score[i]);sum += score[i];
}
printf(“Total:%5d¥n", sum);printf(“Average:%5.2f¥n", (double)sum / 5);
return (0);}
#include <stdio.h>
int main(void){
int i;int score[5];int sum = 0;
puts(“input score ");for (i = 0; i < 5; i++) {
printf( “no%d:", i + 1);scanf("%d", &score[i]);sum += score[i];
}
printf(“Total:%5d¥n", sum);printf(“Average:%5.2f¥n", (double)sum / 5);
return (0);}
2003/10/20 プログラミング入門2 19
もっと便利なプログラムへもっと便利なプログラムへ ~~ オブジェクト形式マクロオブジェクト形式マクロ
先ほどの成績処理プログラム → 点数を読み込む人数を変えるとしたら?
#include <stdio.h>
int main(void){
int i;int score[5];int sum = 0;
puts(“input score ");for (i = 0; i < 5; i++) {
printf( “no%d:", i + 1);scanf("%d", &score[i]);sum += score[i];
}
printf(“Total:%5d¥n", sum);printf(“Average:%5.2f¥n", (double)sum / 5);
return (0);}
#include <stdio.h>
int main(void){
int i;int score[5];int sum = 0;
puts(“input score ");for (i = 0; i < 5; i++) {
printf( “no%d:", i + 1);scanf("%d", &score[i]);sum += score[i];
}
printf(“Total:%5d¥n", sum);printf(“Average:%5.2f¥n", (double)sum / 5);
return (0);}
数字を人数に合わせて全て変更しなければならない
そこで・・・
2003/10/20 プログラミング入門2 20
もっと便利なプログラムへもっと便利なプログラムへ ~~ オブジェクト形式マクロオブジェクト形式マクロ
以下のようにプログラムを変更
#include <stdio.h>
/* 人数を定義 */#define NUMBER 7
int main(void){
int i;int score[NUMBER];int sum = 0;
puts(“input score ");for (i = 0; i < NUMBER; i++) {
printf( “no%d:", i + 1);scanf("%d", &score[i]);sum += score[i];
}
printf(“Total:%5d¥n", sum);printf(“Average:%5.2f¥n", (double)sum / NUMBER );
return (0);}
#include <stdio.h>
/* 人数を定義 */#define NUMBER 7
int main(void){
int i;int score[NUMBER];int sum = 0;
puts(“input score ");for (i = 0; i < NUMBER; i++) {
printf( “no%d:", i + 1);scanf("%d", &score[i]);sum += score[i];
}
printf(“Total:%5d¥n", sum);printf(“Average:%5.2f¥n", (double)sum / NUMBER );
return (0);}
NUMBER に変更
2003/10/20 プログラミング入門2 21
マクロマクロ ((#define#define))
プログラムの中で使う定数を#define指令で置き換える
/* 人数を定義 */#define NUMBER 7
定義 プログラム中にNUMBERと書かれていたら,それを7に置き換える
#define指令のメリット値の管理・変更を一箇所で実現できる
プログラム中で使用する定数に対して,わかりやすい名前を与えられる。コメントを書いておくと更にgood.
見かけ上の動作は変わらないが,中身がわかりやすくなる
見かけ上の動作は変わらないが,中身がわかりやすくなる
2003/10/20 プログラミング入門2 22
多重ループ多重ループ ((p.78p.78))
ソースファイル名: list0415.c (変更あり)for文の中にfor文がある構造
#include <stdio.h>
int main(void){
int i, j;
for (i = 1; i <= 9; i++) {for (j = 1; j <= 9; j++){
printf( "%3d", i * j );
}printf(“¥n”);
}
return (0);}
#include <stdio.h>
int main(void){
int i, j;
for (i = 1; i <= 9; i++) {for (j = 1; j <= 9; j++){
printf( "%3d", i * j );
}printf(“¥n”);
}
return (0);}
まずは実行してみよう
2003/10/20 プログラミング入門2 23
多重ループの実行過程多重ループの実行過程
for文の中にfor文がある構造→ 入れ子 という (その他,if文の中にif文 なども)
for文の入れ子構造: 多重ループ
for (i = 1; i <= 9; i++) {
for (j = 1; j <= 9; j++){
printf( "%3d", i * j );
}printf(“¥n”);
}
外側を固定し,内側にあるfor文からまわす!
i=1 で固定
j=1~9までループ
1 1~9
表示
i=2 で固定 1 2 3 4 5 6 7 8 9 ¥nj
2 4 6 8 10 12 14 16 18 ¥n
i ・・・・・・・・・・・・・・・・・・・・・・・・・・・
2003/10/20 プログラミング入門2 24
多重ループの理解多重ループの理解 ((p.80p.80))ソースファイル名: list0417.c横幅・高さを入力し,*の集まりで長方形を表示
#include <stdio.h>
int main(void){
int i, j;int width, height;
puts(“長方形を作ります");printf("横幅:");scanf("%d", &width);printf("高さ:");scanf("%d", &height);
for (i = 1; i <= height; i++) {for (j = 1; j <= width; j++) {
printf( “*” );}printf( “¥n” );
}
return (0);}
2003/10/20 プログラミング入門2 25
22次元配列(次元配列(p.102p.102))これまでの配列 → 1次元のデータ
行列演算,画像処理 → 2次元のデータを表す配列が必要!
1次元配列
int ma[2];i i=0
ma[1]ma[0]
i=1
2次元配列
int ma[2][3];i j
ma[1][0]
ma[0][0]i=0
i=1
j=0
ma[1][1]
ma[0][1]
j=1
ma[1][2]
ma[0][2]
j=2
縦2 x 横3 の2次元の表ができる!縦2 x 横3 の2次元の表ができる!
2003/10/20 プログラミング入門2 26
22次元配列を用いた行列演算次元配列を用いた行列演算 (p.102)(p.102)ソースファイル名: list0514.c2次元配列を使った行列の足し算
#include <stdio.h>int main(void){
int i, j;int ma[2][3] = { {1, 2, 3}, {4, 5, 6} };int mb[2][3] = { {6, 3, 4}, {5, 1, 2} };int mc[2][3] = { 0 };
for (i = 0; i < 2; i++){ for (j = 0; j < 3; j++){
mc[i][j] = ma[i][j] + mb[i][j];}
}for (i = 0; i < 2; i++) {
for (j = 0; j < 3; j++){printf("%3d", mc[i][j]);
}printf( “¥n” );
}
return (0);}
#include <stdio.h>int main(void){
int i, j;int ma[2][3] = { {1, 2, 3}, {4, 5, 6} };int mb[2][3] = { {6, 3, 4}, {5, 1, 2} };int mc[2][3] = { 0 };
for (i = 0; i < 2; i++){ for (j = 0; j < 3; j++){
mc[i][j] = ma[i][j] + mb[i][j];}
}for (i = 0; i < 2; i++) {
for (j = 0; j < 3; j++){printf("%3d", mc[i][j]);
}printf( “¥n” );
}
return (0);}
2003/10/20 プログラミング入門2 27
22次元配列の初期化次元配列の初期化
2次元配列の初期化
int ma[2][3] = { {1, 2, 3}, {4, 5, 6} };int mb[2][3] = { {6, 3, 4}, {5, 1, 2} };int mc[2][3] = { 0 };
ma[1][0]
ma[0][0]
ma[1][1]
ma[0][1]
ma[1][2]
ma[0][2]
{ 1, 2, 3 }
{ 4, 5, 6 }
全部0で初期化
2003/10/20 プログラミング入門2 28
22次元配列の実例次元配列の実例 ~画像の色データの格納~画像の色データの格納
デジタル画像 → 2次元のデータ(?画素 x ? 画素)画素(Pixel)
2次元配列: image[ i ][ j ] 色(R,G,B)データ
2003/10/20 プログラミング入門2 29
配列配列 まとめまとめ
配列同じ型のデータの集合を効率良く扱うことが可能
データを番号(添え字)を使ってアクセス
場合によっては,一度も文を実行しないこともある
オブジェクト形式マクロ#defineで定数に名前を付けて,プログラムを見やすく!
配列と繰り返し文の併用で効果倍増
2003/10/20 プログラミング入門2 30
今日の課題今日の課題
配列の課題
1.5人分の体重をキーボードから読込んで配列に値を格納した上で,平均体重, 最高体重,最低体重を求めて表示しなさい。但し,データ型には小数も扱えるdouble型の配列を用いること。人数は#defineで記述すること。
ファイル名:kadai0501.c
多重ループの課題
2. 以下の2x3行列Aと3x2行列Bの乗算結果を表示せよ。(行列の確保には2次元配列を使用し,乗算の計算には多重ループを用いること)ファイル名:kadai0502.c
配列,for文,if文を使用
?
BAC
BA
*132231
,123321
=
=
=
2003/10/20 プログラミング入門2 31
余裕のある人向け(課題3)余裕のある人向け(課題3)
課題1,2ができた人は以下の問題にチャレンジ!
以下の連立一次方程式を,行列演算によって解け。
ポイント : 逆行列の算出,課題2の行列積の計算を利用
x + 2y = 8-2x + 4y = 0
の逆行列の求め方
−
−−
=
=
=
−
=
=
=
−
−
−−
acbd
bcadA
dcba
A
BAXyx
BAXyx
1
2x208
4221
08
4221
1
11
行列を用いた解法