1

私は C++ 文字列を扱ってchar *おりstd::stringstrcpy(). パラメータとして受け取るので、次のようにキャストする必要がありますstrcpy()char *

std::string destination;
unsigned char *source;
strcpy((char*)destination.c_str(), (char*)source);

コードは正常に動作し、デバッガーでプログラムを実行すると、 の値*sourceが に格納されますdestinationが、何らかの奇妙な理由でステートメントで出力されません

std::cout << destination;

使ってみたら気づいた

std::cout << destination.c_str();

値が正しく出力され、すべて問題ありません。なぜこれが起こるのですか?unsigned char*または(stringstreams に) をコピーするより良い方法はありますか?これは、コピー操作のように文字列を指定した場合にのみ発生するchar*ようです。std::stringfoo.c_str()

編集:「なぜこれを行うのですか?」という質問に答えるためにstrcpy()、わかりやすい例を使用しています。割り当てよりも複雑な場合もあります。たとえば、バッファのパラメータとして aを受け取る C ライブラリの関数にa を使用するstrncpy()か、a を渡して、文字列 A の X 量だけを文字列 B にコピーする必要があります。std::stringchar *

4

7 に答える 7

9

ここにあなたが欲しいものがあります

 std::string destination = source;

あなたがしていることは非常に多くのレベルで間違っています...あなたはaの内部表現を上書きしています...std::stringつまり...クールな男ではありません...それよりもはるかに複雑で、配列のサイズが変更され、読み取られます-唯一の記憶...作品。

于 2012-05-08T22:14:54.587 に答える
4

これは、次の2つの理由からまったくお勧めできません。

  1. destination.c_str()はconstポインターであり、constをキャストし、書き込みは未定義の動作です。
  2. 文字列のサイズを設定していません。つまり、アクセス違反を引き起こす可能性のある文字列を保持するのに十分な大きさのバッファさえ必要ありません。

std::stringから構築できるコンストラクタがありますchar*ので、次のように記述します。

std::string destination = source

于 2012-05-08T22:15:55.190 に答える
3

さて、あなたがしているのは未定義の振る舞いです。c_str()はconst char *を返し、に割り当てられることを意図していません。定義されたコンストラクターまたは代入演算子を使用してみませんか。

于 2012-05-08T22:16:12.443 に答える
3

std::string からconst char*の暗黙の変換を定義するstd::stringので、それを使用します。

c_str()を返すようにエラーをキャストすることにしましたconst char*。つまり、基になるバッファへの書き込みは許可されません。あなたはそれを回避するためにあなたができるすべてのことをしました、そしてそれはうまくいきませんでした(あなたはこれに驚かないはずです)。

c_str()const char*正当な理由でを返します。このポインタが文字列の基になるバッファを指しているかどうかはわかりません。このポインタが、新しい文字列を保持するのに十分な大きさのメモリブロックを指しているかどうかはわかりません。ライブラリはそのインターフェイスを使用して、の戻り値をどのようにc_str()使用するかを正確に通知しており、それを完全に無視しています。

于 2012-05-08T22:16:29.553 に答える
1

あなたがしていることをしないでください!!!

繰り返します!

あなたがしていることをしないでください!!!

奇妙なことをするとうまくいくように見えるのは、文字列クラスがどのように実装されたかの結果です。あなたはほぼ間違いなく、そうすべきではないことを記憶に書き込んでおり、他の多くの偽物を書いています。

バッファに書き込む C 関数と対話する必要がある場合、次の 2 つの基本的な方法があります。

std::string read_from_sock(int sock) {
    char buffer[1024] = "";

    int recv = read(sock, buffer, 1024);
    if (recv > 0) {
      return std::string(buffer, buffer + recv);
    }
    return std::string();
}

または、peek メソッドを試すこともできます。

std::string read_from_sock(int sock) {

    int recv = read(sock, 0, 0, MSG_PEEK);
    if (recv > 0) {
      std::vector<char> buf(recv);
      recv = read(sock, &buf[0], recv, 0);
      return std::string(buf.begin(), buf.end());
    }
    return std::string();
}

もちろん、これらはあまり堅牢なバージョンではありません...しかし、要点を示しています。

于 2012-05-08T22:47:38.537 に答える
0

c_strまず、によって返される値はaconst char*であり、変更してはならないことに注意してください。実際には、の内部バッファを指す必要はありませんstring

于 2012-05-08T22:15:45.207 に答える
0

あなたの編集に応じて:

strncpy() を使用して、文字列 A の X 量だけを文字列 B にコピーする必要がある

文字列 A が char 配列で、文字列 B が std::string であり、strlen(A) >= X の場合、次のようにすることができます。

B.assign(A, A + X);

バッファのパラメータとして char * を取る C ライブラリの関数に std::string を渡す

パラメータが実際にconst char *である場合は、そのために使用できますc_str()。ただし、それが単純char *で、C++11 準拠のコンパイラを使用している場合は、次のことができます。

c_function(&B[0]);

ただし、データ用の文字列に余裕があることを確認する必要があります (プレーンな c-string を使用している場合と同じ)。これは、resize()関数の呼び出しで行うことができます。関数が指定されていない量の文字を null で終わる c-string として文字列に書き込む場合、おそらく後で次のように文字列を切り捨てたいと思うでしょう:

B.resize(B.find('\0'));

これを C++03 コンパイラではなく C++11 コンパイラで安全に実行できる理由は、C++03 では文字列が連続していると標準で保証されていなかったからですが、C++11 では連続しているためです。 . C++03 で保証が必要な場合は、std::vector<char>代わりに使用できます。

于 2012-05-08T22:51:54.430 に答える