C言語編 第8章 理解の定着・小休止① 解答ページ

先頭へ戻る

問題①

問題① 次のプログラムは間違っています。間違いを指摘して下さい。[★]

#include <stdio.h>

int main(void)
{
    int    a = 15;
    double f = 4.2;

    printf( '%d %f\n', a, f );

    return 0;
}


printf関数の1つ目の情報が、「""」ではなく「''」で囲まれています。 C言語では、「''」は文字を囲む際に使い、文字列を囲むときには使えません。

問題②

問題② 次のプログラムには問題があります。指摘して下さい。[★]

#include <stdio.h>

int main(void)
{
	int a = 0;
	int b = 10;
	int c = 20;
	
	printf( "%d * %d = %d\n", a, b, a * b );
	printf( "%d / %d = %d\n", c, a, c / a );
	printf( "%d + %d = %d\n", b, c, b + c );

	return 0;
}


2つ目の printf関数において、「c / a」の結果を出力しようとしています。 ここで、変数a の値が 0 であることに注目して下さい。 0 で割る行為は未定義であり、このプログラムは正しい結果を得ることができません。

問題③

問題③ 次のプログラムの間違いを指摘して下さい。[★]

#include <stdio.h>

int main(void)
{
    int num = 10;
    char c = 'C';

    puts( "%d, %c\n", num, c );

    return 0;
}


puts関数を使っているにも関わらず、情報の指定の仕方が printf関数の形式になっています。 使う関数を printf関数に変える必要があります。

問題④

問題④ 次のプログラムと同じ結果になるように、puts関数を使ったプログラムを書いて下さい。[★]

#include <stdio.h>

int main(void)
{
    printf( "abc" );
    printf( "def\n" );
    printf( "ghi\n" );

    return 0;
}


puts関数は、自動的に末尾で改行を行います。 printf関数で "\n" を使っている箇所までを1つの puts関数に置き換えると、同じ結果を維持したまま書き換えられます。

#include <stdio.h>

int main(void)
{
    puts( "abcdef" );
    puts( "ghi" );

    return 0;
}

実行結果:

abcdef
ghi

問題⑤

問題⑤ 「\300 の 20%引きは \240 です」という文字列を、puts関数と printf関数で出力するプログラムを書いて下さい。[★★]


「\」には「\n」を表現するなどの特殊な用途があるため、単に「\」を出力するには「\\」のように重ねる必要があります。

printf関数の場合は更に、「%」を変換指定子として使うため、単に「%」を出力するには「%%」のようにしなければなりません。

#include <stdio.h>

int main(void)
{
    puts( "\\300 の 20%引きは \\240 です" );
    printf( "\\300 の 20%%引きは \\240 です\n" );

    return 0;
}

実行結果:

\300 の 20%引きは \240 です
\300 の 20%引きは \240 です

問題⑥

問題⑥ 標準入力から秒数を受け取り、それを時・分・秒に変換して出力するプログラムを書いて下さい。[★★]


除算と剰余を使えば、秒数から変換することが可能です。 数値の入力が欲しいので、fgets + sscanf を使います。

#include <stdio.h>

int main(void)
{
    char str[20];
    int second;

    puts( "秒数を入力して下さい。" );
    fgets( str, sizeof(str), stdin );
    sscanf( str, "%d", &second );

    /* ○時間○分○秒 のような形で出力する */
    printf( "%d時間", second / 3600 );
    printf( "%d分",   second % 3600 / 60 );
    printf( "%d秒",   second % 60 );
    printf( "\n" );

    return 0;
}

実行結果:

秒数を入力して下さい。
5432
1時間30分32秒

問題⑦

問題⑦ 標準入力から3つの整数を受け取り、その合計と平均値を出力するプログラムを書いて下さい。[★★]


合計を出すことができれば、平均値は個数で割れば求められます。

#include <stdio.h>

