PR

【解答例】新・明解C言語 入門編 第2版 演習問題解答【まとめ】

新・明解C言語 入門編 第2版
記事内に広告が含まれています。

『新・明解C言語 入門編 第2版』(著:柴田望洋)の演習問題の解答例を掲載します。

この書籍は職場の研修でC言語を自己学習する際に教材として使用しています。

しかし、演習問題の解答や解説は書籍にはなく、また解説しているサイトも少なかったので、自身で作成したプログラムを公開することにしました。

はじめてのプログラミングなら1st step

  • プログラミングに興味はあるけど、どのように勉強を進めていけばいいかわからない
  • プログラミングが本当にできるようになるのか不安
  • 安定していて需要があるからプログラマーになりたいけど、何をどうしていけばいいかわからない

そんな悩みはないでしょうか。

プログラミングスクール『1st step』では、これからプログラミングに挑戦する方がスムーズに学習を始められるような徹底サポートがあり、プログラマーとして活かしていける基礎をしっかりと学習できます。

ITエンジニアになるメリット

  • 成長市場で需要が高い
  • 勤務地が制限されない
  • 成果主義で活躍できる

成長市場で需要が高い

昨今話題になっているAIの発展、自動化、デジタル化など、IT市場の成長はとどまるところを知りません。

そんな成長市場に身を置くことで、自分の市場価値を高め続けることができ、どこに行っても活躍できる人財になることができます。

勤務地が制限されない

プログラミングのスキルと経験があれば、全国どこからでも仕事をすることが可能になります。実際、海外を旅しながら日本のクライアント向けに仕事をしているエンジニアの方もいます。

成果主義で活躍できる

年齢や学歴が問われることが少なく、実力さえあれば出世することも可能です。

柔軟な発想力によって高いスキルを発揮することができる場面もあり、女性でも男性以上に貢献できるチャンスがあります。

1st stepの3大特徴

  • 完全未経験者支援カリキュラム
  • オンライン完結
  • いつでもエンジニアに質問できる

完全未経験者支援カリキュラム

1st stepは初心者に優しいカリキュラムで、確実な一歩目を踏み出せるようになっています。

また、自走力をつけるため、課題の答えをすぐに教えるのではなく、解き方・考え方を教えるスタンスとなっています。

オンライン完結

自分の好きな場所・時間で学習を進めることができます。教室が存在しない分コストが抑えられ、低価格を実現することができています。

またオンラインのため、いつでも好きな時間に質問ができ、早く回答がもらえるというメリットもあります。開講中は、各コースの担当者が常に質疑応答できる体制となっています。

いつでもエンジニアに質問できる

学習でつまずいたときは、エンジニアに直接質問することができます。質問はチャットもしくは通話で対応してもらえます。

また、プログラミング以外のことでも、パソコンの操作といったことでもサポートを受けられます。

第1章:まずは慣れよう

演習1-1

/* 整数値15から37を減じた結果を丁寧に表示 */

#include <stdio.h>

int main(void)
{
    printf("15から37を引いた値は%dです。\n", 15 - 37);    //整数値15から37を減じた結果を10進数で表示して改行

    return 0;
}

演習1-2

// 守破離を縦に表示する

#include <stdio.h>

int main(void)
{
    printf("守\n破\n離\n");

    return 0;
}

演習1-3

// 挨拶を複数行に表示する

#include <stdio.h>

int main(void)
{
    printf("こんにちは。\nお元気ですか。\n\nさようなら。\n");

    return 0;
}

演習1-4

//int型変数の宣言に実数値の初期化子を与える実験

#include <stdio.h>

int main(void)
{
    int x = 3.14, y = 5.7;

    printf("xの値は%dです。\n", x);     //"3"が表示される
    printf("yの値は%dです。\n", y);     //"5"が表示される

    return 0;
}

演習1-5

// 読み込んだ整数値に13を加えた値を表示

#include <stdio.h>

int main(void)
{
    int no;

    printf("整数を入力してください:");
    scanf("%d", &no);

    printf("%dに13を加えると", no);
    printf("%dです。\n", 13 + no);

    return 0;
}

演習1-6

// 読み込んだ整数値から7を減じた値を表示

#include <stdio.h>

int main(void)
{
    int no;

    printf("整数を入力してください:");
    scanf("%d", &no);

    printf("%dから7を減じると", no);
    printf("%dです。\n", no - 7);

    return 0;
}

演習1-7

// 守破離を縦に表示

#include <stdio.h>

int main(void)
{
    puts("守");
    puts("破");
    puts("離");

    return 0;
}

演習1-8

// 読み込んだ二つの整数値の積を表示

#include <stdio.h>

int main(void)
{
    int n1, n2;

    puts("二つの整数を入力してください。");
    printf("整数n1:");     scanf("%d", &n1);
    printf("整数n2:");     scanf("%d", &n2);

    printf("それらの積は%dです。\n", n1 * n2);

    return 0;
}

演習1-9

// 読み込んだ三つの整数値の和を表示

#include <stdio.h>

int main(void)
{
    int n1, n2, n3;

    puts("二つの整数を入力してください。");
    printf("整数n1:");     scanf("%d", &n1);
    printf("整数n2:");     scanf("%d", &n2);
    printf("整数n3:");     scanf("%d", &n3);

    printf("それらの和は%dです。\n", n1 + n2 + n3);

    return 0;
}

第2章:演算と型

演習2-1

// 二つの整数値を読み込んで前者が後者の何%かを表示

#include <stdio.h>

int main(void)
{
    int x, y;

    puts("2つの整数を入力せよ。");
    printf("整数x:");  scanf("%d", &x);
    printf("整数y:");  scanf("%d", &y);

    printf("xの値はyの%d%%です。\n", 100 * x / y);

    return 0;
}

演習2-2

// 二つの整数値を読み込んで和と積を表示

#include <stdio.h>

int main(void)
{
    int a, b;

    puts("2つの整数を入力せよ。");
    printf("整数a:");  scanf("%d", &a);
    printf("整数b:");  scanf("%d", &b);

    printf("それらの和は%dで積は%dです。\n", a + b, a * b);

    return 0;
}

演習2-3

// 読み込んだ実数値をそのまま表示

#include <stdio.h>

int main(void)
{
    double x;

    printf("実数を入力せよ:"); scanf("%lf", &x);

    printf("あなたは%fと入力しましたね。\n", x);

    return 0;
}

演習2-4

// int型とdouble型の演算確認

#include <stdio.h>

int main(void)
{
    int n = 5;
    double x = 3.14;
    
    printf("定数5 * 定数5 = %d\n", 5 * 5);
    printf("定数5 * 変数5 = %d\n", 5 * n);
    printf("変数5 * 定数5 = %d\n", n * 5);
    printf("変数5 * 変数5 = %d\n\n", n * n);

    printf("定数5 / 定数5 = %d\n", 5 / 5);
    printf("定数5 / 変数5 = %d\n", 5 / n);
    printf("変数5 / 定数5 = %d\n", n / 5);
    printf("変数5 / 変数5 = %d\n\n", n / n);

    printf("定数3.14 * 定数3.14 = %f\n", 3.14 * 3.14);
    printf("定数3.14 * 変数3.14 = %f\n", 3.14 * x);
    printf("変数3.14 * 定数3.14 = %f\n", x * 3.14);
    printf("変数3.14 * 変数3.14 = %f\n\n", x * x);

    printf("定数3.14 / 定数3.14 = %f\n", 3.14 / 3.14);
    printf("定数3.14 / 変数3.14 = %f\n", 3.14 / x);
    printf("変数3.14 / 定数3.14 = %f\n", x / 3.14);
    printf("変数3.14 / 変数3.14 = %f\n\n", x / x);

    printf("定数5 * 定数3.14 = %f\n", 5 * 3.14);
    printf("定数5 * 変数3.14 = %f\n", 5 * x);
    printf("変数5 * 定数3.14 = %f\n", n * 3.14);
    printf("変数5 * 変数3.14 = %f\n\n", n * x);

    printf("定数5 / 定数3.14 = %f\n", 5 / 3.14);
    printf("定数5 / 変数3.14 = %f\n", 5 / x);
    printf("変数5 / 定数3.14 = %f\n", n / 3.14);
    printf("変数5 / 変数3.14 = %f\n\n", n / x);

    printf("定数3.14 * 定数5 = %f\n", 3.14 * 5);
    printf("定数3.14 * 変数5 = %f\n", 3.14 * n);
    printf("変数3.14 * 定数5 = %f\n", x * 5);
    printf("変数3.14 * 変数5 = %f\n\n", x * n);

    printf("定数3.14 / 定数5 = %f\n", 3.14 / 5);
    printf("定数3.14 / 変数5 = %f\n", 3.14 / n);
    printf("変数3.14 / 定数5 = %f\n", x / 5);
    printf("変数3.14 / 変数5 = %f\n\n", x / n);

    return 0;
}

演習2-5

// 二つの整数値を読み込んで、前者の値が後者の何%であるかを実数で表示

#include <stdio.h>

