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

C言語入門

N/A
N/A
Protected

Academic year: 2021

シェア "C言語入門"

Copied!
60
0
0

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

全文

(1)

C言語入門

第4週

プログラミング言語Ⅰ(実習を含む。),

計算機言語Ⅰ・計算機言語演習Ⅰ,

(2)

https://code.visualstudio.com/

• Microsoft 製プログラミング用テキストエディタ

2015-04-29 にリリースされたばかり のテキストエディタ。Windows 以外 にも Mac, Linux 用もある。

(3)

制御構造

条件分岐と繰り返し

(4)

流れ図(フローチャート)

• プログラムの処理の流れを図示する方法

条件分岐 処理 端子 定義済み処理 表示 手操作入力 プログラムの開始と終了 代入や演算等 各ステップにおける処理 サブルーチンや関数等 処理の振り分け 画面等への出力 キーボード等からの入力 各部品を矢印で繋ぐ事で処理の流れ を視覚的に表現する。 各部品の内部にはそれぞれのステップ で行う内容に書き換えて使う。 結合子 別のフローチャートと結合 2015-05-12追加

(5)

条件分岐

if 文と switch 文

(6)

(if 文)

• 真偽値による場合分け

if (条件式1) {

// 条件式1が真の場合の処理1

}

条件式1 真 偽 処理1 if 文を使うと特定の条件下で実行する処理を指定出来る。

(7)

条件分岐

(if, else 文)

• 真偽値による場合分け

if (条件式1) {

// 条件式1が真の場合の処理1

} else {

// 条件式1が偽の場合の処理2

}

教科書 pp.130-133. 条件式1 真 偽 処理1 処理2 if, else 文を使うと特定の条件下で別の処理を指定出来る。

(8)

(if, else 文)

• 真偽値による場合分け

if (条件式1) {

if (条件式2) {

// 条件式1が真かつ

// 条件式2が真の場合の処理1

} else {

// 条件式1が真かつ

// 条件式2が偽の場合の処理2

}

} else {

// 条件式1が偽の場合の処理3

}

条件式1 真 偽 処理3 条件式2 真 偽 処理1 処理2 if, else 文は任意の数入れ子に出来る。 だだし、入れ子が深くなると読み難くなるので注意。 2015-05-15修正 誤:処理2,3,1 正:処理1,2,3

(9)

入れ子の条件分岐

(if, else 文)

• 真偽値による場合分け

if (条件式1) {

// 条件式1が真の場合の処理1

} else {

if (条件式2) {

// 条件式1が偽かつ

// 条件式2が真の場合の処理2

} else {

// 条件式1が偽かつ

// 条件式2が偽の場合の処理3

}

}

条件式1 真 偽 条件式2 真 偽 if, else 文は任意の数入れ子に出来る。 else 側の if は else if で置き換ると入れ子を防げる。 教科書 pp.130-133. 処理1 処理2 処理3

(10)

(if, else if, else 文)

• 真偽値による場合分け

if (条件式1) {

// 条件式1が真の場合の処理1

} else if (条件式2) {

// 条件式1が偽かつ

// 条件式2が真の場合の処理2

} else {

// 条件式1が偽かつ

// 条件式2が偽の場合の処理3

}

else if は任意の数追加出来る。 入れ子を作らずに複数の条件を追加出来る。 条件式1 真 偽 条件式2 真 偽 処理1 処理2 処理3

(11)

多分岐判断機構 (switch 文)

• 値による場合分け

switch (式) {

case 値1:

// 式が値1の場合の処理1

case 値2:

// 式が値2の場合の処理2

default:

// 他の条件に

// 当てはまらない場合の処理N

};

教科書 pp.134-140. break 文を入れておかないと 次の条件の処理を 連続して実行するので注意。 break break break 式 値1 処理1 処理2 default 値2 処理N

(12)

平方根の計算

条件分岐の例題

(13)

sqrt 関数

• 書式:

#include <math.h>

