20140606更新

練習問題2


[next|prev|index]

1. 分岐

if文

現在の時刻

下記のような時刻を書き出すプログラムが在ります。構造体や,まだ学んでいない標準関数が使われていますが、そこは本題ではないので気にしないでください。

/*time.c*/
#include<stdio.h>
#include<time.h>
int main(void)
{
   time_t timer,now;
   int h;
   now=time(&timer);
   /*hに現在の時間を取り出す*/
   h=localtime(&now)->tm_hour;/*警告されますが無視*/

   printf("%d時です\n",h);
   return 0;
}

ここで変数hに入る値は24時間制です。これを12時間制にして午前午後を付けて書き出すように書き換えなさい。

と書き出す

解答例

時刻に合わせて挨拶を書き出す

先ほどの例を基に、時刻に合わせた挨拶を

と書き出すプログラムを書いてください。(条件式の書き方に注意)

解答例

二重の条件

ここで上2つを組み合わせて

「おはようございます。 午前6時です。」のように書き出すプログラムを書いてください。

解答例 

解答例2

どちらが良いと思います?

2. 繰り返し

似たような処理を繰り返すプログラムを、始めから繰り返しの構文で作ろうとすると難しい。

初めは、構文を使わずに少し繰り返しでプログラムを書いてみましょう。まったく同じことの繰り返しなら簡単に繰り返しの構文が使えます。でも繰り返しのように見えてどこか違うことが多いのです。

その違いを上手く繰り返しの構文の中に吸収するノウハウを見つけてください。

for文

for文は繰り返しの回数が明らかなものに用いることが多い構文です。10回まわるとか100回まわるとか解っている場合にはfor文が使われます。

フィボナッチ数列の計算

フィボナッチ数列は
   A0=A1=1で
1<nについては 
   An = An-1 + An-2
となる数列です。ここで、繰り返しの構文を使わずにn=9まで計算する例を作ってみました。

/*Fibonacci.c
  フィボナッチ数列
  Fibonacci sequence
*/
#include<stdio.h>
int main(void)
{
    int a[10];

    a[0]=1; printf("a[0]=%d\n",a[0]);
    a[1]=1; printf("a[1]=%d\n",a[1]);

    a[2]=a[0]+a[1]; printf("a[2]=%d\n",a[2]);
    a[3]=a[1]+a[2]; printf("a[3]=%d\n",a[3]); 
    a[4]=a[2]+a[3]; printf("a[4]=%d\n",a[4]);
    a[5]=a[3]+a[4]; printf("a[5]=%d\n",a[5]);
    a[6]=a[4]+a[5]; printf("a[6]=%d\n",a[6]);
    a[7]=a[5]+a[6]; printf("a[7]=%d\n",a[7]);
    a[8]=a[6]+a[7]; printf("a[8]=%d\n",a[8]); 
    a[9]=a[7]+a[8]; printf("a[9]=%d\n",a[9]); 

    return 0;
}
/*
a[0]=1
a[1]=1
a[2]=2
a[3]=3
a[4]=5
a[5]=8
a[6]=13
a[7]=21
a[8]=34
a[9]=55
*/

問題:for文を用いてn=20まで計算するプログラムを書きなさい。

A20=10946

解答例

配列を使わない解答例 解りにくい解答例

三角関数の数表を作る 

次のような三角関数の表を書き出すプログラムをfor文を使って書きなさい。

角度[deg] sin cos
0deg 0.000000 1.000000
10deg 0.173648 0.984808
20deg 0.342020 0.939693
30deg 0.500000 0.866025
40deg 0.642788 0.766044
50deg 0.766044 0.642788
60deg 0.866025 0.500000
70deg 0.939693 0.342020
80deg 0.984808 0.173648
90deg 1.000000 0.000000

三角関数の計算には下記の標準関数が使えます。

これらの関数を使うにはヘッダーファイルmath.hをincludeすることが必要です。さらに定数として円周率M_PIを使うにはmath.hをインクルードする前に_USE_MATH_DEFINESを#defineで定義しておくことが必要です。 以下にfor文を使わない例を示します。

/*sin_cos.c*/
#include<stdio.h>
#define _USE_MATH_DEFINES
#include<math.h> 
int main(void)
{
    double x; 
    printf("角度[deg] sin cos\n");
    d=0 ; 
    printf("%2ddeg %.6lf %.6lf\n",d,sin(d/180.0*M_PI),cos(d/180.0*M_PI)); 
    d=10; 
    printf("%2ddeg %.6lf %.6lf\n",d,sin(d/180.0*M_PI),cos(d/180.0*M_PI));
    d=20; 
    printf("%2ddeg %.6lf %.6lf\n",d,sin(d/180.0*M_PI),cos(d/180.0*M_PI));
    d=30; 
    printf("%2ddeg %.6lf %.6lf\n",d,sin(d/180.0*M_PI),cos(d/180.0*M_PI));
    d=40; 
    printf("%2ddeg %.6lf %.6lf\n",d,sin(d/180.0*M_PI),cos(d/180.0*M_PI));
    d=50; 
    printf("%2ddeg %.6lf %.6lf\n",d,sin(d/180.0*M_PI),cos(d/180.0*M_PI)); 

    return 0;
}
/*
角度[deg]  sin        cos
 0deg     0.000000  1.000000
10deg     0.173648  0.984808
20deg     0.342020  0.939693
30deg     0.500000  0.866025
40deg     0.642788  0.766044
50deg     0.766044  0.642788
*/

