2つの文字を追加しようとしていますが、何らかの理由でセグメンテーション違反が発生しています。
私のコードは次のようなものです。
#include <string.h>
char *one = (char*)("one");
char *two = (char*)("two");
strcat(one, two);
でセグメンテーション違反が発生しているようですが、strcat(one, two)
それはなぜですか?
2つの文字を追加しようとしていますが、何らかの理由でセグメンテーション違反が発生しています。
私のコードは次のようなものです。
#include <string.h>
char *one = (char*)("one");
char *two = (char*)("two");
strcat(one, two);
でセグメンテーション違反が発生しているようですが、strcat(one, two)
それはなぜですか?
http://www.cplusplus.com/reference/clibrary/cstring/strcat/
strcatの最初のパラメーターは、結果の文字列を保持するのに十分な大きさである必要があります
試す:
//assuming a,b are char*
char* sum = new char[strlen(a) +strlen(b)+1];
strcpy(sum,a);
strcat(sum,b);
文字列全体を保持するのに十分な正当なメモリが必要です。
char *one = new char[128]; //allocating enough memory!
const char *two = "two"; //"two" is const char*
strcpy(one, "one");
strcat(one, two); //now the variable "one" has enough memory to hold the entire string
ちなみに、C ++での使用を好む場合は、そのような処理が簡単になりますstd::string
。char*
#include<string>
std::string one = "one";
std::string two = "two";
one = one + two; //Concatenate
std::cout << one;
出力:
onetwo
これには2つの理由があります。
文字列リテラルに初期化されたポインタがある場合、そのメモリは読み取り専用であり、それを変更すると未定義の動作が発生します。この場合、文字列リテラルに文字列を追加しようとすると、この種のメモリが変更されることになり、問題が発生します。
strcatを使用する場合は、指定する場所に文字列を連結するためのスペースが存在することを保証する必要があります。この場合、文字列リテラルはリテラル自体を保持するのに十分なスペースしかないと保証されていないため、これを保証することはできません。
これを修正するには、nullターミネータを含む2つの文字列の連結を保持するのに十分な大きさのバッファを明示的に割り当てる必要があります。これが1つのアプローチです:
char* buffer = malloc(strlen(one) + strlen(two) + 1);
strcpy(buffer, one);
strcat(buffer, two);
お役に立てれば!
セグメンテーション違反は、読み取り専用メモリに書き込もうとしたためです。strcatの最初のアクションは、2の最初のエントリから「1」の最後のnullに「t」をコピーすることです。したがって、厳密に言えば、セグメンテーション違反はストレージの不足によるものではありません。実際、このコードはセグメンテーション違反を引き起こす可能性があります。
char* one = "one";
char* two = "";
strcat(one, two);
これが行おうとするのは、nullをnullの上にコピーすることだけですが、読み取り専用メモリにあります。一部のプラットフォームでは、オプティマイザーがこれを停止する可能性があると思います。
奇妙なことに、次の(正しくない)コードは(おそらく)セグメンテーション違反を引き起こさず、「正しい」答えを与えることさえありません。
char one[] = "one";
char two[] = "two";
strcat(one, two);
printf("%s\n", one);
これにより、私のマシンのstdoutに「onetwo」が正常に書き込まれます。スタックの落書きを取得しますが、これはたまたま回避されます。
一方、これはセグメンテーション違反を行います:
char* one = "one "; // Plenty of storage, but not writable.
char two[] = "two";
strcat(one,two);
したがって、解決策:
const unsigned enoughSpace = 32;
char one[enoughSpace] = "one";
char two[] = "two";
strcat(one,two);
printf("%s\n", one);
もちろん、これに関する問題は、これから来るものを格納するために十分なスペースを作るのにどれくらいの大きさですか?
したがって、関数strncat、strcat_s、またはより簡単にstd::string。
話の教訓:C ++では、Cと同じように、メモリレイアウトが何であるかを本当に知る必要があります。
文字列用にスペースを予約したことはありません。
#include <string.h>
#include <stdio.h>
int main(void){
char str[20] = "";
strcat(str, "one");
strcat(str, "two");
printf("%s", str);
}
これを行う正しい方法の1つになります。もう1つ(そしてもっと良い方法)は、std::string
クラスを使用することです。
#include <string>
#include <cstdio>
int main(void){
std::string str;
str += "one";
str += "two";
std::printf("%s", str.c_str());
}
ここにはいくつかの問題があります。まず、文字列を可変バージョンにキャストしましたが、実際には文字列リテラルであるため、記述しないでください。次に、文字列バッファの長さを完全に無視して、文字列バッファに書き込むstrcatを使用しています(バッファの長さを指定する必要があるstrncatを使用することをお勧めします)。最後に、これはC ++であるため、次のように使用する方がはるかに優れています。
#include <string>
// ...
string one = "one";
string two = "two";
one.append(two);
strcat
ターゲットとして「書き込み可能な」バッファが必要です。あなたの例では、これは文字列定数(またはリテラル)へのポインタであり、書き込むことができないため、例外が発生します。ターゲットバッファは、スタック上のバッファ、または動的に割り当てられたバッファ(たとえば、mallocを使用)にすることができます。
宛先文字列は、宛先文字列とソース文字列の両方を保持するのに十分な大きさである必要があります。したがって、例は次のようになります
char one[10] = "one";
char two[4] = "two";
strcat(one,two);
これは「スペース不足」の問題ではありません。
char *a = "str";
上記のコードを見てください。ポインタaは「静的メモリ」を指しています。文字列「str」はPCBの静的な場所に保存されているため、上書きできません。
したがって、以下のコードの方が優れています。
#include <string>
using std::string;
string a = "stra";
string b = "strb";
a += b;