int main(void)
{
    int a, b;

    puts("二つの整数を入力せよ。");
    printf("整数a:");  scanf("%d", &a);
    printf("整数b:");  scanf("%d", &b);

    printf("aの値はbの%f%%です。\n", (double)a * 100 / b);

    return 0;
}

演習2-6

// 身長を整数値として読み込んで標準体重を実数で表示

#include <stdio.h>

int main(void)
{
    int height;

    printf("身長を入力せよ:"); scanf("%d", &height);

    double weight = (height - 100) * 0.9;

    printf("標準体重は%.1fです。\n", weight);

    return 0;
}

第3章:プログラムの流れの分岐

演習3-1

// 二つの整数を読み込んで、後者が前者の約数であるか判定

#include <stdio.h>

int main(void)
{
    int a, b;

    puts("二つの整数を入力せよ。");
    printf("整数A:");  scanf("%d", &a);
    printf("整数B:");  scanf("%d", &b);

    if (a % b)
        puts("BはAの約数ではありません。");
    else
        puts("BはAの約数です。");
    
    return 0;
}

演習3-2

// 読み込んだ整数値の符号を判定、list3-9の最後のelseをelse ifにしてみた

#include <stdio.h>

int main(void)
{
    int no;
    
    printf("整数を入力せよ:");
    scanf("%d", &no);

    if (no == 0)
        puts("その数は0です。");
    else if (no > 0)
        puts("その数は正です。");
    else if (no < 0)
        puts("その数は負です。");
    
    return  0;
}

演習3-3

// 読み込んだ整数値の絶対値を表示

#include <stdio.h>

int main(void)
{
    int no;

    printf("整数を入力せよ:");
    scanf("%d", &no);

    if (no >= 0)
        printf("絶対値は%dです。\n", no);
    else
        printf("絶対値は%dです。\n", -no);
    
    return 0;
}

演習3-4

// 読み込んだ二つの整数の大小を判定

#include <stdio.h>

int main(void)
{
    int a, b;

    puts("二つの整数を入力せよ。");
    printf("整数A:");  scanf("%d", &a);
    printf("整数B:");  scanf("%d", &b);

    if (a == b)
        puts("AとBは等しいです。");
    else if (a > b)
        puts("AはBより大きいです");
    else
        puts("AはBより小さいです。");
    
    return 0;
}

演習3-5

// 等価演算子や関係演算子が、1あるいは0の値を生成することを確認する

#include <stdio.h>

int main(void)
{
    int a, b;

    puts("2つの整数を入力せよ。");
    printf("整数A:");  scanf("%d", &a);
    printf("整数B:");  scanf("%d", &b);

    printf("A == Bが生成した値は%dです。\n", a == b);
    printf("A != Bが生成した値は%dです。\n", a != b); 
    printf("A > Bが生成した値は%dです。\n", a > b);
    printf("A < Bが生成した値は%dです。\n", a < b);
    printf("A >= Bが生成した値は%dです。\n", a >= b);
    printf("A <= Bが生成した値は%dです。\n", a <= b);

    return 0;
}

演習3-6

// 読み込んだ三つの整数値の最小値を求めて表示

#include <stdio.h>

int main(void)
{
    int n1, n2, n3;

    puts("三つの整数を入力せよ。");
    printf("整数1:");  scanf("%d", &n1);
    printf("整数2:");  scanf("%d", &n2);
    printf("整数3:");  scanf("%d", &n3);

    int min = n1;
    if (n2 < min) min = n2;
    if (n3 < min) min = n3;

    printf("最小値は%dです。\n", min);

    return 0;
}

演習3-7

// 読み込んだ四つの整数値の最大値を求めて表示

#include <stdio.h>

int main(void)
{
    int n1, n2, n3, n4;

    puts("四つの整数を入力せよ。");
    printf("整数1:");  scanf("%d", &n1);
    printf("整数2:");  scanf("%d", &n2);
    printf("整数3:");  scanf("%d", &n3);
    printf("整数4:");  scanf("%d", &n4);

    int max = n1;
    if (n2 > max)   max = n2;
    if (n3 > max)   max = n3;
    if (n4 > max)   max = n4;

    printf("最大値は%dです。\n", max);
}

演習3-8

// 読み込んだ二つの整数値の差を求めて表示

#include <stdio.h>

int main(void)
{
    int n1, n2;

    puts("二つの整数を入力せよ。");
    printf("整数1:");  scanf("%d", &n1);
    printf("整数2:");  scanf("%d", &n2);

    if (n1 > n2)
        printf("それらの差は%dです。\n", n1 - n2);
    else
        printf("それらの差は%dです。\n", n2 - n1);
    
    return 0;
}

演習3-9

// 読み込んだ三つの整数値の最小値を求めて表示(条件演算子)

#include <stdio.h>

int main(void)
{
    int n1, n2, n3;

    puts("三つの整数を入力せよ。");
    printf("整数1:");  scanf("%d", &n1);
    printf("整数2:");  scanf("%d", &n2);
    printf("整数3:");  scanf("%d", &n3);

    int min = n1 < n2 ? n1 : n2;
    
    printf("最小値は%dです。\n", n3 < min ? n3 : min);

    return 0;
}

演習3-10

// 三つの整数を比較する

#include <stdio.h>

int main(void)
{
    int n1, n2, n3;

    puts("三つの整数を入力せよ。");
    printf("整数A:");  scanf("%d", &n1);
    printf("整数B:");  scanf("%d", &n2);
    printf("整数C:");  scanf("%d", &n3);

    if (n1 == n2 && n2 == n3) {
        puts("三つの値は等しいです。");
    } else if (n1 == n2 || n2 == n3 || n3 == n1) {
        puts("二つの値は等しいです。");
    } else {
        puts("三つの値は異なります。");
    }

    return 0;   
}

演習3-11

// 二つの整数の差が10以下であるか判別

#include <stdio.h>

int main(void)
{
    int a, b;

    puts("二つの整数を入力せよ。");
    printf("整数A:");  scanf("%d", &a);
    printf("整数B:");  scanf("%d", &b);

    if ((a - b) <= 10 || (b - a) <= 10) {
        puts("それらの差は10以下です。");
    } else {
        puts("それらの差は11以上です。");
    }

    return 0;
}

演習3-12

// 読み込んだ整数値は奇数であるか偶数であるか(switch文)

#include <stdio.h>

int main(void)
{
    int n;

    printf("整数を入力せよ:");
    scanf("%d", &n);

    switch (n % 2) {
        case 0 : puts("その数は偶数です。");    break;
        case 1 : puts("その数は奇数です。");    break;
    }
    
    return 0;
}

演習3-13

// 読み込んだ月の季節を表示

#include <stdio.h>

int main(void)
{
    int month;

    printf("何月ですか:");
    scanf("%d", &month);

    switch (month) {
    case 3  : 
    case 4  : 
    case 5  : printf("%d月は春です。\n", month);           break;
    case 6  : 
    case 7  : 
    case 8  : printf("%d月は夏です。\n", month);           break;
    case 9  : 
    case 10 : 
    case 11 : printf("%d月は秋です。\n", month);           break;
    case 1  :
    case 2  :  
    case 12 : printf("%d月は冬です。\n", month);           break;
    default : printf("%d月はありませんよ!\a\n", month);    break;
    }

    return 0;
}

第4章:プログラムの流れの繰返し

演習4-1

// 読み込んだ整数値の符号の判定を好きなだけ繰り返す

#include <stdio.h>

int main(void)
{
    int retry;

    do {
        int no;
        
        printf("整数を入力せよ。");
        scanf("%d", &no);

        if (no == 0){
            puts("その数は0です。");
        } else if (no > 0) {
            puts("その数は正です。");
        } else {
            puts("その数は負です。");
        }

        printf("もう一度?【Yes…0/No…9】:");
        scanf("%d", &retry);
    } while (retry == 0);

    return 0;
}

演習4-2

// 二つの整数の小さい方から大きい方までの総和を表示

#include <stdio.h>

int main(void)
{
    int a,b;

    puts("二つの整数を入力せよ。");
    printf("整数a:");  scanf("%d", &a);
    printf("整数b:");  scanf("%d", &b);

    int min, max;
    
    /*二つの整数の大小を比較して最小値と最大値を設定*/
    if (a < b) {
        min = a;    max = b;
    } else {
        min = b;    max = a;
    }

    int num = min, sum = min;

    do {
        num = num + 1;
        sum = sum + num;    // 総和の計算
    } while (num != max);   // numが最大値に達したらループ終わり

    printf("%d以上%d以下の全整数の和は%dです。", min, max, sum);

    return 0;
}

演習4-3

// 読み込んだ整数値を0までカウントダウン
// 負の値を読み込んだときに改行しない

# include <stdio.h>

int main(void)
{
    int no;

    printf("正の整数を入力せよ:");
    scanf("%d", &no);

    /*noが正のときのみループ*/
    while (no > 0) {
        printf("%d ", no);
        no--;   // noの値をデクリメント(1減らす)
    }

    /*noが0のときのみ0と改行出力、最初に負の値を読み込んだら改行しない*/
    if (no == 0) {
        printf("%d\n", no);
    }

    return 0;
}

