name
次の C++ コードで が誤動作するのはなぜですか?
string name = "ab"+'c';
同等のコードは Java/C# でどのように動作しますか?
試す
std::string name = "ab" "c";
また
std::string name = std::string("ab") + c;
C++ では、「ab」はstd::string
ではなく、文字列へのポインタです。ポインターに整数値を追加すると、文字列のさらに下を指す新しいポインターが得られます。
char *foo = "012345678910121416182022242628303234";
std::string name = foo + ' ';
name
' ' の整数値は 32 であり、foo の先頭から 32 文字後は文字列の末尾の 4 文字前であるため、"3234" に設定されます。文字列が短い場合は、未定義のメモリ領域にある何かにアクセスしようとしています。
これに対する解決策は、文字配列から std:string を作成することです。std:strings を使用すると、期待どおりに文字を追加できます。
std::string foo = "012345678910121416182022242628303234";
std::string name = foo + ' ';
name
「012345678910121416182022242628303234」に設定されます
問題は、「ab」が C++std::string
ではなく、const char[3]
. したがって、探している + 演算子はoperator+ (const char[3], char)
. それが存在しないため、コンパイラは配列をポインターに減衰させようとするため、 を探しますoperator+ (const char*, char)
。それが存在するため、コンパイラはそれを選択しますが、間違ったことをします。整数値 (char) をポインター (const char*) に追加することは十分に一般的な操作であり、明らかに、この operator+ が行うことです。これを理解するための鍵は、最初の引数が 1) 配列であり、2) 配列が意味をなさない場合はいつでもポインターであることを理解することです。はい、Cでも文字列として使用されましたが、文字列ではありません。これはポインター (場合によっては配列) です。
連結する がありますがoperator+ (const std::string&, char)
、最初の引数が std::string ではないため、コンパイラはそれを探しません。
したがって、解決策は、文字列を手動で作成することです。
string name = std::string("ab")+'c';
これで、コンパイラは呼び出す正しい operator+ を見つけ出すことができます。
C++ では、コンパイラは次のプロトタイプを持つ関数を探します。
T operator+ (const char*, char);
存在しないため、T が何であるかを把握できず、operator<<
呼び出しを解決できないため、残された唯一の解決策であるポインターの追加にフォールバックします。関数が存在するため、ジョシュの答えのように文字列に連結しても問題はありません。
C++ コードを考えると:
std::string name = "ab"+'c';
Java での同等物は次のとおりです。
String name = "ab".substring('c');
どちらも char を int に昇格します。もちろん、Java では範囲がチェックされるため、例外がスローされます。C++ では、未定義の動作 (またはそのようなもの) が発生します。
ジャワ:
public class Main
{
public static void main(String[] args)
{
System.out.println("AB" + 'c');
}
}
出力は次のとおりです。
ABc
編集:
実際、コンパイラは文字列 ABc をハードコードしています...
"AB" + argv[0].charAt(0); を実行すると、変数を使用するようにするには、コンパイラはこれを行います(基本的に):
StringBuilder b = new StringBuilder;
b.append("AB");
b.append(argv[0].charAt(0));
System.out.println(b.toString());
私が通常 C++ で行うことは、
文字列名 = 文字列("ab") +'c';
リテラル "ab" は文字列型ではないことに注意してください。あなたがしていたことは、char 配列と char の間で機能する "+" がないことを望んでいました。その後、結果を std::string にしたいことをコンパイラが何らかの形で認識し、式を解析することを望んでいました。演算子と組み合わせてその型の結果を生成できる暗黙的な変換の組み合わせの右側。私にはかなり難しい注文のようです。
とにかく、それは問題ではありません。ご覧のとおり、C では、配列とポインターの唯一の違いは、メモリの割り当て方法です。一度取得すると、基本的に「配列/ポインターのもの」が得られます。したがって、「+」はすべての配列とポインターで定義された演算子であり、任意の整数型の別の引数を取り、ポインター計算を行い、その場所を過ぎた多くの要素へのポインターを返します。また、C では、「char」は実際には別の種類の整数型です。これらの C 設計の決定はどちらも便利なハックでしたが、ハックでよくあることですが、直感的に予想外の結果をもたらします。つまり、"ab" + 'c' が行うことは、"ab" リテラルがたまたまメモリに格納されている場所から 99 バイト後のアドレスを返すことだけです。
暗黙の変換に頼ることができる場合もありますが、それ以外の場合は、コンパイラを少し支援できるように準備する必要があります。
C++ コンパイラは、文字列リテラルと文字リテラルを自動的に連結しません。ただし、文字列リテラルを互いに連結します。構文は次のようになります。
const char * cs = "ab" "c"; // append string-literals
他の人が述べたように、組み込みのC++ 言語型でstring
はありません。しかし、C++ 標準ライブラリには型があります。以下にいくつかの使用例を示します。string
#include <string>
const char * cs = "ab" "c";
std::string s1( cs );
std::string s2( "ab" "c" );
std::string s3 = "ab" "c";
C# では文字列と文字を連結できます。C++ ほど厳密ではないと思います。
これは C# で問題なく動作します。
string test = "foo" + 'b';