C言語の文字列(char配列)の扱い方。strcpy, strlen, strcmp等の文字列関数。
char 配列 + 末尾 \0printf("%s", s); で表示strlen, strcpy, strcmp は <string.h>c + ('a'-'A')strcpy は危険、snprintf を使うint(整数)と double(実数)を使ってきましたね。ここで初めて char(チャー)型を学びます。char は 1 文字 を入れる箱です。サイズは 1 バイト。書き方はとてもシンプル:char c = 'A'; // c に文字 A を入れる printf("%c\n", c); // → A (画面に A が出る)
'A'%c(character の c)'A'(シングル)と "A"(ダブル)はまったく別物'A' ― シングルクォートchar c = 'A';
"A" ― ダブルクォート\0)char s[] = "A";
"A" のように char を並べて末尾に \0 を付けたものです。'A' として見えるのは 「数値 65 を文字として解釈している」だけ なんです。char c = 'A'; と char c = 65; は完全に同じ意味printf("%c", 65) → A / printf("%d", 'A') → 65'A' + 1 が 'B' になる、という芸当ができる
| 文字 | 10進 | 16進 | 説明 |
|---|---|---|---|
| \0 | 0 | 0x00 | ヌル文字(文字列の終端の目印) |
| \t | 9 | 0x09 | 水平タブ |
| \n | 10 | 0x0A | 改行 |
| ␣ | 32 | 0x20 | 半角スペース |
| 文字 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|---|---|---|---|---|---|---|---|---|---|---|
| 10進 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
| 文字 | A | B | C | D | E | F | G | H | I | J | K | L | M |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 10進 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 |
| 文字 | N | O | P | Q | R | S | T | U | V | W | X | Y | Z |
| 10進 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 |
| 文字 | a | b | c | d | e | f | g | h | i | j | k | l | m |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 10進 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 |
| 文字 | n | o | p | q | r | s | t | u | v | w | x | y | z |
| 10進 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 |
'a' - 'A' = 32 がいつでも成立。これが「大文字 ↔ 小文字 変換」のキーになります。
#include <stdio.h> int main(void) { char c = 'A'; printf("c = %c\n", c); // → A (文字として表示) printf("c = %d\n", c); // → 65 (整数として表示) // 文字の「計算」もできる printf("%c\n", c + 1); // → B (65+1=66、'B'のコード) printf("%c\n", 'Z' - 3); // → W // 65 を char に入れても 'A' と等価 char d = 65; printf("%c\n", d); // → A return 0; }
char c = 'A'; char lower = c + ('a' - 'A'); // 'A' + 32 = 'a' // または: char lower = c + 32;
char ch = '7'; // これは 55 ('7'のASCII) int n = ch - '0'; // 55 - 48 = 7 (本当の整数7) printf("%d\n", n); // → 7
if (c >= 'A' && c <= 'Z') // 大文字? if (c >= '0' && c <= '9') // 数字? // 標準ライブラリ <ctype.h> にも isupper(c), isdigit(c) がある
char c = 'あ'; はエラーか警告になります。日本語の1文字は複数バイト(UTF-8 なら 3バイト)必要なので、charの配列で扱うか、wchar_t を使うか、文字コードを自分で扱う必要があります。ASCII の範囲(英数字と記号)だけが char で安全に扱える文字です。'A' や 'あ' が見えていても、メモリには 結局すべて数値(番号)として保存 されています。char が「実は整数」なのは特別な仕様ではなく、「文字に番号を割り当てた」だけ という当たり前の話です。scanf で入力するprintf と対になるのが scanf。書式は %c(character の c)。int の %d と同じ感覚で、変数の住所 & を渡す のがポイントです。#include <stdio.h> int main(void) { char c; printf("1 文字入力してね: "); scanf("%c", &c); // ← & を忘れない! printf("入力された文字: %c\n", c); return 0; } /* 実行例 1 文字入力してね: A ← A を入力して Enter 入力された文字: A */
%c(1 文字)&c のように 住所(アドレス) を渡す(int の scanf("%d", &n) と同じ)c に入る& の有無 だけ。
scanf と続けると「改行」が入ってしまうint n; char c; scanf("%d", &n); // 数字を入力 → Enter scanf("%c", &c); // 続けて 1 文字を入力したい… が、うまくいかない! printf("n=%d c=[%c]\n", n, c);
5 Enter A Enter」と入力したつもりでも、c には 'A' ではなく '\n'(改行)が入ってしまいます。原因は、入力が 「入力バッファ」という見えない待合室 を経由するから。5 Enter」と打つと、入力バッファにはこう並ぶ:scanf("%d", &n) は 5 だけを取り出して n に入れる。改行 \n は 残ったまま:scanf("%c", &c) は バッファの先頭の 1 文字 を取る。先頭は \n なので…:A を入力する前に、c はもう \n で埋まってしまう。" %c" と先頭スペースを入れる%c の前に 半角スペース 1 つ を書くと、scanf は 空白文字(スペース・タブ・改行)を全部読み飛ばして から 1 文字を取ってくれます。int n; char c; scanf("%d", &n); scanf(" %c", &c); // ← " %c" の先頭スペースが \n を吸収! printf("n=%d c=[%c]\n", n, c); // → n=5 c=[A] 期待通り!
%c の前にはスペースを 1 つ」。これだけで連続入力の改行残り問題がほぼ解決します。%d や %s はもともと先頭の空白を読み飛ばす仕様なので、この問題が起きません。%c だけ別ルール)
char が 1 文字 を入れる箱だと学びました。char の配列 を使えば、複数の文字 = 文字列 が表現できます。char の箱を 7 個 並べて、文字列 "Claude" を表現'\0'(ヌル文字) を置きます。「ここで文字列が終わり」の目印で、これがないと printf がどこまで出力していいか分かりません。
char name[20] = "Claude"; // char の箱を 20 個用意(最大19文字 + '\0') printf("%s\n", name); // → Claude
%s は文字列用の書式指定子(string の s)。配列名だけを渡します(先頭の箱の住所が渡る)。"Hello" がメモリにどう並ぶかを見てみましょう。name は、それ自体が先頭要素のアドレスとして扱われます。だから & を付けなくてもアドレスが渡るのです。
fgets が安全)。
strlen(標準ライブラリ)を使えば簡単ですが、仕組みを知るため「自作版」を見てみましょう。#include <string.h> で使える、文字列操作の主要関数をまとめます。| 関数 | 機能 | 使用例 | 注意点 |
|---|---|---|---|
strlen(s) | 文字列の長さ | strlen("abc") → 3 | '\0' は含まない |
strcpy(dst, src) | 文字列コピー | strcpy(s, "Hello") | dst に十分なサイズが必要 |
strncpy(dst, src, n) | 最大n文字コピー | strncpy(s, src, 10) | バッファオーバーフロー防止 |
strcat(dst, src) | 文字列の連結 | strcat(s, " World") | dst に連結後のサイズが必要 |
strcmp(s1, s2) | 文字列の比較 | strcmp(a, b) == 0 | 0なら等しい、正/負で辞書順 |
strncmp(s1, s2, n) | 先頭n文字を比較 | strncmp(s, "ab", 2) | 部分一致の判定に便利 |
strchr(s, c) | 文字を検索 | strchr(s, 'o') | 見つからなければNULL |
strstr(s, sub) | 部分文字列を検索 | strstr(s, "llo") | 見つからなければNULL |
#include <stdio.h> #include <string.h> int main(void) { char greeting[50]; strcpy(greeting, "Hello"); // greeting = "Hello" strcat(greeting, ", World!"); // greeting = "Hello, World!" printf("%s (%lu文字)\n", greeting, strlen(greeting)); return 0; }
if (s1 == s2) はアドレスの比較であり、文字列の内容は比較されません。strcmp(s1, s2) == 0 を使いましょう。strcpy や strcat は書き込み先のサイズをチェックしません。strncpy で最大文字数を制限しましょう。c + ('a'-'A') を逆方向に使う)strlen を使わずに)この講座の理解度をチェックしましょう!
C言語の文字列は必ずヌル文字 \0 で終端されます。これにより文字列の長さを判別できます。
"Hello" は5文字 + 終端の \0 で合計6バイト必要です。char s[6] 以上が必要です。
strcpy がコピー、strcmp が比較、strlen が長さ取得です。string.h をインクルードして使います。