2

for ループに基づく新しい C++11 範囲を使用しようとしています。これが私のプログラムです:

#include <iostream>
#include <string>
#include <sstream>
#include <fstream>

using namespace std;

ofstream logger("log.txt");
void log(string message)
{
    logger << message << std::endl;
    logger.flush();
}

int main( int argc, char* args[] )
{
    log("hello world");
    cout << "hello world\n";

    log("declare sort me");
    int sortMe[10];

    log("loop sortMe");
    for(int i : sortMe) {
        log("in loop " + i);
        sortMe[i] = i + 1;
    }
}

コンパイルにはclang ++を使用しています。コンパイルすると、次の警告が表示されます。

clang++ -o mycpp mycpp.cpp
mycpp.cpp:24:12: warning: range-based for loop is a C++11 extension
      [-Wc++11-extensions]
        for(int i : sortMe) {
                  ^
1 warning generated.

実行すると、次の出力が得られます。

hello world
Segmentation fault (core dumped)

log.txt ファイルによると、プログラムは for ループに到達しますが、for ループには決して入りません。私は何が欠けていますか?

4

5 に答える 5

10

このループ:

for(int i : sortMe) {
    log("in loop " + i);
    sortMe[i] = i + 1;
}

配列のインデックスではなく、配列に格納されているをループして返します。その結果、ルックアップは配列の完全にランダムなインデックスにジャンプし (おそらく範囲外)、セグメンテーション違反を引き起こします。sortMesortMesortMe[i]

各要素をその位置に等しく設定したい場合は、通常の for ループを使用してください:

for (int i = 0; i < 10; i++) {
    sortMe[i] = i + 1;
}

また、@hmjd が指摘したように、への呼び出しはlog正しく機能しません。これは、文字列の連結ではなく、文字列に対してポインター演算を行っているためです。

お役に立てれば!

于 2013-01-20T21:11:48.387 に答える
5

for標準ループを使用する必要がある範囲ベースのループを使用していforます。int iループ内は現在の要素のインデックスではなく、その要素の値です。つまり、配列に が含まれている場合、各反復で{1, 3, 3, 7}の値は、 then 、 then 、 then になります。配列が初期化されていないため、 の値がどうなるかわからず、未定義の動作が発生します。i1337i

for ループでインデックスが必要な場合は、標準の for ループを使用します。

for(int i = 0; i < 10; i++) {
    log("in loop " + std::to_string(i));
    sortMe[i] = i + 1;
}

で文字列連結を行うに+は、オペランドの 1 つが である必要があることに注意してくださいstd::string。そうしないiと、 の最初の文字を指すポインターに追加され"in loop "ます。

于 2013-01-20T21:11:55.003 に答える
3

for ループ内での log() の呼び出しが正しくありません。引数はポインタ演算の結果であり、不明な int 値が文字列リテラルのベース アドレスからのオフセットとして使用されています。

int を std::string に変換するには、std::to_string() を使用します。

std:iotaについて言及すると、範囲の要素を初期値に基づいて増加する値に設定するために使用できます。

std::iota(std::begin(sortMe), std::end(sortMe), 1);
于 2013-01-20T21:11:23.483 に答える
1

範囲ベースのループがそれとは異なることをすることを期待していると思います...

記述for (int var: array) { log(var); }した場合、コードは配列内の要素の数だけ実行されます。毎回var、配列の要素の 1 つに等しくなります。!varではなく、配列要素として直接使用することに注意してください。array[var]

たとえば、 がある場合int[3] array = { 42, 69, 1337 };、前例の for ループは 42、69、および 1336 をログに記録します。

したがって、単純に行うint[3] array;と、先例の for ループは、配列が格納されているメモリに既にあった 3 つのランダムな整数をループします...var直接使用する代わりに使用するarray[var]と、var がの有効なインデックスarray


解決:

配列要素とインデックスの違いに惑わされないでください...

  • 配列の要素を直接操作したい場合:

    for(int element : sortMe) {
        /* Do something with the element */
    }
    
  • インデックスを使用する場合は、範囲ベースのループを使用しないでください。

    for(int index = 0; index < 10; ++index) {
        /* Do something with the index */
    }
    
于 2013-01-20T21:21:42.947 に答える
0

これに賛成票または反対票を投じないでください。質問者を助けるために通常コメントとして追加するポイントを追加しているだけですが、フォーマットできないため....

新しい方法でやりたいことを実行できますが、それはかなり無意味な作業であり、通常の for ループを使用することをお勧めします。範囲ループは、参照ではなく値を返します。少なくともあなたがそれを使用している方法では。

 int count = 0;
 // Use a reference so we can update sortMe
 for (int& i : sortMe) {
    i = ++count;
 }

見てみると、通常の for ループよりも少しコンパクトで、不思議なことに気に入っています。;)

于 2013-01-20T21:23:02.390 に答える