標準ライブラリ

標準ライブラリは工具箱のようなものです——自分でハンマーやドライバーを鍛える必要はなく、手に取って使うだけです。各工具の役割を知っておけば、適切なものを選べます。

math.h 数学演算

数学関数を使うにはヘッダをインクルードし、数 学ライブラリをリンクする必要があります:

C
#include <math.h>

-lmフラグでコンパイル:gcc program.c -lm

よく使う数学関数

関数 目的
fabs(x) 絶対値 fabs(-3.5) → 3.5
sqrt(x) 平方根 sqrt(16.0) → 4.0
pow(x, y) xのy乗 pow(2.0, 10.0) → 1024.0
ceil(x) 切り上げ ceil(3.2) → 4.0
floor(x) 切り捨て floor(3.8) → 3.0
round(x) 四捨五入 round(3.5) → 4.0
fmod(x, y) 浮動小数点剰余 fmod(7.5, 2.5) → 0.0
log(x) 自然対数 log(2.718) → 1.0
log10(x) 常用対数 log10(100.0) → 2.0
sin(x) 正弦 sin(3.14/2) → 1.0
cos(x) 余弦 cos(0.0) → 1.0
tan(x) 正接 tan(0.0) → 0.0
⚠️ 注意: 三角関数の引数は度数ではなくラジアンです!度数からラジアンへの変換:rad = deg * 3.14159265 / 180.0

2点間の距離を計算します:

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

typedef struct {
    double x;
    double y;
} Point;

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

int main(void) {
    Point p1 = {3.0, 4.0};
    Point p2 = {0.0, 0.0};
    printf("距離: %.2f\n", distance(p1, p2));
    return 0;
}
▶ 試してみよう
TEXT
距離: 5.00

stdlib.h 汎用ユーティリティ

乱数

C
int rand(void);
void srand(unsigned int seed);

rand()は0からRAND_MAXまでの疑似乱数を返します。srandを呼び出さないと、プログラムの実行ごとに同じ乱数列が生成されます。

C
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void) {
    srand((unsigned int)time(NULL));

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

    for (int i = 0; i < 5; i++) {
        printf("%d ", rand() % 100);
    }
    printf("\n");

    return 0;
}
TEXT
1804289383 846930886 1681692777 1714636915 1957747793
83 86 77 15 93
⚠️ 注意: rand() % Nは多くの実装で良好なランダム性を提供しません——下位ビットにパターンがある場合があります。高品質なランダム性が必要な場面では、より高度な乱数生成器を使ってください。

型変換

関数 目的
atoi(str) 文字列をintに変換
atol(str) 文字列をlongに変換
atof(str) 文字列をdoubleに変換
strtol(str, &end, base) 文字列をlongに変換(基数指定)
strtod(str, &end) 文字列をdoubleに変換(エラー検出付き)
C
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int a = atoi("42");
    double b = atof("3.14");
    long c = strtol("0xFF", NULL, 16);

    printf("a = %d\n", a);
    printf("b = %.2f\n", b);
    printf("c = %ld\n", c);

    char *end;
    long d = strtol("123abc", &end, 10);
    printf("d = %ld, 変換されなかった部分: %s\n", d, end);

    return 0;
}
TEXT
a = 42
b = 3.14
c = 255
d = 123, 変換されなかった部分: abc
💡 ヒント: atoiはエラーを検出できません——無効な入力は0を返し、正当な0と区別できません。strtol/strtodを推奨します。これらはendポインタで変換が成功したかどうかを判断できます。

動的メモリ管理

C
void *malloc(size_t size);
void *calloc(size_t count, size_t size);
void *realloc(void *ptr, size_t size);
void free(void *ptr);
C
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *arr = calloc(5, sizeof(int));
    if (arr == NULL) {
        return 1;
    }

    for (int i = 0; i < 5; i++) {
        arr[i] = i * 10;
    }

    int *new_arr = realloc(arr, 10 * sizeof(int));
    if (new_arr == NULL) {
        free(arr);
        return 1;
    }
    arr = new_arr;

    for (int i = 5; i < 10; i++) {
        arr[i] = i * 10;
    }

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

    free(arr);
    return 0;
}
TEXT
0 10 20 30 40 50 60 70 80 90
⚠️ 注意: reallocが失敗するとNULLを返しますが、元のメモリは解放されません!したがって、一時変数でreallocの戻り値を受け取る必要があります——失敗時でも元のメモリを解放できます。

