- 1 1. はじめに
- 2 2. C言語の文字列とは?基本概念と終端文字の重要性
- 3 3. C言語で部分文字列を切り出す方法【標準ライブラリ編】
- 4 4. C言語で部分文字列を切り出す方法【自作関数編】
- 5 5. 文字コードごとの文字列切り出し方法
- 6 6. C言語で文字列を分割する方法
- 7 7. 応用例: 特定の文字の前後を抽出する方法
- 8 8. まとめ
1. はじめに
C言語における文字列の操作は、プログラミングを学ぶうえで重要なスキルの一つです。特に、文字列の切り出し(部分文字列の抽出)は、データの処理やフォーマット変換を行う際によく使われます。
本記事では、C言語で文字列を切り出す方法について、標準ライブラリ関数を使用する方法、自作関数を作成する方法、マルチバイト文字(日本語)への対応、文字列の分割方法などを詳しく解説します。また、応用例やエラー処理についても紹介するので、ぜひ最後までご覧ください。
この記事で学べること
本記事を読むことで、次のようなスキルを習得できます。
- C言語の文字列の基本概念と終端文字
'\0'の役割 strncpyやstrchrなどの標準ライブラリ関数を使った部分文字列の切り出し- 自作関数を用いた文字列操作の実装方法
- マルチバイト文字(日本語)を考慮したUTF-8 や Shift_JIS 文字列の処理
strtokを使った文字列の分割方法- 特定の文字の前後を取得する方法とその応用例
初心者の方でも理解しやすいように、コード例を交えながら解説していきます。
なぜC言語で文字列の切り出しが重要なのか?
C言語は文字列を「配列(char型の配列)」として扱うため、他の高級言語(PythonやJavaScriptなど)のように簡単に部分文字列を取得することができません。そのため、以下のような場面で適切な方法を選択することが重要になります。
1. 入力データの処理
たとえば、ログデータやCSVファイルなどのデータを解析する際に、特定の項目を抽出する必要があります。
2. 特定のキーワードを検索
ある文字列の中から特定のキーワードを探し、その前後の情報を取得することは、検索機能やデータ抽出に不可欠です。
3. プログラムの安全性向上
strncpy のような関数を適切に使用することで、バッファオーバーフロー(バッファサイズを超えるデータの書き込み)を防ぐことができます。これは、セキュリティ上のリスクを回避するために重要です。
本記事の構成
本記事では、以下の流れで解説を進めます。
- C言語の文字列とは?基本概念と終端文字の重要性
- C言語で部分文字列を切り出す方法【標準ライブラリ編】
- C言語で部分文字列を切り出す方法【自作関数編】
- 文字コードごとの文字列切り出し方法
- C言語で文字列を分割する方法
- 応用例: 特定の文字の前後を抽出する方法
- まとめ
- FAQ
それでは、まずは「C言語の文字列とは?基本概念と終端文字の重要性」について詳しく見ていきましょう。
2. C言語の文字列とは?基本概念と終端文字の重要性
2.1 C言語の文字列の基本概念
文字列は「charの配列」
C言語では、文字列を文字の配列(char型の配列)として扱います。例えば、以下のコードは文字列の定義と表示の基本的な例です。
#include <stdio.h>
int main() {
char str[] = "Hello, World!"; // Define a string literal as an array
printf("%s ", str); // Output the string
return 0;
}このコードでは、"Hello, World!" という文字列が char 型の配列として格納され、printf("%s\n", str); によって出力されます。
文字列の内部構造
文字列 "Hello" は、メモリ上では次のように格納されます。
| インデックス | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| 文字 | H | e | l | l | o | \0 |
C言語では、文字列の終端を示す特別な文字(ヌル文字 '\0')が最後に自動的に追加されるため、文字列の長さは 「実際の文字数 + 1」 となります。
2.2 終端文字(ヌル文字 'ヌル文字とは?
')の重要性
ヌル文字とは?
'ヌル文字がない場合の問題
ヌル文字('\0')は、文字列の終わりを示す特殊な文字です。C言語の文字列を正しく扱うためには、このヌル文字の存在を理解しておく必要があります。
#include <stdio.h>
int main() {
char str[6] = {'H', 'e', 'l', 'l', 'o', '\0'}; // Explicitly specify the null terminator
printf("%s ", str); // Display correctly
return 0;
}上記のコードでは、'\0' がないと "Hello" の終端が認識されず、意図しない動作が発生する可能性があります。
2.3 文字列の正しい定義方法
以下のように、終端文字を忘れてしまうと、メモリの異常な動作を引き起こす可能性があります。
#include <stdio.h>
int main() {
char str[5] = {'H', 'e', 'l', 'l', 'o'}; // Does not include the null terminator
printf("%s ", str); // May cause unexpected behavior
return 0;
}
}エラーの原因
printf("%s\n", str);はヌル文字'\0'を見つけるまで文字を出力し続ける。- もし
'\0'がなければ、メモリ上の他のデータが出力される可能性がある。
方法① 文字列リテラルを使用する
方法② 明示的に配列を定義する
最も一般的な文字列の定義方法は、文字列リテラルを使うことです。
char str[] = "Hello";この方法では、Cコンパイラが自動的にヌル文字 '\0' を追加してくれるため、特別な処理は不要です。
2.4 文字列のサイズを確認する方法
手動で '\0' を含めて定義する場合は、次のように記述します。
char str[6] = {'H', 'e', 'l', 'l', 'o', '\0'};- 文字数 +1 のサイズを指定し、最後に
'\0'を入れることが重要。 - もし
str[5]に'\0'を入れ忘れると、予期しない動作が発生する。
strlen の動作
文字列の長さ(文字数)を取得するためには、strlen 関数を使用します。
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Hello";
printf("Length of the string: %lu\n", strlen(str)); // Outputs 5 (does not include the null terminator)
return 0;
}
}2.5 まとめ
strlenは、ヌル文字'\0'が現れるまでの文字数を数える。sizeof(str)と異なり、配列のサイズではなく「実際の文字列の長さ」を取得する。
3. C言語で部分文字列を切り出す方法【標準ライブラリ編】
- C言語の文字列は
char配列で表現される。 - 終端文字(ヌル文字
'\0')が文字列の終わりを示すため、必ず含める必要がある。 - 文字列の長さを取得するには
strlenを使う。 - 適切な方法で文字列を定義しないと、予期しないエラーが発生する可能性がある。