演習4-4

// 読み込んだ整数値を1までカウントダウン
// 入力された値が0以下であるときは改行を行わない

#include <stdio.h>

int main(void)
{
    int no;

    printf("正の整数を入力せよ:");
    scanf("%d", &no);

    while (no > 0) {
        printf("%d ", no--);    // noの値を表示した後にデクリメント

        /*デクリメント後に0になったら改行*/
        if (no == 0) {
            printf("\n");
        }
    }

    return 0;
}

演習4-5

// 読み込んだ正の整数値まで1からカウントアップ
// 入力値が0以下であるときには改行を行わない

#include <stdio.h>

int main(void)
{
    int no;

    printf("正の整数を入力せよ:");
    scanf("%d", &no);

    int i = 1;
    while (i <= no) {
        printf("%d ", i++);     // iの値を表示した後にインクリメント
        if (i == no) {           // 読み込んだ整数値に達したら整数と改行
            printf("%d\n", i);
        }
    }

    return 0;
}

演習4-6

// 読み込んだ整数値以下の正の偶数を順に表示

#include <stdio.h>

int main(void)
{
    int no;

    printf("正の整数を入力せよ:");
    scanf("%d", &no);

    int i = 2;
    while (i <= no) {
        printf("%d ", i);
        i += 2;         // iに2を加える
    }

    if (no >= 2) {      //偶数を表示したときに改行
        printf("\n");
    }

    return 0;
}

演習4-7

// 読み込んだ正の整数値以下の2のべき乗の数を順に表示

#include <stdio.h>

int main(void)
{
    int no;

    printf("正の整数を入力せよ:");
    scanf("%d", &no);

    int i = 2;
    while (i <= no)
    {
        printf("%d ", i);
        i *= 2;         // iを2倍にする
    }

    if (no >= 2)        // 2のべき乗を表示したときに改行
    {
        printf("\n");
    }
    
    return 0;
}

演習4-8

// 読み込んだ整数の個数だけ*を連続表示
// 読み込んだ値が1未満であれば改行文字を出力しない

#include <stdio.h>

int main(void)
{
    int no;

    printf("正の整数:");
    scanf("%d", &no);

    while (no-- > 0)    // 0より大きいか判定してデクリメント
    {
        putchar('*');

        if (no == 0)    // noが0になったとき(最後のループ)にだけ改行
        {
            putchar('\n');
        }
    }
    
    return 0;
}

演習4-9

// 読み込んだ値の個数だけ+と-を交互に表示する

# include <stdio.h>

int main(void)
{
    int no;

    printf("正の整数:");   scanf("%d", &no);

    if (no > 0)
    {

        int cnt = 1;        // ループ回数カウント用の変数 

        while (no-- > 0)
        {
            if (cnt++ % 2 == 1)     // 偶奇判定後にインクリメント
            {
                putchar('+');       // 奇数回目のループでは+を出力
            } else {
                putchar('-');       // 偶数回目のループでは-を出力
            }
            
            if (no == 0)
            {
                putchar('\n');
            }
            
        }
        
    }
    
    return 0;
}

演習4-10

// 読み込んだ整数値の数だけ*を縦に表示

# include <stdio.h>

int main(void)
{
    int no;

    printf("正の整数:");   scanf("%d", &no);

    if (no > 0)
    {
        while (no-- > 0)        // noの値を評価した後にデクリメント
        {
            printf("*\n");
        }
        
    }
    
    return 0;
}

演習4-11

// 読み込んだ正の整数値を逆順に表示
// 読み込んだ値も表示

# include <stdio.h>

int main(void)
{
    int no;

    do {
        printf("正の整数を入力せよ:");
        scanf("%d", &no);

        if (no <= 0)
        {
            puts("\a正でない整数を入力しないでください。");
        }
    } while (no <= 0);
    
    printf("%dを逆から読むと", no);
    while (no > 0)
    {
        printf("%d", no % 10);  // 最下位の桁の値を表示
        no /= 10;               // 右に1桁ずらす
    }
    puts("です。");

    return 0;
}

演習4-12

// 読み込んだ正の整数値の桁数を表示

#include <stdio.h>

int main(void)
{
    int no;

    do
    {
        printf("正の整数を入力せよ:");
        scanf("%d", &no);
        if (no <= 0)
        {
            puts("\a正でない整数を入力しないでください。");
        }
    } while (no <= 0);
    
    // noは0より大きい
    printf("%dは", no);

    int cnt = 0;
    while (no > 0)
    {
        no /= 10;   // 桁を1つ減らす
        cnt += 1;   // ループ回数の記録
    }
    
    printf("%d桁です。\n", cnt);

    return 0;
}

演習4-13

// 1からnの総和を求める

#include <stdio.h>

int main(void)
{
    int num;
    
    printf("nの値:");  scanf("%d", &num);

    int sum = 0;
    for (int i = 1; i <= num; i++)
    {
        sum += i;
    }
    
    printf("1から%dまでの総和は%dです。\n", num, sum);

    return 0;
}

演習4-14

// 読み込まれた整数値の個数だけ0123456789を表示

#include <stdio.h>

int main(void)
{
    int num;

    printf("正の整数を入力せよ:"); scanf("%d", &num);

    for (int i = 1; i <= num; i++)
    {
        printf("%d", i % 10);
    }
    
    putchar('\n');

    return 0;
}

演習4-15

// 身長と標準体重の対応表

#include <stdio.h>

int main(void)
{
    int height1, height2, interval;

    printf("何cmから:");   scanf("%d", &height1);
    printf("何cmまで:");   scanf("%d", &height2);
    printf("何cmごと:");   scanf("%d", &interval);

    for (int i = height1; i <= height2; i += interval)
    {
        printf("%dcm   %.2fkg\n", i, (double)(i - 100) * 0.9) ;
    }
    
    return 0;
}

演習4-16

// 読み込んだ整数値以下の奇数を表示

#include <stdio.h>

int main(void)
{
    int n;

    printf("整数値:");
    scanf("%d", &n);

    for (int i = 1; i <= n; i += 2)
    {
        printf("%d ", i);
    }
    putchar('\n');

    return 0;    
}

演習4-17

// 1からnまでの整数値の2乗値を表示

#include <stdio.h>

int main(void)
{
    int n;

    printf("nの値:");
    scanf("%d", &n);

    for (int i = 1; i <= n; i++)
    {
        printf("%dの2乗は%d\n", i, i * i);
    }
    
    return 0;
}

演習4-18

// 読み込んだ整数値の数だけ*を表示
// 5個ごとに改行

#include <stdio.h>

int main(void)
{
    int no;

    printf("何個*を表示しますか:");
    scanf("%d", &no);

    for (int i = 1; i <= no; i++)
    {
        putchar('*');

        if (i % 5 == 0)
        {
            putchar('\n');
        }
    }

    if (no % 5 != 0)
    {
        putchar('\n');
    }

    return 0;
}

演習4-19

// 読み込んだ整数値の全約数と個数を表示

#include <stdio.h>

int main(void)
{
    int n;

    printf("整数値:");
    scanf("%d", &n);

    int j = 0;

    for (int i = 1; i <= n; i++)
    {
        if (n % i == 0)
        {
            printf("%d\n", i);
            j++;                // 約数が見つかったときにインクリメント
        }
        
    }
    
    printf("約数は%d個です。\n", j);

    return 0;
}

演習4-20

// 九九の表を表示

#include <stdio.h>

int main(void)
{
    puts("   |  1  2  3  4  5  6  7  8  9 ");
    puts("---+----------------------------");

    for (int i = 1; i <= 9 ; i++)
    {
        printf(" %d |", i);

        for (int j = 1; j <= 9; j++)
        {
            printf("%3d", i * j);
        }
        
        putchar('\n');
    }
    
    return 0;
}

演習4-21

// 正方形を表示

#include <stdio.h>

int main(void)
{
    int n;

    puts("正方形を作ります。");
    printf("何段ですか:");
    scanf("%d", &n);

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            printf("*");
        }
        putchar('\n');
    }
    
    return 0;
}

演習4-22

//横長の長方形を作る
// 二つの整数値を読み込んで小さい方を高さ/大きい方を幅にする

#include <stdio.h>

int main(void)
{
    int n1, n2;

    puts("横長の長方形を作ります。");
    printf("一辺(その1):");  scanf("%d", &n1);
    printf("一辺(その2):");  scanf("%d", &n2);

    int height, width;

    // 長い方を幅にする
    if (n1 < n2)
    {
        height = n1;    width = n2;
    } else
    {
        height = n2;    width = n1;
    }
    
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            putchar('*');
        }
        putchar('\n');
    }
    return 0;
}

演習4-23

// 左上が直角の直角二等辺三角形を表示

#include <stdio.h>

