文字列の結合

文字列操作3

文字列の末尾に別の文字列を結合するにはstrcat関数strncat関数、またはstrcat_s関数strncat_s関数を使用します。

strcat_s関数、strncat_s関数はコンパイラによっては使用できません。

strcat関数、strncat関数はVisualStudio既定の設定では使用するとエラーとなります。
詳しくは_s系関数とエラー表示についてを参照してください。

strcat関数、strncat関数

#include <stdio.h>
#include <string.h>

int main()
{
	char strDest1[32] = "ABC";
	char strDest2[32] = "ABC";
	const char strSource[] = "DEF";

	strcat(strDest1, strSource);
	strncat(strDest2, strSource, sizeof(strSource));

	printf("%s\n", strDest1);
	printf("%s\n", strDest2);
	getchar();
}
ABCDEF
ABCDEF
char *strcat(
 char *strDestination,
 const char *strSource
);
文字列strDestinationの末尾に文字列strSourceを結合する。
戻り値は文字列strDestination。
char *strncat(
 char *strDest,
 const char *strSource
 size_t count
);
文字列strDestinationの末尾に文字列strSourceをcount文字分結合する。
終端がNULL文字でない場合はNULL文字に置き換える。
戻り値は文字列strDestination。

これらの関数はいずれも結合される文字列の末尾のNULL文字から文字列の結合が開始されます。
つまり文字列strDestinationの末尾のNULL文字は文字列strSourceの一文字目に置き換えられ、文字列と文字列の間にNULL文字が入ることはありません。

strcpy関数の時と同様、strcat関数は配列サイズのチェック機能がないため、結合先配列のサイズが足りないとバッファオーバーランが発生します。

strncpy関数は第三引数countで結合する文字数を制限できます。
strncpy関数は必ず末尾にNULL文字を付加するため、結合先配列の空き容量ギリギリの値をcountに指定すると、文字列の切り捨てが発生した場合にバッファオーバーランが発生します。
(NULL文字がはみ出る)
なので、countに指定できる値は最大で「空き容量-1」となります。

char strDest[5] = "ABC";
const char strSource[] = "DEF";

//strDest[5]の位置をNULL文字に置き換えてしまう
//(バッファオーバーラン)
//strncat(strDest, strSource, sizeof(strDest) - strlen(strDest));

//strDest[4]の位置がNULL文字になる
strncat(strDest, strSource, sizeof(strDest) - strlen(strDest) - 1);

printf("%s\n", strDest);
ABCD

strcat_s関数、strncat_s関数

#include <stdio.h>
#include <string.h>

int main()
{
	char strDest1[32] = "ABC";
	char strDest2[32] = "ABC";
	const char strSource[] = "DEF";

	strcat_s(strDest1, sizeof(strDest1), strSource);
	strncat_s(strDest2, sizeof(strDest2), strSource, sizeof(strSource));

	printf("%s\n", strDest1);
	printf("%s\n", strDest2);
	getchar();
	getchar();
}
ABCDEF
ABCDEF
errno_t strcat_s(
 char *strDestination,
 size_t numberOfElements,
 const char *strSource
);
文字列strDestination(サイズはnumberOfElements)の末尾に文字列strSourceを結合する。
正常終了すると0を、エラーの場合は0以外を返す。
errno_t strncat_s(
 char *strDest,
 size_t numberOfElements,
 const char *strSource
 size_t count
);
文字列strDest(サイズはnumberOfElements)の末尾に文字列strSourceをcount文字分結合する。
正常終了すると0を、エラーの場合は0以外を返す。

strcat_s関数の第二引数numberOfElementsはstrncat関数の第三引数countとは意味が異なります。
strncat関数のcountは結合される文字列のサイズ指定ですが、strcat_s関数のnumberOfElementsは「結合される文字列+結合する文字列+NULL文字」の総サイズを指定します。
要するに第一引数strDestの(空き容量も含めた)配列サイズを指定します。
このサイズ指定よりも実際に生成される文字列のサイズの方が大きいとプログラムが停止します。

strncat_s関数は第四引数countで結合する文字列のサイズを制限することができます。
配列の空容量-1を指定すれば安全に結合が可能です。

#include <stdio.h>
#include <string.h>

int main()
{
	char strDest1[8] = "ABCDE";
	char strDest2[32] = "ABCDE";
	const char strSource[] = "FGHIJ";

	strncat_s(strDest1, sizeof(strDest1), strSource, sizeof(strDest1) - strlen(strDest1) - 1);
	strncat_s(strDest2, sizeof(strDest2), strSource, sizeof(strDest2) - strlen(strDest2) - 1);

	printf("%s\n", strDest1);
	printf("%s\n", strDest2);
	
	getchar();
}
ABCDEFG
ABCDEFGHIJ

第四引数に_TRUNCATEマクロを指定しても同じ動作となります。

strncat_s(strDest, sizeof(strDest), strSource, sizeof(strDest) - strlen(strDest) - 1);
//↑↓同じ意味
strncat_s(strDest, sizeof(strDest), strSource, _TRUNCATE);