C言語で文字列を扱う場面では、「特定の文字がどこにあるか」「指定した単語が含まれているか」を調べたいことがとても多いです。
この記事では、標準ライブラリのstrchrとstrstrという2つの関数を中心に、文字列検索のしくみをポインタ初心者でも理解しやすい形で解説します。
実際に動くサンプルコードを交えながら、間違えやすいポイントも丁寧に整理していきます。
C言語の文字列検索とは?strchr, strstrの基本
文字列検索でできることと用途
C言語での文字列検索とは、ある文字列の中に特定の文字や単語(部分文字列)が含まれているかどうか、また含まれているならどの位置にあるかを調べる処理のことです。
たとえば次のような場面で、文字列検索が役に立ちます。
- 入力されたメールアドレスに@が含まれているかどうかを確認する
- ファイル名から.txtや.pngなどの拡張子を取り出す
- URL文字列からhttps://のような接頭辞を見つける
- 文章から特定の単語が出てくる位置を探す
こうした処理を自前で1文字ずつループして書くこともできますが、C言語には標準ライブラリとして文字列検索のための関数が用意されています。
その代表がstrchrとstrstrです。
strchrとstrstrの役割の違い
strchrとstrstrは、どちらも文字列の中から何かを探す関数ですが、役割がはっきり分かれています。
- strchr
1文字だけを探す関数です。文字列の中から特定のcharが最初に現れる位置を見つけます。たとえば'@'、','、'\n'など、1文字の検索に使います。 - strstr
複数文字からなる部分文字列を探す関数です。たとえば“http”、“error”、“.jpg”などの「単語」や「パターン」の検索に使います。
「1文字ならstrchr」「文字列(単語)ならstrstr」と覚えておくと整理しやすくなります。
事前に知っておきたいC言語の文字列の仕組み
C言語の文字列は、他の言語の文字列とは少し仕組みが違います。
そのため文字列検索の関数を理解するには、Cの文字列の基本を知っておくことが重要です。
1つの文字列は、実際にはchar型の配列としてメモリ上に並んでいます。
そして最後には必ず'\0'(ヌル文字)が付きます。
この'\0'が文字列の終わりの印になります。
例として、文字列"cat"は次のようにメモリに並びます。
| インデックス | 中身 |
|---|---|
| 0 | ‘c’ |
| 1 | ‘a’ |
| 2 | ‘t’ |
| 3 | ‘\0’ |
このようにCの文字列は「終端文字付きのchar配列」であり、その先頭のアドレスをchar *のポインタとして扱います。
strchrやstrstrは、この先頭ポインタから順に文字を見て、目的の文字や部分文字列を探していく関数です。
strchrで1文字を検索する基本
strchrとは?文字を探す標準ライブラリ関数
strchrは、文字列の中から指定した1文字が最初に現れる場所を探してくれる関数です。
標準ライブラリの<string.h>で定義されています。
主な用途としては、区切り文字や特定の記号の位置を知りたいときに使います。
例えば次のような処理です。
- メールアドレス中の‘@’を探す
- CSVの1行から‘,’の位置を探す
- 文章中の最初の‘.’を見つけて、そこまでを1文として切り出す
strchrの書式と引数の意味
strchrの宣言は次のようになっています。
#include <string.h>
char *strchr(const char *s, int c);
引数の意味を整理すると次のようになります。
| 引数 | 型 | 意味 |
|---|---|---|
| s | const char * | 検索対象となる文字列(先頭ポインタ) |
| c | int | 探したい文字(charとして扱われる) |
ポイントとして、2番目の引数はint型ですが、実際にはcharとして評価されます。
通常は'a'のように文字定数を渡すので、あまり意識しなくても構いません。
strchrの戻り値(charポインタ)の考え方
strchrの戻り値はchar *です。
これは、見つかった位置へのポインタを表します。
- 文字が見つかった場合
→ その文字が格納されている位置を指すchar *が返ります。 - 見つからなかった場合
→NULLが返ります。
具体例として、次のコードを見てみます。
#include <stdio.h>
#include <string.h>
int main(void) {
const char *text = "hello world";
char target = 'o';
// 'o' を検索する
char *pos = strchr(text, target);
if (pos != NULL) {
printf("最初の '%c' は \"%s\" の %ld 文字目にあります。\n",
target,
text,
pos - text); // ポインタ差でインデックスを計算
printf("pos が指す位置以降は \"%s\" です。\n", pos);
} else {
printf("文字 '%c' は見つかりませんでした。\n", target);
}
return 0;
}
最初の 'o' は "hello world" の 4 文字目にあります。
pos が指す位置以降は "o world" です。
ここではposは文字列"hello world"の4番目(0始まり)の’o’を指すポインタになっています。
さらにprintfで"%s"として表示すると、その位置以降の部分文字列が表示されていることも分かります。
見つかった位置をインデックスとして使う方法
ポインタで位置が返されても、初心者のうちは「配列の何番目か」というインデックスで考えたいことが多いと思います。
このときポインタ同士の差を使うと、簡単にインデックスを求められます。
インデックスは次の式で求めます。
見つかった位置のポインタ - 文字列先頭のポインタ
これはptrdiff_t型(通常はlong相当)になるので、%ldなどで表示します。
#include <stdio.h>
#include <string.h>
int main(void) {
const char *str = "ABCDEFABC";
char target = 'D';
char *p = strchr(str, target);
if (p != NULL) {
// インデックスは「見つかった位置 - 先頭位置」
long index = p - str;
printf("文字 '%c' はインデックス %ld にあります。\n", target, index);
} else {
printf("文字 '%c' は見つかりませんでした。\n", target);
}
return 0;
}
文字 'D' はインデックス 3 にあります。
このように、ポインタの差がそのままインデックスになると理解しておくと、strchrと配列インデックスの両方を行き来できて便利です。
見つからないとき(NULL)の扱い方
strchrで最も重要なポイントの1つがNULLチェックです。
目的の文字が見つからなかった場合、戻り値はNULLになります。
NULLかどうかを確認せずにポインタを使うと、未定義動作(クラッシュなど)になります。
典型的な安全な書き方は次のようになります。
#include <stdio.h>
#include <string.h>
int main(void) {
const char *email = "user.example.com"; // '@' がないメールアドレス
char *at = strchr(email, '@');
if (at == NULL) {
printf("メールアドレスに '@' が含まれていません。\n");
// ここでエラー処理などを行う
return 1;
}
// ここに来る時点で、at は必ず '@' を指している
printf("'@' が見つかりました: %s\n", at);
return 0;
}
メールアドレスに '@' が含まれていません。
ポインタを使う前にNULLかどうか必ず確認するという習慣は、文字列関数に限らずC全般で非常に重要です。
終端文字(‘\0’)を検索するときの注意
strchrは、実は終端文字'\0'を検索することもできます。
これは仕様で認められており、便利な場面があります。
#include <stdio.h>
#include <string.h>
int main(void) {
const char *str = "ABC";
// '#include <stdio.h>
#include <string.h>
int main(void) {
const char *str = "ABC";
// '\0' を検索してみる
char *end = strchr(str, '\0');
if (end != NULL) {
long len = end - str;
printf("文字列 \"%s\" の長さは %ld です。\n", str, len);
}
return 0;
}
' を検索してみる
char *end = strchr(str, '#include <stdio.h>
#include <string.h>
int main(void) {
const char *str = "ABC";
// '\0' を検索してみる
char *end = strchr(str, '\0');
if (end != NULL) {
long len = end - str;
printf("文字列 \"%s\" の長さは %ld です。\n", str, len);
}
return 0;
}
');
if (end != NULL) {
long len = end - str;
printf("文字列 \"%s\" の長さは %ld です。\n", str, len);
}
return 0;
}
文字列 "ABC" の長さは 3 です。
これはstrlenと同じ結果が得られています。
実用ではstrlenを使うほうが分かりやすいですが、strchrは終端文字も正しく見つけるという仕様を知っておくと理解が深まります。
ただし、終端の先(未領域)まで検索してしまうようなコードは非常に危険なので、必ずヌル終端された文字列に対してだけstrchrを使うようにしてください。
strchrのよくあるつまずきポイント
初心者がstrchrでつまずきやすいポイントを整理します。
- 戻り値がインデックスだと思ってしまう
実際にはchar *ポインタです。インデックスが必要ならp - sと自分で計算します。 - NULLチェックを忘れる
見つからなかったときにNULLが返るので、そのまま*pやprintf("%s", p)などをすると危険です。 - constの扱い
引数const char *sに対して戻り値はchar *です。しかし、元の文字列がリテラルの場合、書き換えてはいけません。読み取り専用の領域にあることが多く、書き換えは未定義動作になります。
安全のため、文字列リテラルを検索してもstrchrの戻り値を使って書き換えを行わないようにしてください。
strstrで部分文字列を検索する基本
strstrとは?単語や部分文字列を探す関数
strstrは、ある文字列の中から別の文字列(部分文字列)が最初に出現する位置を検索する関数です。
こちらも<string.h>に含まれます。
用途としては、次のような「単語検索」が挙げられます。
- URLから“https://”を探す
- ログメッセージから“ERROR”を探す
- ファイルパスから“.png”を探す
- テキストから“C言語”という語を探す
1文字検索がstrchr、文字列検索がstrstrという関係です。
strstrの書式と引数の意味
strstrの宣言は次の通りです。
#include <string.h>
char *strstr(const char *haystack, const char *needle);
引数の意味を整理します。
| 引数 | 型 | 意味 |
|---|---|---|
| haystack | const char * | 検索対象となる文字列(「干し草」) |
| needle | const char * | 探したい部分文字列(「針」) |
変数名のhaystackとneedleは、英語の「干し草の山から針を探す」という慣用表現から来ています。
haystackが全体の文字列、needleが探したい部分文字列です。
strstrの戻り値とポインタの使い方
strstrもchar *を返します。
意味は見つかった部分文字列の先頭を指すポインタです。
見つからなければNULLを返します。
次のサンプルで動きを確認してみます。
#include <stdio.h>
#include <string.h>
int main(void) {
const char *text = "This is a simple sample.";
const char *word = "simple";
char *p = strstr(text, word);
if (p != NULL) {
long index = p - text;
printf("\"%s\" の中で \"%s\" が見つかりました。\n", text, word);
printf("インデックス: %ld\n", index);
printf("見つかった位置以降: \"%s\"\n", p);
} else {
printf("\"%s\" の中に \"%s\" は見つかりませんでした。\n", text, word);
}
return 0;
}
実行例です。
"This is a simple sample." の中で "simple" が見つかりました。
インデックス: 10
見つかった位置以降: "simple sample."
見つかった位置以降をそのまま部分文字列として扱えるのが、ポインタを返す方式の利点です。
見つからない場合のNULLチェック
strstrも見つからなければNULLを返します。
したがって戻り値に対して必ずNULLチェックが必要です。
#include <stdio.h>
#include <string.h>
int main(void) {
const char *log = "INFO: all systems are normal.";
const char *keyword = "ERROR";
char *pos = strstr(log, keyword);
if (pos == NULL) {
printf("ログに \"%s\" は含まれていません。\n", keyword);
} else {
printf("エラーキーワードが見つかりました: %s\n", pos);
}
return 0;
}
ログに "ERROR" は含まれていません。
NULLかどうかを確認せずに*posやprintf("%s", pos)を行うと危険なので、常にチェックを挟みます。
大文字小文字の違いと検索の挙動
strstrは大文字と小文字を区別します。
つまり、"Hello"の中で"he"を検索しても見つかりません。
#include <stdio.h>
#include <string.h>
int main(void) {
const char *text = "Hello world";
char *p1 = strstr(text, "Hello"); // 一致する
char *p2 = strstr(text, "hello"); // 一致しない(大文字小文字が違う)
printf("検索 \"Hello\": %s\n", (p1 != NULL) ? "見つかった" : "見つからない");
printf("検索 \"hello\": %s\n", (p2 != NULL) ? "見つかった" : "見つからない");
return 0;
}
検索 "Hello": 見つかった
検索 "hello": 見つからない
大文字小文字を区別しない検索を行いたい場合、標準Cには直接の関数はありません。
代わりに次のような工夫が必要になります。
- 検索前に文字列をすべて小文字(または大文字)に変換してから
strstrを使う - 自分で1文字ずつ
tolowerなどを使いながら比較する関数を書く - 環境依存ですが、POSIXの
strcasestrを利用することもあります
初心者のうちは、標準のstrstrは大文字小文字を区別すると覚えておくとよいです。
空文字列を検索したときの特別なルール
strstrには空文字列に関する特別なルールがあります。
探したい文字列needleが""(長さ0)の場合、strstrはhaystackそのものを返します。
#include <stdio.h>
#include <string.h>
int main(void) {
const char *text = "ABC";
// needle が空文字列
char *p = strstr(text, "");
if (p != NULL) {
printf("戻り値は text と同じアドレスですか? -> %s\n",
(p == text) ? "はい" : "いいえ");
printf("p が指す文字列: \"%s\"\n", p);
}
return 0;
}
実行例です。
戻り値は text と同じアドレスですか? -> はい
p が指す文字列: "ABC"
この仕様は標準で定められており、「空文字列はどの文字列にも先頭から含まれている」という考え方に対応しています。
strstrで複数箇所を順に見つける方法
strstrは最初に見つかった位置だけを返します。
しかし、文章の中に同じ単語が何度も出てくることは多いので、複数箇所を順に探したいことがあります。
このときは、見つかった位置から1文字進めて再度strstrを呼び出すことで、次の位置を見つけていきます。
#include <stdio.h>
#include <string.h>
int main(void) {
const char *text = "one and one and one";
const char *word = "one";
const char *p = text; // 検索開始位置
int count = 0;
while (1) {
// p から word を検索
char *found = strstr(p, word);
if (found == NULL) {
break; // これ以上見つからなければ終了
}
long index = found - text;
printf("%d 回目: インデックス %ld に \"%s\" が見つかりました。\n",
count + 1, index, word);
count++;
// 今見つかった位置の1文字先から、さらに検索を続ける
p = found + 1;
}
printf("合計 %d 回見つかりました。\n", count);
return 0;
}
実行例です。
1 回目: インデックス 0 に "one" が見つかりました。
2 回目: インデックス 8 に "one" が見つかりました。
3 回目: インデックス 16 に "one" が見つかりました。
合計 3 回見つかりました。
検索開始位置を少しずつ進めながらstrstrを繰り返し呼ぶというパターンは、実践でよく使うテクニックです。
strchr, strstrを使いこなす実践テクニック
文字列の中から最初の出現位置を調べる
最初の出現位置を知りたいだけであれば、ここまで紹介したようにstrchrやstrstrを1回呼び出し、必要ならインデックスを計算すれば十分です。
次は、ユーザー入力の中から'@'の位置を調べる例です。
見つからなければエラー、見つかれば最初の位置を表示します。
#include <stdio.h>
#include <string.h>
int main(void) {
char email[100];
printf("メールアドレスを入力してください: ");
if (scanf("%99s", email) != 1) {
printf("入力エラーです。\n");
return 1;
}
char *at = strchr(email, '@');
if (at == NULL) {
printf("メールアドレスに '@' が含まれていません。\n");
} else {
long index = at - email;
printf("'@' の位置はインデックス %ld です。\n", index);
}
return 0;
}
メールアドレスを入力してください: user@example.com
'@' の位置はインデックス 4 です。
このように「最初の1件だけ分かればよい」場合はシンプルな書き方で済みます。
文字列の中からすべての出現箇所を列挙する
先ほどstrstrを使って複数箇所を順に探す方法を紹介しました。
同じことはstrchrでも可能です。
次のサンプルは、文字列の中のすべての','の位置を列挙します。
#include <stdio.h>
#include <string.h>
int main(void) {
const char *csv = "apple,banana,orange,,grape";
const char *p = csv; // 検索開始位置
int index = 0;
int field = 0;
printf("文字列: \"%s\"\n", csv);
printf("カンマの位置一覧:\n");
while (1) {
const char *comma = strchr(p, ',');
if (comma == NULL) {
break;
}
index = (int)(comma - csv);
printf(" フィールド区切り %d: インデックス %d\n", field + 1, index);
// 次の検索開始位置を、今見つけたカンマの1文字先にする
p = comma + 1;
field++;
}
return 0;
}
文字列: "apple,banana,orange,,grape"
カンマの位置一覧:
フィールド区切り 1: インデックス 5
フィールド区切り 2: インデックス 12
フィールド区切り 3: インデックス 19
フィールド区切り 4: インデックス 20
「見つけた位置+1」から検索を繰り返すというパターンは、複数の出現箇所を列挙したいときに共通して使えます。
区切り文字を見つけて部分文字列を取り出す
strchrを使うと、文字列を「区切り文字で分割する」処理を自前で実装しやすくなります。
C標準ライブラリにはstrtokという関数もありますが、内部状態を持つため初心者には少し扱いづらい面もあります。
strchrだけで簡単な分割処理を書いてみます。
次の例では、':'で区切られた"キー:値"形式の文字列から、キー部分と値部分を取り出します。
#include <stdio.h>
#include <string.h>
int main(void) {
const char *line = "Content-Type:text/html";
// ':' の位置を探す
const char *colon = strchr(line, ':');
if (colon == NULL) {
printf("区切り文字 ':' が見つかりません。\n");
return 1;
}
// キーと値を格納するバッファ
char key[50];
char value[50];
// キー部分の長さは「':' の位置 - 先頭」
size_t key_len = (size_t)(colon - line);
// 安全のため長さをチェック
if (key_len >= sizeof(key)) {
printf("キーが長すぎます。\n");
return 1;
}
// キー部分をコピーしてヌル終端
memcpy(key, line, key_len);
key[key_len] = '#include <stdio.h>
#include <string.h>
int main(void) {
const char *line = "Content-Type:text/html";
// ':' の位置を探す
const char *colon = strchr(line, ':');
if (colon == NULL) {
printf("区切り文字 ':' が見つかりません。\n");
return 1;
}
// キーと値を格納するバッファ
char key[50];
char value[50];
// キー部分の長さは「':' の位置 - 先頭」
size_t key_len = (size_t)(colon - line);
// 安全のため長さをチェック
if (key_len >= sizeof(key)) {
printf("キーが長すぎます。\n");
return 1;
}
// キー部分をコピーしてヌル終端
memcpy(key, line, key_len);
key[key_len] = '\0';
// 値部分は ':' の次の文字から末尾まで
const char *value_start = colon + 1;
// 安全のため長さチェック
if (strlen(value_start) >= sizeof(value)) {
printf("値が長すぎます。\n");
return 1;
}
strcpy(value, value_start);
printf("キー: \"%s\"\n", key);
printf("値: \"%s\"\n", value);
return 0;
}
';
// 値部分は ':' の次の文字から末尾まで
const char *value_start = colon + 1;
// 安全のため長さチェック
if (strlen(value_start) >= sizeof(value)) {
printf("値が長すぎます。\n");
return 1;
}
strcpy(value, value_start);
printf("キー: \"%s\"\n", key);
printf("値: \"%s\"\n", value);
return 0;
}
キー: "Content-Type"
値: "text/html"
この例では、区切り文字の位置をstrchrで見つけ、そこまでをmemcpyでコピーすることで「キーだけ」を取り出しています。
区切り文字を使ったパース処理の基本パターンです。
拡張子やドメイン名を探す実用的な例
文字列検索は、ファイル名やURLの処理にもよく使われます。
ここではファイルパスから拡張子を取り出す例を見てみます。
拡張子は通常、「最後の'.'の後ろ」なので、strchrではなくstrrchr(最後に一致する位置を探す関数)を使うのが一般的ですが、ここではstrstrとループで簡単に似たことを行う例を紹介します。
#include <stdio.h>
#include <string.h>
int main(void) {
const char *filename = "archive.backup.tar.gz";
const char *dot = filename;
const char *last = NULL;
// すべての "." を順に検索し、最後に見つかった位置を覚えておく
while (1) {
const char *p = strchr(dot, '.');
if (p == NULL) {
break;
}
last = p; // ここまでに見つかった '.' のうち一番後ろのもの
dot = p + 1; // 次の位置から続きを検索
}
if (last == NULL || *(last + 1) == '#include <stdio.h>
#include <string.h>
int main(void) {
const char *filename = "archive.backup.tar.gz";
const char *dot = filename;
const char *last = NULL;
// すべての "." を順に検索し、最後に見つかった位置を覚えておく
while (1) {
const char *p = strchr(dot, '.');
if (p == NULL) {
break;
}
last = p; // ここまでに見つかった '.' のうち一番後ろのもの
dot = p + 1; // 次の位置から続きを検索
}
if (last == NULL || *(last + 1) == '\0') {
printf("拡張子が見つかりません。\n");
} else {
printf("ファイル名: \"%s\"\n", filename);
printf("拡張子: \"%s\"\n", last + 1);
}
return 0;
}
') {
printf("拡張子が見つかりません。\n");
} else {
printf("ファイル名: \"%s\"\n", filename);
printf("拡張子: \"%s\"\n", last + 1);
}
return 0;
}
ファイル名: "archive.backup.tar.gz"
拡張子: "gz"
「最後に見つかった位置」を覚えておくという発想は、拡張子だけでなく、ドメイン名やパスの抽出にも応用できます。
NULLポインタ参照を防ぐ安全な書き方
strchrやstrstrを使うときに最も注意すべきなのはNULLポインタ参照です。
これを防ぐための基本的なルールをまとめます。
1つ目のルールは、関数の戻り値をすぐに変数へ保存し、すぐにNULLチェックを行うことです。
次のような形が典型です。
char *p = strstr(text, "target");
if (p == NULL) {
// 見つからない場合の処理
} else {
// 見つかった場合だけ p を使う処理
}
2つ目のルールは、NULLかどうかを確認する前にデリファレンス(内容参照)しないことです。
たとえば次のような書き方は避けてください。
// 悪い例: p が NULL かもしれないのに、すぐ *p を使っている
char *p = strchr(str, 'x');
if (*p == 'x') {
/* ... */
}
代わりに、かならず先にNULLチェックをします。
// 良い例
char *p = strchr(str, 'x');
if (p != NULL && *p == 'x') {
/* ... */
}
ここでは論理演算の左から順に評価される性質により、p != NULLが偽の場合は*p == 'x'が評価されず、安全に動きます。
3つ目のルールとして、もともとNULLかもしれないポインタを、検索関数の引数に渡さないことも重要です。
char *maybe_null = NULL;
// 悪い例: maybe_null が NULL のままだと未定義動作
char *p = strchr(maybe_null, 'a');
もともとのポインタがNULLになる可能性がある場合は、strchrやstrstrを使う前に、そちらのチェックも行う必要があります。
strchr, strstrと他の文字列関数との組み合わせ方
strchrやstrstrは、それ単体で使うよりも他の文字列関数と組み合わせることで威力を発揮します。
ここではいくつかの代表的な組み合わせを紹介します。
- strchr + strlen
特定の位置までの長さを計算したいときに使います。
const char *str = "path/to/file.txt";
const char *slash = strrchr(str, '/'); // 最後の '/' (ここでは strrchr を使用)
size_t dirname_len = (slash != NULL) ? (size_t)(slash - str) : 0;
- strstr + strncpy(またはmemcpy)
見つかった部分より前や後ろを切り出す処理に使えます。
const char *text = "ID=12345;NAME=Alice";
const char *key = "ID=";
char *p = strstr(text, key);
if (p != NULL) {
p += strlen(key); // "ID=" の直後に進める
char id[10];
int i = 0;
while (*p != ';' && *p != 'const char *text = "ID=12345;NAME=Alice";
const char *key = "ID=";
char *p = strstr(text, key);
if (p != NULL) {
p += strlen(key); // "ID=" の直後に進める
char id[10];
int i = 0;
while (*p != ';' && *p != '\0' && i < (int)sizeof(id) - 1) {
id[i++] = *p++;
}
id[i] = '\0';
printf("ID は %s です。\n", id);
}
' && i < (int)sizeof(id) - 1) {
id[i++] = *p++;
}
id[i] = 'const char *text = "ID=12345;NAME=Alice";
const char *key = "ID=";
char *p = strstr(text, key);
if (p != NULL) {
p += strlen(key); // "ID=" の直後に進める
char id[10];
int i = 0;
while (*p != ';' && *p != '\0' && i < (int)sizeof(id) - 1) {
id[i++] = *p++;
}
id[i] = '\0';
printf("ID は %s です。\n", id);
}
';
printf("ID は %s です。\n", id);
}
- strchr/strstr + strcmp/strncmp
キーワードの位置を探してから、その前後で文字列比較を行うことで、簡易的なパーサを組むことができます。
このように、「検索して位置を特定する関数」+「コピーする関数」+「長さを調べる関数」を組み合わせると、さまざまな文字列処理を表現できるようになります。
まとめ
strchrとstrstrは、C言語で文字列検索を行ううえで欠かせない標準関数です。
strchrは1文字の位置を、strstrは部分文字列の位置をポインタで返すという共通点があり、インデックスへ変換したり、部分文字列としてそのまま利用したりできます。
利用時にはNULLチェックを徹底することと、終端文字'\0'を含むCの文字列の仕組みを理解しておくことが重要です。
ここで紹介した実践テクニックを参考に、区切り文字による分割や、拡張子・キーワード抽出など、さまざまな文字列処理に挑戦してみてください。
