整数値を2つ入力し、大きいほうの値を返却する関数を作成してください。
関数名 maxof 仮引数 int n1:値1 int n2:値2 返却値 int型:大きいほうの値
/* a8-1-1.c */ #include <stdio.h> int maxof(int n1, int n2); int main(void) { int a, b; printf("値を2つ入力してください。\n"); printf("> "); scanf("%d", &a); printf("> "); scanf("%d", &b); printf("大きいほうの値は%dです。\n", maxof(a, b)); return 0; } /*** 大きいほうを求める ***/ /* (仮引数)n1:値1 n2:値2 (返却値)大きいほうの値 */ int maxof(int n1, int n2) { int max; if (n1 >= n2) { max = n1; } else { max = n2; } return max; }
年月日を入力して曜日を求める関数を作成してください。
関数名 week_of_day 仮引数 int型 y:西暦年 int型 m:月 int型 d:日 返却値 int型:曜日 0=日、1=月、2=火、3=水、4=木、5=金、6=土
なお、西暦y年m月d日が何曜日であるかは、下記のZellerの公式によりwに求めることができます。
w = ( 5y / 4 - y / 100 + y / 400 + ( 26m + 16 ) / 10 + d ) % 7
ただし、1月と2月は、前年の13月と14月として計算する必要があります。つまり、2012年2月某日であれば、2011年14月某日としてZellerの公式を使用しないと正しい結果が得られません。
/* a8-1-2.c */ #include <stdio.h> int week_of_day(int y, int m, int d); int main(void) { int year, month, day, week; char *w[] = {"日", "月", "火", "水", "木", "金", "土"}; printf("西暦を入力してください。> "); scanf("%d", &year); printf("月を入力してください。> "); scanf("%d", &month); printf("日を入力してください。> "); scanf("%d", &day); /* 曜日を求める */ week = week_of_day(year, month, day); if (week >= 0 && week <= 6) { printf("%d年%d月%d日は%s曜日です。\n", year, month, day, w[week]); } return 0; } /*** 曜日を求める ***/ /* (仮引数)y:西暦年 m:月 d:日 (返却値)曜日 0=日 1=月 2=火 3=水 4=木 5=金 6=土 */ int week_of_day(int y, int m, int d) { if(m == 1) { y = y - 1; m = 13; } else if(m == 2) { y = y - 1; m = 14; } return (5 * y / 4 - y / 100 + y / 400 + (26 * m + 16) / 10 + d ) % 7; }
is_leap_year関数をそのまま利用し、月の最終日を求める関数を作成してください。つまり、month_last_day から is_leap_year を呼び出し閏年を判定します。
関数名 month_last_day 仮引数 int型 y:西暦年 int型 m:月 返却値 int型:月の最終日
/* a8-1-3.c */ #include <stdio.h> int is_leap_year(int y); int month_last_day(int y, int m); int main(void) { int year, month, last_day; printf("西暦を入力してください。> "); scanf("%d", &year); printf("月を入力してください。> "); scanf("%d", &month); last_day = month_last_day(year, month); /* 月の最終日を求める */ printf("%d年%d月の最終日は%d日です。\n", year, month, last_day); return 0; } /*** 月の最終日 ***/ /* (仮引数)y:西暦年 m:月 (返却値)月の最終日 */ int month_last_day(int y, int m) { int d = 0, last[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; if (m == 2) { d = last[m-1] + is_leap_year(y); /* 閏年なら+1 */ } else if (m >= 1 && m <= 12) { d = last[m-1]; } return d; } /*** 閏年の判定 ***/ /*(仮引数)y:西暦年 (返却値)1:閏年 0:閏年以外 */ int is_leap_year(int y) { int rc = 0; if (y % 4 == 0 && y % 100 != 0 || y % 400 == 0) { rc = 1; } return rc; }
実行結果例のようにオープニング画面を表示する関数を作成してください。
関数名 opening 仮引数 なし 返却値 なし
【実行結果例】 ★☆★☆★☆★☆★☆★☆★☆★☆★☆★ ☆ ☆ ★ じゃんけんゲーム スタート! ★ ☆ ☆ ★☆★☆★☆★☆★☆★☆★☆★☆★☆★
/* a8-2-1.c */ #include <stdio.h> void opening(void); int main(void) { /* オープニング表示 */ opening(); return 0; } /*** オープニング表示 ***/ /* (仮引数)なし (返却値)なし */ void opening(void) { printf("★☆★☆★☆★☆★☆★☆★☆★☆★☆★\n"); printf("☆ ☆\n"); printf("★ じゃんけんゲーム スタート! ★\n"); printf("☆ ☆\n"); printf("★☆★☆★☆★☆★☆★☆★☆★☆★☆★\n"); }
食堂のメニューを選択する関数を作成してください。
関数名 menu 仮引数 なし 返却値 メニュー番号
/* a8-2-2.c */ #include <stdio.h> int menu(void); int main(void) { int n; n = menu(); printf("選択したメニューは%d番です。\n", n); return 0; } /*** 選択したメニュー番号を返す ***/ /* (仮引数)なし (返却値)メニュー番号 */ int menu(void) { int no; do { printf("メニューを選択してください。\n"); printf("*** メニュー ***\n"); printf("1.日替わり定食\n"); printf("2.麺(タンメン)\n"); printf("3.どんぶり(親子丼)\n"); printf("1〜3? > "); scanf("%d", &no); } while (no < 1 || no > 3); return no; }
西暦年と月を入力するとカレンダーを表示する関数を作成してください。なお、必要ならP.266の演習2、3で作成した関数を呼び出して利用してください。
関数名 calendar 仮引数 int型 y:西暦年 int型 m:月 返却値 なし
/* a8-2-3.c */ #include <stdio.h> void calendar(int y, int m); int month_last_day(int y, int m); int week_of_day(int y, int m, int d); int is_leap_year(int y); int main(void) { int year, month; printf("西暦を入力してください。> "); scanf("%d", &year); printf("月を入力してください。> "); scanf("%d", &month); /* カレンダーの表示 */ calendar(year, month); return 0; } /*** カレンダーの表示 ***/ /* (仮引数)y:西暦年 m:月 (返却値)なし */ void calendar(int y, int m) { int i, e, w; w = week_of_day(y, m, 1); /* 1日の曜日を求める */ e = month_last_day(y, m); /* 月の最終日を求める */ printf(" ** %d年%d月 **\n", y, m); printf(" 日 月 火 水 木 金 土\n"); printf("---------------------\n"); for (i = 1; i <= w; i++) { /* 1日まで空白で埋める */ printf(" "); } for (i = 1; i <= e; i++) { /* 最終日まで表示する */ printf(" %2d", i); if ( (i + w) % 7 == 0) { /* 土曜日で改行する */ putchar('\n'); } } } /*** 曜日を求める ***/ /* (仮引数)y:西暦年 m:月 d:日 (返却値)曜日 0=日 1=月 2=火 3=水 4=木 5=金 6=土 */ int week_of_day(int y, int m, int d) { if(m == 1) { y = y - 1; m = 13; } else if(m == 2) { y = y - 1; m = 14; } return (5 * y / 4 - y / 100 + y / 400 + (26 * m + 16) / 10 + d ) % 7; } /*** 月の最終日 ***/ /* (仮引数)y:西暦年 m:月 (返却値)月の最終日 */ int month_last_day(int y, int m) { int d = 0, last[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; if (m == 2) { d = last[m-1] + is_leap_year(y); /* 閏年なら+1 */ } else if (m >= 1 && m <= 12) { d = last[m-1]; } return d; } /*** 閏年の判定 ***/ /*(仮引数)y:西暦年 (返却値)1:閏年 0:閏年以外 */ int is_leap_year(int y) { int rc = 0; if (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) { rc = 1; } return rc; }
1日の曜日を求めるためにweek_of_day関数を、月の最終日を求めるためにmonth_last_day関数を利用しています。
配列要素の平均値を求める関数を作成してください。
関数名 get_avg 仮引数 int *p:平均値を求める配列のポインタ int n:配列の要素数 返却値 double型:平均値
/* a8-3-1.c */ #include <stdio.h> #define N 10 double get_avg(int *p, int n); int get_sum(int *p, int n); int main(void) { int ten[N] = {56, 89, 66, 37, 98, 77, 62, 82, 50, 71}; double average; average = get_avg(ten, N); printf("平均点は%f点です。\n", average); return 0; } /*** 配列の平均を求める ***/ /* (仮引数)*p:ポインタ n:要素数 (返却値)平均 */ double get_avg(int *p, int n) { /* 合計を要素数で割った値を返却 */ return (double)get_sum(p, n) / n; } /*** 配列の合計を求める ***/ /* (仮引数)*p:ポインタ n:要素数 (返却値)合計 */ int get_sum(int *p, int n) { int i, sum = 0; for (i = 0; i < n; i++) { sum += *(p + i); } return sum; }
配列要素の分散を求める関数を作成してください。
関数名 get_var 仮引数 int array[]:分散を求める配列 int n:配列の要素数 返却値 double型:分散
/* a8-3-2.c */ #include <stdio.h> #define N 10 double get_var(int array[], int n); double get_avg(int array[], int n); int get_sum(int array[], int n); int main(void) { int ten[N] = {56, 89, 66, 37, 98, 77, 62, 82, 50, 71}; double variance; variance = get_var(ten, N); printf("分散は%fです。\n", variance); return 0; } /*** 配列の分散を求める ***/ /* (仮引数)array:配列 n:要素数 (返却値)分散 */ double get_var(int array[], int n) { int i; double avg, var = 0.0; /* 平均を求める */ avg = get_avg(array, n); for (i = 0; i < n; i++) { var += (avg - array[i]) * (avg - array[i]); } return var / n; } /*** 配列の平均を求める ***/ /* (仮引数)array:配列 n:要素数 (返却値)平均 */ double get_avg(int array[], int n) { /* 合計を要素数で割った値を返却 */ return (double)get_sum(array, n) / n; } /*** 配列の合計を求める ***/ /* (仮引数)array:配列 n:要素数 (返却値)合計 */ int get_sum(int array[], int n) { int i, sum = 0; for (i = 0; i < n; i++) { sum += array[i]; } return sum; }
配列要素の標準偏差を求める関数を作成してください。
関数名 get_dev 仮引数 int array[]:標準偏差を求める配列 int n:配列の要素数 返却値 double型:標準偏差
/* a8-3-3.c */ #include <stdio.h> #include <math.h> #define N 10 double get_dev(int array[], int n); double get_var(int array[], int n); double get_avg(int array[], int n); int get_sum(int array[], int n); int main(void) { int ten[N] = {56, 89, 66, 37, 98, 77, 62, 82, 50, 71}; double deviation; deviation = get_dev(ten, N); printf("標準偏差は%fです。\n", deviation); return 0; } /*** 配列の標準偏差を求める ***/ /* (仮引数)array:配列 n:要素数 (返却値)標準偏差 */ double get_dev(int array[], int n) { /* 分散の平方根を返す */ return sqrt(get_var(array, n)); } /*** 配列の分散を求める ***/ /* (仮引数)array:配列 n:要素数 (返却値)分散 */ double get_var(int array[], int n) { int i; double avg, var = 0.0; /* 平均を求める */ avg = get_avg(array, n); for (i = 0; i < n; i++) { var += (avg - array[i]) * (avg - array[i]); } return var / n; } /*** 配列の平均を求める ***/ /* (仮引数)array:配列 n:要素数 (返却値)平均 */ double get_avg(int array[], int n) { /* 合計を要素数で割った値を返却 */ return (double)get_sum(array, n) / n; } /*** 配列の合計を求める ***/ /* (仮引数)array:配列 n:要素数 (返却値)合計 */ int get_sum(int array[], int n) { int i, sum = 0; for (i = 0; i < n; i++) { sum += array[i]; } return sum; }
文字列を大文字に変換する関数を作成してください。なお、main関数からは2次元配列に格納された文字列を繰り返し渡して大文字に変換させてみましょう。
関数名 oomoji 仮引数 char *s:文字列へのポインタ 返却値 なし
/* a8-4-1.c */ #include <stdio.h> #include <ctype.h> void to_upper_str(char *s); int main(void) { char str[3][10] = { "persimmon", "apple", "chestnut"}; int i; for (i = 0; i < 3; i++) { printf("%s => ", str[i]); to_upper_str(str[i]); printf("%s\n", str[i]); } return 0; } /*** 文字列を大文字に変換する ***/ /* (仮引数)*s:文字列へのポインタ (返却値)なし */ void to_upper_str(char *s) { while(*s != '\0') { *s = toupper(*s); s++; } }
to_upper_str(str[i]); で、2次元配列に格納された各文字列を関数に渡すことができます。
整数値を2つ渡すと四則演算の結果を配列に返す関数を作成してください。
関数名 arithmetic 仮引数 int x:整数1 int y:整数2 int *p:演算結果格納配列へのポインタ 返却値 なし
/* a8-4-2.c */ #include <stdio.h> void arithmetic(int x, int y, int *p); int main(void) { int dt1, dt2, result[4]; printf("整数値を2つ入力してください。\n"); printf("> "); scanf("%d", &dt1); printf("> "); scanf("%d", &dt2); arithmetic(dt1, dt2, result); printf("和 = %d 差 = %d 積 = %d 商 = %d\n", result[0], result[1], result[2], result[3]); return 0; } /*** 四則演算 ***/ /* (仮引数)x:整数1 y:整数2 *p:演算結果格納配列へのポインタ */ /* (返却値)なし */ void arithmetic(int x, int y, int *p) { *p = x + y; *(p + 1) = x - y; *(p + 2) = x * y; if (y != 0) { *(p + 3) = x / y; } else { printf("0で割り算はできません。\n"); } }
配列要素から最大値と最小値を求める関数を作成してください。
関数名 get_maxmin 仮引数 int型 *p:配列へのポインタ int型 n:データ個数 int型 *max:最大値を格納するポインタ int型 *min:最小値を格納するポインタ 返却値 なし
/* a8-4-3.c */ #include <stdio.h> #define N 10 void get_maxmin(int *p, int n, int *max, int *min); int main(void) { int ten[N] = {56, 89, 66, 37, 98, 77, 62, 82, 50, 71}; int max, min; get_maxmin(ten, N, &max, &min); printf("最大値 = %d 最小値 = %d\n", max, min); return 0; } /*** 最大値と最小値を求める ***/ /* (仮引数)*p:配列へのポインタ n:データ個数 *max:最大値 *min:最小値 (返却値)なし */ void get_maxmin(int *p, int n, int *max, int *min) { int i; *max = *min = *p; for (i = 1; i < n; i++) { if (*(p + i) > *max) { *max = *(p + i); } if (*(p + i) < *min) { *min = *(p + i); } } }
3つの整数を渡すと、中身を入れ替える関数を作成してください。ただし、s8-4-2.c(P.284)で作成したswap をその関数内で呼び出してください。
関数名 swap3 仮引数 int型 *p1:入れ替える値1へのポインタ int型 *p2:入れ替える値2へのポインタ int型 *p3:入れ替える値3へのポインタ 返却値 なし
/* a8-4-4.c */ #include <stdio.h> void swap3(int *p1, int *p2, int *p3); void swap(int *p1, int *p2); int main(void) { int x = 10, y = 20, z = 30; printf("入れ替え前 x = %d y = %d z = %d\n", x, y, z); swap3(&x, &y, &z); printf("入れ替え後 x = %d y = %d z = %d\n", x, y, z); return 0; } /*** 3つの値を交換する ***/ /* (仮引数)*p1:交換する値1 *p2:交換する値2 *p3:交換する値3 (返却値)なし */ void swap3(int *p1, int *p2, int *p3) { swap(p1, p2); swap(p3, p1); } /*** 2つの値を交換する ***/ /* (仮引数)*p1:交換する値1 *p2:交換する値2 (返却値)なし */ void swap(int *p1, int *p2) { int temp; temp = *p1; *p1 = *p2; *p2 = temp; }
図のように、swap3を通してswapに渡されたポインタを使って入れ替えます。
P.281で作成したs8-4-1.cの関数の仮引数をconst型修飾子を使って書き換えてください。
/* a8-4-5.c */ #include <stdio.h> #define N 10 int even_number(const int *p, int n, int *e); int main(void) { int array[N] = {56, 89, 66, 37, 98, 77, 62, 82, 50, 71}; int even[N], i, n; n = even_number(array, N, even); printf("偶数 = "); for (i = 0; i < n; i++) { printf("%d ", even[i]); } printf("\n"); return 0; } /*** 偶数を配列に格納しその数を返却する ***/ /* (仮引数)*p:元の配列のポインタ n:要素数 *e:偶数を格納する配列のポインタ (返却値)偶数値の数 */ int even_number(const int *p, int n, int *e) { int i, j; for (i = 0, j = 0; i < n; i++) { if (*(p + i) % 2 == 0) { *(e + j) = *(p + i); j++; } } return j; }
コマンドラインで数値を入力し、その合計値を求めるプログラムを作成してください。
/* a8-5-1.c */ #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { int i, sum = 0; for (i = 1; i < argc; i++) { sum += atoi(argv[i]); } printf("合計は%dです。\n", sum); return 0; }
argv[0]にはプログラム名へのポインタが格納されているので、合計値の計算からは除いてください。
コマンドラインで文字列を入力し、その長さを表示するプログラムを作成してください。
/* a8-5-2.c */ #include <stdio.h> #include <string.h> int main(int argc, char *argv[]) { int i; for (i = 1; i < argc; i++) { printf("argv[%d] = %s : %d文字\n", i, argv[i], strlen(argv[i])); } return 0; }
P.221の演習2で作成したじゃんけんプログラムのa6-5-3.cを次のように関数に分割し、効率よく3回勝負を行ってください。その際、各関数で共通に使用する変数や配列はグローバル変数にしてください。
/* a8-6-1.c */ #include <stdio.h> #include <stdlib.h> #include <time.h> int user(void); int computer(void); void judge(int u, int c); char ken[3][8] = {"グー", "チョキ", "パー"}; int main(void) { int u, c, n; srand((unsigned)time(NULL)); printf("3回勝負だ\n"); for (n = 1; n <=3; n++) { u = user(); c = computer(); judge(u, c); } return 0; } /*** ユーザーのじゃんけんを入力する ***/ /* (仮引数)なし (返却値)ユーザーのじゃんけん */ int user(void) { int u; do { printf("じゃん、けん、ぽん!(1:グー 2:チョキ 3:パー) > "); scanf("%d", &u); } while (u < 1 || u > 3); u--; printf("あなたは%s\n", ken[u]); return u; } /***コンピュータのじゃんけんを決定する ***/ /* (仮引数)なし (返却値)コンピュータのじゃんけん */ int computer(void) { int c; c = rand() % 3; printf("コンピュータは%s\n", ken[c]); return c; } /*** 勝敗を決定する ***/ /* (仮引数)u:ユーザー c:コンピュータ (返却値)なし */ void judge(int u, int c) { char judge_table[3][14] = {"あいこ", "あなたの勝ち", "あなたの負け"}; /* 判定 0:あいこ 1:ユーザーの勝ち 2:ユーザーの負け */ int table[3][3] = { /* コンピュータ グー チョキ パー */ /* ユーザー グー */ {0, 1, 2}, /* チョキ */ {2, 0, 1}, /* パー */ {1, 2, 0} }; if (u >= 0 && u <= 2 && c >= 0 && c <= 2) { printf("%sです。\n", judge_table[table[u][c]]); } }
配列kenは、user関数とcomputer関数の両方から参照されるので、main関数からの引数渡しにするよりもグローバル変数にしたほうが管理が簡単になります。
むやみな使用は避けるべきですが、
・プログラム全体を管理するために使う変数
・プログラム全体で参照する変数
はグローバル変数にしたほうがわかりやすいプログラムが作成できます。
なお、judge関数では、仮引数uとcの値が不適切な場合に、配列tableを超えたアクセスをしてしまいます。そのためuとcの範囲チェックの処理を追加しました。
渡された引数の最大値を返す関数を作成してください。なお、最大値の初期値は、<limits.h>ヘッダファイルの中でマクロ定義されているINT_MIN(P.307参照)というint型の最小値を用いてください。
/* a8-6-2.c */ #include <stdio.h> #include <limits.h> int maxof(int n); int main(void) { int n, max; printf("整数値を入力してください。(終了条件:Ctrl+Z)\n"); printf("> "); while (scanf("%d", &n) != EOF) { max = maxof(n); printf("> "); } printf("最大値は%dです。\n", max); return 0; } /*** 最大値を返却する ***/ /* (仮引数)n:整数値 (返却値)最大値 */ int maxof(int n) { static int max = INT_MIN; if (max < n) { max = n; } return max; }
P.295の演習で作成したじゃんけんプログラムのa8-6-1.cを次のようにファイルに分割してください。
/* jyanken.h */
int user(void);
int computer(void);
void judge(int u, int c);
/* jyanken.c */ #include <stdio.h> #include <stdlib.h> #include <time.h> #include "jyanken.h" char ken[3][8] = {"グー", "チョキ", "パー"}; int main(void) { int u, c, n; srand((unsigned)time(NULL)); printf("3回勝負だ\n"); for (n = 1; n <=3; n++) { u = user(); c = computer(); judge(u, c); } return 0; }
/* user.c */ #include <stdio.h> #include "jyanken.h" extern char ken[3][8]; /*** ユーザーのじゃんけんを入力する ***/ /* (仮引数)なし (返却値)ユーザーのじゃんけん */ int user(void) { int u; do { printf("じゃん、けん、ぽん!(1:グー 2:チョキ 3:パー) > "); scanf("%d", &u); } while (u < 1 || u > 3); u--; printf("あなたは%s\n", ken[u]); return u; }
/* computer.c */ #include <stdio.h> #include <stdlib.h> #include "jyanken.h" extern char ken[3][8]; /***コンピュータのじゃんけんを決定する ***/ /* (仮引数)なし (返却値)コンピュータのじゃんけん */ int computer(void) { int c; c = rand() % 3; printf("コンピュータは%s\n", ken[c]); return c; }
/* judge.c */ #include <stdio.h> #include "jyanken.h" /*** 勝敗を決定する ***/ /* (仮引数)u:ユーザー c:コンピュータ (返却値)なし */ void judge(int u, int c) { char judge_table[3][14] = {"あいこ", "あなたの勝ち", "あなたの負け"}; /* 判定 0:あいこ 1:ユーザーの勝ち 2:ユーザーの負け */ int table[3][3] = { /* コンピュータ グー チョキ パー */ /* ユーザー グー */ {0, 1, 2}, /* チョキ */ {2, 0, 1}, /* パー */ {1, 2, 0} }; if (u >= 0 && u <= 2 && c >= 0 && c <= 2) { printf("%sです。\n", judge_table[table[u][c]]); } }
Copyright© 2006,2012 Tomoko Sugawara. All Rights Reserved.