3.1 strncpy を使った部分文字列の取得
C言語で部分文字列を切り出すには、標準ライブラリを活用する方法があります。本セクションでは、strncpy や strchr などの標準ライブラリ関数を使用して、文字列を部分的に取得する方法を解説します。
strncpy の基本構文
strncpy は、文字列の一部を別のバッファにコピーする関数です。
基本的な使用例
char *strncpy(char *dest, const char *src, size_t n);dest: コピー先のバッファsrc: コピー元の文字列n: コピーする最大文字数('\0'を含めない)
strncpy の注意点
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest[6]; // Buffer to store the substring
strncpy(dest, src, 5); // Copy the first 5 characters "Hello"
dest[5] = '\0'; // Manually add the null terminator
printf("Substring: %s\n", dest); // Output "Hello"
return 0;
}
}3.2 strncpy_s を使った安全な文字列コピー
- ヌル文字
'\0'を手動で追加する必要がある
strncpyは最大n文字をコピーするが、'\0'を自動的に追加しないため、明示的にdest[n] = '\0';を追加する必要があります。 - バッファオーバーフローに注意
destのサイズよりnが大きいと、バッファを超えて書き込む可能性があります。
strncpy_s の基本構文
strncpy_s は、strncpy の安全性を強化したバージョンで、バッファオーバーフローを防ぐことができます。
使用例
errno_t strncpy_s(char *dest, rsize_t destsz, const char *src, rsize_t n);dest: コピー先のバッファdestsz:destのサイズsrc: コピー元の文字列n: コピーする最大文字数
strncpy_s のメリット
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest[6];
if (strncpy_s(dest, sizeof(dest), src, 5) == 0) {
dest[5] = '\0'; // Add null terminator just in case
printf("Substring: %s\n", dest);
} else {
printf("Copy error\n");
}
return 0;
}
}3.3 strchr を使った特定の文字までの切り出し
- バッファサイズ (
destsz) を指定するため、安全にコピーできる。 destszよりnが大きい場合、エラーを返す。
ただし、strncpy_s はC11規格で追加されたため、一部の環境では使用できない点に注意が必要です。
strchr の基本構文
strchr を使うと、特定の文字の位置を見つけ、その部分までの文字列を取得できます。
使用例
char *strchr(const char *str, int c);str: 検索対象の文字列c: 探したい文字(char型)
ポイント
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Hello, World!";
char *pos = strchr(str, ','); // Find the position of ','
if (pos != NULL) {
int length = pos - str; // Calculate the number of characters up to ','
char result[20];
strncpy(result, str, length);
result[length] = '\0'; // Add the null terminator
printf("Substring: %s\n", result); // Output "Hello"
}
return 0;
}3.4 strstr を使ったキーワード検索と切り出し
strchrは最初に見つかったcのアドレスを返すため、部分文字列の範囲を決定するのに使える。pos - strで部分文字列の長さを計算し、strncpyでコピーすれば特定の文字までの部分文字列が取得可能。
strstr の基本構文
strstr は、部分文字列を検索し、そこから先の文字列を取得するのに便利です。
使用例
char *strstr(const char *haystack, const char *needle);haystack: 検索対象の文字列needle: 検索する部分文字列
ポイント
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Hello, World!";
char *pos = strstr(str, "World"); // Search for the position of "World"
if (pos != NULL) {
printf("Found substring: %s\n", pos);
} else {
printf("Substring not found.\n");
}
return 0;
}3.5 まとめ
strstrは最初に見つかったneedleのポインタを返す。NULLが返る場合、needleがhaystackに存在しない。
4. C言語で部分文字列を切り出す方法【自作関数編】
strncpyを使うと、部分文字列を安全にコピーできるが、ヌル文字を手動で追加する必要がある。strncpy_sはdestszを指定でき、安全性が向上する。strchrを使えば、特定の文字までの部分文字列を取得できる。strstrを使えば、特定のキーワードの位置を取得し、そこから先を切り出せる。
標準ライブラリを活用することで、C言語での文字列処理をシンプルかつ安全に実装できます。
4.1 自作関数を作るメリット
標準ライブラリを活用すれば、基本的な部分文字列の切り出しは可能ですが、場合によってはより柔軟な方法が求められることがあります。そこで、本セクションでは自作関数を使った部分文字列の切り出しについて解説します。
4.2 基本的な部分文字列抽出関数
標準ライブラリを使うと、部分文字列のコピーや検索ができますが、以下のような問題点があります。
strncpyはヌル文字'\0'を自動追加しないstrchrやstrstrは部分的な検索しかできない- より柔軟な文字列の操作が難しい
そのため、特定の用途に応じてカスタマイズできる自作関数を作成するのが有効です。
関数の仕様
まず、指定した位置から文字列を切り出す基本的な関数を作成します。
実装コード
- 引数
const char *source(元の文字列)int start(開始位置)int length(切り出す文字数)char *dest(切り出した文字列を格納するバッファ)- 処理内容
startからlength分の文字列をdestにコピーする'\0'を自動的に追加
ポイント
#include <stdio.h>
#include <string.h>
void substring(const char *source, int start, int length, char *dest) {
int i;
for (i = 0; i < length && source[start + i] != '\0'; i++) {
dest[i] = source[start + i];
}
dest[i] = '\0'; // Add null terminator
}
int main() {
char text[] = "Hello, World!";
char result[10];
substring(text, 7, 5, result); // Extract "World"
printf("Substring: %s\n", result);
return 0;
}4.3 malloc を使用した動的な部分文字列取得
forループで指定されたlengthの文字をコピー。'\0'に到達した場合はループを終了。dest[i] = '\0';を追加して必ずヌル文字を末尾に配置。
関数の仕様
上記の関数では、dest のサイズを事前に確保する必要があります。しかし、必要なサイズを動的に確保できれば、より汎用的な関数になります。
実装コード
- 必要なメモリを
mallocで確保 startからlength文字分の部分文字列を新しいバッファにコピー- 呼び出し元で
freeする必要がある
ポイント
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *substring_dynamic(const char *source, int start, int length) {
char *dest = (char *)malloc(length + 1); // +1 for the null terminator
if (dest == NULL) {
return NULL; // Memory allocation failed
}
int i;
for (i = 0; i < length && source[start + i] != '\0'; i++) {
dest[i] = source[start + i];
}
dest[i] = '\0';
return dest;
}
int main() {
char text[] = "Hello, World!";
char *result = substring_dynamic(text, 7, 5);
if (result != NULL) {
printf("Substring: %s\n", result);
free(result); // Free allocated memory
} else {
printf("Memory allocation failed.\n");
}
return 0;
}4.4 マルチバイト文字(日本語)対応
mallocで動的にメモリを確保するため、バッファのサイズを気にせずに済む。- 使用後は
free(result);でメモリを解放する必要がある。
マルチバイト文字を考慮した実装
日本語(UTF-8 などのマルチバイト文字)を扱う場合、1文字が 1バイトとは限らない ため、単純な substring 関数では正しく動作しません。
実装コード(UTF-8 対応)
mbstowcsを使用し、マルチバイト文字列をワイド文字列(wchar_t)に変換wcsncpyを使用して部分文字列を取得wcstombsで再びマルチバイト文字列に戻す
ポイント
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <locale.h>
void substring_utf8(const char *source, int start, int length, char *dest) {
setlocale(LC_ALL, ""); // Set the locale
wchar_t wsource[256];
mbstowcs(wsource, source, 256); // Convert UTF-8 string to wide-character string
wchar_t wresult[256];
wcsncpy(wresult, wsource + start, length); // Extract substring in wide characters
wresult[length] = L'\0';
wcstombs(dest, wresult, 256); // Convert back to multibyte string
}
int main() {
char text[] = "こんにちは、世界!"; // UTF-8 string
char result[20];
substring_utf8(text, 5, 3, result); // Extract "世界"
printf("Substring: %s\n", result);
return 0;
}4.5 まとめ
setlocale(LC_ALL, "");でロケールを設定し、マルチバイト対応。mbstowcsでマルチバイト文字列をワイド文字列に変換。wcsncpyで部分文字列を取得後、wcstombsでマルチバイトに戻す。
5. 文字コードごとの文字列切り出し方法
substringを自作すれば、柔軟に部分文字列を取得できる。- 動的メモリ確保 (
malloc) を利用すると、可変サイズの部分文字列を取得可能。 - マルチバイト文字(日本語)を扱う場合は、
mbstowcs/wcstombsを活用する。
標準ライブラリの strncpy や strchr では対応しづらい場合、自作関数を作成することで、C言語の文字列処理をより強力にすることができます。
5.1 ASCII(1バイト文字)の場合
C言語では、文字コードの違いに注意しないと、文字列の切り出し処理が正しく動作しないことがあります。特に、日本語のようなマルチバイト文字(UTF-8、Shift_JIS、EUC-JPなど)を扱う場合、1文字=1バイトではないため、単純な strncpy や substring 関数では適切に処理できません。
本セクションでは、文字コードごとの文字列切り出し方法について詳しく解説します。
基本的な部分文字列取得
実装例
ASCII 文字は 1文字 = 1バイト なので、strncpy や substring 関数で簡単に処理できます。
5.2 UTF-8(マルチバイト文字)の場合
#include <stdio.h>
#include <string.h>
void substring_ascii(const char *source, int start, int length, char *dest) {
strncpy(dest, source + start, length);
dest[length] = '\0'; // Add null terminator
}
int main() {
char text[] = "Hello, World!";
char result[6];
substring_ascii(text, 7, 5, result); // Extract "World"
printf("Substring: %s\n", result);
return 0;
}ポイント
- ASCII 文字(英数字のみ)の場合は
strncpyで十分対応可能 '\0'(ヌル文字)を必ず追加する
UTF-8 の特性
正しい処理方法
UTF-8 では、1文字のバイト数が 1~4バイト と可変のため、単純に strncpy を使うと文字の途中で切れてしまう可能性があります。
UTF-8 に対応した部分文字列取得
C言語では、UTF-8 を安全に処理するには mbstowcs を使ってワイド文字列(wchar_t)に変換し、部分文字列を取得する方法が推奨されます。
5.3 Shift_JIS(マルチバイト文字)の場合
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <locale.h>
void substring_utf8(const char *source, int start, int length, char *dest) {
setlocale(LC_ALL, ""); // Set the locale
wchar_t wsource[256];
mbstowcs(wsource, source, 256); // Convert multibyte string to wide-character string
wchar_t wresult[256];
wcsncpy(wresult, wsource + start, length); // Get the substring
wresult[length] = L'\0';
wcstombs(dest, wresult, 256); // Convert wide-character string back to multibyte
}
int main() {
char text[] = "こんにちは、世界!"; // UTF-8 string
char result[20];
substring_utf8(text, 5, 3, result); // Extract "世界"
printf("Substring: %s\n", result);
return 0;
}ポイント
setlocale(LC_ALL, "");でロケール設定をしないと、マルチバイト文字が正しく処理されない。mbstowcsでマルチバイト文字列をwchar_tに変換し、wcsncpyで安全に処理する。wcstombsで再びマルチバイト文字列に戻す。
Shift_JIS の特性
Shift_JIS に対応した部分文字列取得
Shift_JIS では、1文字が1バイトまたは2バイト になるため、単純な strncpy では文字化けの原因になります。
Shift_JIS での実装
Shift_JIS の場合も ワイド文字列に変換して処理する方法 が推奨されます。
5.4 EUC-JP(マルチバイト文字)の場合
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <locale.h>
void substring_sjis(const char *source, int start, int length, char *dest) {
setlocale(LC_ALL, "Japanese"); // Set locale to handle Shift_JIS
wchar_t wsource[256];
mbstowcs(wsource, source, 256); // Convert multibyte string (Shift_JIS) to wide-character string
wchar_t wresult[256];
wcsncpy(wresult, wsource + start, length); // Extract substring
wresult[length] = L'\0';
wcstombs(dest, wresult, 256); // Convert wide-character string back to multibyte (Shift_JIS)
}
int main() {
char text[] = "こんにちは、世界!"; // Shift_JIS string (depending on environment)
char result[20];
substring_sjis(text, 5, 3, result); // Extract "世界"
printf("Substring: %s\n", result);
return 0;
}ポイント
- Shift_JIS を正しく処理するには
setlocale(LC_ALL, "Japanese");を設定。 mbstowcsとwcstombsを使用して、安全に文字列を処理。
EUC-JP の特性
EUC-JP に対応した部分文字列取得
EUC-JP も Shift_JIS と同様に、1文字のバイト数が異なるため、ワイド文字を利用した変換処理が必要 になります。
5.5 まとめ
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <locale.h>
void substring_eucjp(const char *source, int start, int length, char *dest) {
setlocale(LC_ALL, "ja_JP.eucJP"); // Set locale to handle EUC-JP
wchar_t wsource[256];
mbstowcs(wsource, source, 256); // Convert multibyte string (EUC-JP) to wide-character string
wchar_t wresult[256];
wcsncpy(wresult, wsource + start, length); // Extract substring
wresult[length] = L'\0';
wcstombs(dest, wresult, 256); // Convert wide-character string back to multibyte (EUC-JP)
}
int main() {
char text[] = "こんにちは、世界!"; // EUC-JP string (depending on environment)
char result[20];
substring_eucjp(text, 5, 3, result); // Extract "世界"
printf("Substring: %s\n", result);
return 0;
}ポイント
setlocale(LC_ALL, "ja_JP.eucJP");で EUC-JP のロケールを設定。mbstowcs/wcstombsを使い、マルチバイト文字を正しく処理。
6. C言語で文字列を分割する方法
| 文字コード | バイト数 | 推奨する処理方法 |
|---|---|---|
| ASCII | 1バイト | strncpy でOK |
| UTF-8 | 1~4バイト | mbstowcs / wcstombs を使用 |
| Shift_JIS | 1 or 2バイト | mbstowcs / wcstombs を使用 |
| EUC-JP | 1 or 2バイト | mbstowcs / wcstombs を使用 |
- ASCII 文字のみなら
strncpyでOK - UTF-8, Shift_JIS, EUC-JP の場合は
mbstowcs/wcstombsを使用 - 環境に応じて
setlocale(LC_ALL, "...");を適切に設定する
6.1 strtok を使った文字列分割
文字列を分割する処理は、CSVデータの解析、コマンドラインの引数処理、ログデータの解析など、多くの場面で必要になります。C言語では、strtok や strtok_r などの標準ライブラリ関数を使う方法や、自作関数を作る方法があります。
本セクションでは、文字列を特定の区切り文字で分割する方法について詳しく解説します。
基本構文
strtok は、指定した区切り文字(デリミタ)で文字列を分割する関数です。
使用例:カンマ , で文字列を分割
char *strtok(char *str, const char *delim);str: 分割対象の文字列(最初の呼び出し時に指定)delim: 区切り文字(複数指定可能)- 戻り値: 最初のトークン(分割された最初の部分)
- 注意点:
strtokは元の文字列を改変する(区切り文字を'\0'に変える)
実行結果
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "apple,banana,orange,grape"; // String to be split
char *token = strtok(str, ","); // Get the first token
while (token != NULL) {
printf("Token: %s\n", token);
token = strtok(NULL, ","); // Get the next token
}
return 0;
}strtok の注意点
token: apple
token: banana
token: orange
token: grape6.2 strtok_r を使ったスレッドセーフな文字列分割
- 元の文字列を変更する
strtokは、区切り文字を'\0'に書き換える ため、元の文字列が失われる。
- スレッドセーフではない
strtokはグローバルな静的変数を内部で使用するため、マルチスレッド環境では使わない方がよい。
基本構文
strtok_r は、strtok のスレッドセーフ版であり、状態を saveptr に保存するため、マルチスレッド環境でも安全に使用可能です。
使用例:スペース で文字列を分割
char *strtok_r(char *str, const char *delim, char **saveptr);str: 分割対象の文字列(最初の呼び出し時に指定)delim: 区切り文字(複数指定可能)saveptr: 内部状態を保持するポインタ(呼び出しごとに更新)
strtok_r のメリット
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "Hello World from C"; // String to be split
char *token;
char *saveptr; // Pointer to store internal state
token = strtok_r(str, " ", &saveptr); // Get the first token
while (token != NULL) {
printf("Token: %s\n", token);
token = strtok_r(NULL, " ", &saveptr); // Get the next token
}
return 0;
}6.3 自作関数で文字列を分割する(strtok を使わない方法)
- スレッドセーフ
- 複数の文字列を並行処理できる
自作関数の仕様
strtok は元の文字列を変更するため、変更せずに文字列を分割する自作関数を作成することも可能です。
実装コード
- 入力
const char *source(元の文字列)const char delim(区切り文字)char tokens[][50](分割された文字列を格納する配列)- 処理
sourceをコピーし、オリジナルを変更しないようにするdelimに基づいてtokensに分割結果を格納
実行結果
#include <stdio.h>
#include <string.h>
void split_string(const char *source, char delim, char tokens[][50], int *count) {
int i = 0, j = 0, token_index = 0;
while (source[i] != '\0') {
if (source[i] == delim) {
tokens[token_index][j] = '\0';
token_index++;
j = 0;
} else {
tokens[token_index][j] = source[i];
j++;
}
i++;
}
tokens[token_index][j] = '\0';
*count = token_index + 1;
}
int main() {
char text[] = "dog,cat,bird,fish";
char tokens[10][50]; // Can store up to 10 words
int count;
split_string(text, ',', tokens, &count);
for (int i = 0; i < count; i++) {
printf("Token: %s\n", tokens[i]);
}
return 0;
}ポイント
Token: dog
Token: cat
Token: bird
Token: fish
6.4 文字列分割の応用(CSVデータの処理)
sourceを変更せずにコピーを作成して処理する。tokens配列に分割結果を格納し、オリジナルの文字列を保持する。
CSVデータ解析の例
CSV(カンマ区切り)データを strtok を使って解析することができます。
実行結果
#include <stdio.h>
#include <string.h>
int main() {
char csv[] = "Alice,24,Female\nBob,30,Male\nCharlie,28,Male"; // CSV data
char *line = strtok(csv, "\n"); // Process line by line
while (line != NULL) {
char *name = strtok(line, ",");
char *age = strtok(NULL, ",");
char *gender = strtok(NULL, ",");
printf("Name: %s, Age: %s, Gender: %s\n", name, age, gender);
line = strtok(NULL, "\n");
}
return 0;
}6.5 まとめ
Name: Alice, Age: 24, Gender: Female
Name: Bob, Age: 30, Gender: Male
Name: Charlie, Age: 28, Gender: Male結論
| 方法 | メリット | デメリット |
|---|---|---|
strtok | 簡単に分割できる | 元の文字列を変更する |
strtok_r | スレッドセーフ | 使い方が少し複雑 |
| 自作関数 | 元の文字列を変更しない | コードが長くなる |
| CSV解析 | データ処理に便利 | strtok の制限に注意 |
7. 応用例: 特定の文字の前後を抽出する方法
- 単純な分割なら
strtok - マルチスレッドなら
strtok_r - オリジナルを変更したくないなら自作関数
- CSVデータ解析にも応用可能
次のセクションでは、「応用例: 特定の文字の前後を抽出する方法」について詳しく解説します。
7.1 strchr を使って特定の文字の前の文字列を取得
文字列の処理では、特定の文字やキーワードの前後を抽出する操作が必要になることがよくあります。たとえば、以下のようなケースが考えられます。
- URL からドメイン部分のみを取得
- ファイルパスからファイル名を抽出
- 特定のタグや記号の前後の文字列を取得
C言語では、strchr や strstr を利用することで、こうした処理を実現できます。また、より柔軟な処理が必要な場合は、自作関数を作成する方法も有効です。
基本構文
strchr を使うと、特定の文字(最初に見つかったもの)の位置を特定できます。
使用例: ファイルパスからファイル名を取得
char *strchr(const char *str, int c);str: 検索対象の文字列c: 探したい文字(char型)
strchr は c を見つけた場合、そのアドレスを返します。
実行結果
#include <stdio.h>
#include <string.h>
void get_filename(const char *path, char *filename) {
char *pos = strrchr(path, '/'); // Search for the last '/'
if (pos != NULL) {
strcpy(filename, pos + 1); // Copy from the character after '/'
} else {
strcpy(filename, path); // If no '/', copy the whole path
}
}
int main() {
char path[] = "/home/user/documents/report.txt";
char filename[50];
get_filename(path, filename);
printf("Filename: %s\n", filename);
return 0;
}ポイント
Filename: report.txt7.2 strstr を使って特定のキーワードの後の文字列を取得
strrchrを使うことで、最後に出現した特定の文字(/)の位置を取得できる。pos + 1で、スラッシュの次の文字列をコピーすれば、ファイル名だけを取得可能。
基本構文
strstr を使うと、特定の文字列(キーワード)を検索し、その位置から先の文字列を取得できます。
使用例: URL からドメインを取得
char *strstr(const char *haystack, const char *needle);haystack: 検索対象の文字列needle: 検索する部分文字列
strstr は needle を見つけた場合、その位置のアドレスを返します。
実行結果
#include <stdio.h>
#include <string.h>
void get_domain(const char *url, char *domain) {
char *pos = strstr(url, "://"); // Search for the position of "://"
if (pos != NULL) {
strcpy(domain, pos + 3); // Copy from the character after "://"
} else {
strcpy(domain, url); // If "://" is not found, copy the entire string
}
}
int main() {
char url[] = "https://www.example.com/page.html";
char domain[50];
get_domain(url, domain);
printf("Domain part: %s\n", domain);
return 0;
}ポイント
Domein part: www.example.com/page.html7.3 strchr を使って特定の文字の前後の部分を分割
strstrを使って"https://"や"http://"の"//"以降を取得。pos + 3で://の次からコピー。
使用例: メールアドレスからユーザー名とドメインを分離
strchr を活用すれば、特定の文字の前後の文字列を分割して取得できます。
実行結果
#include <stdio.h>
#include <string.h>
void split_email(const char *email, char *username, char *domain) {
char *pos = strchr(email, '@'); // Search for the position of '@'
if (pos != NULL) {
strncpy(username, email, pos - email); // Copy the part before '@'
username[pos - email] = '\0'; // Add null terminator
strcpy(domain, pos + 1); // Copy the part after '@'
}
}
int main() {
char email[] = "user@example.com";
char username[50], domain[50];
split_email(email, username, domain);
printf("Username: %s\n", username);
printf("Domain: %s\n", domain);
return 0;
}ポイント
Username: user
Domain: example.com7.4 応用: HTMLタグ内の特定の属性を抽出
strchrで'@'の位置を検索。strncpyで'@'の前の部分をコピーし、ヌル文字を追加。strcpyで'@'の後の部分をコピー。
使用例: <a href="URL"> から URL を取得
HTML タグの中から特定の属性を取得する場合も、strstr を活用できます。
実行結果
#include <stdio.h>
#include <string.h>
void get_href(const char *html, char *url) {
char *start = strstr(html, "href=\""); // Search for the position of href="
if (start != NULL) {
start += 6; // Move past href="
char *end = strchr(start, '"'); // Search for the next "
if (end != NULL) {
strncpy(url, start, end - start);
url[end - start] = '\0'; // Add null terminator
}
}
}
int main() {
char html[] = "<a href=\"https://example.com\">Click Here</a>";
char url[100];
get_href(html, url);
printf("Extracted URL: %s\n", url);
return 0;
}ポイント
Extracted URL: https://example.com7.5 まとめ
strstrで"href=\""の位置を検索し、6文字分移動。strchrで"(クオート)の位置を検索し、範囲を決定。
結論
| 処理内容 | 使用関数 | メリット |
|---|---|---|
| 特定の文字の前を取得 | strchr / strrchr | シンプルで高速 |
| 特定の文字の後を取得 | strstr | キーワードの検索が可能 |
| 特定の文字で前後を分割 | strchr + strncpy | ユーザー名・ドメイン分割などに便利 |
| HTMLタグの属性取得 | strstr + strchr | Webスクレイピングに応用可能 |
8. まとめ
strchrやstrstrを活用すると、特定の文字・キーワードの前後を簡単に取得できる。- ファイルパスの処理、URLの解析、メールアドレスの分割など、多くの場面で役立つ。
- Webスクレイピングのような高度な処理にも応用可能。
8.1 記事の振り返り
本記事では、C言語における文字列の切り出し方法について、基本から応用まで詳しく解説しました。ここで、各セクションの重要ポイントを振り返り、用途別に最適な方法を整理します。
8.2 用途別の最適な方法
| セクション | 内容 | 重要ポイント |
|---|---|---|
| C言語の文字列の基本 | C言語では文字列は char 配列として扱われ、終端文字 '\0' が重要 | 文字列を扱う際は ヌル終端を忘れないこと |
| 標準ライブラリでの切り出し | strncpy、strchr などを活用 | strncpy は ヌル終端を手動で追加 する必要あり |
| 自作関数による切り出し | 柔軟な substring 関数を作成 | malloc を使うと 可変長の部分文字列取得が可能 |
| 文字コードごとの処理 | UTF-8, Shift_JIS, EUC-JP への対応方法 | mbstowcs / wcstombs を使って ワイド文字に変換するのが安全 |
| 文字列の分割方法 | strtok, strtok_r, 自作関数による分割 | strtok は 元の文字列を変更 するので注意 |
| 特定の文字の前後を抽出 | strchr, strstr によるデータ取得 | ファイル名の取得、URL解析、HTML解析 に応用できる |
1. 部分文字列の切り出し
2. 文字列の分割
| 使用場面 | 最適な方法 |
|---|---|
| 一定の長さの文字列を取得したい | strncpy or substring() |
| 安全な切り出しをしたい | strncpy_s(C11以降) |
| マルチバイト文字(UTF-8, Shift_JIS, EUC-JP)を扱う | mbstowcs / wcstombs |
3. 特定の文字の前後を取得
| 使用場面 | 最適な方法 |
|---|---|
| シンプルに文字列を区切りたい | strtok |
| スレッドセーフな分割をしたい | strtok_r |
| 元の文字列を変更せずに分割したい | 自作関数(split_string()) |
8.3 C言語の文字列処理の注意点
| 使用場面 | 最適な方法 |
|---|---|
| ファイルパスからファイル名を取得 | strrchr(path, '/') |
| URLからドメイン部分を取得 | strstr(url, "://") |
| メールアドレスからユーザー名とドメインを分離 | strchr(email, '@') |
| HTMLタグから属性値を取得 | strstr(tag, "href=\"") + strchr(tag, '"') |
1. ヌル終端 '安全な文字列コピーの例
' の管理を徹底する
安全な文字列コピーの例
'2. バッファオーバーフローに注意する
C言語の文字列処理では、終端文字 '\0' を適切に管理することが最も重要です。特に strncpy や strchr を使用する際は、ヌル文字を手動で追加するように注意してください。
3. マルチバイト文字の処理には mbstowcs を使う
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest[6];
strncpy(dest, src, 5);
dest[5] = '\0'; // Add null terminator for safety
printf("Substring: %s\n", dest);
return 0;
}4. バッファサイズの管理
C言語の文字列操作では、配列の範囲外にアクセスしないように慎重に実装する必要があります。特に、strncpy を使う際はコピーするバイト数を制御することが重要です。
安全な文字列コピーの例
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest[6];
strncpy(dest, src, sizeof(dest) - 1);
dest[5] = '\0'; // Explicitly add null terminator
printf("Substring: %s\n", dest);
return 0;
}8.4 さらなる学習に向けて
UTF-8 や Shift_JIS などのマルチバイト文字を扱う場合、単純に strncpy や strlen が正しく動作しない。
そのため、マルチバイト文字を扱う場合は、一度 mbstowcs でワイド文字列に変換し、適切に処理することが推奨されます。
#include <stdio.h>
#include <wchar.h>
#include <locale.h>
int main() {
setlocale(LC_ALL, ""); // Set the locale
char text[] = "こんにちは、世界!"; // UTF-8
wchar_t wtext[256];
mbstowcs(wtext, text, 256); // Convert to wide-character string
printf("Converted wide-character string: %ls\n", wtext);
return 0;
}学習を深めるためのトピック
文字列処理では、必要なメモリサイズを事前に計算し、バッファのオーバーフローを防ぐことが重要です。特に、malloc を使って動的メモリを確保する際には、そのサイズを正確に把握するようにしましょう。
8.5 まとめ
C言語の文字列処理は、プログラムの安全性や可読性を向上させる重要なスキルです。本記事で紹介した内容を踏まえて、さらに以下のトピックも学習すると、より高度な文字列処理が可能になります。
学習を深めるためのトピック
- 正規表現(regex)(C言語の外部ライブラリで対応可能)
- ファイル操作(fgets, fscanf を使った文字列処理)
- メモリ管理(malloc, realloc を使った動的文字列処理)
- データ解析(JSON, XML の解析方法)
8.5 まとめ
- C言語の文字列は
char配列で管理されるため、終端文字'\0'の扱いが重要 - 部分文字列の切り出しには
strncpy,substring(),mallocを使う - 文字列の分割には
strtok/strtok_r/ 自作関数を活用 - 特定の文字の前後を取得する場合は
strchr,strstrを活用 - マルチバイト文字(日本語)を扱う場合は、
mbstowcsを利用 - 安全な文字列処理を心がけ、バッファオーバーフローに注意
本記事の内容を活用すれば、C言語での実用的な文字列処理が可能になります。基本的な関数を理解した上で、自作関数や応用処理に挑戦し、より効率的なコードを書けるようになりましょう!



