🇯🇵 日本語 | 🇺🇸 English
広告スペース

疑似コードからC言語へ変換する練習

アルゴリズムの「考え方」と「実装」の違いを理解する。基本情報技術者試験の対策にも。

疑似コード ↔ C言語 対応表

まず、疑似コードの書き方がC言語でどう対応するかを確認しましょう。
疑似コードC言語
整数型: xint x;
実数型: xdouble x;
文字型: cchar c;
x ← 10x = 10;
x を表示するprintf("%d", x);
x を入力するscanf("%d", &x);
もし x > 0 ならば
  処理
そうでなければ
  処理
を実行する
if (x > 0) {
  処理;
} else {
  処理;
}
i を 1 から n まで 繰り返す
  処理
を実行する
for (int i = 1; i <= n; i++) {
  処理;
}
条件 の間 繰り返す
  処理
を実行する
while (条件) {
  処理;
}
整数型の配列: A[n]int A[n];
関数 add(a, b)
  戻り値: a + b
int add(int a, int b) {
  return a + b;
}
x の絶対値abs(x) or fabs(x)
x の平方根sqrt(x)
A[i] と A[j] を交換するint t=A[i]; A[i]=A[j]; A[j]=t;
疑似コードのポイント: は代入、= は等値比較(C言語の ==)。セミコロンや中括弧は不要で、インデントで構造を示します。

初級:基本構文の変換

P-01
合計を求める
整数型: sum ← 0
i を 1 から 10 まで 繰り返す
sum ← sum + i
を実行する
sum を表示する
#include <stdio.h>

int main(void) {
    int sum = 0;
    for (int i = 1; i <= 10; i++) {
        sum = sum + i;
    }
    printf("%d\n", sum); // 55
    return 0;
}
P-02
正負の判定
整数型: x
x を入力する
もし x > 0 ならば
"正" を表示する
そうでなくもし x = 0 ならば
"零" を表示する
そうでなければ
"負" を表示する
を実行する
#include <stdio.h>

int main(void) {
    int x;
    scanf("%d", &x);
    if (x > 0) {
        printf("正\n");
    } else if (x == 0) {      // 疑似コードの = はC言語では ==
        printf("零\n");
    } else {
        printf("負\n");
    }
    return 0;
}
P-03
偶数を数える
整数型の配列: A[5] ← {3, 8, 15, 22, 7}
整数型: count ← 0
i を 0 から 4 まで 繰り返す
もし A[i] を 2 で割った余りが 0 ならば
count ← count + 1
を実行する
を実行する
"偶数の個数:" と count を表示する
#include <stdio.h>

int main(void) {
    int A[] = {3, 8, 15, 22, 7};
    int count = 0;
    for (int i = 0; i <= 4; i++) {
        if (A[i] % 2 == 0) {
            count++;
        }
    }
    printf("偶数の個数: %d\n", count); // 2
    return 0;
}
P-04
カウントダウン
整数型: n ← 5
n > 0 の間 繰り返す
n を表示する
n ← n - 1
を実行する
"発射!" を表示する
#include <stdio.h>

int main(void) {
    int n = 5;
    while (n > 0) {
        printf("%d\n", n);
        n--;
    }
    printf("発射!\n");
    return 0;
}
P-05
2つの数の大きい方
関数 max(a, b)
もし a > b ならば
戻り値: a
そうでなければ
戻り値: b
を実行する

max(7, 12) を表示する
#include <stdio.h>

int max(int a, int b) {
    if (a > b) return a;
    else return b;
}

int main(void) {
    printf("%d\n", max(7, 12)); // 12
    return 0;
}

中級:アルゴリズムの変換