double sqrt(double x);

• 引数:

• x:

求める平方根の2乗

• 戻り値:

0 ≤ 𝑥 の場合 𝑥 を返す。

0 ≤ 𝑥 でない場合は処理系依存?

• x が負なら、nan (=非数) を返し、グローバル変数 errno に EDOM

を代入する(errno は errno.h を include すると参照出来る)。

• x が 0 なら 0 を、inf (=∞) なら inf を返す。

• x が nan なら nan を返す。

(14)

平方根の計算

• sqrt() 関数は引数が負の場合計算出来ない。

sqrt_practice_1.c #include <stdio.h> #include <math.h> void main() { double x; fprintf(stderr, "x = ?¥b"); scanf("%lf", &x); printf("x: %f¥n", x); printf("sqrt(x): %f¥n", sqrt(x)); } 1 2 3 4 5 6 7 8 9 10 11 mintty+bash+gcc

$ gcc sqrt_practice_1.c && ./a x = 2 x: 2.000000 sqrt(x): 1.414214 $ ./a x = -2 x: -2.000000 sqrt(x): nan

(15)

演習: 平方根の計算(if文)

• sqrt_practice_1.c を参考に 0 ≤ 𝑥 の場合は実

数の平方根

𝑥を、 𝑥 < 0 の場合は虚数の平

方根

−𝑥𝑖 を if 文で場合分けして表示する

sqrt_practice_if.c を完成させよ。虚数は数値

の後に i を表示する事で表現すれば良い。

• 例えば x=-2 の場合は以下のようになる。

mintty+bash+gcc

$ gcc sqrt_practice_if.c && ./a x = -2

x: -2.000000

(16)

演習: 平方根の計算(if文) ヒント

• sqrt_practice_1.c の 10 行目は 𝑥 を表示して

いる。これを if 文で場合分けしてやれば良い。

条件式 真 偽 𝑥 −𝑥 𝑖 sqrt_practice_1.c printf("sqrt(x): %f¥n", sqrt(x)); 10 𝑥 sqrt_practice_if.c if (条件式) { // 𝑥 を表示 } else { // −𝑥 と 𝑖 を表示 } 10 11 12 13 14

(17)

• 書式:

• 条件式 ? 式1 : 式2

条件演算子

三項演算子(?:)

[1] pp.63-66, 256-257. 条件式 真 偽 式1 式2 condexprtest.c #include <stdio.h> void main() { int i; fprintf(stderr, "i = ?¥b"); scanf("%d", &i);

printf("%s¥n", i ? "not zero" : "zero"); } 1 2 3 4 5 6 7 8 9 mintty+bash+gcc

$ gcc condexprtest.c && ./a i = 1

not zero $ ./a i = 0 zero

(18)

演習: 平方根の計算(条件演算子)

• 先程の負の数の平方根の計算を条件演算子

を用いて解決してみよう。

• 10行目の printf では 2 つ目の引数が %f に 3

つ目の引数が %s へ埋め込まれる。

sqrt_practice_condexpr.c

double x;

fprintf(stderr, "x = ?¥b");

scanf("%lf", &x);

printf("x: %f¥n", x);

printf("sqrt(x): %f%s¥n", sqrt(

/*WYCH*/

),

/*WYCH*/

);

6

7

8

9

10

(19)

奇数と偶数の判定

条件分岐の例題

(20)

奇数と偶数

• 整数のうち 2 で割り切れるのが偶数、2 で割

り切れないのが奇数

• 2 で割り切れるとは?

• 整数を 2 で割った余り(剰余)が 0

• 2 で割り切れないとは

• 整数を 2 で割った余り(剰余)が 0 以外

(21)

C言語の剰余

• 剰余は二項演算子 %

• i % 2 で 2 で割った余りが求まる

• 同じかどうか比較するのは二項演算子 == や !=

• i % 2 == 0 は i を 2 で割った余りが 0 なら真、そ

れ以外は偽