int main(void)
{
    char str[20];
    int num1;
    int num2;
    int num3;
    int sum;

    puts( "整数を3回入力して下さい。" );
    fgets( str, sizeof(str), stdin );
    sscanf( str, "%d", &num1 );
    fgets( str, sizeof(str), stdin );
    sscanf( str, "%d", &num2 );
    fgets( str, sizeof(str), stdin );
    sscanf( str, "%d", &num3 );

    /* 合計を求める */
    sum = num1 + num2 + num3;

    /* 合計と平均値を出力する */
    printf( "合計: %d\n", sum );
    printf( "平均: %d\n", sum / 3 );

    return 0;
}

実行結果:

整数を3回入力して下さい。
64
48
92
合計: 204
平均: 68

問題⑧

問題⑧ 標準入力から受け取った整数を、次の表の規則性に従うように変換し、出力するプログラムを書いて下さい。[★★★]

入力値 出力値
0 0
1 2
2 2
3 4
4 4
5 6
6 6
7 8
8以上も同様に続く ???


規則性は、「出力値は入力値以上の偶数のうち最小のものになる」と言えます。 入力値が既に偶数なら、そのまま出力されます。 やり方は幾つもあるでしょう。 以下は一例です。

#include <stdio.h>

int main(void)
{
    char str[20];
    int num;
    int out_num;

    puts( "整数を入力して下さい。" );
    fgets( str, sizeof(str), stdin );
    sscanf( str, "%d", &num );


    /* 出力値に変換 */
    out_num = num + (num % 2);

    /* 入力値 -> 出力値 の形で出力 */
    printf( "%d -> %d\n", num, out_num );

    return 0;
}

実行結果:

整数を入力して下さい。
3
3 -> 4

入力値を 2 で割った余りを求め、それを入力値自身に加算したものを出力値としています。 2 で剰余を求めるのは、その数が奇数なのか偶数なのかを調べる常套手段で、奇数ならば結果は 1 に、偶数ならば結果は 0 になります。 従って、入力値が偶数なら +0 になるので、入力値がそのまま出力値になります。 奇数なら、+1 になるので、1つ大きい偶数に変換できます。

問題⑨

問題⑨ 標準入力から受け取った整数の符号を反転して出力するプログラムを書いて下さい。 「10」なら「-10」に、「-10」なら「10」にします。[★★]


マイナスの符号(-) を付ければ、常に符号は反転できます。 元が+なら-になるし、元が-なら+になります。

#include <stdio.h>

int main(void)
{
    char str[20];
    int num;

    puts( "整数を入力して下さい。" );
    fgets( str, sizeof(str), stdin );
    sscanf( str, "%d", &num );


    /* 符号を反転して出力する */
    printf( "%d\n", -num );

    return 0;
}

実行結果:

整数を入力して下さい。
-10
10

あるいは、-1 を乗算しても良いです。

問題⑩

問題⑩ 標準入力から受け取った文字列を、"" で挟んで出力するプログラムを書いて下さい。[★★★]


fgets関数を使う場合、改行文字まで受け取ってしまうため、案外難しかったかも知れません。

#include <stdio.h>

int main(void)
{
    char str[80];
    char str2[80];

    puts( "文字列を入力して下さい。" );
    fgets( str, sizeof(str), stdin );
    sscanf( str, "%s", str2 );


    /* "" で囲んで出力する */
    printf( "\"%s\"\n", str2 );

    return 0;
}

実行結果:

文字列を入力して下さい。
abcde
"abcde"

fgets関数で文字列を受け取った後、更に sscanf関数の "%s" 変換指定子を使って、 文字列を取り出し直せば、うまく改行文字を消し去ることができます。 「"」を出力する際には、「\"」という記述が必要です。

問題⑪

問題⑪ 標準入力から半径の長さを受け取り、円の面積と、円周の長さを出力するプログラムを書いて下さい。 円周率にどの程度の精度を与えるかは各自の自由としますが、最低でも 3.14 として下さい。[★★★]


円の面積は「半径×半径×円周率」、円周の長さは「直径×円周率」ですね。

#include <stdio.h>

int main(void)
{
    char   str[20];
    double radius;
    double pi = 3.141592;  /* 円周率 */

    puts( "半径を入力して下さい。" );
    fgets( str, sizeof(str), stdin );
    sscanf( str, "%lf", &radius );


    /* 円の面積と、円周の長さを出力 */
    printf( "面積: %f\n", radius * radius * pi );
    printf( "円周: %f\n", radius * 2 * pi );

    return 0;
}