P-06
配列の最大値
整数型の配列: A[n] // n個のデータが入っている
整数型: max ← A[0]
i を 1 から n-1 まで 繰り返す
もし A[i] > max ならば
max ← A[i]
を実行する
を実行する
max を返す
int find_max(int A[], int n) {
    int max = A[0];
    for (int i = 1; i < n; i++) {
        if (A[i] > max) {
            max = A[i];
        }
    }
    return max;
}
変換ポイント: 疑似コードの「n-1まで」はC言語では i < n(0始まりなので)。配列を関数に渡すとき、サイズも引数で渡す必要がある。
P-07
線形探索
関数 search(A, n, key)
i を 0 から n-1 まで 繰り返す
もし A[i] = key ならば
i を返す
を実行する
を実行する
-1 を返す // 見つからなかった
int search(int A[], int n, int key) {
    for (int i = 0; i < n; i++) {
        if (A[i] == key) {  // ← 疑似コードの = はC言語で ==
            return i;
        }
    }
    return -1;
}
P-08
バブルソート
関数 bubbleSort(A, n)
i を 0 から n-2 まで 繰り返す
j を n-1 から i+1 まで(降順) 繰り返す
もし A[j-1] > A[j] ならば
A[j-1] ��� A[j] を交換する
を実行する
を実行する
を実行する
void bubbleSort(int A[], int n) {
    for (int i = 0; i < n - 1; i++) {
        for (int j = n - 1; j > i; j--) {  // 降順ループ
            if (A[j-1] > A[j]) {
                int tmp = A[j-1];  // 交換には一時変数が必要
                A[j-1] = A[j];
                A[j] = tmp;
            }
        }
    }
}
変換ポイント: 「交換する」は疑似コードでは1行だが、C言語では一時変数を使って3行必要。「降順ループ」は j--
P-09
ユークリッドの互除法(GCD)
関数 gcd(a, b)
b ≠ 0 の間 繰り返す
整数型: temp ← b
b ← a を b で割った余り
a ← temp
を実行する
a を返す
int gcd(int a, int b) {
    while (b != 0) {
        int temp = b;
        b = a % b;
        a = temp;
    }
    return a;
}
P-10
二分探索
関数 binarySearch(A, n, key)
整数型: lo ← 0, hi ← n - 1
lo ≤ hi の間 繰り返す
整数型: mid ← (lo + hi) ÷ 2
もし A[mid] = key ならば
mid を返す
そうでなくもし A[mid] < key ならば
lo ← mid + 1
そうでなければ
hi ← mid - 1
を実行する
を実行する
-1 を返す
int binarySearch(int A[], int n, int key) {
    int lo = 0, hi = n - 1;
    while (lo <= hi) {
        int mid = (lo + hi) / 2;   // ÷ はC言語では /(整数除算)
        if (A[mid] == key) return mid;
        else if (A[mid] < key) lo = mid + 1;
        else hi = mid - 1;
    }
    return -1;
}

上級:再帰・ポインタ・構造体の変換

P-11
階乗(再帰)
関数 factorial(n)
もし n ≤ 1 ならば
1 を返す
そうでなければ
n × factorial(n - 1) を返す
を実行する
int factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}
P-12
ポインタ経由で値を変更
関数 addTen(xのアドレス)
xのアドレスが指す値 ← xのアドレスが指す値 + 10

整数型: a ← 5
addTen(a のアドレス) を呼び出す
a を表示する // 15 になる
#include <stdio.h>

void addTen(int *px) {     // 「アドレス」→ ポインタ引数
    *px = *px + 10;          // 「アドレスが指す値」→ *px
}

int main(void) {
    int a = 5;
    addTen(&a);              // 「aのアドレス」→ &a
    printf("%d\n", a);       // 15
    return 0;
}
変換ポイント: 疑似コードの「アドレス」はC言語では &(アドレス取得)と *(間接参照)で表現。これがポインタの本質。
P-13
構造体で座標を管理
構造体 Point:
実数型: x, y

関数 distance(p1, p2) // 2点間の距離
dx ← p2.x - p1.x
dy ← p2.y - p1.y
(dx² + dy²) の平方根 を返す

