基礎
Hello World
#include int main(void) { printf("Hello, World!\n"); return 0; }
コンパイル & 実行
gcc -o app main.c # compile gcc -Wall -Wextra -std=c17 main.c # strict ./app # run
コメント
// single-line comment (C99+) /* multi-line comment */
データ型
プリミティブ型
char1 バイト、文字または小整数
short最低 16 ビット
int最低 16 ビット(通常 32)
long最低 32 ビット
long long最低 64 ビット(C99+)
float32 ビット IEEE-754
double64 ビット IEEE-754
_Bool / bool0 または 1bool には を使用)
固定幅型(stdint.h)
int8_t, uint8_t厳密な 8 ビット符号付き / なし
int16_t, uint16_t厳密な 16 ビット
int32_t, uint32_t厳密な 32 ビット
int64_t, uint64_t厳密な 64 ビット
size_t符号なし、sizeof の結果型
型キャスト
int i = (int)3.14; // explicit cast double d = (double)5 / 2; // 2.5, not 2 char c = (char)65; // 'A'
制御フロー
If / Else
if (x > 0) { printf("positive\n"); } else if (x == 0) { printf("zero\n"); } else { printf("negative\n"); }
Switch
switch (choice) { case 1: printf("one\n"); break; case 2: printf("two\n"); break; default: printf("other\n"); }
ループ
for (int i = 0; i < 10; i++) { } while (condition) { } do { } while (condition);
ジャンプ文
break最内側のループまたは switch を抜ける
continue次のイテレーションへスキップ
returnオプションの値と共に関数を終了
goto labelラベルへジャンプ(使用は最小限に)
関数
宣言 & 定義
int add(int a, int b); // prototype int add(int a, int b) { return a + b; }
関数ポインタ
int (*op)(int, int) = add; int result = op(3, 4); // calls add(3, 4) typedef int (*MathFn)(int, int); MathFn fn = add;
static 関数
// visible only within this translation unit static int helper(int x) { return x * 2; }
ポインタ
ポインタの基礎
int x = 42; int *p = &x; // p points to x printf("%d\n", *p); // dereference: 42 *p = 100; // x is now 100
ポインタ演算
int arr[] = {10, 20, 30}; int *p = arr; printf("%d\n", *(p + 1)); // 20 printf("%d\n", p[2]); // 30 (same as *(p+2))
ポインタのよくあるパターン
int *p = NULLヌルポインタ(常に初期化)
void *汎用ポインタ(使用時にキャスト必要)
const int *p定数へのポインタ(値の変更不可)
int *const p定数ポインタ(ポインタ自体の再代入不可)
int **ppポインタへのポインタ(二重参照)
配列 & 文字列
配列
int nums[5] = {1, 2, 3, 4, 5}; int matrix[2][3] = {{1,2,3}, {4,5,6}}; int len = sizeof(nums) / sizeof(nums[0]);
文字列関数(string.h)
strlen(s)長さ(ヌル終端文字を除く)
strcpy(dst, src)文字列をコピー(危険、strncpy を推奨)
strncpy(dst, src, n)最大 n 文字をコピー
strcat(dst, src)文字列を連結
strcmp(a, b)比較: 等しければ 0、そうでなければ <0 か >0
strchr(s, c)文字の最初の出現を検索
strstr(haystack, needle)部分文字列を検索
文字列リテラル
char greeting[] = "hello"; // mutable array const char *msg = "world"; // pointer to literal char buf[64]; snprintf(buf, sizeof(buf), "%s %s", greeting, msg);
構造体
定義 & 使用
struct Point { double x; double y; }; struct Point p = {1.0, 2.0}; printf("(%g, %g)\n", p.x, p.y);
typedef
typedef struct { char name[50]; int age; } Person; Person p = {"Alice", 30};
構造体ポインタ
void set_age(Person *p, int age) { p->age = age; // arrow operator }
enum & union
enum Color { RED, GREEN, BLUE }; union Data { int i; float f; char c; }; // union members share the same memory
メモリ管理
動的確保(stdlib.h)
int *arr = malloc(10 * sizeof(int)); if (arr == NULL) { /* handle error */ } arr = realloc(arr, 20 * sizeof(int)); free(arr); arr = NULL; // avoid dangling pointer
確保関数
malloc(size)未初期化メモリを確保
calloc(count, size)ゼロ初期化して確保
realloc(ptr, size)確保済みブロックをリサイズ
free(ptr)確保したメモリを解放
よくある落とし穴
メモリリーク確保したメモリの free() 忘れ
二重解放同じポインタを free() で2回解放
ダングリングポインタfree() 後にポインタを使用 — NULL を代入
バッファオーバーフロー確保した境界を超えて書き込み
ファイル I/O
ファイルの読み込み
FILE *f = fopen("data.txt", "r"); if (!f) { perror("open"); return 1; } char line[256]; while (fgets(line, sizeof(line), f)) printf("%s", line); fclose(f);
ファイルへの書き込み
FILE *f = fopen("out.txt", "w"); fprintf(f, "value: %d\n", 42); fputs("hello\n", f); fclose(f);
ファイルモード
"r"読み込み(ファイルが存在必要)
"w"書き込み(切り捨てまたは作成)
"a"追記(なければ作成)
"rb", "wb"バイナリ読み込み / 書き込み
"r+"読み書き(ファイルが存在必要)
プリプロセッサ
ディレクティブ
#include // system header #include "myheader.h" // local header #define PI 3.14159 #define MAX(a, b) ((a) > (b) ? (a) : (b))
条件コンパイル
#ifdef DEBUG printf("debug: x = %d\n", x); #endif #ifndef HEADER_H /* include guard */ #define HEADER_H /* ... */ #endif
よく使うマクロ
__FILE__現在のソースファイル名
__LINE__現在の行番号
__func__現在の関数名(C99+)
__DATE__コンパイル日付の文字列
NULLヌルポインタ定数
sizeof(x)型または変数のサイズ(バイト単位)