• i % 2 != 0 は i を 2 で割った余りが 0 以外なら真、

それ以外は偽

• i % 2 != 0 は単項演算子 ! を用いて

!(i % 2 == 0) としても同じ意味になる

(22)

演算子の優先度

演算子 結合規則 備考

( ) [ ] -> . 左から右→

! ~ ++ -- + - * & (type) sizeof 右から左← 単項演算子 * / % 左から右→ 二項演算子 + - 左から右→ 二項演算子 << >> 左から右→ bitシフト < <= > >= 左から右→ 関係演算子 == != 左から右→ 等値演算子 & 左から右→ bit毎のAND ^ 左から右→ bit毎のXOR | 左から右→ bit毎のOR && 左から右→ 論理演算子(AND) || 左から右→ 論理演算子(OR) ?: 右から左← 三項演算子 = += -= *= /= %= &= ^= |= <<= >>= 右から左← 代入演算子 , 左から右→ [1] p.65. より 高 低 優先度

(23)

演習: 偶数かどうか判定する

• 標準入力から入力された整数値が奇数かど

うか判別して、奇数であれば入力された数値

に続けて " is even number¥n" そうでなければ

" is not even number¥n" と表示するプログラ

ムを作成せよ。奇数でない場合は何も表示し

なくて良い。

• if_practice_even.c の

/*WYCH*/

の個所を修

(24)

演習: 奇数かどうか判定する

• 標準入力から入力された整数値が奇数かど

うか判別して、奇数であれば入力された数値

に続けて " is odd number¥n" そうでなければ

" is not odd number¥n" と表示するプログラム

を作成せよ。奇数でない場合は何も表示しな

くて良い。

• if_practice_odd.c の

/*WYCH*/

の個所を修正

(25)

演習: 奇数か偶数か判定する

• 標準入力から入力された整数値が奇数かど

うか判別して、奇数であれば入力された数値

に続けて " is odd number¥n"、偶数であれば

入力された数値に続けて "is even number¥n"

と表示するプログラムを作成せよ。

• if_practice_evenodd.c の

/*WYCH*/

の個所を

(26)

閏年の判定

入れ子の条件分岐の例題

(27)

閏年(leap year)とは

• 地球の平均回帰年は365日+約1/4日である

ため1年を356日にしているとカレンダー上の

日付と季節が4年で1日ずつずれてしまう。こ

れを防ぐのが4年に1回設ける2月29日(閏日)。

• 閏年の求め方

• 西暦を4で割り切れるなら閏年?

閏年 判定式 閏年 平年 真 偽

(28)

閏年(leap year)の判定

• 4で割り切れる(割れる)とは?

• 4で割った余りが0ということ

• 4で割り切れる

: year % 4 == 0

• 4で割り切れない : year % 4 != 0

• C言語では0は偽、0以外は真だったから

• 以下のようにも書けるが・・・

• 4で割り切れる

: !(year % 4)

• 4で割り切れない : (year % 4)

ぱっと見て意味の分かり易い書き方をしましょう % : 剰余算演算子 等値演算子 == : 等しい != : 等しくない ! : 論理否定演算子

(29)

演算子の優先度

演算子 結合規則 備考

( ) [ ] -> . 左から右→

! ~ ++ -- + - * & (type) sizeof 右から左← 単項演算子 * / % 左から右→ 二項演算子 + - 左から右→ 二項演算子 << >> 左から右→ bitシフト < <= > >= 左から右→ 関係演算子 == != 左から右→ 等値演算子 & 左から右→ bit毎のAND ^ 左から右→ bit毎のXOR | 左から右→ bit毎のOR && 左から右→ 論理演算子(AND) || 左から右→ 論理演算子(OR) ?: 右から左← 三項演算子 = += -= *= /= %= &= ^= |= <<= >>= 右から左← 代入演算子 , 左から右→ [1] p.65. より 高 低 優先度

(30)

演習: 4 で割り切れるか表示する

• leap_year_practice_1.c の