Point型: a ← (0.0, 0.0)
Point型: b ← (3.0, 4.0)
distance(a, b) を表示する // 5.0
#include <stdio.h>
#include <math.h>

struct Point {
    double x, y;
};

double distance(struct Point p1, struct Point p2) {
    double dx = p2.x - p1.x;
    double dy = p2.y - p1.y;
    return sqrt(dx*dx + dy*dy);
}

int main(void) {
    struct Point a = {0.0, 0.0};
    struct Point b = {3.0, 4.0};
    printf("%.1f\n", distance(a, b)); // 5.0
    return 0;
}
P-14
クイックソート(再帰)
関数 quickSort(A, lo, hi)
もし lo >= hi ならば 終了する
整数型: pivot ← A[hi]
整数型: i ← lo
j を lo から hi-1 まで 繰り返す
もし A[j] < pivot ならば
A[i] と A[j] を交換する
i ← i + 1
を実行する
を実行する
A[i] と A[hi] を交換する
quickSort(A, lo, i - 1)
quickSort(A, i + 1, hi)
void swap(int *a, int *b) {
    int t = *a; *a = *b; *b = t;
}

void quickSort(int A[], int lo, int hi) {
    if (lo >= hi) return;
    int pivot = A[hi];
    int i = lo;
    for (int j = lo; j < hi; j++) {
        if (A[j] < pivot) {
            swap(&A[i], &A[j]);
            i++;
        }
    }
    swap(&A[i], &A[hi]);
    quickSort(A, lo, i - 1);
    quickSort(A, i + 1, hi);
}
変換ポイント: 「交換する」をswap関数として切り出す。疑似コードの「終了する」はC言語では return;
P-15
ニュートン法
関数 newton(f, df, x0, eps)
実数型: x ← x0
繰り返す
実数型: x_new ← x - f(x) / df(x)
もし |x_new - x| < eps ならば
x_new を返す
を実行する
x ← x_new
を実行する
#include <math.h>

double f(double x)  { return x*x - 2; }
double df(double x) { return 2*x; }

double newton(double x0, double eps) {
    double x = x0;
    while (1) {                      // 「繰り返す」→ 無限ループ
        double x_new = x - f(x) / df(x);
        if (fabs(x_new - x) < eps)  // |...| → fabs()
            return x_new;
        x = x_new;
    }
}
変換ポイント: 疑似コードの「繰り返す」(条件なし)は while(1)。「|x|」(絶対値)は fabs(x)。関数を引数に渡す疑似コードは、C言語では関数ポインタになるが、初心者向けにグローバル関数として実装するのが簡単。

変換でよく間違えるポイントまとめ

疑似コードC言語での落とし穴
x = y (比較)x == y (= だと代入になる!)
A[i] と A[j] を交換する一時変数 tmp が必要(1行では書けない)
x の平方根sqrt(x) (math.h の include が必要)
繰り返す(条件なし)while(1) + break で脱出
i を 1 から n までfor(i=1; i<=n; i++) (0始まりの配列と混同注意)
関数(配列, サイズ)配列のサイズも引数で渡す(Cには配列長の取得方法がない)
アドレスで渡すポインタ引数 int *px と & で渡す
÷(整数の割り算)/(intどうしなら自動的に切り捨て)
この記事をシェア
X(Twitter)でシェア はてブ

アルゴリズムをさらに深めるなら

疑似コードの読み書きは試験対策にも直結します

📘
苦しんで覚えるC言語
MMGames 著
初心者向けの定番入門書。
Amazonで見る
📗
新・明解C言語 入門編
柴田望洋 著
図解が豊富で演習問題も充実。
Amazonで見る
📙
プログラミング言語C 第2版
B.W.カーニハン, D.M.リッチー 著
通称K&R。C言語の原典。
Amazonで見る

※ 上記リンクはアフィリエイトリンクです。購入によりサイト運営を支援いただけます。