Cでは、関数strcat
は、連結文字列を含む新しい文字配列を作成しません。新しい文字を格納するのに十分な要素を持っていれば、2番目の文字列の文字を最初の文字配列の最初の文字列に追加します。それ以外の場合、関数は未定義の動作を引き起こす文字配列を越えてメモリを上書きしようとします。
だから、最初のプログラム中の関数の有効な使用は文字の配列は、11個の要素を持つように宣言されたこのプログラムでは、次のよう
#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[]) {
char s1[11] = "12345";
char s2[] = "abcde";
strcat(s1, s2);
puts(s1);
puts(s2);
return 0;
}
を見ることができます。したがって、追加された文字列"abcde"
を収容することができます。
2番目のプログラムでは、ポインタs1
が指す文字列リテラルを変更しようとしています。 CおよびC++の文字列リテラルは不変です。文字列リテラルを変更しようとすると、C++の文字列リテラルとは反対のC言語では非定数文字配列の型がありますが、未定義の動作になります。 C標準(6.4.5文字列リテラル)から
7は、それら 要素が適切な値を持って設けられ、これらの配列が異なっているかどうかを指定されていません。 プログラムが にそのような配列を変更しようとすると、動作は未定義です。
したがって、2番目のプログラムでは、十分な要素を持つ文字配列を使用する必要があります。例
#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[]) {
char s1[11] = "12345";
char* s2 = "abcde";
strcat(s1, s2);
puts(s1);
puts(s2);
return 0;
}
やコンパイラがサポートしているか、動的配列を割り当てる場合は、可変長配列(VLA)のいずれかを使用する可能性があるため。例えば
#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[]) {
char *s1 = "12345";
char* s2 = "abcde";
char s3[strlen(s1) + strlen(s2) + 1];
strcpy(s3, s1);
strcat(s3, s2);
puts(s1);
puts(s2);
puts(s3);
return 0;
}
それとも
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, const char *argv[]) {
char *s1 = "12345";
char* s2 = "abcde";
char *s3 = malloc(strlen(s1) + strlen(s2) + 1);
if (s3 != NULL)
{
strcpy(s3, s1);
strcat(s3, s2);
puts(s1);
puts(s2);
puts(s3);
}
free(s3);
return 0;
}
bashの - >男のstrcatの – Jonas
は、あなたはそれが必要とするメモリを割り当てると信じているようです。まあ、そうではありません。 – Siguza
これらはどちらも未定義の動作です。 – BLUEPIXY