文字列処理

関数

区分 関数 使用方法
文字数の取得 strlen 文字列の長さを取得する
_scprintf 書式設定された文字列内の、文字数を返す
_strncnt 指定した文字数内の文字の、バイト数を返す
書式の設定 sprintf 文字列に書式付きデータを書き込む
vsprintf 引数リストへのポインターを使用して、書式付き出力を書き込む
vsnprintf 引数リストへのポインターを使用して、書式付き出力を書き込む
sscanf 指定した長さの書式付きデータを、標準入力ストリームから読み取る
_snscanf 指定した長さの書式付きデータを、標準入力ストリームから読み取る
strftime 日付と時刻の文字列の書式を設定する
文字の追加 strcat 文字列を、別の文字列に追加する
strncat 文字列の文字を追加する
文字のコピー strcpy 文字列の全体を、別の文字列にコピーする
strncpy 文字列の一部を、別の文字列にコピーする
_strdup 文字列を複製する
文字の検索 strtok 文字列の次のトークンを検索する
_strnextc 文字列の次の文字を検索する
strchr 指定した文字が最初に出現する位置を、文字列内で検索する
strrchr 指定した文字が最後に出現する位置を、文字列内で検索する
strstr 指定した文字列が最初に出現する位置を、別の文字列内で検索する
strcspn 指定した文字セットの文字が最初に出現する位置を検索し、そのインデックスを返す
strpbrk 指定した文字セットの文字が最初に出現する位置を検索し、その文字へのポインタを返す
strspn 別の文字列内では見つからない文字の文字列が最初に出現する位置を、文字列内で検索する
_strspnp 指定した一方の文字列の文字のうち、もう一方の指定した文字列にはない最初の文字へのポインターを返す
文字の変換 _strlwr 文字列を小文字に変換する
_strupr 文字列を大文字に変換する
_strset すべての文字を、指定した文字に置換する
_strnset 先頭のn文字を、指定した文字に置換する
strxfrm ロケール固有の情報に基づいて、文字列を照合形式に変換する
文字列の比較 strcmp 2つの文字列を比較する
strncmp 2つの文字列の部分文字列を比較する
_stricmp 大文字小文字に関係なく、2つの文字列を比較する
_strnicmp 大文字小文字に関係なく、2つの文字列の部分文字列を比較する
strcoll 現在のロケールの情報を使用して、2つの文字列を比較する
_strncoll 現在のロケールの情報を使用して、2つの文字列の部分文字列を比較する
ポインターの操作 _strinc 文字列ポインターを、1文字進める
_strdec 文字列ポインターを、1文字前に移動する
_strninc 文字列ポインターを、n文字進める
その他 _strrev 文字列の順序を逆にする
strerror エラー番号をメッセージ文字列にマップする
文字列操作 (CRT) | MSDN

文字列の生成

文字数の取得

size_t strlen(
   const char *str
);
strlen、wcslen、_mbslen、_mbslen_l、_mbstrlen、_mbstrlen_l | MSDN
char* s1 = "ABC";
wchar_t* w1 = L"ABC";

char* s2 = "あいう";
wchar_t* w2 = L"あいう";


size_t s1_len = strlen(s1); // 3
size_t w1_len = wcslen(w1); // 3

size_t s2_len = strlen(s2); // 6
size_t w2_len = wcslen(w2); // 3


size_t s1_size = sizeof(s1); // 4 (char*型のバイト数)
size_t w1_size = sizeof(w1); // 4 (wchar_t*型のバイト数)

文字の追加

末尾への追加

char *strcat(
   char *strDestination, // NULLで終わる追加先の文字列
   const char *strSource // NULLで終わる元の文字列
);
strcat、wcscat、_mbscat | MSDN

strDestinationの終端のNULLに上書きするように、strSourceを末尾に追加します。そしてstrDestinationのアドレスを返します。

char s[5] = "AA";
strcat(s, "BB"); // AABB\0
strcat(s, "CC"); // バッファオーバーラン発生

追加する文字列が大きすぎると、バッファがオーバーフローします。これを回避するには次のstrncat()を使用します。

char *strncat(
   char *strDest,         // NULLで終わる追加先の文字列
   const char *strSource, // NULLで終わる元の文字列
   size_t count           // 追加する文字数
);
strncat、_strncat_l、wcsncat、_wcsncat_l、_mbsncat、_mbsncat_l | MSDN

strDestinationの終端のNULLに上書きするように、strSourceを最大count文字数だけ末尾に追加します。そしてstrDestinationのアドレスを返します。

char s1[5] = "AA";
strncat(s1, "BBBB", 2); // AABB\0

char s2[5] = "AA";
strncat(s2, "BBBB", 3); // バッファオーバーラン発生

追加する文字数をcountで制限できますが、制限を誤ればバッファオーバーランが発生します。

関数を用いない方法

単純な処理ならば、配列としてアクセスすることで末尾に文字列を追加できます。

char s[5] = "AA";
s[2] = 'B';
s[3] = 'B';
s[4] = NULL; // "AABB\0"

指定位置への追加 (挿入)

sprintf()で書式設定することで、指定位置へ文字列を挿入できます。

char source[] = "ABCD";
char str[] = "xx"; // 挿入する文字列
int pos = 2;       // 挿入する位置