実行結果:

半径を入力して下さい。
4.5
面積: 63.617238
円周: 28.274328

円周率は実数になるので、double型を使います。 それならば、入力させる値も double型として扱うようにしましょう。 sscanf関数で、double型の値を取り出すには "%f" ではなく、"%lf" を使わなければならないことに注意して下さい。

問題⑫

問題⑫ 次のプログラムは正しいでしょうか。[★]

#include <stdio.h>

int main(void)
{
    /*  puts関数に変えてみた
    printf( "コメントは /* と */ で挟む\n" );
    */
    puts( "コメントは /* と */ で挟む" );

    return 0;
}


正しくありません。 printf関数の部分をコメントアウトしたつもりですが、printf関数が出力しようとしていた文字列の中に、 コメントの終わりを表す「*/」が含まれてしまっているため、コメントアウトの効果が途切れてしまいます。 分かりやすく色分けすると、以下のようになります。

#include <stdio.h>

int main(void)
{
    /*  puts関数に変えてみた
    printf( "コメントは /* と */ で挟む\n" );
    */
    puts( "コメントは /* と */ で挟む" );

    return 0;
}

/* と */ は、複数行にまたがってコメントにできますが、この問題のような現象に引っ掛かることがよくあります。

問題⑬

問題⑬ 次のプログラムは正しいでしょうか。[★]

int main(void)
{
    3 + 7;

    return 0;
}


これは正しいプログラムです(コンパイラによっては警告が出るかも知れません)。 普通、「int num = 3 + 7;」のように書くはずですが、「3 + 7;」だけでも、文として有効な記述です。 しかし、このような文には全く意味がなく無駄です。

問題⑭

問題⑭ 次のプログラムは正しいでしょうか。[★]

#include <stdio.h>

int main(void)
{
    puts( "Hello!!" );;;;;;;;;;;;;;;;;;;

    return 0;
}


これも正しいプログラムです(コンパイラによっては警告が出るかも知れません)。 大量にセミコロンを並べていますが、1つ1つが「空文」と見なされるので、C言語の文法としては正しいです。 しかし、これもやはり無意味です。意味のないことはやめましょう。

問題⑮

問題⑮ 次のプログラムが出力する値は幾つになるでしょう。[★]

#include <stdio.h>

int main(void)
{
    int num = 50;

    printf( "%d\n", num / 100 * 80 );	/* num の 80% を出力 */

    return 0;
}


コメントを信じると、50 の 80% を出力するという意図で作られたプログラムなので、40 が出力されそうですが、 実際には 0 が出力されてしまいます。 コメントを信じすぎてはいけないという例でもあります。

まず、「num / 100」が計算され、これは整数同士の計算なので、結果も整数に切り捨てられてしまいます。 従って、この時点で結果は「0」です。 「0 * 80」をしたところで、やはり結果は「0」のままなので、出力される値は 0 になります。

この手の計算を正しく行うための基本は、先に乗算を行わせることです。

#include <stdio.h>

int main(void)
{
    int num = 50;

    printf( "%d\n", num * 80 / 100 );	/* num の 80% を出力 */

    return 0;
}

この場合、先に「num * 80」が計算され「4000」になり、更に「4000 / 100」が計算されて「40」になります。

今の時点で気にすることではありませんが、先に乗算を行うと、一時的に非常に大きな数になり、 変数で表現できる限界値を超えてしまう可能性があります。 本格的なプログラムでは、こういうことも気を付ける必要があります。

なお、結果が実数になっても構わないのなら、そもそも「num * 0.8」と書く方が自然で簡単です。


参考リンク

更新履歴

'2018/2/2 全面的に文章を見直し、修正を行った。

'2011/2/5 単に「小数」と表記していた箇所を、「実数」や「浮動小数点数」に改めた。

'2010/7/31 問題⑥の解答例が、入力した秒数が 3600 を超える場合に、間違って出力されるようになっていたのを修正。

'2009/1/31 新規作成。





第8章のメインページへ

C言語編のトップページへ

Programming Place Plus のトップページへ


このエントリーをはてなブックマークに追加
rss1.0 取得ボタン RSS