/*WYCH*/

を書き

換えて、year が 4 で割り切れる場合 "can be

divided by 4."、割り切れない場合 "can not be

divided by 4." と表示するプログラムを完成せ

よ。

mintty+bash+gcc

$ gcc leap_year_practice_1.c && ./a year = 2015

2015 can not be divided by 4. $ ./a year = 2016 2016 can be divided by 4. 2015-05-11修正 誤:dividec 正:divided

(31)

閏年(leap year)の定義

• グレゴリオ暦における閏年の定義

• 判定したい年を西暦で表した際

• 4で割り切れる場合は閏年

(条件1)

• 但し100で割り切れる場合は平年 (条件2)

• 但し400で割り切れる場合は閏年 (条件3)

• 地球の平均回帰年は約365.242199日であ

るため、上記ルールだと約3320年で1日ずれ

る程度で済む。

(32)

閏年(leap year)の判定

4で 割れる 平年 真 偽 閏年 条件1

(33)

閏年(leap year)の判定

4で 割れる 平年 真 偽 100で 割れる 閏年 真 偽 平年 条件1 +条件2

(34)

閏年(leap year)の判定

4で 割れる 平年 真 偽 100で 割れる 閏年 真 偽 400で 割れる 閏年 平年 真 偽 条件1 +条件2 +条件3 完成

(35)

演習: 閏年(leap year)の判定

• leap_year_practice_2.c の

/*WYCH*/

部分を書き換えて閏年か判定するプログラムを

完成せよ。

• /*WYCH*/

の部分には year に格納された西

暦が閏年であれば変数 leap_year_flag に

1 を閏年でなければ 0 を代入するコード作成

すれば良い。これは前のページのフローチャート

を参考に if 文を 3 重の入れ子にすれば出

来る。

• なおここでは紀元前については考慮する必要は

ない。

(36)

演習: 閏年(leap year)の判定

• ヒント1

• 前述の条件1~3のフローチャートをif,else文

で書くと以下のようになる。

条件1 if (/*条件1*/) { /*閏年*/ } else { /*平年*/ } 条件1+条件2 if (/*条件1*/) { if (/*条件2*/) { /*平年*/ } else { /*閏年*/ } } else { /*平年*/ } 条件1+条件2+条件3 if (/*条件1*/) { if (/*条件2*/) { /*条件3のif,else文*/ } else { /*閏年*/ } } else { /*平年*/ }

(37)

演習: 閏年(leap year)の判定

• ヒント2

• 閏年なら leap_year_flag に 1 そうでなけれ

ば 0 を代入すれば良い。

条件1 if (/*条件1*/) { leap_year_flag = 1; /*閏年*/ } else { /*平年*/ }

(38)

月の名前

多分岐の例題

(39)

演習: 月の名前の表示

• monthname_practice_1.c の /*WYCH*/ の部

分を変更し、入力した月 month に対応する英

語の月名(January, February, March, April,

June, July, August, September, October,

November, December )を表示せよ。

mintty+bash+gcc

$ gcc monthname_practice_1.c && ./a month = 1

(40)

繰り返し(ループ)

for文, while文, do-while 文によるループと

(41)

ループの再開と脱出

• continue 文

• while, do while, for 文内で使用可能

• 以降の処理を中断してループ末尾から再開する

• for文では後処理(第3パラメータ)も実行する

• break 文

• while, do while, for, switch 文内で使用可能

• 以降の処理を中断してループを脱出する

• switch文の場合はswitch文から脱出する

(42)

後判定ループ (do while 文)

• 真偽値による繰り返し

do {

// 条件式 が真の場合の処理

} while (条件式);

条件式 処理 真 偽 continue break do while 文は、ループ内の処理を 1回以上実行する(=最低1回は実行する)。

(43)

前判定ループ (while 文)

• 真偽値による繰り返し

while (条件式) {

// 条件式が真の場合の処理

}

