• 検索結果がありません。

講習No.10

N/A
N/A
Protected

Academic year: 2021

シェア "講習No.10"

Copied!
17
0
0

読み込み中.... (全文を見る)

全文

(1)

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]は存 在しない

復習

(2)

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} }; 初期化は宣言と同時に!

復習

(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 続行するには何かキーを. . . 改良型:縦の合計を出力 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 合計を求める 外側ループ 合計を求める 内側ループ

復習

(4)

xxの値は5である xxの値は 5である xxの値は005である yyの値は3.140000である yyの値は 3.140000である yyの値は 3.140である 続行するには何かキーを押してください . . .

printf()関数における書式指定

#include <stdio.h> main() { int xx = 5; float yy = 3.14; printf("xxの値は%dである¥n", xx); printf("xxの値は%3dである¥n", xx); //全体で3文字の範囲に右詰 printf("xxの値は%03dである¥n", xx); //同上に加えて,0を詰める printf("yyの値は%fである¥n", yy); printf("yyの値は%10fである¥n", yy); //全体で10文字の範囲に右詰 printf("yyの値は%10.3fである¥n", yy); //同上に加えて,小数以下3桁 } 3文字右詰 3文字右詰で左は0で埋める 10文字右詰(少数以下6桁)

3.140

全体で10文字 少数以下3文字 10文字右詰で少数以下3桁

復習

(5)

例えば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つ目の[ ]を付けない.

文字列の配列

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 最後は0 ss[0] → "kandai" ss[2] → "densi" ss[4]は無い

4行

(6)

文字列の配列を用いたプログラムの例

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文字まで):Matsushima 2人目の名前を入れてください(30文字まで):Abe 3人目の名前を入れてください(30文字まで):Putin 4人目の名前を入れてください(30文字まで):Trump 入力された名前は次のとおりである 1番 Matsushima 2番 Abe 3番 Putin 4番 Trump 続行するには何かキーを押してください . . . 横方向の列数は最大 文字数プラス1にする 普通,「0人目」とは 言わないので,こ こではプラス1して おいた &と2つ目の[ ]を付けない. 2つ目の[ ]を付けない. 文字列の配列のポイント ss[i][j]のようにインデックスを二つ指定した 場合は文字コードを表すchar型変数 ss[i]のようにインデックスを一つだけ指定した 場合は文字列を表すchar型変数の1次元配列 %-11sで,「11文字で左詰め表示」と なる(マイナス記号は左詰め指定) char型 2次元配列 !特殊ルール! &が不要なのは文 字列を%sで入力す る場合だけ!

(7)

関数の作成

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

#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個

プログラムの見通しが悪い

後から見て理解できない

一つの修正が別の箇所に影響

デバッグ困難

複数人で共同作業できない

大量の変数を用いる

変数名が重複する

ある変数に関係する修正が他

の変数に影響

大規模なプログラムの例

(8)

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

モジュール1

モジュール2

モジュール3

モジュール4

プログラム

プログラムを小さな機能単位である

モジュール

に分割

モジュール内では見通しが良い

複数のプログラマーが異なったモ

ジュールを担当できる(共同作業)

モジュールを部品として再利用できる

各モジュールごとに変数名が独立

プログラム内で変数名が重複しない

このようなモジュールを

サブルーチン

と呼ぶ

int a; int a;

同じ変数名

a

でもモジュールごとに異なっ

た変数と見なされる.

ローカル変数

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

(9)

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

データ入力モジュール scanf()を用いて配列に100個 までのデータを入力する 平均値計算モジュール 配列の値の平均値を求める 確率誤差計算モジュール 配列の値とその平均値から 確率誤差を求める 最大値計算モジュール 配列の値の最大値を求める 画面表示モジュール 配列の値を綺麗に画面表示 する プログラムA モジュール1 モジュール2 モジュール3 結果の表示 プログラムB モジュール1 モジュール2 モジュール3 結果の表示 モジュール4

(10)

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

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

関数

#include <stdio.h> #include <math.h> int main(void) { double x, y; scanf(‶%lf‶, &x); y = sqrt(x); printf(‶%e‶, y); } 平方根を求める関数 入力をする関数 出力をする関数

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

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

(11)

数学の場合

関数とは何か?

底辺

a

で高さ

b

の三角形の面積を求める関数

2

)

,

(

a

b

ab

f

)

4

,

3

(

f

s 

三角形の面積

を表す関数

もしも 底辺

3

[cm]で,

高さ

4

[cm]なら

sは

6

[cm

2

]になる

引数の代入

関数値を代入

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

(12)

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()関数の先頭 から実行される 関数の呼び出し (関数の実行)

引数の代入

ローカル変数 (関数内での み有効)

関数値の代入

(13)

関数定義における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文で返る値を返却値,返り値あるいは戻り値と呼ぶ

(14)

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:

仮引数

仮引数もローカル変数

→関数内でのみ有効

(15)

ローカル変数(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()関数

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

main()関数

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

(16)

ローカル変数(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という 変数は定義され ていない ⇒ エラー!

(17)

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

#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()関数は短くすっきり

参照

関連したドキュメント

1-1 睡眠習慣データの基礎集計 ……… p.4-p.9 1-2 学習習慣データの基礎集計 ……… p.10-p.12 1-3 デジタル機器の活用習慣データの基礎集計………

シートの入力方法について シート内の【入力例】に基づいて以下の項目について、入力してください。 ・住宅の名称 ・住宅の所在地

1200V 第三世代 SiC MOSFET と一般的な IGBT に対し、印可する V DS を変えながら大気中を模したスペクトルの中性子を照射 した試験の結果を Figure

サンプル 入力列 A、B、C、D のいずれかに指定した値「東京」が含まれている場合、「含む判定」フラグに True を

パキロビッドパックを処方入力の上、 F8特殊指示 →「(治)」 の列に 「1:する」 を入力して F9更新 を押下してください。.. 備考欄に「治」と登録されます。

のうちいずれかに加入している世帯の平均加入金額であるため、平均金額の低い機関の世帯加入金額にひ

・電源投入直後の MPIO は出力状態に設定されているため全ての S/PDIF 信号を入力する前に MPSEL レジスタで MPIO を入力状態に設定する必要がある。MPSEL

Dual I/O リードコマンドは、SI/SIO0、SO/SIO1 のピン機能が入出力に切り替わり、アドレス入力 とデータ出力の両方を x2