- ベストアンサー
なぜSTLのstringのサイズが0なのに、printfできちゃうの?
- stringの初期化時に文字列長を確保してしまうことはできない
- strTmpのサイズが0にもかかわらず、printfで期待通りの結果が出力される理由は、printfがヌル文字まで出力するため
- サンプルコードを用いて問題が発生する原因と解決策を説明
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
ざっと見た感じですが、strTempの割り付けられている領域を超えて書き込みを行っているようです。 つまり、未定義の動作なので、たまたま今回のような結果になったと考えるべきです。 > std::transform( str.begin(), str.end(), strTmp.begin(), ptr_fun(::tolower) ); この部分は、 std::transform( str.begin(), str.end(), std::back_inserter(strTmp), ptr_fun(::tolower) ); では? > 1.stringの初期化時に確保した文字列長は、その後変更できないのでしょうか?今まで、普通に""で初期化した後、別の文字列を代入したりしていたような気がするのですが…。 変更できます。 代入やassignでもできますし、push_back、append、resizeなどでも変更できます。 > 2.strTmpのサイズが0にもかかわらず、printfで(一見)期待通りの結果が出力されたのは、なぜでしょうか?printfは、ヌル文字までを出力する仕様みたいですが、そもそもstringのsize()も、ヌル文字までの長さを返すのではなかったでしょうか。 std::stringは、ナル文字までを文字列とするのではなく、別の方法で長さの管理をしているからです。 今回は、正規の方法ではなく、強引にメモリに書き込んでいますので、内部の状態が破壊されているのです。
その他の回答 (2)
- επιστημη(@episteme)
- ベストアンサー率46% (546/1184)
間違ったコードの結果に疑問が生じるのはアタリマエ。 transformするからには出力先には入力と同じかそれ以上のサイズの領域が 確保されていなければなりません。なので正しくは: std::string str = "ABC"; std::string strTmp = ""; strTmp.resize(str.size()); // 領域確保 std::transform( str.begin(), str.end(), strTmp.begin(), std::ptr_fun(::tolower) );
お礼
お礼が遅くなり、すみません。ご回答どうもありがとうございました。ご指摘の通りで、納得しました。
- D-Matsu
- ベストアンサー率45% (1080/2394)
1. std::stringは可変長文字列ですから、stringオブジェクト自体への変更があればそれは反映されます。 2. STLの実装次第です。但し、結果から逆に見ると「文字列長」は別途メンバ変数で持っていてstringオブジェクト自身への演算結果でのみ変更される、という状況に見えます。 で、この前提においてstd::transform()の結果がどうなるかというと…… strTmp.begin()はもちろん内部バッファへのイテレータを返しますね。見掛け上はほぼchar *と変わりません。 となると、ここで「内部バッファにだけ変更がありサイズに適用されない」という状況が発生します。 これでうまく動作しているのは、おそらく文字列長メンバの値とは関係なく一定量のメモリを文字列用に持っているんじゃないかと。
お礼
早速のご回答、どうもありがとうございました。お礼が遅くなり、申し訳ありません。元々不正な処理をしているので、おっしゃるとおり、例外で落ちたりしなかったのは、たまたまだったのですね。すっきりしました。
お礼
お礼が遅くなり、申し訳ありません。早速のご回答、どうもありがとうございました。恥ずかしながら、back_inserterというのがあるのは知りませんでした。挿入イテレータというのですね。stringの長さ管理は\0とは直接関係ないのですね。勉強になりました。