int main(void)
{
    int len;

    puts("左上直角二等辺三角形を表示します。");
    printf("短辺:");
    scanf("%d", &len);

    for (int i = len; i > 0; i--)
    {
        for (int j = 1; j <= i; j++)
        {
            putchar('*');
        }
        putchar('\n');
    }
    return 0;
}
// 右上が直角の直角二等辺三角形を表示

#include <stdio.h>

int main(void)
{
    int len;

    puts("右上直角二等辺三角形を表示します。");
    printf("短辺:");
    scanf("%d", &len);

    for (int i = len; i > 0; i--)
    {
         for (int j = 1; j <= len - i; j++)
        {
            putchar(' ');
        }
        for (int j = 1; j <= i; j++)
        {
            putchar('*');
        }
       
        putchar('\n');
    }
    return 0;
}

演習4-24

// ピラミッドを表示

#include <stdio.h>

int main(void)
{
    int n;

    puts("ピラミッドを作ります。");
    printf("何段ですか:");
    scanf("%d", &n);

    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n - i; j++)
        {
            putchar(' ');
        }
        for (int j = 1; j <= (i - 1) * 2 + 1; j++)
        {
            putchar('*');
        }
        putchar('\n');
    }
    return 0;
}

演習4-25

// 下向き数字ピラミッドを表示

#include <stdio.h>

int main(void)
{
    int n;

    puts("下向き数字ピラミッドを作ります。");
    printf("何段ですか:");
    scanf("%d", &n);

    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= i - 1; j++)
        {
            putchar(' ');
        }
        for (int j = 1; j <= (n - i) * 2 + 1; j++)
        {
            printf("%d", i % 10);
        }
        putchar('\n');
    }
    return 0;
}

第5章:配列

演習5-1

// 配列の各要素に戦闘から順に0~4を代入

#include <stdio.h>

int main(void)
{
    int a[5];   // int[5]型の配列

    for (int i = 0; i < 5; i++)
    {
        a[i] = i;
        printf("a[%d] = %d\n", i, a[i]);
    }
    return 0;
}

演習5-2

// 配列の各要素に戦闘から順に5~1を代入

#include <stdio.h>

int main(void)
{
    int a[5];

    for (int i = 0; i < 5; i++)
    {
        a[i] = 5 - i;
        printf("a[%d] = %d\n", i, a[i]);
    }
    return 0;
}

演習5-3

//配列の各要素を先頭から順に5~1で初期化して表示

#include <stdio.h>

int main(void)
{
    int a[5] = {5, 4, 3, 2, 1}; // 初期化

    for (int i = 0; i < 5; i++)
        printf("a[%d] = %d\n", i, a[i]);

    return 0;
}

演習5-4

// 配列の全要素の並びを反転する(オブジェクト形式マクロ)

#include <stdio.h>

#define NUMBER 7    // 要素数

int main(void)
{
    int x[NUMBER];

    for (int i = 0; i < NUMBER; i++)            // 要素に値を読み込む
    {
        printf("x[%d]:", i);
        scanf("%d", &x[i]);
    }
    
    for (int i = 0; i < NUMBER / 2; i++)    // 要素の並びを反転
    {
        int t             = x[i];
        x[i]              = x[NUMBER - 1 - i];
        x[NUMBER - 1 - i] = t;
    }
    
    puts("反転しました。");
    for (int i = 0; i < NUMBER; i++)            // 要素の値を表示
    {
        printf("x[%d] = %d\n", i, x[i]);
    }
    
    return 0;
}

演習5-5

// aがdouble型でbがint型のときa = b = 1.5はどうなるか
// まずb = 1.5から評価されるが、bはint型のためb = 1となる
// つづいてa = b、つまりa = 1が評価されるが、aはdouble型のためa = 1.000000となる

#include <stdio.h>

int main(void)
{
    double a;
    int    b;

    a = b = 1.5;    // コンパイル時にエラーが出る

    printf("a = %f\n", a);
    printf("b = %d\n", b);

    return 0;
}

演習5-6

// データ数と値を読み込んでその値を表示

#include <stdio.h>

#define NUMBER 120      // データ数の上限

int main(void)
{
    int num;            // 実際のデータ数
    int data[NUMBER];   // 読み込むデータ

    printf("データ数:");

    do
    {
        scanf("%d", &num);
        if (num < 1 || num > NUMBER)
        {
            printf("\a1〜%dで入力せよ:", NUMBER);
        }
    } while (num < 1 || num > NUMBER);
    
    for (int i = 0; i < num; i++)
    {
        printf("%3d番:", i + 1);
        scanf("%d", &data[i]);
    }
    
    printf("{%d", data[0]);

    for (int i = 1; i < num; i++)
    {
        printf(", %d", data[i]);
    }
    
    printf("}\n");

    return 0;
}

演習5-7

// 学生の点数を読み込んで分布を表示

#include <stdio.h>

#define NUMBER 120  // 人数の上限

int main(void)
{
    int num;
    int tensu[NUMBER];
    int bunpu[11] = {0};

    printf("人数を入力せよ:");

    do
    {
        scanf("%d", &num);
        if (num < 1 || num > NUMBER)
        {
            printf("\a1〜%dで入力せよ:", NUMBER);
        }
    } while (num < 1 || num > NUMBER);
    
    printf("%d人の点数を入力せよ。\n", num);

    for (int i = 0; i < num; i++)
    {
        printf("%3d番:", i + 1);
        do
        {
            scanf("%d", &tensu[i]);
            if (tensu[i] < 0 || tensu[i] > 100)
            {
                printf("\a1〜100で入力せよ:");
            }
        } while (tensu[i] < 0 || tensu[i] > 100);
        bunpu[tensu[i] / 10]++;
    }
    
    puts("\n---分布グラフ---");
    for (int i = 0; i <= 9; i++)
    {
        printf("%3d  〜%3d:", i * 10, i * 10 + 9);
        for (int j = 0; j < bunpu[i]; j++)
        {
            putchar('*');
        }
        putchar('\n');
    }

    printf("     100:");

    for (int j = 0; j < bunpu[10]; j++)
    {
        putchar('*');
    }
    putchar('\n');

    return 0;
}

演習5-8

//学生の点数を読み込んで分布を縦に表示

#include <stdio.h>

#define NUMBER 120

int main(void)
{
    int num;                // 実際の人数
    int tensu[NUMBER];      // 学生の点数
    int bunpu[11] = {0};    // 点数の分布

    printf("人数を入力せよ:");

    /* 読み込む値を1〜NUMBERに制限 */
    do
    {
        scanf("%d", &num);
        if (num < 1 || num > NUMBER)
        {
            printf("\a1〜%dで入力せよ:", NUMBER);
        }
    } while (num < 1 || num > NUMBER);
    
    printf("%d人の点数を入力せよ。\n", num);

    for (int i = 0; i < num; i++)
    {
        printf("%3d番:", i + 1);
        /* 読み込む値を1〜100に制限 */
        do
        {
            scanf("%d", &tensu[i]);
            if (tensu[i] < 0 || tensu[i] > 100)
            {
                printf("\a0〜100で入力せよ:");
            }
        } while (tensu[i] < 0 || tensu[i] > 100);
        bunpu[tensu[i] / 10]++;
    }

    puts("\n-----分布グラフ-----");

    int height = 0;             // 分布グラフの高さ

    /* 分布グラフの高さ決定 */
    for (int i = 0; i < 11; i++)
    {
        if (height < bunpu[i])
        {
            height = bunpu[i];
        }
    }
    
    /* 分布グラフの描画 */
    for (int i = height; i > 0; i--)
    {
        for (int j = 0; j < 11; j++)
        {
            if (bunpu[j] == i)
            {
                printf(" * ");
                bunpu[j]--;
            }
            else
            {
                printf("   ");
            }
        }
        putchar('\n');
    }
    for (int i = 0; i < 11; i++)
    {
        printf("---");
    }
    puts("-");
    for (int i = 0; i < 10; i++)
    {
        printf("%2d ", i * 10);
    }
    printf("100\n");
    
    return 0;
}

演習5-9

// 配列の全要素を別の配列に逆順にコピー

#include <stdio.h>

int main(void)
{
    int a[5];
    int b[5];

    for (int i = 0; i < 5; i++)
    {
        printf("a[%d]:", i);
        scanf("%d", &a[i]);
    }
    
    for (int i = 0; i < 5; i++)
    {
        b[i] = a[4 - i] ;
    }
    
    puts("  a    b");
    puts("---------");
    for (int i = 0; i < 5; i++)
    {
        printf("%4d%4d\n", a[i], b[i]);
    }
    
    return 0;
}

演習5-10

// 4行3列の行列と3行4列の積を求める

#include <stdio.h>

int main(void)
{
    int queue1[4][3];
    int queue2[3][4];
    int seki[4][4];

    // 4行3列の行列の読込み
    printf("行列1(4行3列)\n");
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            printf("%d行目・%d列目の値:", i + 1, j + 1);
            scanf("%d", &queue1[i][j]);
        }
        putchar('\n');
    }
    putchar('\n');

    // 3行4列の行列の読込み
    printf("行列2(3行4列)\n");
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            printf("%d行目・%d列目の値:", i + 1, j + 1);
            scanf("%d", &queue2[i][j]);
        }
        putchar('\n');
    }
    putchar('\n');

    // 積の計算
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            seki[i][j] = 0;
            for (int k = 0; k < 3; k++)
            {
                seki[i][j] += queue1[i][k] * queue2[k][j];
            }
        }
    }
    
    // 計算結果の表示
    puts("行列1と行列2の積");
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            printf("%4d", seki[i][j]);
        }
        putchar('\n');
    }
    
    return 0;
}

