プログラミング入門2yaoki/program2/pdf/p05.pdfプログラミング入門2 第 5 回 配列...

32
プログラミング入門2 プログラミング入門2 5 5 配列 配列 同じデータの集合を効率よく扱う 同じデータの集合を効率よく扱う 芝浦工業大学情報工学科 芝浦工業大学情報工学科 講師 講師 青木 青木 義満 義満

Upload: others

Post on 25-Apr-2020

3 views

Category:

Documents


0 download

TRANSCRIPT

プログラミング入門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

行列を用いた解法

2003/10/20 プログラミング入門2 32

プログラミング入門プログラミング入門22 中間試験実施中間試験実施

日時: 11月10日(月) 4限(14:40~)※3限の通常授業終了後に実施

3限はいつも通りPC実習室にて

場所: 斉藤記念館 大教室

範囲: 10月27日までに学習した内容

持ち込み:全て不許可