プログラミング演習I

プログラミング演習I
1
プログラミング演習I 概要
• プログラミング論Iの内容を実際にコンピュー
タで解く.
– プログラミング力を付ける
– アルゴリズムについて学ぶ
– 主に数学的問題を解く
– 使用する言語は C言語
2
プログラミング論Iと演習I
• 論Iで理論を学び,演習Iでそれを実践してみ
る.
• 両科目を併せて取ることをお勧めします.
3
C言語の基礎
C言語,ソースファイルの作成,コン
パイル,実行
4
C言語
• プログラムとは,“計算機を動かす手順を記
述したもの”.
– 計算機に命令を与えて動かすには“プログラムを
作成する”ことになる.
• C言語はプログラミング言語の1個
– 手続き型言語に分類される.
– C/C++ は非常に多くの場面で使われる言語
• C++はC言語をオブジェクト指向に拡張したもの
5
C言語プログラミングの手順
• ソースファイルを作成し,コンパイルし,実行.
“hello.c”
ソースファイル
source file
C言語
人間が記述する.
“hello.exe”
コンパイルする
compile
コンパイラ compiler
実行ファイル
executable exe
マシン語
通常人間に読めない
(Visual C++, gcc, bcc など)
・C言語では,ソースファイルを直接実行することができない.
ソースファイルをコンパイルして実行ファイルを作成し,実行ファイルを実行する.
・“ソースファイル” を “原始ファイル” と呼ぶこともある(ごくまれ).
・実行ファイルの拡張子はOSに依存する.Windows では “.exe” となる.
・厳密には,コンパイルとリンク(link)を行い実行ファイルを作る.
6
コンパイルとリンク
エディタ
コンパイラ
ソースファイル
“abc.c”
コンパイル
エディタ
コンパイラ
ソースファイル
“def.c”
コンパイル
オブジェクト
ファイル
“abc.o”
リンカ
オブジェクト
ファイル
“def.o”
リンク
実行ファイル
“xyz.exe”
標準ライブラリ
7
C言語のソースファイルの骨格
#include <stdio.h>
ヘッダ(header)ファイルの
読み込み.
先頭に必ず書く.
void main(){
void main(){
と
}
でプログラム本体を
挟む
ここにプログラムの本体を
記述する.
}
void main(){
と
}
でプログラム本体を
挟む
8
何も起きないプログラム
1
2
3
4
#include <stdio.h>
void main(){
}
empty.c
半角で記述する.大文字と小文字は明確に区別される.
上記を入力し,実行する.
Error メッセージ,Warning(警告)メッセージ を確認する.
Errorは明確な誤りへのメッセージ
Warningは誤りではないが好ましくないことへのメッセージ
9
文字列を表示するプログラム
1
2
3
4
5
#include <stdio.h>
void main(){
printf("Hello, World!\n");
}
hello00.c
“Hello world!” と 表示するプログラム.
printf を 使えば,” ” で囲った文字列を表示できる.
“\n”は,改行を意味する.
printf(“Hello\nWorld!\n”);
として実行.動作を確認.
10
C言語の式と文
式
a
3 < a
10
3+4
a+4
”hello”
a++
a = 7
printf(”hello”)
文 (式文) は 式;
printf(”hello”);
a=3;
a++;
a;
正しいが,
通常あり得ない
11
C言語の文 (関数の呼び出し)
printf("Hello, World!\n");
関数名
関数の引数
セミコロン
関数の引数は()で囲み,中に式を書く.
12
文字列を表示するプログラム
1
2
3
4
5
6
7
#include <stdio.h>
void main(){
printf("Hello,\n");
printf(“C lang.\n");
printf("World!\n");
}
上
か
ら
下
に
進
む
hello01.c
13
インデントとフリーフォーマット
#include <stdio.h>
void main(){
int i;
for(i=0; i<5; i++){
printf(”i=%d\n”, i);
}
}
#include <stdio.h>
#include <stdio.h>
void main(){
int i;
for(i=0; i<5; i++){
printf(”i=%d\n”, i);
}
}
void main(){
int i;
for(i=0; i<5; i++){
printf(”i=%d\n”, i);
}
}
↑対応関係がわかりづらい.
プログラム内の
空白,TAB文字,改行は
無視される.
よって,どのように
書いても問題ない.
当然,見やすく書くことが
好ましい.
↑対応関係が誤り.
#include <stdio.h>
void main(){ int i; for(i=0; i<5; i++){ printf(”i=%d\n”, i); }}
↑理解が困難.対応関係が分かりづらい.
14
コメント
1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
/* と */ で挟まれた領域は,
コメントとして 無視される.
実行されない.
void main(){
/* print hello */
// print hello
printf("Hello,\n");
// から行末までの領域も,
コメントとして無視される.
実行されない.
/*
printf("World!\n");
*/
}
hello02.c
ただし,これはC++の機能であり
C言語の機能ではない.
(実際はほとんどのC言語のコンパ
イラにこの機能が付いている)
コメント部にはデタラメに書
いても問題ない.
正しいC言語の文も無視さ
れる.
15
数値計算を行う
変数,演算
16
変数
• 変数
– 変数とは,データ(数値)の入れ物.
– 変数に数値を代入して,計算を行う.
– 変数はブロックの先頭で宣言してから使う.
– 変数には,型がある.名前がある.
ブロックについては,後日解説.
17
変数の宣言,代入,表示
1
2
3
4
5
6
“age”という名前の変数を宣言.
以後 age を使用可能.
#include <stdio.h>
void main(){
変数 age に整数19を代入.
int age;
以後, age には19が入っている.
age = 19;
printf("age = %d\n", age);
}
variable00.c
変数 age を表示する.
実行結果
age = 19
18
変数の宣言
• 変数の宣言方法
型名 変数名;
int age;
float x, y;
言
int型変数 “age” の宣言
float型変数“x”と“y”の宣
19
変数の宣言
• 変数の宣言はブロックの先頭で行う.
OK
#include <stdio.h>
void main(){
int x;
int y, z; 最初に全変数を宣言
x = 3;
NG
y = 4;
z = x + y;
#include <stdio.h>
printf("z=%d\n", z);
void main(){
}
int x;
変数宣言
宣言以外が開始された
再度、宣言が行われる
x = 3;
int y, z;
y = 4;
z = x + y;
printf("z=%d\n", z);
}
20
変数のデータ型
• 変数のデータ型には,
int, char, float などがある.
整数を格納
浮動小数点を格納
符号付き
char, short int, int,
long int, long long int
float, double, long double
符号なし
unsigned char,
unsigned short int,
unsigned int,
unsigned long int,
unsigned long long int
long long 型は,計算機センターのVisual Studio .NET にはない?21
整数型の大きさ
• char型:1バイト.-128~127を格納可能.
• unsigned char型:1バイト.0~255
• int 型の大きさは定められていない.
– OS,CPU,コンパイラにより異なる.
– 必ず
short int ≦ int ≦ long int ≦ long long int
の関係にある
– 符号付き と 符号なしの大きさは同じ.
22
整数型の大きさ
• 工学院大学計算機センターの例では
short int 型 : 2バイト
int 型 : 4バイト
long int 型 : 4バイト
• 4バイトの符号付き整数の場合
-2147483648 ~ 2147483647 の範囲を格納可能.
このプログラムで確認可能
#include <stdio.h>
void main(){
printf("short int=%d\n", sizeof(short int));
printf("int=%d\n", sizeof(int));
printf("long int=%d\n", sizeof(long int));
}
23
変数への値の代入
• 代入は,以下のように行う
変数名 = 値;
int age, x;
age = 19;
x = age;
右の値が,左の変数にコピーされる.
19 = age;
はNG.
age に19を代入.
x に age(19)を代入.
24
変数への値の代入
int
i;
double d;
i = 19;
i = 19.7;
整数型変数 i を宣言.
浮動小数点型変数 d を宣言.
i に19(整数)が代入される.
i に19(整数)が代入される.
iは整数型なので,切り捨ての整数を代入.
d = 3.7;
d = 3;
d=3.7; i=d;
d に 3.7(浮動小数点)が代入される.
d に 3.0(浮動小数点)が代入される.
i に 3(整数)が代入される.
25
変数の表示
• printf を用いて変数の値を表示できる.
printf("age = %d\n", age);
実行結果 age = 19
%d に int型変数の値が入って表示される.
long intなら %ld, floatなら%f, doubleなら%lf
printf("i=%d, d=%lf\n", i, d);
26
四則演算
+ 加算
- 減算
* 乗算
/ 除算
% 剰余 (除算の余り)
++ インクリメント(1増やす)
-- デクリメント(1減らす)
27
その他 演算子
関係演算子
等価演算子
論理演算子
ビット演算子
代入演算子
条件演算子
文式の結合
sizeof演算子
ポインタ演算子
キャスト
メンバアクセス演算子
< <= >= >
== !=
&& || !
& | ^ ~ << >>
= += ー= *= など
?:
,
sizeof
& *
(型)
. ー>
28
定数の記述
整数の 12
浮動小数点の12.0
8進数表記の12 (10進数の10)
16進数表記の12 (10進数の18)
0x1Aなら,10進数の26
3.456E4 3.456×104
12
12.0
012
0x12
29
定数の記述
’A’
‘A‘ という1文字.
実際は,‘A’の文字コードの
“65”
"Hello"
‘H’ ‘e’ ‘l’ ‘l’ ‘o’
という文字列.
30
演算結果の型
• X型とX型の演算結果はX型.
int a=7, b=2;
double d;
d = a + b;
d = a / b;
a + b は int型とint型の演算.
演算結果も int 型.
a+b は 9 (int型).
dには9.0 (double型)が入る.
a / b は int型とint型の演算.
演算結果も int 型.
a / b は 3 (int型).
dには 3.0 (double型)が格納される.
3.5 は格納されない.
31
演算結果の型
• X型とY型の演算結果はXorY型.
優先度の高い型が勝つ.
double > float > long > int > char の優先順
int a=7;
double d=2.0, e;
e = a / d;
a / b は int型とdouble型の演算.
double型が勝つので,
演算結果はdouble型.
7.0 / 2.0 と解釈され,
演算結果は 3.5 (double型).
32
演算結果の型
double d;
d = 7 / 2;
d = 7 / 2.0;
d = 7.0 / 2;
d = 7.0 / 2.0;
/* intとintの演算.結果はintの 3 */
/* intとdoubleの演算.
結果はdoubleの3.5 */
/* doubleとintの演算.
結果はdoubleの3.5 */
/* doubleとdoubleの演算.
結果はdoubleの3.5 */
33
制御文
34
真偽
条件が成り立つ場合,その条件式は真である.
例えば,
(3 < 4) は真
(3 == 4) は偽
35
比較演算子
a==b
a!=b
a<b
a<=b
a>b
a>=b
:
:
:
:
:
:
aとbが等しい
aとbが等しくない
bはaより大きい
bはa以上(大きいか等しい)
aはbより大きい
aはb以上
36
論理演算子
条件 && 条件
論理積(and):両方成り立つ場合に真
条件 || 条件
論理和(or):少なくとも片方が成り立つ場合に真
!条件
否定(not):条件が成り立たないときに真.
真偽が逆転される
37
真偽
厳密には,C言語には条件や真や偽はない.
値(式分)が「0以外」なら真,「0」なら偽とみなす.
注意:NULL は「0」なので 偽 である.
if( 1+2 ){
プログラムA
} else {
プログラムB
}
「3」は真を意味する.
結果,プログラムAに入る
「0」は偽を意味する.
結果,プログラムBに入る
if( 4-4 ){
プログラムA
} else {
プログラムB
}
38
条件分岐 if 文
if( 条件式X ){
プログラムA
}
if( 条件式X ){
プログラムA
} else {
プログラムB
}
式Xが真の場合(成り立つ場合),
中身(プログラムA)が
実行される.
偽の場合(成り立たない場合)は
何も実行されない.
条件Xが真の場合
前半のプログラムAが
実行され,
偽の場合(成り立たない場合)
後半(else部)の
プログラムBが実行される
39
条件分岐 if 文
if( 条件式X ){
プログラムA
} else if( 条件式Y ){
プログラムB
} else if( 条件式Z ){
プログラムC
} else {
プログラムD
}
プログラムE
条件式Xが成り立つ場合,
プログラムAが実行され,
その後プログラムEに移る.
プログラムB,C,Dは全て“条件式Xのelse”の
中にあるため,たとえ条件式Yや条件式Zが成り立っ
ても実行されない.
条件式Xが偽の場合に限り,条件式Yが検証さ
れる.
条件式Xが偽で かつ 条件式Yが真 の場合,プ
ログラムBが実行され,プログラムEに移る.
プログラムC,Dは実行されない.
条件式Xが偽,条件式Yが偽,条件式Zが真の
場合,プログラムC,Eが実行される.
全てが偽の場合,プログラムD, Eが実行され
る.
40
条件分岐 if 文
1
2
3
4
5
6
7
8
9
#include <stdio.h>
void main(){
int a=12;
if( a < 10 ){
printf("a < 10 (a = %d)\n", a);
} else {
printf("10 <= a (a = %d)\n", a);
}
}
41
繰り返し for 文
• 同じ処理を何度も繰り返すには for 文を使う.
int i;
for( i=0; i<5; i++){
処理A;
}
例
int i;
for(i=0; i<3; i++){
printf("Hello!\n");
}
int i;
for(i=0; i<7; i++){
printf("World!\n");
}
処理Aを
5 回繰り返す.
結果
結果
Hello!
Hello!
Hello!
World!
World!
World!
World!
World!
World!
World! 42
繰り返し for 文
int i;
for(i=0; i<3; i++){
printf("Hello,\n");
printf("World!\n");
}
i=0 として
printf("Hello,\n");
printf("World!\n");
i=1 として
printf("Hello,\n");
printf("World!\n");
i=2 として
printf("Hello,\n");
printf("World!\n");
(i=0; i<3; i++)
「i が 0 から 3未満の範囲で(2まで),
繰り返す.i は1ずつ増える.」
という意味の 繰り返し.
i=0 → iが0から始まる.
i<3 → iが3未満である限り続ける
i++ → i は1ずつ増える
i が“0から3未満(2まで)”なので,
i =0, i =1, i=2 の3回繰り返す.
printf("Hello,\n");
printf("World!\n");
printf("Hello,\n");
printf("World!\n");
printf("Hello,\n");
printf("World!\n");
43
繰り返し for 文
int i;
for(i=10; i<13; i++){
printf(“i=%d\n“,i);
}
「i が 10 から始まり 13未満の範囲で
(12まで),繰り返す.i は1ずつ増える.」
という意味の 繰り返し.
結局,i=10, i=11, i=12 の3回繰り返す.
int i;
for(i=0; i<6; i+=2){
printf(“i=%d\n“,i);
}
「i が 0 から始まり 6未満の範囲で,
繰り返す.i は2ずつ増える.」
という意味の 繰り返し.
結局,i=0, i=2, i=4 の3回繰り返す.
int i;
for(i=2; 0<=i; i--){
printf(“i=%d¥n“,i);
}
「i が 2 から始まり 0 以上の範囲で,
繰り返す.i は1ずつ減る.」
という意味の 繰り返し.
結局,i=2, i=1, i=0 の3回繰り返す.
44
繰り返し for 文
int i;
for(i=10; i<3; i++){
printf(“i=%d\n“,i);
}
「i が 10 から始まり,3未満の範囲で,
繰り返す.i は1ずつ増える.」
という意味の 繰り返し.
結局,(10<3が偽なので)1回も実行しない.
int i;
for(i=3; 0<=i; i++){
printf(“i=%d\n“,i);
}
「i が 10 から始まり,0以上の範囲で,
繰り返す.i は1ずつ増える.」
という意味の 繰り返し.
結局,無限に繰り返す.
int i;
for(i=0; ; i++){
printf(“i=%d¥n“,i);
}
「i が 0 から始まり,無条件で,
繰り返す.i は1ずつ増える.」
という意味の 繰り返し.
結局,無限に繰り返す.
45
繰り返し for 文
• for文の中にfor文
int i, j;
for(i=0; i<3; i++){
for(j=0; j<4; j++){
printf("i=%d,j=%d\n",i,j);
}
}
『printf() をj=0~3の4回繰り返す』をi=0~2の3回繰り返す.
結果,4回×3回=12回繰り返す.
46
繰り返し for 文
for( 式1; 式2; 式3 ){
プログラム
}
最初に式1を行う
式2が真である限り,
ブロックの中身を繰り返す.
1回繰り返すたびに式3を
行う.
int i;
for (i=0; i<2; i++){
printf("i=%d\n");
}
iが0になる.
i<2 の真偽を調べる.真である(i=0).
よって,forの中のブロックに入る.
printf()を実行.
ブロックが終わり,i++を行い,ブロックの
最初に戻る.
i<2 の真偽を調べる.真である(i=1).
よって,forの中のブロックに入る.
printf()を実行.
ブロックが終わり,i++を行い,ブロックの
最初に戻る.
i<2 の真偽を調べる.偽である(i=2).
47
よって,forを終了する.
繰り返し for 文
i=0;
• 動作原理
i<3?
printf("Hello,\n");
printf("World!\n");
int i;
for(i=0; i<3; i++){
printf("Hello,\n");
printf("World!\n");
}
i++; /*i=1となる*/
i<3?
printf("Hello,\n");
printf("World!\n");
i++; /*i=2となる*/
i<3?
printf("Hello,\n");
printf("World!\n");
i++; /*i=3となる*/
終了
i<3?
48
繰り返し while 文
while( 条件式X ){
プログラムA
}
条件Xが真である限り,
中身(プログラムA)を
繰り返し実行する.
毎回,条件式を評価してから,
プログラムを実行する.
int i=0;
while( i<2 ){
printf("i=%d\n");
i++;
}
iが0になる.
i<2 の真偽を調べる.真である(i=0).
よって,whileの中のブロックに入る.
printf()を実行.
i++ により i が1になる.
ブロックが終わり,ブロックの最初に戻る.
i<2 の真偽を調べる.真である(i=1).
よって,whileの中のブロックに入る.
printf()を実行.
i++ により i が2になる.
ブロックが終わり,ブロックの最初に戻る.
i<2 の真偽を調べる.偽である(i=2).
49
よって,whileを終了する.
繰り返し do-while 文
do{
プログラムA
}while(条件式X );
条件Xが真である限り,
中身(プログラムA)を繰り返し実行する.
毎回,プログラムを実行してから,
条件式を評価する.
よって,最低でも1回は実行される.
int i=0;
do{
printf("i=%d\n");
i++;
} while( i<2 );
iが0になる.
printf()を実行.
i++ により i が1になる.
ブロックが終わり,i<2 の真偽を調べる.
真である(i=1).
よって,再度,whileブロックの中を実行.
printf()を実行.
i++ により i が2になる.
ブロックが終わり,i<2 の真偽を調べる.
偽である(i=2).
よって,再度,whileブロックの中を実行.
50
break による 繰り返しの中断
int i;
for(i=0; i<10; i++){
printf(“i=%d\n“,i);
if( i==3 ){
break;
}
} 繰り返し中断
printf(“Fin!\n“,i);
実行結果
i=0
i=1
i=2
i=3
Fin!
break; を実行すると,
繰り返しが中断される.
51
無限ループ
for(;;){
printf("Hello, World!\n");
}
while(1){
printf("Hello, World!\n");
}
for文で条件部を書かないと,
無条件で繰り返し.
無限ループとなる.
while文で条件部に1と書くと,
条件が必ず成立するので
無限ループとなる.
(1は真偽における“真”であるた
め.)
52
関数
53
関数の概要 1/3
• 関数とは,“複数の処理をひとまとめにしたも
の”.
– 同じ処理/似た処理を 何度も記述するような場合
に便利.
• 関数は“引数”を受け取り,“戻り値”を返すこ
とができる.
– 実は,printf() も main() も関数.
54
関数の概要 2/3
1 #include <stdio.h>
2 void main(){
3
printf("Hello,");
4
printf("World");
5
printf("!!!!\n");
6
printf("------------\n");
7
printf("Hello,");
8
printf("World");
9
printf("!!!!\n");
10
printf("############\n");
11
printf("Hello,");
12
printf("World");
実
13
printf("!!!!\n");
行
14 }
結
この3行まとめて,
1個のグループに
したい.
Hello,World!!!!
-----------Hello,World!!!!
############
果 Hello,World!!!!
55
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
関数の概要 3/3
#include <stdio.h>
void printHW(){
printf("Hello,");
printf("World");
printf("!!!!\n");
}
この3行が1個の
グループになった.
グループ名は
printHW
printHW();で,
printHWグループを
一括して実行できる.
void main(){
printHW();
printf("------------\n");
printHW();
printf("############\n");
printHW();
}
正しくは,グループ
関数を“呼び出す”と言う.
ではなく“関数”と呼ぶ56
関数の動作 1/2
①
3 void printHW(){
④
4
printf("Hello,");
5
printf("World");
6
printf("!!!!\n");
7 }
⑤
9 void main(){
③
②
10
printHW();
⑥
11
printf("------------\n");
12
printHW();
13
printf("############\n");
14
printHW();
15 }
57
関数の動作 2/2
3 void printHW(){
⑨
4
printf("Hello,");
5
printf("World");
6
printf("!!!!\n");
7 }
⑩
9 void main(){
10
printHW();
⑦ printf("------------\n");
11
⑧
12
printHW();
⑪
13
printf("############\n");
14
printHW();
15 }
58
関数の作り方
戻り値(後述)
この例では,
“void”である.
関数名(後述)
この例では,
“printHW”である.
3 void printHW (){
4
printf("Hello,");
5
printf("World");
6
printf("!!!!\n");
7 }
引数(後述)
この例では,
空である.
関数の中身
main() の書き方と同じである.main() も関数である.
59
関数の作り方 (例)
#include <stdio.h>
void printHW(){
関数名に数字も使用可.
printf("Hello,");
ただし,数字から
printf("World");
始まる関数名はNG.
printf("!!!!\n");
例:“10pHW”はNG
}
void pHW10(){
関数の中で
int i;
変数を使うことも可能.
for(i=0; i<10; i++){
この変数はpHW10の
printf("Hello,World!\n");
中でしか使えない.
}
}
void main(){
printHW();
pHW10();
}
60
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
void sankaku(){
printf("*\n");
printf("**\n");
printf("***\n");
printf("****\n");
}
void gyaku_sankaku(){
printf("****\n");
printf("***\n");
printf("**\n");
printf("*\n");
}
void main(){
sankaku();
gyaku_sankaku();
sankaku();
sankaku();
gyaku_sankaku();
}
関数の作り方 (例)
この1行で,
sankaku() の
全てが一括して
実行される.
実
行
結
果
*
**
***
****
****
***
**
*
*
**
***
****
*
**
***
****
****
***
**
*
61
関数の作り方 (引数)
• 引数とは,関数に与える情報.
– 関数に情報を与えることが可能.
– 関数では,与えられた情報を使用して処理するこ
とが可能.
– “情報”とは,int型の値,double型の値などであ
る.
62
関数の作り方 (引数)
この部分に,引数について記述する.
この例では引数は なし(空,void).
3 void printHW (){
4
printf("Hello,");
5
printf("World");
6
printf("!!!!\n");
7 }
63
関数の作り方 (引数)
• 引数を受け取る関数.
戻り値(後述)
この例では,
“void”である.
関数名.
この例では,
“print_int”.
引数.
この例では,int型変数1個.
それを i とする.
厳密には仮引数と言う.
void print_int (int i){
printf("i=%d\n", i);
}
64
関数の作り方 (引数)
• 関数に引数を渡す.
void main(){
print_int(3);
}
変数 i が宣言
されており,
i を使用可能.
i = 3 として関数が
始まる.
引数がint型1個なので,
int型1個(この例では3)を
与えて関数呼び出し.
void print_int (int i){
printf("i=%d\n", i);
}
実行結果 i=3
65
関数の作り方 (引数)
• 呼び出される関数と,呼出し処理をまとめると,
print_int()を
呼び出すには,
呼び出すよりも前に
print_int()が
宣言(記述)されて
いなくてはならない.
(あるいは,宣言されている
ことが推奨される.
C言語では推奨.
C++では必須.)
ただし,プロトタイプ宣言を
行えばこの限りでない.
#include <stdio.h>
void print_int (int i){
printf("i=%d\n", i);
}
プログラムは,必
ずmain()
から始まる.
void main(){
print_int(3);
}
66
関数の作り方 (引数の例)
#include <stdio.h>
void printHW_n(int n){
int i;
printf("Hello,World");
for(i=0; i<n; i++){
printf("!");
} /* n個の ! を表示 */
printf("\n");
}
void main(){
printHW_n(4);
printHW_n(7);
}
実行結果
Hello,World!!!!
Hello,World!!!!!!!
67
関数の作り方 (引数の例)
引数2個の例.
,(カンマ)で区切る
#include <stdio.h>
void print_sum(int a, int b){
printf("%d + %d = %d\n", a, b, (a+b));
}
void main(){
int x=3, y=7;
print_sum(x,y);
}
実引数に,
変数を使った例.
実行結果
3 + 7 = 10
68
関数の作り方 (引数の例)
#include <stdio.h>
void print_nchar(char c, int n){
int i=0;
char型とint型を
for(i=0; i<n; i++){
受け取った例.
char型は「文字」型.
printf("%c", c);
文字1個を表す.
}
printf("\n");
}
引数は,char型と,int型なので,
char型の値と,int型の値を入れて
void main(){
呼び出す
char ch = '*';
int x = 7;
実行結果
print_nchar(ch,x);
******* 69
}
関数の作り方 (戻り値)
• 戻り値とは,「関数が呼び出しもとに返す情
報」.
– 関数から,関数の呼び出しもとに情報を返すこと
が可能.
– 戻り値は,関数の終了時に返される.
– “情報”とは,int型の値,double型の値などであ
る.
70
関数の作り方 (戻り値)
この部分に,戻り値について記述する.
この例では引数は なし(空,void).
3 void printHW (){
4
printf("Hello,");
5
printf("World");
6
printf("!!!!\n");
7 }
71
関数の作り方 (戻り値)
• 戻り値を返す関数.
戻り値.
この例では,
“int”である.
関数名.
この例では,
“square”.
引数.
この例では,
int型変数1個.
int square(int n){
int sq;
sq = n*n;
printf("%d^2 = %d\n", n, sq);
return sq;
}
72
関数の作り方 (戻り値)
• 戻り値を返す関数.
①
引数 5
②i=5
int square(int n){
int sq;
sq = n*n; ③sq=25
printf("%d^2 = %d\n", n, sq);
return sq;
}
④
戻り値 25
void main(){
int s;
s = square(5);
printf("square=%d\n", s);
}
戻り値が"25"なので,
square(5) が
25となる.
よって,
s = 25; 73
関数の作り方 (戻り値の例)
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
int square(int n){
int sq;
sq = n*n;
printf("%d^2 = %d\n", n, sq);
return sq;
}
void main(){
int s;
s = square(5);
printf("square=%d\n", s);
}
実行結果
5^2 = 25
square=25
74
関数の作り方 (戻り値の例)
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
double double_square(double d){
引数がdouble型1個なら,
double sq;
double型の値1個を
sq = d*d;
入れて,呼び出す.
printf("%lf^2 = %lf\n", d, sq);
return sq;
}
実行結果
1.500000^2 = 2.250000
void main(){
square=2.250000
double s;
s = double_square(1.5);
printf("square=%lf\n", s);
75
}
関数の作り方 (戻り値の例)
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
double double_square(double d){
戻り値がdouble型なら,
double sq;
double型の値を
sq = d*d;
return する.
printf("%lf^2 = %lf\n", d, sq);
return sq;
}
実行結果
1.500000^2 = 2.250000
void main(){
square=2.250000
double s;
s = double_square(1.5);
printf("square=%lf\n", s);
76
}
関数の作り方 (戻り値の例)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
int one(){
return 1;
}
int two(){
return 2;
}
int three(){
return 3;
}
i=1,
void main(){
int i, j, k;
i = one();
j = two();
k = three();
printf("i=%d, j=%d, k=%d\n", i, j, k);
}
実行結果
j=2, k=3
77
関数の作り方 (戻り値の例)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
int one(){
return 1;
}
int two(){
return 2;
}
int three(){
実行結果
return 3;
}
i=1, j=2, k=3
void main(){
int i, j, k;
printf("i=%d, j=%d, k=%d\n", one(), two(), three());
}
printf()の中に直接記述してもOK.
one() が"1",two()が"2"と思えば良い.
78
関数の作り方 (まとめ)
戻り値の型 関数名(引数の型 変数名,…){
関数の中身...
(変数の宣言なども可能)
return
○; (←戻り値がvoidなら,省略可)
}
79
関数:戻り値を捨てる
double d_sq(double d){
double sq = d*d;
printf("%lf^2 = %lf\n", d, sq);
return sq;
実行結果
1.200000^2 = 1.440000
}
3.400000^2 = 11.560000
void main(){
double x;
戻り値を受け止めて,xに代入.
x = d_sq(1.2);
戻り値を受け止めずに,
d_sq(3.4);
捨てる.特に問題ない.
戻り値情報は失われるが,
}
関数は正しく実行される. 80
関数:複数のreturn
• 関数内に
return が
何個あってもよい.
実行結果
x=3 |x|=3
x=-4 |x|=4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
int zettaichi(int n){
if( n<0 ){
return (-n);
} else {
return n;
}
}
void main(){
int x, z;
x = 3;
z = zettaichi(x);
printf("x=%d |x|=%d\n", x, z);
x = -4;
z = zettaichi(x);
printf("x=%d |x|=%d\n", x, z);
81
}
関数:return
• return により,
関数は強制的に
終了する.
実行結果
AAAA
BBBB
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
void funct(){
printf("AAAA\n");
printf("BBBB\n");
return;
printf("CCCC\n");
}
void main(){
funct();
}
82
関数:ローカル変数
1
2
3
4
5
6
7
8
9
10
void funct(){
int x;
x = 3;
i = 4;
}
void main(){
int i;
i = 5;
funct();
}
ブロックの外で
使おうとしている.
これは,NG.
コンパイルエラーとなる.
int i は,
このブロック内で
宣言されているため,
このブロックの中でしか
使用できない.
ブロック内の変数を
ローカル変数という.
ブロックの範囲
83
関数:仮引数と実引数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void func0(int x){
xが仮引数
x = 3;
}
void func1(int i){
i = 3;
}
void main(){
int i = 5;
printf("i=%d¥n", i);
func0(i);
printf("i=%d¥n", i);
func1(i); iが実引数
printf("i=%d¥n", i);
}
mainのiと,func0のxは
別の変数.
mainのiの値が,func0のxに
代入(コピー)される.
func0のxを変更しても,
mainのiには影響なし.
mainのiと,func1のiは
別の変数.
名前が同じ別の変数.
mainのiの値が,func1のiに
代入(コピー)される.
func1のiを変更しても,
mainのiには影響なし.
i=5
実行結果 i=5
i=5
84
関数の多段呼び出し 1/3
1
2
3
4
10
11
12
void func0(){
printf("func0 start!¥n");
printf("func0 end!¥n");
}
void main(){
main()
func0();
}
func0()
実行結果
func0()
func0 start!
func0 end!
85
関数の多段呼び出し 2/3
1
2
3
4
5
6
7
8
9
10
11
12
void func0(){
printf("func0
printf("func0
}
void func1(){
printf("func1
func0();
printf("func1
}
void main(){
func1();
}
start!¥n");
end!¥n");
start!¥n");
end!¥n");
実行結果
func1
func0
func0
func1
start!
start!
end!
end! 86
関数の多段呼び出し 3/3
func1()
func1()
func1()
func1()
main()
87
関数の再帰呼び出し
• ある関数から,自分自身を呼び出すことを再
帰呼び出しという.
– 例えば,関数funct() の中で,funct() を呼
び出すなど.
• 使い方を間違える,永遠に終了しないプログ
ラムになりやすいので注意.
88
関数の再帰呼び出し
1
2
3
4
5
6
7
8
void pr_hl(){
printf("Hello!start\n");
pr_hl();
printf("Hello!end\n");
}
void main(){
print_hello();
}
動作の解説は次ページ
注意!これは失敗例です.
89
pr_hl()が
呼ばれたので,
pr_hl()に移動.
main()
pr_hl()
呼び出しを永遠に続け,
このプログラムは
終わらない.
pr_hl()
main()から,
pr_hl()が
呼ばれたので,
pr_hl()に移動.
pr_hl()
pr_hl()
90
再帰:nの階乗 1/5
• nの階乗を,n!と記述する.
• n! は,n×(n-1)×(n-2)×…×2×1
• n! は,n × (n-1)!
• 5! は,5×4×3×2×1
• 5! は,5×4!
91
再帰:nの階乗 2/5
• nの階乗は
もし n == 1 なら,
答えは,1
もし n > 1 なら,
答えは,n×(n-1)!
上(n==1)が無いと,永遠に終わらない
92
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int kaijoh(int x){
int r;
if( x == 1 ){
return 1;
} else {
r = x * kaijoh(x-1);
return r;
}
}
void main(){
int n, k;
n = 5;
k = kaijoh( n );
printf("%d! = %d\n", n, k);
}
再帰:nの階乗 3/5
93
main()
再帰:nの階乗 4/5
kaijoh(3)
kaijoh(3)は,3*kaijoh(2)
kaijoh(2)
kaijoh(2)は,2*kaijoh(1)
kaijoh(1)
kaijoh(1)は,1
kaijoh(1)=1
kaijoh(1)=1
kaijoh(2)=2
kaijoh(2)は,2*1
kaijoh(2)=2
kaijoh(3)は,3*2
kaijoh(3)=6
n==1の時は,
これ以上再帰呼
び出ししない.
これがないと
無限に続く 94
再帰:nの階乗 5/5
kaijoh(
4
=4* kaijoh(
3
=4* (3* kaijoh( 2
=4* (3* (2* kaijoh(1)
=4* (3* (2*
1
=4* (3* (
2
=4* (
6
=24
)
)
)
)
)
)
)
)
)
)
)
95
失敗例
1
2
3
4
5
6
7
8
9
10
11
int kaijoh(int x){
int r;
r = x * kaijoh(x-1);
return r;
}
void main(){
int n, k;
n = 5;
k = kaijoh( n );
printf("%d! = %d\n", n, k);
}
kaijoh(5)を呼び出し
↓
kaijoh(4)を呼び出し
↓
kaijoh(3)を呼び出し
↓
kaijoh(2)を呼び出し
↓
kaijoh(2)を呼び出し
↓
kaijoh(1)を呼び出し
↓
kaijoh(0)を呼び出し
↓
kaijoh(-1)を呼び出し
↓
kaijoh(-2)を呼び出し
↓
kaijoh(-3)を呼び出し
↓
無限に続く
96
再帰:組み合わせ nCr
• 組み合わせ(Conbination)
nCr は,
r>1なら, nCr=n-1Cr-1 * n / r
r==1なら, nCr=n
97
再帰:組み合わせ nCr
1
2
3
4
5
6
7
8
9
10
11
int conbin(int n, int r){
if( r == 1 ){
return n;
} else {
return conbin(n-1,r-1)*n/r;
}
}
void main(){
int n=5, r=2;
printf("%d C %d = %d", n, r, conbin(n,r));
}
98