演習5-11

// 6人の2科目の点数の、科目ごとの合計点と平均点、学生ごとの合計点と平均点を求める

#include <stdio.h>

int main(void)
{
    int tensu[6][2];

    /* 点数の読み込み */
    for (int i = 0; i < 6; i++)
    {
        for (int j = 0; j < 2; j++)
        {
            if (j == 0)
            {
                printf("学生%dの国語の点数:", i + 1);
                scanf("%d", &tensu[i][j]);
            }
            else
            {
                printf("学生%dの数学の点数;", i + 1);
                scanf("%d", &tensu[i][j]);
            }
        }
        putchar('\n');
    }
    
    /* 科目ごとの合計点と平均点 */
    int kokugosum = 0;
    int sugakusum = 0;

    for (int i = 0; i < 6; i++)
    {
        kokugosum += tensu[i][0];
        sugakusum += tensu[i][1];
    }
    
    printf("国語の合計点は%d点、平均点は%.1f点です。\n", kokugosum, kokugosum / 6.0);
    printf("数学の合計点は%d点、平均点は%.1f点です。\n", sugakusum, sugakusum / 6.0);
    putchar('\n');

    /* 学生ごとの合計点と平均点 */
    for (int i = 0; i < 6; i++)
    {
        int sum = tensu[i][0] + tensu[i][1];
        printf("学生%dの合計点は%d点、平均点は%.1f点です。\n", i + 1, sum, sum / 2.0);
    }
    
    return 0;
}

演習5-12

// 4人の学生の3科目のテスト2回分の点数を3次元配列に格納、合計を求めて表示

#include <stdio.h>

int main(void)
{
    int tensu[2][4][3] =   {{{91, 63, 78}, {67, 72, 46}, {89, 34, 53}, {32, 54, 34}},
                            {{97, 67, 82}, {73, 43, 46}, {97, 56, 21}, {85, 46, 35}}};
    int sum[4][3];
    
    // 2回分の点数の合計を求める
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            sum[i][j] = tensu[0][i][j] + tensu[1][i][j];
        }
    }
    
    // 点数を表示
    for (int i = 0; i < 2; i++)
    {
        printf("%d回目の点数\n", i + 1);
        for (int j = 0; j < 4; j++)
        {
            for (int k = 0; k < 3; k++)
            {
                printf("%4d", tensu[i][j][k]);
            }
            putchar('\n');
        }
    }
    
    // 合計点を表示
    puts("合計点");
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            printf("%4d", sum[i][j]);
        }
        putchar('\n');
    }

    return 0;
}

第6章:関数

演習6-1

// 二つの整数の小さいほうの値を求める

#include <stdio.h>

/*--- 小さい方の値を返す ---*/
int min2(int a, int b)
{
    return a < b ? a : b;
}

int main(void)
{
    int n1, n2;

    puts("二つの整数を入力せよ。");
    printf("整数1:");  scanf("%d", &n1);
    printf("整数2:");  scanf("%d", &n2);

    printf("小さい方の値は%dです。\n", min2(n1,n2));

    return 0;
}

演習6-2

// 三つの整数の最小値を求める

#include <stdio.h>

/*--- 三つの整数の最小値を返す ---*/
int min3(int a, int b, int c)
{
    int min = a < b ? a : b;
    min = min < c ? min : c;
    
    return min;
}

int main(void)
{
    int a, b, c;

    puts("三つの整数を入力せよ。");
    printf("整数a:");  scanf("%d", &a);
    printf("整数b:");  scanf("%d", &b);
    printf("整数c:");  scanf("%d", &c);

    printf("最小値は%dです。\n", min3(a, b, c));

    return 0;
}

演習6-3

// 整数の3乗値を求める

#include <stdio.h>

/*--- xの3乗値を返す ---*/
int cube(int x)
{
    return x * x * x;
}

int main(void)
{
    int n;

    printf("整数n:");
    scanf("%d", &n);

    printf("nの3乗は%dです。\n", cube(n));

    return 0;
}

演習6-4

// 整数の4乗値を求める

#include <stdio.h>

/*--- nの2乗値を返す ---*/
int sqr(int n)
{
    return n * n;
}

/*--- xの4乗値を返す ---*/
int pow4(int x)
{
    return sqr(x) * sqr(x);
}

int main(void)
{
    int n;

    printf("整数n:");
    scanf("%d", &n);

    printf("nの4乗は%dです。\n", pow4(n));

    return 0;
}

演習6-5

// 1からnまでの全整数の和を求める

#include <stdio.h>

/*--- 1からnまでの全整数の和を返す ---*/
int sumup(int n)
{
    int sum = 0;
    for (int i = 1; i <= n; i++)
    {
        sum += i;
    }
    
    return sum;
}

int main(void)
{
    int n;

    puts("1からnまでの全整数の和を求めます。");
    printf("整数n:");  scanf("%d", &n);

    printf("1から%dまでの全整数の和は%dです。\n", n, sumup(n));

    return 0;
}

演習6-6

// 警報をn回連続して発する

#include <stdio.h>

/*--- 警報をn回連続して発する関数 ---*/
void alert(int n)
{
    while (n-- > 0)
    {
        putchar('\a');
    }
}

int main(void)
{
    int n;

    printf("警報を発する回数:");
    scanf("%d", &n);
    alert(n);

    return 0;
}

演習6-7

// 画面に『こんにちは。』と表示する

#include <stdio.h>

/* 『こんにちは。』と表示する関数 */
void hello(void)
{
    printf("こんにちは。\n");
}

int main(void)
{
    hello();
    return 0;
}

演習6-8

// 配列の要素の最小値を求める

#include <stdio.h>

/* 配列vの要素の最小値を返す */
int min_of(const int v[], int n)
{
    int min = v[0];

    for (int i = 0; i < n; i++)
        min = v[i] < min ? v[i] : min;
    
    return min;
}

int main(void)
{
    /* 要素数の設定 */
    int n;
    printf("要素数:"); scanf("%d", &n);

    int v[n];  // 要素数nの配列

    printf("%d個の整数を入力せよ。\n", n);
    for (int i = 0; i < n; i++)
    {
        printf("整数%d:", i + 1);
        scanf("%d", &v[i]);
    }
    
    printf("これらの最小値は%dです。", min_of(v, n));

    return 0;
}

演習6-9

// 配列の全要素の並びを反転する

#include <stdio.h>

/* 配列の要素の並びを反転する */
void rev_intary(int v[], int n)
{
    for (int i = 0; i < n / 2; i++)
    {
        int t = v[i];
        v[i] = v[n - i - 1];
        v[n - i - 1] = t;
    }
}

int main(void)
{
    /* 要素数の設定 */
    int n;
    printf("要素数:"); scanf("%d", &n);

    int v[n];  // 要素数nの配列

    printf("%d個の整数を入力せよ。\n", n);
    for (int i = 0; i < n; i++)
    {
        printf("x[%d]:", i);
        scanf("%d", &v[i]);
    }

    rev_intary(v,n);
    puts("反転しました。");
    for (int i = 0; i < n; i++)
        printf("x[%d] = %d\n", i, v[i]);
    
    return 0;
}

演習6-10

// 配列の並びを反転する

#include <stdio.h>

/* 要素数がnであるintの配列v2の並びを反転したものを配列v1に格納 */
void intary_rcpy(int v1[], const int v2[], int n)
{
    for (int i = 0; i < n; i++)
        v1[i] = v2[n - i - 1];    
}

int main(void)
{
    int n;
    printf("要素数:"); scanf("%d", &n);    // 要素数の設定

    int v1[n], v2[n];

    for (int i = 0; i < n; i++)
    {
        printf("要素%d:", i + 1);
        scanf("%d", &v2[i]);
    }
    
    intary_rcpy(v1, v2, n);
    puts("反転しました。");
    for (int i = 0; i < n; i++)
        printf("要素%d:%d\n", i + 1, v1[i]);
    
    return 0;
}

演習6-11

// 配列から指定した整数と等しい全要素の添字を抽出する

#include <stdio.h>

/*  要素数nの配列v内のkeyと等しい全要素の添字を配列idxに格納
    keyと等しい要素の個数を返す */
int search_idx(const int v[], int idx[], int key, int n)
{
    int k = 0;

    for (int i = 0; i < n; i++)
    {
        if (v[i] == key)
        {
            idx[k] = i;
            k++;
        }
    }
    
    return k;
}