char destination[256];

sprintf(
    destination,
    "%.*s%s%s",
    pos,         // 精度指定で最大文字数を指定
    source,      // 前半部
    str,         // 挿入する文字列
    source + pos // 後半部の位置までポインタをずらして指定
    ); // "ABxxCD"
insert a char in the middle of a string - C / C++

文字の削除

末尾から削除

NULLの位置を移動することで、見かけ上切り詰められます。

char s[] = "ABCD";
s[2] = NULL; // "AB"

文字のコピー

char *strcpy(
   char *strDestination, // コピー先のアドレス
   const char *strSource // コピー元の文字列のアドレス
);
strcpy、wcscpy、_mbscpy | MSDN

strSourceを終端のNULLも含めてstrDestinationへコピーし、strDestinationのアドレスを返します。

char source[] = "ABC";
char destination[256];

char* p = strcpy(destination, source);
// destination[0] … 'A'
// destination[1] … 'B'
// destination[2] … 'C'
// destination[3] … '\0'
// destination[4] … ?
// p == destination は、true

コピー先のstrDestinationに十分な領域がないとバッファオーバーランが発生します。これを防止するにはstrcpy_s()で、呼び出し時に領域のサイズを提供するようにします。

errno_t strcpy_s(
   char *strDestination,
   size_t numberOfElements, // コピー先バッファのchar単位のサイズ。つまり要素数
   const char *strSource
);
strcpy_s、wcscpy_s、_mbscpy_s | MSDN
char source[] = "ABC";
char destination[256];

errno_t error = strcpy_s(destination, 256, source);

次のように_countofマクロを用いれば、要素数を明示する必要はありません。

errno_t error = strcpy_s(destination, _countof(destination), source);

またはテンプレート オーバーロードが有効ならば、要素数の指定すら不要です。

errno_t error = strcpy_s(destination, source);

もしくは_strdup()を用いれば、コピー先の指定すら不要です。

char *_strdup(
   const char *strSource
);
_strdup、_wcsdup、_mbsdup | MSDN

ただしこの関数の戻り値はmalloc()により確保された領域のため、不要になった時点でfree()により解放する必要があります。

一部のコピー

char *strncpy(
   char *strDest,
   const char *strSource,
   size_t count
);
strncpy、_strncpy_l、wcsncpy、_wcsncpy_l、_mbsncpy、_mbsncpy_l | MSDN

strDestの先頭count文字だけをstrSourceへコピーし、strDestを返します。

文字の検索

char *strchr(
   char *str, // 検索対象の文字列
   int c      // 検索する文字
);
strchr、wcschr、_mbschr、_mbschr_l | MSDN

結果はマッチした文字を指すポインタで返されるため、その位置を知りたいならば対象の文字列のポインタから減算します。

char* s = "ABCABC";

int index = -1;
char* ret = strchr(s, 'B');
if( ret != NULL)
{
    index = (int)(ret - s); // 1
}

char* ret1 = strchr(s, 'b'); // NULL
char* ret2 = strchr(s, 'Z'); // NULL

文字の変換

置換

char *_strnset(
   char *str,   // 変換する文字
   int c,       // 設定する文字
   size_t count // 設定する文字の数
);
_strnset、_strnset_l、_wcsnset、_wcsnset_l、_mbsnset、_mbsnset_l | MSDN

文字列strの先頭count文字分を、cに置換します。

char string[15] = "This is a test";
_strnset( string, '*', 4 ); // "**** is a test"

文字列の比較

int strcmp(
    const char *string1,
    const char *string2
);
strcmp、wcscmp、_mbscmp | MSDN

"C"ロケールでは、ASCII文字セット内の順で比較されます。

戻り値 string1string2の関係
-1 (0より小さい値) string1string2より小さい
0 string1string2と同一
1 (0より大きい値) string1string2より大きい
char str1[] = "a";
char str2[] = "b";

int r1 = strcmp(str1, str2); // -1
int r2 = strcmp(str2, str1); // 1
int r3 = strcmp(str1, str1); // 0

strcmp("AB", "BA"); // -1

型変換

数値への変換

文字列を数値に変換する関数 | Microsoft Learn

__int64

__int64 _strtoi64(
   const char *strSource,
   char **endptr,
   int base
);
_strtoi64, _wcstoi64, _strtoi64_l, _wcstoi64_l | Microsoft Learn
char *source = "20";
char *end;

__int64 v1 = _strtoi64(source, &end, 10); // 20
__int64 v2 = _strtoi64(source, &end, 16); // 32

double

double strtod(
   const char *strSource,
   char **endptr
);
strtod, _strtod_l, wcstod, _wcstod_l | Microsoft Learn
char *source1 = "1.23ABC";
char *end1;

double x1 = strtod(source1, &end1);
bool s1 = (source1 == end1); // false
// x1: 1.2300000000000000
// end1: ABC

数値としての解釈に失敗したことは、strSourceendptrが等しいことで確認できます。それ以外の問題は、errnoで確認できます。

char *source2 = "a";
char *end2;

double x2 = strtod(source2, &end2);
bool s2 = (source2 == end2); // true
// x2: 0.0000000000000000
// end2: a

参考

参考書

Microsoft Learnから検索