ソートと探索

qsort

C
void qsort(void *base, size_t count, size_t size,
           int (*compare)(const void *, const void *));

比較関数の規則:a < bなら負、等しければ0、a > bなら正を返します。

C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int cmp_int(const void *a, const void *b) {
    return *(const int *)a - *(const int *)b;
}

int cmp_str(const void *a, const void *b) {
    return strcmp(*(const char )a, *(const char )b);
}

int main(void) {
    int nums[] = {42, 17, 8, 95, 3, 61};
    int n = sizeof(nums) / sizeof(nums[0]);

    qsort(nums, n, sizeof(int), cmp_int);
    for (int i = 0; i < n; i++) {
        printf("%d ", nums[i]);
    }
    printf("\n");

    const char *names[] = {"Alice", "Bob", "Charlie", "Diana"};
    int m = sizeof(names) / sizeof(names[0]);

    qsort(names, m, sizeof(char *), cmp_str);
    for (int i = 0; i < m; i++) {
        printf("%s ", names[i]);
    }
    printf("\n");

    return 0;
}
TEXT
3 8 17 42 61 95
Alice Bob Charlie Diana

bsearch

C
void *bsearch(const void *key, const void *base, size_t count,
              size_t size, int (*compare)(const void *, const void *));

ソート済み配列に対して二分探索を行います。見つかった要素へのポインタを返し、見つからない場合はNULLを返します。

C
#include <stdio.h>
#include <stdlib.h>

int cmp_int(const void *a, const void *b) {
    return *(const int *)a - *(const int *)b;
}

int main(void) {
    int nums[] = {3, 8, 17, 42, 61, 95};
    int n = sizeof(nums) / sizeof(nums[0]);

    int key = 42;
    int *result = bsearch(&key, nums, n, sizeof(int), cmp_int);

    if (result != NULL) {
        printf("%dがインデックス%ldで見つかりました\n", key, result - nums);
    } else {
        printf("%dは見つかりませんでした\n", key);
    }

    return 0;
}
TEXT
42がインデックス3で見つかりました

time.h 時間処理

時間関数

関数/型 目的
time_t 時間型(通常1970-01-01からの秒数)
time(&t) 現在時刻を取得
clock() プログラムが使用したCPUクロックティックを取得
localtime() ローカル時刻の構造体に変換
gmtime() UTC時刻の構造体に変換
strftime() 時刻を文字列にフォーマット
difftime() 2つの時刻の差を計算(秒)

struct tm

C
struct tm {
    int tm_sec;
    int tm_min;
    int tm_hour;
    int tm_mday;
    int tm_mon;
    int tm_year;
    int tm_wday;
    int tm_yday;
    int tm_isdst;
};

tm_monは0〜11(0=1月)、tm_yearは1900年からの年数、tm_wdayは0が日曜日です。

C
#include <stdio.h>
#include <time.h>

int main(void) {
    time_t now = time(NULL);
    struct tm *local = localtime(&now);

    char buf[64];
    strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", local);
    printf("現在の時刻: %s\n", buf);

    printf("今日は曜日%d(0=日曜)\n", local->tm_wday);

    return 0;
}
▶ 試してみよう
TEXT
現在の時刻: 2025-03-15 14:30:22
今日は曜日6(0=日曜)

プログラムの実行時間計測

C
#include <stdio.h>
#include <time.h>