int main(void)
{
    int n;
    printf("要素数:");
    scanf("%d", &n);

    int v[n];
    int idx[n];

    puts("配列の要素の設定");
    for (int i = 0; i < n; i++)
    {
        printf("配列[%d]:", i);
        scanf("%d", &v[i]);
    }
    
    int key;
    printf("探索する数:");
    scanf("%d", &key);

    int m = search_idx(v, idx, key, n);

    printf("探索する数と等しい要素の添字:");
    for (int i = 0; i < m; i++)
    {
        printf("%d", idx[i]);
        if (i == m - 1)
        {
            putchar('\n');
            break;
        }
        printf(", ");
    }
    
    return 0;
}

演習6-12

// 4行3列の行列と3行4列の積を求める

#include <stdio.h>

/* 4行3列の行列aと3行4列の行列bの積を
   4行4列の行列cに格納 */
void mat_mul(const int a[4][3], const int b[3][4], int c[4][4])
{
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            c[i][j] = 0;
            for (int k = 0; k < 3; k++)
                c[i][j] += a[i][k] * b[k][j];
        }
        
    }
    
}

int main(void)
{
    int queue1[4][3];
    int queue2[3][4];
    int seki[4][4];

    // 4行3列の行列の読込み
    printf("行列1(4行3列)\n");
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            printf("%d行目・%d列目の値:", i + 1, j + 1);
            scanf("%d", &queue1[i][j]);
        }
        putchar('\n');
    }
    putchar('\n');

    // 3行4列の行列の読込み
    printf("行列2(3行4列)\n");
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            printf("%d行目・%d列目の値:", i + 1, j + 1);
            scanf("%d", &queue2[i][j]);
        }
        putchar('\n');
    }
    putchar('\n');

    // 積の計算
    mat_mul(queue1, queue2, seki);
    
    // 計算結果の表示
    puts("行列1と行列2の積");
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            printf("%4d", seki[i][j]);
        }
        putchar('\n');
    }
    
    return 0;
}

演習6-13

// 4人の学生の3科目のテスト2回分の合計を求めて表示

#include <stdio.h>

/* 2次元配列を3次元配列にする */
void mat_con(int a[2][4][3], const int b[4][3], const int c[4][3])
{
    for (int i = 0; i < 4; i++)
        for (int j = 0; j < 3; j++)
        {
            a[0][i][j] = b[i][j];
            a[1][i][j] = c[i][j];
        }
}

/* 3次元配列から中の2つの4行3列の和をcに格納する */
void mat_add(const int a[2][4][3], int c[4][3])
{
    for (int i = 0; i < 4; i++)
        for (int j = 0; j < 3; j++)
            c[i][j] = a[0][i][j] + a[1][i][j];
}

/* 4行3列の行列mを表示 */
void mat_print(const int m[4][3])
{
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 3; j++)
            printf("%4d", m[i][j]);
        putchar('\n');
    }   
}

int main(void)
{
    int tensu1[4][3] = { {91, 63, 78}, {67, 72, 46}, {89, 34, 53}, {32, 54, 34} };
    int tensu2[4][3] = { {97, 67, 82}, {73, 43, 46}, {97, 56, 21}, {85, 46, 35} };
    int tensu[2][4][3];
    int sum[4][3];

    mat_con(tensu, tensu1, tensu2);
    mat_add(tensu, sum);

    puts("1回目の点数");    mat_print(tensu1);
    puts("2回目の点数");    mat_print(tensu2);
    puts("合計点");        mat_print(sum);

    return 0;
}

演習6-14

// 静的記憶域期間が与えられたdouble型配列の暗黙の初期化を確認

#include <stdio.h>

int main(void)
{
    static double sa[5];

    for (int i = 0; i < 5; i++)
        printf("sa[%d] = %f\n", i, sa[i]);

    return 0;
}

演習6-15

// 関数が呼び出された回数を表示する

#include <stdio.h>

/* 呼び出された回数を表示する */
void put_count()
{
    static int count = 1;
    printf("put_count:%d回目\n", count++);
}

int main(void)
{
    for (int i = 0; i < 5; i++)
        put_count();
    
    return 0;
}

第7章:基本型

演習7-1

// 式の大きさを表示

# include <stdio.h>

int main(void)
{
    int n;

    printf("sizeof 1           = %zu\n", sizeof 1);             // 1という式の大きさを示す、int
    printf("sizeof(unsigned)-1 = %zu\n", sizeof(unsigned)-1);   // (sizeof(unsigned)) - 1
    printf("sizeof n+2         = %zu\n", sizeof n+2);           // (sizeof(n)) + 2
    printf("sizeof+1           = %zu\n", sizeof+1);             // +1という式の大きさを示す、int
    printf("sizeof(double)-1   = %zu\n", sizeof(double)-1);     // (sizeof(double)) - 1
    printf("sizeof(n+2)        = %zu\n", sizeof(n+2));          // int + intでint
    printf("sizeof-1           = %zu\n", sizeof-1);             // -1という式の大きさを示す、int
    printf("sizeof((double)-1) = %zu\n", sizeof((double)-1));   // double - intでdouble
    printf("sizeof(n+2.0)      = %zu\n", sizeof(n+2.0));        // int + doubleでdouble

    return 0;
}

演習7-2

//符号無し整数を左右にシフトした値が2のべき乗での乗算や除算の演算結果と一致することを確認

#include <stdio.h>

/* 整数x中のセットされたビット数を返す */
int count_bits(unsigned x)
{
    int bits = 0;
    while (x)
    {
        if (x & 1U) bits++;
        x >>= 1;
    }
    return bits;
}

/* unsigned型のビット数を返す */
int int_bits(void)
{
    return count_bits(~0U);
}

/* unsigned型のビット内容を表示 */
void print_bits(unsigned x)
{
    for (int i = int_bits() - 1; i >= 0; i--)
        putchar(((x >> i) & 1U) ? '1' : '0');
}

/* unsigned型の2のn乗を返す */
unsigned power(unsigned n)
{
    unsigned pw = 1;
    while (n--)
        pw *= 2;
    return pw;
}

int main(void)
{
    unsigned x, n;

    printf("非負の整数:");        scanf("%u", &x);
    printf("シフトするビット数:"); scanf("%u", &n);

    putchar('\n');
    printf("整数       = ");  print_bits(x);              putchar('\n');
    printf("左シフト     = ");  print_bits(x << n);         putchar('\n');
    printf("2のべき乗で乗算 = ");  print_bits(x * power(n));   putchar('\n');
    printf("右シフト     = ");  print_bits(x >> n);         putchar('\n');
    printf("2のべき乗で除算 = ");  print_bits(x / power(n));   putchar('\n');

    return 0;
}

演習7-3

// 符号無し整数xの全ビットを回転した値を求める

#include <stdio.h>

/* 整数x中のセットされたビット数を返す */
int count_bits(unsigned x)
{
    int bits = 0;
    while (x)
    {
        if (x & 1U) bits++;
        x >>= 1;
    }
    return bits;
}

/* unsigned型のビット数を返す */
int int_bits(void)
{
    return count_bits(~0U);
}

/* unsigned型のビット内容を表示 */
void print_bits(unsigned x)
{
    for (int i = int_bits() - 1; i >= 0; i--)
        putchar(((x >> i) & 1U) ? '1' : '0');
}

/* 符号無し整数xの全ビットを右にnビット回転した値を返す */
unsigned rrotate(unsigned x, int n)
{
    int i = int_bits();
    return ((x >> n) | (x << (i - n)));
}

/* 符号無し整数xの全ビットを左にnビット回転した値を返す */
unsigned lrotate(unsigned x, int n)
{
    int i = int_bits();
    return ((x << n) | (x >> (i - n)));
}

int main(void)
{
    unsigned x, n;

    printf("非負の整数:");        scanf("%u", &x);
    printf("回転するビット数:");   scanf("%u", &n);

    putchar('\n');
    printf("整数 :"); print_bits(x);              putchar('\n');
    printf("右回転;"); print_bits(rrotate(x, n));  putchar('\n');
    printf("左回転:"); print_bits(lrotate(x, n));  putchar('\n');

    return 0;
}

演習7-4

// 第posビットのセット/リセット/反転

#include <stdio.h>

/* 整数x中のセットされたビット数を返す */
int count_bits(unsigned x)
{
    int bits = 0;
    while (x)
    {
        if (x & 1U) bits++;
        x >>= 1;
    }
    return bits;
}

/* unsigned型のビット数を返す */
int int_bits(void)
{
    return count_bits(~0U);
}

/* unsigned型のビット内容を表示 */
void print_bits(unsigned x)
{
    for (int i = int_bits() - 1; i >= 0; i--)
        putchar(((x >> i) & 1U) ? '1' : '0');
}

/* 整数xの第posビットをセットした値を返す */
unsigned set(unsigned x, int pos)
{
    return (x | (1U << pos));
}

/* 整数xの第posビットをリセットした値を返す */
unsigned reset(unsigned x, int pos)
{
    return (x & ~(1U << pos));
}

/* 整数xの第posビットを反転した値を返す */
unsigned inverse(unsigned x, int pos)
{
    return (x ^ (1U << pos));
}

