18
次次次次 float d[3][4]; d[0][0] d[0][1] d[0][2] d[0][3] d[1][0] d[1][1] d[1][2] d[1][3] d[2][0] d[2][1] d[2][2] d[2][3] i = 0 i = 1 i = 2 次次次次 d[i][j] ⇒ 2 次次次次次次次次 i 次次次次次次次次次次 次次 3 次 次次 4 次 次 float 次次次 次次次次次次次次次次次 次次次次次次次次次次次 j = 0 j = 1 j = 2 j = 3 次次 d[3][4] 次次 次次次次 次次

2次元配列を用いたソースプログラムの例 (3)

  • Upload
    lilith

  • View
    61

  • Download
    0

Embed Size (px)

DESCRIPTION

復習. 2次元配列を用いたソースプログラムの例 (3). 改良型:縦の合計を出力. #include main() { int aa[][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} }; int i , j , sum = 0; for ( i = 0; i < 3; i ++) // 配列内容を出力 { for ( j = 0; j < 4; j ++) { - PowerPoint PPT Presentation

Citation preview

Page 1: 2次元配列を用いたソースプログラムの例 (3)

2次元配列

float d[3][4];

d[0][0] d[0][1] d[0][2] d[0][3]

d[1][0] d[1][1] d[1][2] d[1][3]

d[2][0] d[2][1] d[2][2] d[2][3]

i = 0

i = 1

i = 2

3行

2次元配列 d[i][j] ⇒ 2 つのインデックス i とjでデータが指定される

縦が 3行

横が 4列 の float 型の表

縦のインデックスは2まで

横のインデックスは3まで

j = 0 j = 1 j = 2 j = 3

4列

d[3][4] は存在しない

復習

Page 2: 2次元配列を用いたソースプログラムの例 (3)

2次元配列の初期化 (2)

int aa[][] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };

d[0][0] = 1

d[0][1] = 2

d[0][2] = 3

d[0][3] = 4

d[1][0] = 5

d[1][1] = 6

d[1][2] d[1][3]

d[2][0] = 9

d[2][1] = 10

d[2][2] = 11

d[2][3]

i = 0

i = 1

i = 2

j = 0 j = 1 j = 2 j = 3 この部分は0に初期化

される

注意  int aa[3][4];のように初期化しない配列の値は未定義

int aa[][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };

縦の行数は省略可

横の列数は省略不可

⇒ 使用予定の最大の列数を指定する

int aa[][4] = { {1, 2, 3, 4}, {5, 6}, {9, 10, 11} };

int aa[3][4];aa[][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };

初期化は宣言と同時に!

復習

Page 3: 2次元配列を用いたソースプログラムの例 (3)

2次元配列を用いたソースプログラムの例 (3)

#include <stdio.h>main(){ int aa[][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} }; int i, j, sum = 0; for (i = 0; i < 3; i++) // 配列内容を出力 { for (j = 0; j < 4; j++) { printf("%2d ", aa[i][j]); } printf("\n"); } printf("==============\n"); for (j = 0; j < 4; j++) // 縦の合計を出力 { sum = 0; for (i = 0; i < 3; i++) { sum = sum + aa[i][j]; } printf("%2d ", sum); } printf("\n");}

1 2 3 4 5 6 7 8 9 10 11 12==============15 18 21 24続行するには何かキーを . . .

1 2 3 4 5 6 7 8 9 10 11 12==============15 18 21 24続行するには何かキーを . . .

改良型:縦の合計を出力

d[0][0] = 1

d[0][1] = 2

d[0][2] = 3

d[0][3] = 4

d[1][0] = 5

d[1][1] = 6

d[1][2] = 7

d[1][3] = 8

d[2][0] = 9

d[2][1] = 10

d[2][2] = 11

d[2][3] = 12

復習

Page 4: 2次元配列を用いたソースプログラムの例 (3)

文字列の配列

char ss[4][7] = { "kandai", "denki", "densi", "joho" };

'k' 'a' 'n' 'd' 'a' 'i' 0

'd' 'e' 'n' 'k' 'i' 0

'd' 'e' ‘n' 's' ‘i' 0

'j' 'o' 'h' 'o' 0

ss[0][4] = 'a'

ss[2][2] = 'n'

i = 0

i = 1

i = 2

i = 3

j = 0 j = 1 j = 2 j = 3 j = 4 j = 5 j = 6

値が 0