教科書 pp.119-122. 条件式 真 偽 処理 continue break while 文は、ループ内の処理を 0回以上実行する(=実行しない場合もある) 。 2015-06-04修正 誤:式2 正:条件式

(44)

初期化・更新処理付きループ (for 文)

• 真偽値による繰り返し

for (式1; 式2; 式3) {

// 式2が真の場合の処理

};

式2 式1 真 偽 処理 式3 continue break for 分は前判定ループで 式1による初期化と 式3による更新処理を ひとまとめにしてコンパクトに書ける。

(45)

for文とwhile文 (前判定ループ)

• 以下のループは等価

• ただしcontinue時の式3の扱いに注意

for (式1; 式2; 式3) {

// 式2が真の場合の処理

};

式2 式1 真 偽 処理 式3 教科書 pp.123-129. for文の continue break

式1;

while (式2) {

// 式2が真の場合の処理

式3;

};

while文の continue

(46)

for文とwhile文 (前判定ループ)

• 以下のループは等価

• continue時の式3の扱いに注意

for (i = 0; i < 10; i++) {

// ループ内の処理

};

i = 0;

while (i < 10) {

// ループ内の処理

i++;

};

i < 10 i = 0 真 偽 処理 i++ for文の continue break while文の continue

(47)

後判定ループ (do while 文)

• continue, break 後の処理(iの値)に注目

looptest_dowhile.c int i = 0, j = 0, n; fprintf(stderr, "n = "); scanf("%d", &n); do { j++; printf("%d, %d: 1st", i, j);

if (j == 2) {printf(" continue¥n"); continue;} printf(" 2nd");

if (j == 4) {printf(" break¥n"); break;} printf(" 3rd¥n"); i++; } while (i < n); 教科書 pp.119-122. mintty + bash $ ./looptest_dowhile n = 10 0, 1: 1st 2nd 3rd 1, 2: 1st continue 1, 3: 1st 2nd 3rd 2, 4: 1st 2nd break mintty + bash $ ./looptest_dowhile n = 0 0, 1: 1st 2nd 3rd do while 文は、 ループ内の処理を 最低1回は実行する。

(48)

前判定ループ (while 文)

• continue, break 後の処理(iの値)に注目

looptest_while.c int i = 0, j = 0, n; fprintf(stderr, "n = "); scanf("%d", &n); while (i < n) { j++; printf("%d, %d: 1st", i, j);

if (j == 2) {printf(" continue¥n"); continue;} printf(" 2nd");

if (j == 4) {printf(" break¥n"); break;} printf(" 3rd¥n"); i++; } mintty + bash $ ./looptest_while n = 10 0, 1: 1st 2nd 3rd 1, 2: 1st continue 1, 3: 1st 2nd 3rd 2, 4: 1st 2nd break mintty + bash $ ./looptest_while n = 0

(49)

初期化・更新処理付きループ (for 文)

• continue, break 後の処理(iの値)に注目

looptest_for.c int i = 0, j = 0, n; fprintf(stderr, "n = "); scanf("%d", &n); for (i = 0; i < n; i++) { j++; printf("%d, %d: 1st", i, j);

if (j == 2) {printf(" continue¥n"); continue;} printf(" 2nd");

if (j == 4) {printf(" break¥n"); break;} printf(" 3rd¥n"); } 教科書 pp.124-129. mintty + bash $ ./looptest_for n = 10 0, 1: 1st 2nd 3rd 1, 2: 1st continue 2, 3: 1st 2nd 3rd 3, 4: 1st 2nd break mintty + bash $ ./looptest_for n = 0

(50)

continue 文

• 以下のループ内に更に小さなループが含ま

れない場合の continue は goto contin と同義