int main(void)
{
    unsigned x, n;

    printf("非負の整数:");        scanf("%u", &x);
    printf("論理演算するビット:"); scanf("%u", &n);

    putchar('\n');
    printf("もとの値 = ");  print_bits(x);              putchar('\n');
    printf("セット  = ");  print_bits(set(x, n));      putchar('\n');
    printf("リセット = ");  print_bits(reset(x, n));    putchar('\n');
    printf("反転   = ");  print_bits(inverse(x, n));  putchar('\n');

    return 0;
}

演習7-5

// 第posビットから第pos + n - 1ビットまでセット/リセット/反転

#include <stdio.h>

/* 整数x中のセットされたビット数を返す */
int count_bits(unsigned x)
{
    int bits = 0;
    while (x)
    {
        if (x & 1U) bits++;
        x >>= 1;
    }
    return bits;
}

/* unsigned型のビット数を返す */
int int_bits(void)
{
    return count_bits(~0U);
}

/* unsigned型のビット内容を表示 */
void print_bits(unsigned x)
{
    for (int i = int_bits() - 1; i >= 0; i--)
        putchar(((x >> i) & 1U) ? '1' : '0');
}

/* 整数xの第posビットから第pos + n - 1までをセットした値を返す */
unsigned set_n(unsigned x, int pos, int n)
{
    for (int i = pos; i < (pos + n); i++)
        x = (x | (1U << i));
    
    return x;
}

/* 整数xの第posビットから第pos + n - 1までをリセットした値を返す */
unsigned reset_n(unsigned x, int pos, int n)
{
    for (int i = pos; i < (pos + n); i++)
        x = (x & ~(1U << i));
    
    return x;
}

/* 整数xの第posビットから第pos + n - 1までを反転した値を返す */
unsigned inverse_n(unsigned x, int pos, int n)
{
    for (int i = pos; i < (pos + n); i++)
        x = (x ^ (1U << i));
    
    return x;
}

int main(void)
{
    unsigned x, pos, n;

    printf("非負の整数:");         scanf("%u", &x);
    printf("論理演算するビット:");  scanf("%u", &pos);
    printf("論理演算する数:");     scanf("%u", &n);

    putchar('\n');
    printf("もとの値 = ");  print_bits(x);                  putchar('\n');
    printf("セット  = ");  print_bits(set_n(x, pos, n));     putchar('\n');
    printf("リセット = ");  print_bits(reset_n(x, pos, n));   putchar('\n');
    printf("反転   = ");  print_bits(inverse_n(x, pos, n)); putchar('\n');

    return 0;
}

演習7-6

// 符号無し整数に対する算術演算ではオーバーフローが発生しないことを確認

#include <stdio.h>
#include <limits.h>

int main(void)
{
    unsigned x;

    printf("本環境での符号無し整数型の値の範囲:");
    printf("%u〜%u\n", 0U, UINT_MAX);

    x = UINT_MAX;

    printf("x            = %u\n", x);
    printf("x + 4782     = %u\n", x + 4782);
    printf("(x + 2) × 31 = %u\n", (x + 2) * 31);

    return 0;
}

演習7-7

// 3種の浮動小数点型の変数にキーボードから数値を読み込んで表示

#include <stdio.h>

int main(void)
{
    puts("少数を入力してください。");

    float a;
    double b;
    long double c;

    printf("float型      :");  scanf("%f", &a);
    printf("double型     :");  scanf("%lf", &b);
    printf("long double型:");  scanf("%Lf", &c);

    printf("float型の値      :%f\n", a);
    printf("double型の値     :%f\n", b);
    printf("long double型の値:%Lf\n", c);

    return 0;
}

演習7-8

// 3種類の浮動小数点型の大きさを表示

#include <stdio.h>

int main(void)
{
    printf("sizeof(float)      = %zu\n", sizeof(float));
    printf("sizeof(double)     = %zu\n", sizeof(double));
    printf("sizeof(long double = %zu\n)", sizeof(long double));

    return 0;
}

演習7-9

// 読み込んだ面積をもつ正方形の一辺の長さを求める

#include <stdio.h>
#include <math.h>

int main(void)
{
    double x;

    printf("読み込んだ面積をもつ正方形の一辺の長さを求めます。\n");
    printf("面積(実数値):"); scanf("%lf", &x);

    printf("一辺の長さは%fです。\n", sqrt(x));

    return 0;
}

演習7-10

// 0.0から1.0まで0.01単位で2種類の方法で繰り返す

#include <stdio.h>

int main(void)
{
    float x_float = 0.0;
    float x_int;

    for (int i = 0; i <= 100; i++)
    {
        x_int = i / 100.0;
        printf("x = %f   x = %f\n", x_float, x_int);
        x_float += 0.01;
    }
    
    return 0;
}

演習7-11

// 0.0から1.0まで0.01ずつ増やした値すべての累計を求める

#include <stdio.h>

int main(void)
{
    float sum_float, sum_int;

    for (float x = 0.0; x <= 1.0; x += 0.01)
        sum_float += x;
    
    for (int i = 0; i <= 100; i++)
    {
        float x;
        x = i / 100.0;
        sum_int += x;
    }
    
    printf("float型の変数を0.0から1.0まで0.01ずつ増やした値の累計        :%f\n", sum_float);
    printf("int型の変数を0から100までインクリメントした値を100.0で割った値の累計:%f\n", sum_int);

    /*  理論的には50.500000になるはずだが、いずれの結果でも誤差がある。
        ただし、誤差はint型累計の方が小さい。
        float型累計には5050個分の誤差が累積している一方で、
        int型累計には誤差の累積は100個分であるためだと考えられる。 */

    return 0;
}

第8章:いろいろなプログラムを作ってみよう

演習8-1

// 二つの値xとyの差を求める

#include <stdio.h>

#define diff(x, y)  ((x) > (y) ? (x) - (y) : (y )- (x)) // 二つの値xとyの差を求める関数形式マクロ

int main(void)
{
    int x, y;

    printf("整数x:");  scanf("%d", &x);
    printf("整数y:");  scanf("%d", &y);

    printf("これらの差は%dです。\n", diff(x, y));

    return 0;
}

演習8-2

/*  
    #define max(x, y)   (((x) > (y)) ? (x) : (y))
    と定義されているとき、
        max(max(a, b), max(c, d))
    は、
        ((a > b ? a : b) > (c > d ? c : d)) ? (a > b ? a : b) : (c > d ? c : d)
    と展開される。
    また、
        max(max(max(a, b), c), d)
    は、
        ((a > b ? a : b) > c ? (a > b ? a : b) : c) > d ? (a > b ? a : b) > c ? (a > b ? a : b) : c) : d
    と展開される。
    前者と後者を比較すると、二つの値の大小比較を行う回数が前者の方が少ない。
    そのため、前者の方が処理にかかる時間が短いと考えられる。
*/

演習8-3

// 二つの値を交換する

#include <stdio.h>

#define swap(type, a,  b)   do{type t = a; a = b; b = t;} while (0) // type型の二つの値を交換する関数形式マクロ

int main(void)
{
    int x, y;

    printf("整数x:");  scanf("%d", &x);
    printf("整数y:");  scanf("%d", &y);

    puts("xとyを交換します。");
    swap(int, x, y);

    printf("整数x:%d\n", x);
    printf("整数y:%d\n", y);

    return 0;
}

演習8-4

// 学生の身長を読み込んでソート

#include <stdio.h>

#define NUMBER 5    // 人数

/* 先頭から走査するバブルソート */
void bsort(int a[], int n)
{
    for (int i = n - 1; i > 0; i--)
    {
        for (int j = 0; j < i; j++)
        {
            if (a[j] > a[j + 1])
            {
                int temp = a[j];
                a[j] = a[j + 1];
                a[j + 1] = temp;
            }
        }
    }
}

int main(void)
{
    int height[NUMBER];     // NUMBER人の学生の身長

    printf("%d人の身長を入力せよ。\n", NUMBER);
    for (int i = 0; i < NUMBER; i++)
    {
        printf("%2d番:", i + 1);
        scanf("%d", &height[i]);
    }
    
    bsort(height, NUMBER);  // ソート

    puts("昇順にソートしました。");
    for (int i = 0; i < NUMBER; i++)
        printf("%2d番:%d\n", i + 1, height[i]);

    return 0;
}

演習8-5

// 季節に応じた枕草子を1文表示

#include <stdio.h>

enum season { Spring, Summer, Fall, Winter, Invalid };

/* 春 */
void spring(void)
{
    puts("春は、あけぼの。");
}

/* 夏 */
void summer(void)
{
    puts("夏は、夜。");
}

/* 秋 */
void fall(void)
{
    puts("秋は、夕暮。");
}

/* 冬 */
void winter(void)
{
    puts("冬は、つとめて。");
}

/* 季節を選ぶ */
enum season select(void)
{
    int tmp;

    do
    {
        printf("0…春 1…夏 2…秋 3…冬 4…終了:");
        scanf("%d", &tmp);
    } while (tmp < Spring || tmp > Invalid);
    return tmp;
}