最後は 0ss[0] →"kandai"

ss[2] →"densi"

ss[4] は無い

4 行

例えば ss[0][4] は a, ss[2][2] は nという文字である.横方向に見れば, ss[0] は kandai, ss[2] は densi という文字列である.続行するには何かキーを押してください . . .

#include <stdio.h>main(){ char ss[][7] = { "kandai", "denki", "densi", "joho" }; printf("例えば ss[0][4]は %c, ss[2][2]は %cという文字である. \n", ss[0][4], ss[2][2]); printf("横方向に見れば, ss[0]は %s, ss[2]は %sという文字列である. \n", ss[0], ss[2]);}

行数は省略可 列数は省略不可.最大文字数プラス 1 にする.

2 つ目の [ ] を付けない.

Page 5: 2次元配列を用いたソースプログラムの例 (3)

文字列の配列を用いたプログラムの例int main(void){ char ss[4][31]; int i; for (i = 0; i < 4; i++) { printf("%d人目の名前を入れてください (30文字まで ):", i + 1); scanf("%s", ss[i]); } printf("入力された名前は次のとおりである \n"); for (i = 0; i < 4; i++) { printf("%d番 %-11s\n", i + 1, ss[i]); }}1 人目の名前を入れてください (30文字まで ):Matsushima2 人目の名前を入れてください (30文字まで ):Abe3 人目の名前を入れてください (30文字まで ):Putin4 人目の名前を入れてください (30文字まで ):Obama入力された名前は次のとおりである1 番 Matsushima2 番 Abe3 番 Putin4 番 Obama続行するには何かキーを押してください . . .

横方向の列数は最大文字数プラス 1 にす

普通,「 0 人目」とは言わないので,ここではプラス 1 しておいた

& と 2 つ目の [ ] を付けない.

2 つ目の [ ] を付けない.

文字列の配列のポイントss[i][j] のようにインデックスを二つ指定した場合は文字を表すss[i] のようにインデックスを一つだけ指定した場合は文字列を表す

文字列の配列のポイントss[i][j] のようにインデックスを二つ指定した場合は文字を表すss[i] のようにインデックスを一つだけ指定した場合は文字列を表す

%-11s で,「 11 桁で左詰め表示」となる ( マイナス記号は左詰め指定 )

Page 6: 2次元配列を用いたソースプログラムの例 (3)

文字列操作ライブラリを用いたソースプログラムの例

#include <stdio.h>#include <string.h>int main(void){ char ss1[] = "Kandai-sei", ss2[] = "Computer Science"; char ss3[100] = ""; //初めは空の文字列.十分な文字数を確保する.

printf("ss1の文字数は %dですが, ss3の文字数は %dです. \n", strlen(ss1), strlen(ss3)); strcpy(ss3, ss1); //ss1の内容を ss3にコピー printf("ss3の内容は %sになり,文字数は %dになりました. \n", ss3, strlen(ss3)); strcat(ss3, " / "); //ss3の最後に " / " を付加 strcat(ss3, ss2); //ss3の最後に ss2を付加 printf("今度の ss3は %sで,文字数は %dです. \n", ss3, strlen(ss3));}ss1の文字数は 10ですが, ss3の文字数は 0 です.ss3の内容は Kandai-seiになり,文字数は 10になりました.今度の ss3は Kandai-sei / Computer Scienceで,文字数は29です.続行するには何かキーを押してください . . .

配列なので, ss3=ss1という代入はできない

空の文字列として初期化することは重要!

復習

Page 7: 2次元配列を用いたソースプログラムの例 (3)

文字列を操作するライブラリ関数の例

ライブラリ関数 意味int strlen(char s[]) 文字列 s の文字数を返すchar* _strset(char s[], int c)

文字列 s をアスキーコード c の文字で埋める

char* strcpy(char s1[], char s2[])

文字列 s2 を文字列 s1 にコピーする

char* strcat(char s1[], char s2[])

文字列 s1 の末尾に文字列 s2 を付加する

int strcmp(char s1[], char s2[])

文字列 s1 と文字列 s2 を比較する.同じ文字列なら 0 を返す.辞書の順序でs1 が s2 より前なら,正の値を返す.s1 が s2 より後なら,負の値を返す.

これらの文字列操作用ライブラリ関数を利用するには #include <string.h>が必要.

char* はポインタ. 2 年生で学習

