1

スペースで区切られた入力行を取得し、データを 2 つの整数変数に読み取ろうとしています。

たとえば、「0 1」は , を与えるはずchild1 == 0ですchild2 == 1

私が使用しているコードは次のとおりです。

int separator = input.find(' ');
const char* child1_str = input.substr(0, separator).c_str(); // Everything is as expected here.
const char* child2_str = input.substr(
    separator+1,  //Start with the next char after the separator
    input.length()-(separator+1) // And work to the end of the input string.
    ).c_str();     // But now child1_str is showing the same location in memory as child2_str!
int child1 = atoi(child1_str);
int child2 = atoi(child2_str);      // and thus are both of these getting assigned the integer '1'.
// do work

何が起こっているのか、私は果てしなく困惑しています。Eclipse デバッガー (gdb) でシーケンスを監視しています。関数が開始されるchild1_strchild2_str、異なるメモリ位置があることが示されます (本来あるべき姿)。文字列を分割しseparatorて最初の値を取得した後child1_str、期待どおり「0」を保持します。

ただし、値を に割り当てる次の行は、 にchild2_str正しい値を割り当てるだけchild2_strでなく、 を上書きしますchild1_str。文字値が上書きされるという意味でもありません。デバッガーが表示child1_strchild2_strれ、メモリ内の同じ場所を共有することを意味します。

なに?

1) はい、文字列を int に変換するための他の提案を喜んで聞きます - これは私がずっと前にそれを行うことを学んだ方法であり、私はそれで問題を抱えたことがないので、決して必要ありませんでしたただし、次のように変更します。

2) 変換を実行するためのより良い方法があるとしても、ここで何が起こっているのか知りたいです! これは私の最終的な質問です。したがって、より良いアルゴリズムを思いついたとしても、選択された答えは、アルゴリズムが失敗する理由を理解するのに役立つものになります.

3) はい、std::string は C++ で、const char* は標準 C です。atoi には ac 文字列が必要です。入力は、使用しているフレームワークから std::string として絶対に来るため、これを C++ としてタグ付けしています。

4

4 に答える 4

4

まず、優れたソリューション。

std::stoiC++11 では、newfangled関数を使用できます。

int child1 = std::stoi(input.substr(0, separator));

それができない場合は、次を使用できますboost::lexical_cast

int child1 = boost::lexical_cast<int>(input.substr(0, separator));

では、解説です。

input.substr(0, separator)セミコロンで終了する一時 std::stringオブジェクトを作成します。その一時オブジェクトを呼び出すと、一時オブジェクトが存続している間だけ有効なポインタが得られます。これは、次の行でポインタがすでに無効であることを意味します。そのポインターを逆参照すると、未定義の動作が発生します。その後、未定義の動作でよくあるように、奇妙なことが起こります。c_str()

于 2012-07-03T17:06:09.027 に答える
4

c_str()文字列が破棄された後、によって返される値は無効です。したがって、次の行を実行すると:

const char* child1_str = input.substr(0, separator).c_str();

このsubstr関数は一時的な文字列を返します。行が実行されると、この一時文字列は破棄され、child1_strポインターは無効になります。そのポインターにアクセスすると、未定義の動作が発生します。

あなたがすべきことは、結果をsubstrローカルstd::string変数に代入することです。次に、その変数を呼び出すことができますc_str()。その結果は、変数が破棄されるまで (ブロックの最後で) 有効になります。

于 2012-07-03T17:06:54.247 に答える
3

他の人は、現在のコードの問題をすでに指摘しています。変換を行う方法は次のとおりです。

std::istringstream buffer(input);

buffer >> child1 >> child2;

はるかに単純で簡単で、柔軟性が大幅に向上したことは言うまでもありません (たとえば、入力にタブまたは数字の間に 2 つのスペースが含まれていても機能し続けます)。

于 2012-07-03T17:09:19.330 に答える
1

input.substr一時的な を返しますstd::string。どこにも保存していないため、破棄されます。その後どうなるかはあなたの運次第です。

を使用することをお勧めしますistringstream

于 2012-07-03T17:07:05.067 に答える