解答例

16進数でF×Fの掛け算表を作る 

次のような、99の掛け算表の16進数版を書き出すプログラムを書きなさい。

 1  2  3  4  5  6  7  8  9  A  B  C  D  E  F 
 2  4  6  8  A  C  E 10 12 14 16 18 1A 1C 1E 
 3  6  9  C  F 12 15 18 1B 1E 21 24 27 2A 2D 
 4  8  C 10 14 18 1C 20 24 28 2C 30 34 38 3C 
 5  A  F 14 19 1E 23 28 2D 32 37 3C 41 46 4B 
 6  C 12 18 1E 24 2A 30 36 3C 42 48 4E 54 5A 
 7  E 15 1C 23 2A 31 38 3F 46 4D 54 5B 62 69 
 8 10 18 20 28 30 38 40 48 50 58 60 68 70 78 
 9 12 1B 24 2D 36 3F 48 51 5A 63 6C 75 7E 87 
 A 14 1E 28 32 3C 46 50 5A 64 6E 78 82 8C 96 
 B 16 21 2C 37 42 4D 58 63 6E 79 84 8F 9A A5 
 C 18 24 30 3C 48 54 60 6C 78 84 90 9C A8 B4 
 D 1A 27 34 41 4E 5B 68 75 82 8F 9C A9 B6 C3 
 E 1C 2A 38 46 54 62 70 7E 8C 9A A8 B6 C4 D2 
 F 1E 2D 3C 4B 5A 69 78 87 96 A5 B4 C3 D2 E1 

16進数で数値を書き出す書式指定子は%Xです。

解答例

while文

while文は繰り返しの回数が不明で、繰り返しの条件のみが解っているときに良く使われます。

回数が不明なのでfor文の例題のように同じことを何度も書く形のプログラムにはできないことが多い。初めから繰り返しの構文を使って考えることになるでしょう。ここで大事なのは繰り返しの条件です。

合計の計算

標準入力からスペースや改行で区切られた整数値を読み込んで合計する。0が読みこまれた時を合計の終端とし、そこまでの合計値を標準出力に書き出すプログラムを書きなさい。

ヒント:scanf関数を使って読み取った数値を入れる変数、 数値を積算して行く変数などが必要です。

ヒント:繰り返しの条件は読み取った数値が0以外。

解答例

for文の書き換え

for文、while文のどちらでも繰り返しのプログラムを書くことができます。for文で書かれたプログラムをwhile文で書き直すのは難しくありません。繰り返しの回数が固定ならfor文の方が解り易く書けるだけのことです。

次のfor文で書かれたプログラムをwhile文で書き直しなさい。

#include<stdio.h>

int main(void)
{
    double sum=0;
    int n;
    int max=10000;
    
    for( n=max; 0<n; n--)
    { 
        sum += 1.0/(n*n);
    }
    printf("1/n^2のn=1から%dまでの合計は %lf\n",max,sum);
    return 0;
}
/*
1/n^2のn=1から10000までの合計は 1.644834
*/

解答例

逐次代入法

関数f(x)が与えられていて、方程式 x=f(x) の解を求めたいとき、fのxによる微分df(x)/dxの絶対値が1以下であれば逐次代入法と呼ばれる計算方法が使えます。この方法はxの初期値x0から初めて

x1=f(x0);
x2=f(x1);
x3=f(x2);
x4=f(x3);
x5=f(x4);
...

と繰り返し計算しているうちにxnとxn-1の差が小さくなり収束して近似解xnが得られる手法です。

プログラムでこの部分を書くとしたら、添え字の終わりが見えないxnは使えませんから2つの変数x0,x1を使いまわすような工夫が必要になります。

x0=1;/*初期値*/
x1=f(x0);
x0とx1の差が大きい場合以下を繰り返す。小さければ終了
x0=x1;
x1=f(x0);
x0とx1の差が大きい場合以下を繰り返す。小さければ終了
...

1回計算するごとにx0とx1の差を見て収束判定が必要になります。この判定条件は

eps < fabs(x1-x0)

のような条件式で行えます。ここで関数fabsはdouble型の絶対値を戻す標準関数です。epsは十分に小さな数ですが、double型の有効数字は15〜16桁なので10のマイナス14乗程度が良いでしょう。

※fabsを使うためにはmath.hのインクルードが必要です。

問題:
次はx=cos(x)の解xを求める if と goto を用いたプログラム例です。これをwhileを用いて書きなおしなさい。

#include<stdio.h>
#include<math.h>
double f(double x)
{
    return cos(x);
}
int main(void)
{
    double x0=1,x1;
    double eps=1E-14;

    x1=f(x0);
  LOOP:
    if( eps < fabs(x1-x0) )
    {
        x0=x1;
        x1=f(x0);
        goto LOOP;
    }

    printf("解は %lf\n",x1);
    return 0;
}
    

解答例

do-whileを用いた解答例