>100 Views
February 21, 22
スライド概要
C プログラミング入門 (スライド資料とプログラム例)(Visual Studio 2019 を使用)(全15回)
https://www.kkaneko.jp/pro/adp/index.html
金子邦彦研究室ホームページ
https://www.kkaneko.jp/index.html
金子邦彦(かねこくにひこ) 福山大学・工学部・教授 ホームページ: https://www.kkaneko.jp/index.html 金子邦彦 YouTube チャンネル: https://youtube.com/user/kunihikokaneko
cp-8. 関数 (C プログラミング入門) URL: https://www.kkaneko.jp/pro/adp/index.html 金子邦彦 1
内容 例題1.棒グラフ 関数とは.プログラム実行順.データの流れ. 引数と仮引数 例題2.月の日数 return 文 例題3.1か月分のカレンダー 例題4.月初めの曜日 例題5.カレンダー 関数の集まりとしてのプログラム 2
仕事の分割 ○○の仕事を 頼む! △△の仕事を 頼む! 頼む人 担当者A 担当者B 3
関数とは 関数A 呼び出し側 関数C 関数B 呼び出され側 呼び出され側 プログラムは,しばしば,複数の関 数に「分割」される 4
目標 • 1つの main 関数と,その他の複数の関数から 構成されたプログラムを読んで,理解できる能 力を習得する • 複数の関数の間での「情報の受け渡し」につい て理解する 5
例題1.棒グラフ • 整数から,その長さだけの棒を表示する関数を作 る 例) 5 → ***** • 上記で作った関数を使って,「整数を読み込んで, 読み込んだ長さの棒を表示するプログラム」を作 る 6
棒グラフ
#include <stdio.h>
#pragma warning(disable:4996)
void bar( int len )
{
int i;
for (i=0; i<len; i++) {
printf("*");
bar関数
}
printf("\n");
return;
}
int main()
{
int len;
printf( "len=" );
scanf( "%d", &len );
bar( len );
return 0;
}
main関数
7
棒グラフ 実行結果の例 len=5 ***** 8
関数呼び出しの流れ main 関数 int main() 関数呼び出し bar(len); bar 関数 void bar( int len ) 戻り return; 9
プログラム実行順
#include <stdio.h>
#pragma warning(disable:4996)
void bar( int len )
{
int i;
for (i=0; i<len; i++) {
④
printf("*");
bar関数
}
⑤ printf("\n");
⑥ return; 戻り
}
main 関数の先頭行
int main()
がプログラムの始まり
{
int len;
① printf( "len=" );
② scanf( "%d", &len );
main関数
③ bar( len ); 関数呼び出し
⑦ return 0;
main 関数内の return
}
がプログラムの終わり
10
プログラム実行順 bar 関数 void bar( int len ) main 関数 int main() printf( "len=" ); 関数 呼び出し scanf( "%d", &len ); if( i < len ) No bar( len ); return 0; i = 0; Yes printf( "*" ); i++; 戻り printf("\n"); return; 11
プログラム実行順 • 普通,プログラム中の文は逐次的に実行され る • 関数呼び出しでは,関数の先頭に「ジャン プ」する. 関数呼び出しの例) bar( len ); • 関数の中で return 文に出会うと,関数呼び出 しの場所に戻る. 12
main 関数 • プログラムの実行を開始すると,自動的にmain 関数が呼ばれる • プログラムの開始は,main 関数の最初の行から • main 関数内の return 文は,「プログラムの終わり」 を示す • プログラムには,必ず main 関数が書かれていな ければならない 13
関数定義の例
#include <stdio.h>
#pragma warning(disable:4996)
頭部
void bar( int len )
{
型int名前
i; 仮引数
for (i=0; i<len; i++) {
printf("*");
bar関数
}
本体
printf("\n");
return;
}
int main()
{
型名前
int len;仮引数(は空)
printf( "len=" );
scanf( "%d", &len );
bar( len );
return 0;
}
頭部
本体
main関数
14
関数定義 • 関数定義とは,関数の実体をプログラムとして 書くこと • 関数には,名前,型,仮引数がある 例) void bar( int len ) int main() 型 名前 関数側から呼び出し側に 返されるデータに関係する 仮引数 呼び出し側から関数側に 渡されるデータに関係する • 仮引数のそれぞれにも,型と名前がある 15
関数でのデータの流れ 関数A 関数呼び出し時に, データ(処理すべき データ)を渡す 呼び出し側 関数からの戻り時に, データ(処理結果の データ)を返す 関数B 呼び出され側 16
データの流れ main 関数 int main() 関数呼び出し bar(len); ① len の値を, bar 関数に渡す bar 関数 void bar( int len ) 型 仮引数 ②整数を受け取って, 「len」という名前で使う 戻り return; ③main 関数には, 何も返さない 17
データの流れ 値がコピーされる len 5 main 関数内で宣言された len main 関数 int main() 関数呼び出し bar(len); ① len の値を, bar 関数に渡す len 5 仮引数で宣言された len len 5 こちらは使われない main 関数内で宣言された len と,仮引数で宣言された len は 別のもの sum 関数 void bar( int len ) 仮引数 型 ②整数を受け取って, 「len」という名前で使う 戻り return; ③main 関数には, 何も返さない 18
引数と仮引数 • 関数呼び出し側 • カッコの中に書いた変数等の値(引数という)が, 関数に渡される (例) bar( len ); len の値を,bar 関数に渡す(引数) • 呼び出された関数側 • 呼び出された関数は,値を受け取って,名前を付け て使用する(仮引数という) (例) int bar( int len ) 整数を受け取って,「len」 という名前で使う(仮引数) 19
引数と仮引数 • 引数 • 関数などに実際に渡される「データ」のこと • 関数呼出しの(,)内に並べる • 定数や変数や式を書く • 仮引数(パラメータともいう) • 関数定義の(,)中で宣言された変数のこと. (例) void bar(int len)では,変数 len が宣言されている. • 関数は,呼び出された時点において,値を受け取り,当 該関数の仮引数である変数にセットする. • 引数で与えられた値が,仮引数の変数に代入され て情報の受け渡しが行われる. 20
例題2.月の日数 • 年と月から,日数を求める関数を作る • うるう年の2月ならば29 • 求めた日数は,関数の返り値として,呼び出し側に返 すこと. 例) 2001 年 11 月 → 30 • 上記で作った関数を使って,「年と月を読み込ん で,日数を求めるプログラム」を作る 21
#include <stdio.h>
#pragma warning(disable:4996)
int num_of_day( int y, int m)
{
int num_days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if ( (m == 2) && (((y % 400) == 0) || (((y % 100) != 0) && ((y % 4) ==
0)))){
return 29;
}
else {
return num_days[m-1];
}
}
int main()
{
int y;
int m;
int n;
printf( "y=" );
scanf( "%d", &y );
printf( "m=" );
scanf( "%d", &m );
n = num_of_day(y, m);
printf( "number of days(%d) = %d\n", m, n );
return 0;
}
22
月の日数 実行結果の例 y=2001 m=11 number of days(11) = 30 23
関数呼び出しの流れ main 関数 int main() 関数呼び出し n = num_of_day(y, m); num_of_day 関数 int num_of_day( int y, int m ) 戻り return 29; うるう年のとき return num_days[m-1]; うるう年 でないとき 24
#include <stdio.h>
プログラム実行順
#pragma warning(disable:4996)
int num_of_day( int y, int m)
{
int num_days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
⑤ if ( ( m == 2 ) && (((y % 400) == 0) || (((y % 100) != 0) && ((y %4) == 0)))){
⑥ return 29;
}
else {
⑥ return num_days[m-1];
}
}
int main()
{
int y;
int m;
int n;
① printf( "y=" );
② scanf( "%d", &y );
③ printf( "m=" );
④ scanf( "%d", &m );
⑦ n = num_of_day(y, m);
⑧ printf( "number of days(%d) = %d\n", m, n );
⑨ return 0;
25
}
プログラム実行順 main 関数 num_of_day 関数 int main() int num_of_day( int y, int m) 関数 呼び出し n = num_of_day(y, m); if( ・・・ ) Yes No return 29; return num_days[m戻り 1]; 26
データの流れ main 関数 int main() 関数呼び出し n = num_of_day(y, m); ① y と m の値を, num_of_day 関数に渡す num_of_day 関数 int num_of_day( int y, int m ) 仮引数 型 ②整数を2つを受け取って, 「y」 と 「m」という名前で使う 戻り うるう年のとき return 29; ③main 関数に,29 を返す うるう年 return num_days[m-1]; でないとき ③main 関数に,num_days[m-1] 27 の値を返す
データの流れ 値がコピーされる y m 2001 11 main 関数 int main() 関数呼び出し n = num_of_day(y, m); ① y と m の値を, num_of_day 関数に渡す y m y m 2001 11 2001 11 num_of_day 関数 int num_of_day( int y, int m ) 型 仮引数 ②整数を2つを受け取って, 「y」 と 「m」という名前で使う 戻り うるう年のとき return 29; ③main 関数に,29 を返す うるう年 return num_days[m-1]; でないとき ③main 関数に,num_days[m-1] 28 の値を返す
関数の中の return 文 • 関数の呼び出しの場所に戻ることを示す • return 文で書いた式の値が,呼び出し側に返される (例)return; return 29; ← 何も返さない ← 29 を返す return num_days[m-1]; ← num_days[m-1] を返す 29
void の意味 • 関数には,型がある • • • • int double void など 但し,void は,「関数が return 文で,何も返さな いこと(値を返さない関数)」 を示す 例) void print_calendar( int num_days, int youbi ) • void で関数定義したら,return の次に式を書 かない( 「return;」 ). 30
関数から返された値の使い方 n = num_of_day(y, m); 関数呼び出し num_of_day 関数から返された値が n に入る • 関数は,一種の「式」であって,「値」を持 つ • この「値」が,関数から返された値 31
例題3.1か月分のカレンダー • 日数と曜日から,1か月分のカレンダーを表示す る関数を作る • 日数は,28,29,30,31 のいずれか • 曜日は,0,1,…,6 のいずれか • 表示される日付は,2桁の幅とし,それぞれの間に1 つの空白を置くこと. 32
#include <stdio.h>
#pragma warning(disable:4996)
void print_calendar( int num_days, int youbi )
{
int i;
int d;
int x;
if ( ( num_days < 28 ) || ( num_days > 31 ) || ( youbi < 0 ) || ( youbi > 6 ) )
{
渡された値がおかしいときは,
return;
何もせずに終わる
}
}
for ( i = 0; i < ( youbi * 3 ); i++ ) {
曜日の分だけ空白を表示
printf( " " );
}
d = 1;
x = youbi;
do {
日付を書く
printf( "%2d ", d );
d++;
if ( x == 6 ) {
printf( "\n" );
土曜日に来たら改行する
x = 0;
}
else {
x++;
}
月末まで書いたら終える
} while ( d <= num_days );
return;
33
前のページからの続き int main() { int num_days; int youbi; printf( "num_days=" ); scanf( "%d", &num_days ); printf( "youbi=" ); scanf( "%d", &youbi ); print_calendar( num_days, youbi ); return 0; } 34
1か月分のカレンダー 実行結果の例 num_days=30 youbi=4 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 35
関数呼び出しの流れ main 関数 int main() 関数呼び出し print_calendar(num_days, youbi); num_of_day 関数 void print_calendar( int num_days, int youbi ) 戻り return; 渡された値が おかしいとき return; 36
プログラム実行順 print_calendar 関数 main 関数 void print_calendar( int num_days, int youbi ) int main() 関数 呼び出し if( ・・・ ) Yes No return; print_calendar( num_days, youbi ); 1か月分のカレンダーの表示 戻り return; 37
1か月分のカレンダーの表示 「曜日」の分だけ空白を表示 日付を書く 書いた日付は土曜日か? No Yes 改行する 日付を1足す 日付を0にする 日付が「日数」を超えたか?No Yes 38
例題4.月初めの曜日 • ツエラーの公式を使い,年と月から,月初め の曜日を求める関数を作る • 曜日は,0,1,…,6 のいずれか 0:日曜日 1:月曜日 2:火曜日 3:水曜日 4:木曜日 5:金曜日 6:土曜日 39
月初めの曜日
#include <stdio.h>
#pragma warning(disable:4996)
int zeller( int y, int m, int d )
{
if ( ( m == 1 ) || ( m == 2 ) ) {
y = y - 1;
m = m + 12;
}
return (y + (y/4) - (y/100) + (y/400) + ((13 * m + 8 ) / 5) + d) % 7;
}
int first_day( int y, int m )
{
return zeller( y, m, 1 );
}
int main()
{
int y;
int m;
int f;
printf( "y=" );
scanf( "%d", &y );
printf( "m=" );
scanf( "%d", &m );
f = first_day(y, m);
printf( "first days(%d, %d) = %d\n", y, m, f);
return 0;
}
40
例題5.カレンダー • 年と月から,カレンダーを表示するプログラ ムを作る 41
「カレンダー」のプログラムの関数分 割 • 役割ごとに,関数を作る. 1. 本体 2. 月の日数 3. 月初めの曜日 4. 1ヶ月分のカレンダー 42
カレンダー 年 月 月の日数 例題2で 作成済み 日数 年 main関数 月 main関数 のみを新規 に作成 曜日 日数 曜日 月初めの 曜日 1か月分の カレンダー 例題4で 作成済み 例題3で 作成済み 43
コメントでおおまかな処理を書く int main() { /* 年と月を読み込む */ /* 年と月から「月の日数」を求める */ /*年と月から「月初めの曜日」を求める */ /* 「月の日数」と「月初めの曜日」からカレンダーを表示す る */ return 0; } 44
コメント • コメントは,プログラムの中に書く注釈のこと. • プログラムの説明や使用上の注意などを書く. • コメントは,プログラム実行では無視される. • コメントの始まりは/*で,終わりは*/である.あ るいは//を使って,1行分のコメントを書くことも ある.コメントは,入れ子にすることができない. • 次のコメントは入れ子になっていて,間違いである. /* n = n + 1; /* n は「空き領域」の先頭を指す */ */ 45
warning(disable:4996) カレンダー#pragma int main() { int y; int m; int nissu; int youbi1; /* 年と月を読み込む */ printf( "y=" ); scanf( "%d", &y ); printf( "m=" ); scanf( "%d", &m ); printf( "日 月 火 水 木 金 土\n" ); /* 年と月から「月の日数」を求める */ nissu = num_of_day(y, m); /*年と月から「月初めの曜日」を求める */ youbi1 = first_day(y, m); /* 「月の日数」と「月初めの曜日」からカレンダーを表示する */ print_calendar( nissu, youbi1 ); return 0; } 46
-関数と変数- データ 変数 処理手順 関数 プログラム main 関数 ライブラリ関数 (printf, scanf など) ユーザが自分で 定義した関数 47
関数の種類 • main関数 • プログラムは,main 関数を必ず含む • ライブラリ関数 • システムに既に組み込まれた関数 • ユーザが定義した関数 • プログラマが独自の関数を定義可能 48