標準ライブラリ
標準ライブラリは工具箱のようなものです——自分でハンマーやドライバーを鍛える必要はなく、手に取って使うだけです。各工具の役割を知っておけば、適切なものを選べます。
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);
malloc:sizeバイトを確保、初期化しないcalloc:count*sizeバイトを確保、すべて0で初期化realloc:以前に確保したメモリのサイズを変更、アドレスが移動する場合があるfree:メモリを解放
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チェックは実行時に起こりうるエラーを処理し、常に存在します。
📖 まとめ
math.hは数学関数を提供、三角関数はラジアン使用、-lmでコンパイルrand/srandで疑似乱数を生成、srand(time(NULL))で時刻をシードにstrtol/strtodはatoi/atofより安全で変換エラーを検出可能qsort/bsearchは標準ライブラリのソートと探索ツール、カスタム比較関数が必要assertは開発中のデバッグ用、リリースビルドではNDEBUGで無効化
📝 練習問題
- 1〜1000の乱数100個を生成し、qsortでソートして最大値と最小値を出力するプログラムを作成してください
clock()を使って、バブルソートとqsortで10,000個の整数をソートする時間の違いを比較するプログラムを作成してください- ctype.h関数を使って文字列の大文字小文字変換関数を実装してください(文字列を入力し、すべて大文字とすべて小文字のバージョンを出力)



