web-dev-qa-db-ja.com

C ++配列のループの正しい方法

最近、私は多くの例を見つけました。それらのほとんどはC++ 98に関するもので、とにかく単純な配列とループを作成しました( codepad ):

#include <iostream>
using namespace std;

int main ()
{
   string texts[] = {"Apple", "Banana", "Orange"};
   for( unsigned int a = 0; a < sizeof(texts); a = a + 1 )
   {
       cout << "value of a: " << texts[a] << endl;
   }

   return 0;
}

出力:

aの値:Apple 
 aの値:Banana 
 aの値:Orange 
 
 Segmentation fault

最後のセグメンテーションフォールトを除き、正常に機能しています。

私の質問は、この配列/ループスルーは良い方法ですか?私はC++ 11を使用しているので、標準に適合し、より良い方法で実行できないことを確認したいですか?

44
Lucas

C/C++ではsizeof。オブジェクト全体のバイト数を常に与え、配列は1つのオブジェクトとして扱われます。注:sizeofは、配列の最初の要素または単一のオブジェクトへのポインターであり、指すオブジェクトではなくpointerのサイズを与えます。いずれにしても、sizeofnot配列内の要素数(その長さ)を提供します。長さを取得するには、各要素のサイズで除算する必要があります。例えば。、

for( unsigned int a = 0; a < sizeof(texts)/sizeof(texts[0]); a = a + 1 )

それをC++ 11の方法で行う場合、それを行う最良の方法はおそらく

for(const string &text : texts)
    cout << "value of text: " << text << endl;

これにより、コンパイラは必要な反復回数を把握できます。

編集:他の人が指摘したように、C++ 11ではstd::arrayがraw配列よりも優先されます。しかし、他の回答はいずれもsizeofがそのまま失敗する理由を扱っていないため、これがより良い答えだと思います。

76
Nicu Stiurca
string texts[] = {"Apple", "Banana", "Orange"};
for( unsigned int a = 0; a < sizeof(texts); a = a + 1 )
{
    cout << "value of a: " << texts[a] << endl;
}

いや。配列を反復処理するまったく間違った方法です。 sizeof(texts)は配列内の要素の数と等しくありません!

最新のC++ 11の方法は次のとおりです。

  • コンパイル時にサイズがわかっている配列が必要な場合は、std::arrayを使用します。または
  • サイズがランタイムに依存する場合はstd::vectorを使用します

次に、反復時にrange-forを使用します。

#include <iostream>
#include <array>


int main() {
    std::array<std::string, 3> texts = {"Apple", "Banana", "Orange"};
    // ^ An array of 3 elements with the type std::string

    for(const auto& text : texts) {   // Range-for!
        std::cout << text << std::endl;
    }
}

実例


std::arrayはol 'C配列よりもどのように優れているのでしょうか?答えは、他の標準ライブラリコンテナの追加の安全性と機能があり、ほとんどがstd::vectorに似ているということです。さらに、答えは、ポインターに減衰して型情報を失うという癖がないため、元の配列型を失うと、その上でrange-forまたはstd::begin/endを使用できなくなります。

17
Mark Garcia

sizeofは、要素の数ではなく、もののサイズを示します。あなたがやっていることを行うためのより多くのC++ 11の方法は次のとおりです:

#include <array>
#include <string>
#include <iostream>

int main()
{
    std::array<std::string, 3> texts { "Apple", "Banana", "Orange" };
    for (auto& text : texts) {
        std::cout << text << '\n';
    }
    return 0;
}

ideoneデモ: http://ideone.com/6xmSrn

8
kfsone

配列に停止値を追加します。

#include <iostream>
using namespace std;

int main ()
{
   string texts[] = {"Apple", "Banana", "Orange", ""};
   for( unsigned int a = 0; texts[a].length(); a = a + 1 )
   {
       cout << "value of a: " << texts[a] << endl;
   }

   return 0;
}

処理したい要素の非常に短いリストがある場合は、C++ 11で導入された std :: initializer_list をautoと一緒に使用できます。

#include <iostream>

int main(int, char*[])
{
    for(const auto& ext : { ".slice", ".socket", ".service", ".target" })
        std::cout << "Handling *" << ext << " systemd files" << std::endl;

    return 0;
}
1
Phidelux

システム上のsizeof(texts)は96と評価されました:配列とその文字列インスタンスに必要なバイト数。

他の場所で述べたように、sizeof(texts)/sizeof(texts[0])は期待した3の値を与えます。

1
bvj