int main(void) {
    clock_t start = clock();

    volatile long sum = 0;
    for (long i = 0; i < 100000000L; i++) {
        sum += i;
    }

    clock_t end = clock();
    double elapsed = (double)(end - start) / CLOCKS_PER_SEC;
    printf("経過時間: %.3f 秒\n", elapsed);

    return 0;
}
TEXT
経過時間: 0.235 秒
⚠️ 注意: clock()はCPU時間を計測し、実時間ではありません。プログラムにsleepやI/O待ちがある場合、その時間はカウントされません。実際の経過時間を計測するにはdifftimeを使ってください。

ctype.h 文字処理

関数 テスト条件
isalpha(c) アルファベット
isdigit(c) 数字
isalnum(c) アルファベットまたは数字
isupper(c) 大文字
islower(c) 小文字
isspace(c) 空白文字(スペース、タブ、改行など)
ispunct(c) 句読点
isprint(c) 印字可能文字
toupper(c) 大文字に変換
tolower(c) 小文字に変換

これらの関数は引数としてunsigned charの値またはEOFが必要です。負のchar値を渡すと未定義動作になります。

文字列中のアルファベット、数字、その他の文字を数えます:

C
#include <stdio.h>
#include <ctype.h>

int main(void) {
    char str[] = "Hello, World! 123";
    int letters = 0, digits = 0, others = 0;

    for (int i = 0; str[i] != '\0'; i++) {
        if (isalpha((unsigned char)str[i])) {
            letters++;
        } else if (isdigit((unsigned char)str[i])) {
            digits++;
        } else {
            others++;
        }
    }

    printf("アルファベット: %d, 数字: %d, その他: %d\n", letters, digits, others);
    return 0;
}
▶ 試してみよう
TEXT
アルファベット: 10, 数字: 3, その他: 6

assert.h アサーション

C
void assert(int expression);

式が偽のとき、プログラムを終了しエラーメッセージ(ファイル名、行番号、式)を出力します。#include <assert.h>の前にNDEBUGマクロを定義すると、すべてのアサーションが無効になります。

C
#include <stdio.h>
#include <assert.h>

double safe_divide(double a, double b) {
    assert(b != 0 && "除数はゼロにできません");
    return a / b;
}

int main(void) {
    printf("10 / 2 = %.1f\n", safe_divide(10.0, 2.0));
    printf("10 / 0 = %.1f\n", safe_divide(10.0, 0.0));
    return 0;
}
TEXT
10 / 2 = 5.0
Assertion failed: b != 0 && "除数はゼロにできません", file main.c, line 5
💡 ヒント: assert内の文字列リテラルは出力されるため、コメントより"除数はゼロにできません"と書く方が効果的です——アサーションが失敗したときに理由がすぐに分かります。

❓ よくある質問

Q なぜrand()は実行のたびに同じ列を生成するのですか?
A 乱数のシードを設定するsrandが呼び出されていないためです。デフォルトのシードは1なので、列が固定されます。srand(time(NULL))で現在時刻をシードにしてください。
Q なぜqsortの比較関数はvoidポインタを使うのですか?
A qsortはジェネリック関数であり、ソートする型を知りません。voidポインタは任意の型を指せるため、比較関数が内部で特定の型にキャストし直します。
Q なぜctype.h関数の引数はunsigned charにキャストすべきですか?
A charが符号付きの場合、上位ビットがセットされた文字は負の値になり、ctype関数に渡すと未定義動作になります。unsigned charへのキャストで値が0〜255の範囲にあることを保証します。
Q assertとifチェックの違いは何ですか?
A assertは開発中に起こるべきではないこと(論理エラー)をチェックし、NDEBUGが定義されると消滅します。ifチェックは実行時に起こりうるエラーを処理し、常に存在します。

📖 まとめ

📝 練習問題

  1. 1〜1000の乱数100個を生成し、qsortでソートして最大値と最小値を出力するプログラムを作成してください
  2. clock()を使って、バブルソートとqsortで10,000個の整数をソートする時間の違いを比較するプログラムを作成してください
  3. ctype.h関数を使って文字列の大文字小文字変換関数を実装してください(文字列を入力し、すべて大文字とすべて小文字のバージョンを出力)
100%