int main(void)
{
    enum season selected;

    do
    {
        switch (selected = select())
        {
        case Spring : spring(); break;
        case Summer : summer(); break;
        case Fall   : fall();   break;
        case Winter : winter(); break;
        default     :           break;
        }
    } while (selected != Invalid);

    return 0;
}

演習8-6

// 階乗を再帰呼出しを用いずに求める

#include <stdio.h>

/* 整数値nの階乗値を返却 */
int fanctional(int n)
{
    int func = 1;

    for (int i = n; i > 0; i--)
    {
        func = func * i;    
    }
    
    return func;
}

int main(void)
{
    int num;

    printf("整数を入力せよ:");
    scanf("%d", &num);

    printf("%dの階乗は%dです。\n", num, fanctional(num));

    return 0;
}

演習8-7

// 組合せの数を再帰的に求める

#include <stdio.h>

/* 異なるn個の整数からr個の整数を取り出す組合せの数を返す */
int combination(int n, int r)
{
    if (n == r || r == 0)
        return 1;
    else if (r == 1)
        return n;
    else
        return combination(n - 1, r - 1) + combination(n - 1, r);
}

int main(void)
{
    int n, r;

    puts("異なるn個の整数からr個の整数を取り出す組合せの数を求めます。");

    printf("整数n:");  scanf("%d", &n);
    printf("整数r:");  scanf("%d", &r);

    printf("異なる%d個の整数から%d個の整数を取り出す組合せの数は%dです。\n", n, r, combination(n, r));

    return 0;
}

演習8-8

// ユークリッドの互除法で二つの整数値の最大公約数を求める

#include <stdio.h>

/*  ユークリッドの互除法で最大公約数を返す
    *** x > yとなるようにすること*** */
int gcd(int x, int y)
{
    int temp = y;
    y = x % y;
    x = temp;

    if (y == 0)
        return x;
    else
        return gcd(x, y);
}

int main(void)
{
    int x, y;

    puts("二つの整数の最大公約数を求めます。");
    
    printf("整数x:");  scanf("%d", &x);
    printf("整数y:");  scanf("%d", &y);

    int max = (x > y ? x : y);
    int min = (x > y ? y : x);

    printf("これらの最大公約数は%dです。\n", gcd(max, min));

    return 0;
}

演習8-9

// 標準入力に現れた行数をカウントする

#include <stdio.h>

int main(void)
{
    int ch;
    int i = 0;

    while ((ch = getchar()) != EOF)
    {
        if (ch == '\n')
            i++;       
    }
    
    printf("入力した行数は%d行です。\n", i);

    return 0;
}

演習8-10

// 標準入力から読み込まれた数字文字をカウントしてグラフ表示する

#include <stdio.h>

int main(void)
{
    int ch;
    int cnt[10] = {0};  // 数字文字の出現回数

    while ((ch = getchar()) != EOF)
        if (ch >= '0' && ch <= '9')
            cnt[ch - '0']++;

    puts("数字の出現回数 表示パターン1");
    for (int i = 0; i < 10; i++)
    {
        printf("'%d':", i);
        for (int j = 0; j < cnt[i]; j++)
            putchar('*');
        putchar('\n');
    }
    
    puts("\n数字の出現回数 表示パターン2");
    int height = 0;             // 分布グラフの高さ

    /* 分布グラフの高さ決定 */
    for (int i = 0; i < 10; i++)
        if (height < cnt[i])
            height = cnt[i];
    
    /* 分布グラフの描画 */
    for (int i = height; i > 0; i--)
    {
        for (int j = 0; j < 10; j++)
        {
            if (cnt[j] == i)
            {
                printf(" * ");
                cnt[j]--;
            }
            else
                printf("   ");
        }
        putchar('\n');
    }

    for (int i = 0; i < 10; i++)
        printf("---");

    puts("-");
    for (int i = 0; i < 10; i++)
        printf("'%d'", i);

    printf("\n");
    return 0;
}

第9章:文字列の基本

演習9-1

// 配列に文字列リテラルを格納して表示

#include <stdio.h>

int main(void)
{
    char str[] = "ABC\0DEF";

    printf("文字列strは\"%s\"です。\n", str);   // 表示

    /*  実行結果は「文字列strは"ABC"です。」となる。
        これは、charの配列に格納できるのは文字列であって、
        文字列とみなされるのは最初に出現するナル文字までであるため、
        格納がABC\0のみ行われたためであると考えられる。 */
        
    return 0;
}

演習9-2

// 宣言された文字列を空文字列にする

#include <stdio.h>

int main(void)
{
    char s1[] = "ABC";
    s1[0] = '\0';    // 文字列要素の1個目にナル文字を格納
    printf("文字列s:%s\n", s1);

    return 0;
}

演習9-3

// 文字列の配列を読み込んで表示

#include <stdio.h>

#define NUMBER 5

int main(void)
{
    char s[NUMBER][128];
    int count = 0;

    for (int i = 0; i < NUMBER; i++)
    {
        printf("s[%d]:", i);
        scanf("%s", s[i]);
        count++;
        if (s[i][0] == '$' && s[i][1] == '$' && s[i][2] == '$' && s[i][3] == '$' && s[i][4] == '$')
            i = NUMBER;
    }
    
    for (int i = 0; i < count - 1; i++)
        printf("s[%d] = \"%s\"\n", i, s[i]);
    
    return 0;
}

演習9-4

// 文字列を空文字列にする

#include <stdio.h>

//--- 文字列sを空文字列にする ---//
void null_string(char s[])
{
    s[0] = '\0';
}

int main(void)
{
    char str[128];

    printf("文字列を入力せよ:");
    scanf("%s", str);

    printf("入力された文字列:%s\n", str);

    null_string(str);

    printf("空文字列にした後:%s\n", str);

    return 0;
}

演習9-5

// 文字列中のどこに特定の文字が含まれているか

#include <stdio.h>

//--- 文字列sの中に、文字cが含まれていればその添字を返し、含まれていなければ-1を返す ---//
int str_char(const char s[], int c)
{
    for (int i = 0; s[i] != '\0'; i++)
    {
        if (s[i] == c)
        {
            return i;
        }
    }

    return -1;
}

int main(void)
{
    int i;
    char str[128];

    printf("文字列を入力せよ:");   scanf("%s", str);

    i = str_char(str, 'x');

    if (i == -1)
        printf("\'x\'は含まれていません\n");
    else
        printf("\'x\'は%d番目にあります\n", i + 1);
    
    return 0;
}

演習9-6

// 文字列中にある特定の文字の個数を表示

#include <stdio.h>

//--- 文字列sの中に文字cが含まれている個数を返す ---//
int str_chnum(const char s[], int c)
{
    int num = 0;
    for (int i = 0; s[i] != '\0'; i++)
    {
        if (s[i] == c)
            num++;
    }
    
    return num;
}

int main(void)
{
    int n;
    char str[128];

    printf("文字列を入力せよ:");
    scanf("%s", str);

    n = str_chnum(str, 'q');

    printf("入力された文字列のうち文字'q'は%d個です。\n", n);

    return 0;
}

演習9-7

//文字列を複数回連続して表示する

#include <stdio.h>

//--- 文字列sをn回だけ連続して表示する ---//
void put_stringn(const char s[], int n)
{
    for (int i = 0; i < n; i++)
    {
        int j = 0;
        while (s[j])
            putchar(s[j++]);
    }
}

int main(void)
{
    char str[128];
    int n;

    printf("文字列を入力せよ:");
    scanf("%s", str);

    printf("連続表示の回数:");
    scanf("%d", &n);

    put_stringn(str, n);
    putchar('\n');

    return 0;
}

演習9-8

// 文字列を後ろから逆に表示する

#include <stdio.h>

//--- 文字列sを後ろから逆に表示する関数 ---//
void put_stringr(const char s[])
{
    int len = 0;
    while (s[len])
        len++;

    while (s[--len])
        putchar(s[len]);
}

int main(void)
{
    char str[128];

    printf("文字列を入力せよ:");
    scanf("%s", str);

    printf("入力した文字列を後ろから逆に表示:");
    put_stringr(str);
    putchar('\n');

    return 0;
}

演習9-9

// 文字列を後ろから逆に表示する

#include <stdio.h>

//--- 文字列sの文字の並びを反転する ---//
void rev_string(char s[])
{
    int i = 0;
    while (s[i])
        i++;
    
    char temp[i];
    for (int k = 0; k < (i / 2); k++)
    {
        temp[k] = s[k];
        s[k] = s[(i - 1) - k];
        s[(i - 1) - k] = temp[k];
    }
}

//--- 文字列sを表示 ---//
void put_string(const char s[])
{
    int i = 0;
    while (s[i])
        putchar(s[i++]);
}

int main(void)
{
    char str[128];

    printf("文字列を入力せよ:");
    scanf("%s", str);

    printf("文字列を反転しました:");
    rev_string(str);
    put_string(str);
    putchar('\n');

    return 0;
}

演習9-10

演習9-11

演習9-12

タイトルとURLをコピーしました