for (...) { // ... contin: ; } do { // ... contin: ; } while (...); while (...) { // ... contin: ; }

(51)

goto文

• 指定した名札付き文へ移動(ジャンプ)する

• 名札(label)は以下のように設定出来る

ラベル名: 文

[1] p.281.

do while 文相当 while 文相当 for 文相当 loop: ;

{

// something to do contin: ;

}

if (expr) goto loop; brk: ; loop: ; if (expr) { // something to do contin: ; goto loop; } brk: ; expr1; loop: ; if (expr2) { // something to do contin: ; expr3; goto loop; } brk: ; goto 文は 余程理由がない限り使わないこと

(52)

簡易版 seq コマンドの作成

前判定ループの演習

(53)

seq コマンド

• UNIX系のOSに標準で搭載されているコマンド

• 書式:

• seq FIRST LAST

• 機能:

• FIRST から LAST までの整数を 1 刻みで小さい順に表示す

る。

• 他にも詳細な機能があるが、ここでは省略

(54)

• seq_practice_1_while.c の /*WYCH*/ の部分

を修正して以下のプログラムを完成させよ。

• 標準入力から int 型の変数 first, last に整数

値を読み取り、first 以上、last 以下の整数を1

刻みで小さい順に表示せよ。

mintty + bash

$ gcc seq_practice_1_while.c && ./a first = 5 last = 9 5 6 7 8 9

(55)

演習: for 文による簡易 seq コマンド

• seq_practice_1_for.c の /*WYCH*/ の部分を

修正して以下のプログラムを完成させよ。

• 標準入力から int 型の変数 first, last に整数

値を読み取り、first 以上、last 以下の整数を1

刻みで小さい順に表示せよ。

mintty + bash

$ gcc seq_practice_1_for.c && ./a first = 5 last = 9 5 6 7 8 9

(56)

素数判定

(57)

素数

• 1と自分以外に正の約数を持たない自然数

(正整数)で1でない数

• 調べたい数をiとすると、2以上i/2以下の整

数jの全てについてiが割り切れないことを確

認すれば良い。

• ※厳密には2以上 𝑖以下の整数jについて調

べれば良いが、平方根の計算は除算に比べ

かなり遅いのでここではi/2以下について確

認する。

(58)

演習: 素数判定

• 標準入力から入力された正整数が素数かど

うか判定するプログラムを作成せよ。

• isprime_practice_1.c の

/*WYCH*/

の箇所を修正すれば良い。

mintty + bash $ gcc is_prime_practice_1.c $ ./a i = 1

1 is not prime number $ ./a i = 2 2 is prime number $ ./a i = 3 3 is prime number $ ./a i = 4

(59)

演習: 素数判定(ヒント)

• 作成すべきプログラム

の素数判定部分のフ

ローチャートは以下の

通りである

素数判定部分

jを2から i/2の範囲 で繰り返し iがjで 割切れる 非素数 真 偽 break iは2以上 素数と 仮定 1 1 非素数 偽 真 j++

(60)

参考文献

• [1] B.W.カーニハン/D.M.リッチー著 石田晴久

訳、プログラミング言語C 第2版 ANSI 規格準

拠、共立出版(1989)

参照

関連したドキュメント

過水タンク並びに Sr 処理水貯槽のうち Sr 処理水貯槽(K2 エリア)及び Sr 処理水貯槽(K1 南エリア)の放射能濃度は,水分析結果を基に線源条件を設定する。RO

過水タンク並びに Sr 処理水貯槽のうち Sr 処理水貯槽(K2 エリア)及び Sr 処理水貯槽(K1 南エリア)の放射能濃度は,水分析結果を基に線源条件を設定する。RO

廃棄物の再生利用の促進︑処理施設の整備等の総合的施策を推進することにより︑廃棄物としての要最終処分械の減少等を図るととも

産業廃棄物の種類 排    出   量. 産業廃棄物の種類 排   

引き続き、中間処理業者の現地確認を1回/3年実施し評価を実施す

[r]

産業廃棄物の種類 排    出   量. 産業廃棄物の種類 排   

処理処分の流れ図(図 1-1 及び図 1-2)の各項目の処理量は、産業廃棄物・特別管理産業廃 棄物処理計画実施状況報告書(平成