注 1 ) 関数の表記は,現在の学習レベルに合わせて変更してある.注 2 ) 関数については第 10 回以降で詳しく学習.

復習

Page 8: 2次元配列を用いたソースプログラムの例 (3)

関数の作成: なぜ自分で関数を作るのか?

#include <stdio.h>

int main(void){ char err[] = "BMPOut"; int i, j; outpath = fname; if ((outfile = fopen(outpath, "wb")) == NULL) LW_ERROR(FILEOPEN, outpath);

int Wx = w.right - w.left; int Wy = w.top - w.bottom; int Ox; if (Wx % 4 == 0) Ox = Wx; else Ox = (Wx/4 + 1)*4;

// バッファー領域の確保 int imageSize = Ox * Wy;

unsigned char* bmpimage = (unsigned char*) Malloc(sizeof(char)*Ox, err);

BITMAPFILEHEADER bfh; bfh.bfType = ('M'<< 8)|'B'; bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256; bfh.bfSize = bfh.bfOffBits + imageSize; bfh.bfReserved1 = bfh.bfReserved2 = 0; ewrite(&bfh, sizeof(bfh), 1); BITMAPINFOHEADER bmih; bmih.biSize = sizeof(bmih); bmih.biWidth = Wx; bmih.biHeight = Wy; bmih.biPlanes = 1; bmih.biBitCount = 8; bmih.biCompression = BI_RGB;

長いプログラム例えば,ソース 500

行変数 100 個

プログラムの見通しが悪い後から見て理解できない一つの修正が別の箇所に影響

→  デバッグ困難複数人で共同作業できない

大量の変数を用いる変数名が重複するある変数に関係する修正が他の変数に影響

大規模なプログラムの例

Page 9: 2次元配列を用いたソースプログラムの例 (3)

プログラムのモジュール化

モジュール 1

モジュール 2

モジュール 3

モジュール 4

プログラムプログラムを小さな機能単位であるモジュールモジュールに分割モジュール内では見通しが良い複数のプログラマーが異なったモジュールを担当できる ( 共同作業 )モジュールを部品として再利用できる

各モジュールごとに変数名が独立プログラム内で変数名が重複しない

このようなモジュールを

サブルーチンと呼ぶint a;

int a; 同じ変数名 a でもモジュールごとに異なった変数と見なされる.ローカ

ル変数

注意 ここでは、機能単位の意味で「モジュール」という用語を用いているが、より専門的なソフトウェア工学では用語「モジュール」にはもっと厳密な定義がある。

注意 ここでは、機能単位の意味で「モジュール」という用語を用いているが、より専門的なソフトウェア工学では用語「モジュール」にはもっと厳密な定義がある。

Page 10: 2次元配列を用いたソースプログラムの例 (3)

プログラムのモジュール例

データ入力モジュールscanf() を用いて配列に100 個までのデータを入力する平均値計算モジュール配列の値の平均値を求める

確率誤差計算モジュール配列の値とその平均値から確率誤差を求める

最大値計算モジュール配列の値の最大値を求める

画面表示モジュール配列の値を綺麗に画面表示する

プログラムA

モジュール1

モジュール2

モジュール3

結果の表示

プログラムB

モジュール1

モジュール2

モジュール3

結果の表示

モジュール4

Page 11: 2次元配列を用いたソースプログラムの例 (3)

C 言語においてモジュールとして働くもの

C 言語のおける機能単位(モジュール) = 関数

#include <stdio.h>#include <math.h>

int main(void){

double x, y;scanf(‶%lf‶, &x);y = sqrt(x);printf(‶%e‶, y);

}

平方根を求める関数

入力をする関数

出力をする関数

プログラムは関数の組み合わせでできている!

自分で作ったプログラムをモジュール化するにはどうするか?⇒  関数を自分で作る!

Page 12: 2次元配列を用いたソースプログラムの例 (3)

数学の場合

関数とは何か?

底辺 aで高さ bの三角形の面積を求める関数

2),(ab

baf

)4,3(fs

三角形の面積を表す関数

もしも 底辺 3 [cm] で,

高さ 4 [cm] なら

sは 6 [cm2] になる

引数の代入関数値を代入

プログラミングでは・・・変数には型がある →変数が文字や配列の場合もある関数値の代入でも型が重要 →関数値が文字や配列の場合もある

プログラミングでは・・・変数には型がある →変数が文字や配列の場合もある関数値の代入でも型が重要 →関数値が文字や配列の場合もある

Page 13: 2次元配列を用いたソースプログラムの例 (3)

C における関数の宣言と呼び出し (1)

#include <stdio.h>

float menseki(float a, float b){

float s;s = a * b / 2;return s ;

}

int main(void){

float kekka;printf("面積を求めます. \n");kekka = menseki(3, 4);printf("面積は %f です. \n",

kekka);}

関数の定義(実行ではな

い)

関数値の型

関数の名前

引数の型と名前

!注意!プログラムは必ずmain() 関数の先頭

から実行される

関数の呼び出し( 関数の実行 )

引数の代入

ローカル変数

( 関数内でのみ有効 )

関数値の代入

Page 14: 2次元配列を用いたソースプログラムの例 (3)

関数定義における return 文

float menseki(float a, float b){ return a * b / 2;}

float menseki(float a, float b){ float s; s = a * b / 2; return s;}int func(int x, int y){ if (x*y % 2 == 0) { return 1; }}

return 文を実行しない場合があるのでダメ.

int func(int x, int y){ if (x*y % 2 == 0) { return 1; } else { return 0; }}

return 文は複数あってもOK.但し,どのような場合でも必ずその一つを実行すること.

return 文の文法

return 式 ;

return 文を実行すると関数を終了する.式で計算した値を返す.

return 文の文法

return 式 ;

return 文を実行すると関数を終了する.式で計算した値を返す.

return 文で返る値を返却値,返り値あるいは戻り値と呼ぶ

Page 15: 2次元配列を用いたソースプログラムの例 (3)

C における関数の宣言と呼び出し (2)

#include <stdio.h>

float menseki(float a, float b){

return a * b / 2;}

int main(void){

float x, y, kekka;printf("底辺は ?"); scanf("%f", &x);printf("高さは ?"); scanf("%f", &y);

kekka = menseki(x, y);printf("面積は %f です. \n", kekka);

}

printf("面積は %f です. \n", menseki(x, y)); でもOK

x,y:実引数

a, b: 仮引数仮引数もローカル変

数→ 関数内でのみ有効

Page 16: 2次元配列を用いたソースプログラムの例 (3)

ローカル変数 (1)#include <stdio.h>

float menseki(float a, float b){

float s;s = a * b / 2;return s;

}

int main(void){

float a, b, kekka;printf("底辺は ?"); scanf(" %f ",

&a);printf("高さは ?"); scanf(" %f ",

&b);kekka = menseki();printf("面積は %f です. \n", kekka);

}

menseki() 関数menseki() 関数

ローカル変数同じ変数名 a, b でも,関数が違うと,別の変数と見なされる⇒赤色 a,b と青色 a,b は別の変数

menseki()関数内のローカル

変数 a と b

main() 関数main() 関数

main()関数内のローカル変数 a と b

Page 17: 2次元配列を用いたソースプログラムの例 (3)

ローカル変数 (2)

#include <stdio.h>

float menseki(float a, float b){

kekka = a * b / 2;}

int main(void){

float a, b, kekka;printf("底辺は ?"); scanf(" %f ",

&a);printf("高さは ?"); scanf(" %f ",

&b);menseki(a,b);printf("面積は %f です. \n", kekka);

}変数は,それを宣言した関数内でのみ有効

変数 kekka は main() 関数中でのみ使える

関数menseki() 内では kekka という変数は定義されていない ⇒ エラー!

Page 18: 2次元配列を用いたソースプログラムの例 (3)

プログラムのモジュール化 ( 関数化 ) のススメ

#include <stdio.h>int main(void){   float a, b, x[100]; int i, j, n;  ・・・

//データ入力 for (i = 0; i < n; i++) scanf(" %f ", &a); ・・・  ・・・

// データ処理 for (i = 0; i < n; i++) ・・・  ・・・

// 結果出力 ・・・  ・・・ printf("面積は %f です. \n", kekka);}

#include <stdio.h>

int Input(float x[]){ ・・・}

int Calculation(float x[], int n){ ・・・}

int Output(float x[], int n){ ・・・}

int main(void){ Input() //データ入力 Calculation() //データ処理 Output() // 結果出力}

ダメプログラマAさん 優秀プログラマBさん

全ての処理がmain() 関数にダラダラ書かれている

機能ごとにくっきりと関数 ( モジュール )分け

main() 関数は短くすっきり