7

数字のリストを反復処理するにはどうすればよいですか。また、それを実行するためのさまざまな方法がいくつありますか。

私がうまくいくと思ったこと:

#include <cstdlib>
#include <iostream>
#include <list>


using namespace std;


int main()

{
    int numbers[] = {2, 4, 6, 8};
    int i = 0;
    for(i=0; i< numbers.size();i++)
            cout << "the current number is " << numbers[i];


    system("pause");

    return 0;

}

forループ行でエラーが発生します:

非クラスタイプののメンバー'size'のリクエスト'numbers''int[4]'

4

9 に答える 9

28

多くの現代言語とは異なり、プレーンC++配列には関数がありません.size()。ストレージの種類に応じて、リストを反復処理するためのオプションがいくつかあります。

ストレージの一般的なオプションは次のとおりです。

// used for fixed size storage. Requires #include <array>
std::array<type, size> collection;

// used for dynamic sized storage. Requires #include <vector>
std::vector<type> collection;

// Dynamic storage. In general: slower iteration, faster insert
// Requires #include <list>     
std::list<type> collection;  

// Old style C arrays
int myarray[size]; 

反復のオプションは、使用しているタイプによって異なります。単純な古いC配列を使用している場合は、サイズを別の場所に格納するか、配列の型のサイズに基づいて配列のサイズを計算できます。配列のサイズを計算することには、DevSolarによるこの回答で概説されているいくつかの欠点があります

// Store the value as a constant
int oldschool[10];
for(int i = 0; i < 10; ++i) {
    oldschool[i]; // Get
    oldschool[i] = 5; // Set
} 

// Calculate the size of the array
int size = sizeof(oldschool)/sizeof(int);
for(int i = 0; i < size; ++i) {
    oldschool[i]; // Get
    oldschool[i] = 5; // Set
}

.begin()および関数を提供する任意の型を使用している場合は、.end()それらを使用して、インデックスベースの反復と比較してC++で適切なスタイルと見なされるイテレータを取得できます。

// Could also be an array, list, or anything with begin()/end()
std::vector<int> newschool;     

// Regular iterator, non-C++11
for(std::vector<int>::iterator num = newschool.begin(); num != newschool.end(); ++num) {
    int current = *num; // * gets the number out of the iterator
    *num = 5; // Sets the number.
}

// Better syntax, use auto! automatically gets the right iterator type (C++11)
for(auto num = newschool.begin(); num != newschool.end(); ++num) {
    int current = *num; // As above
    *num = 5;
}

// std::for_each also available
std::for_each(newschool.begin(), newschool.end(), function_taking_int);

// std::for_each with lambdas (C++11)
std::for_each(newschool.begin(), newschool.end(), [](int i) {
    // Just use i, can't modify though.
});

ベクトルは、配列のドロップイン置換として設計されているため、特別です。関数を使用して配列を反復処理するのとまったく同じように、ベクトルを反復処理でき.size()ます。ただし、これはC ++では悪い習慣と見なされており、可能な場合はイテレータを使用することをお勧めします。

std::vector<int> badpractice;
for(int i = 0; i < badpractice.size(); ++i) {
    badpractice[i]; // Get
    badpractice[i] = 5; // Set
}

.begin()C ++ 11(新しい標準)は、それに基づいた新しいファンシーな範囲ももたらします。これは、およびを提供するすべてのタイプで機能するはず.end()です。ただし、コンパイラのサポートはこの機能によって異なる場合があります。begin(type)代わりにとを使用することもできますend(type)

std::array<int, 10> fancy;
for(int i : fancy) {
    // Just use i, can't modify though.
}

// begin/end requires #include <iterator> also included in most container headers.
for(auto num = std::begin(fancy); num != std::end(fancy); ++num) {
    int current = *num; // Get
    *num = 131; // Set
}

std::beginまた、もう1つの興味深い特性があります。それは、生の配列で機能します。これは、配列と非配列の間で同じ反復セマンティクスを使用できることを意味します(生の配列よりも標準タイプを優先する必要があります)。

int raw[10];
for(auto num = std::begin(raw); num != std::end(raw); ++num) {
    int current = *num; // Get
    *num = 131; // Set
}

container.erase()呼び出し中に既存のすべてのイテレータが無効になるため、ループ中にコレクションからアイテムを削除する場合にも注意する必要があります。

std::vector<int> numbers;
for(auto num = numbers.begin(); num != numbers.end(); /* Intentionally empty */) {
    ...

    if(someDeleteCondition) {
        num = numbers.erase(num);
    } else {
        // No deletition, no problem
        ++num;
    }
}

このリストは包括的ではありませんが、ご覧のとおり、コレクションを反復処理する方法はたくさんあります。一般に、他の方法で行う正当な理由がない限り、イテレータを優先します。

于 2013-01-16T03:46:11.250 に答える
6

forループをに変更します

 for(i=0; i< sizeof(numbers)/sizeof(int);i++){

簡単 sizeof(numbers)に言うと、配列内の要素の平均数*プリミティブ型intのサイズなので、で割ってsizeof(int)要素の数を取得します

于 2013-01-16T03:29:19.003 に答える
5

次のように修正した場合list<int> numbers = {1,2,3,4}

イテレータを使用した反復:

#include <iterator>

for(auto it = std::begin(numbers); it != std::end(numbers); ++it) { ... }

を使用して繰り返すstd::for_each

#include <algorithm>
#include <iterator>

std::for_each(numbers.begin(), numbers.end(), some_func);

for-eachループの利用(C ++ 11):

for(int i : numbers) { ... }
于 2013-01-16T03:30:46.637 に答える
2

size「プレーンな」Cスタイルの配列には機能がありません。std::vectorを使用する場合はを使用するか、を使用してsizeサイズを計算する必要がありますsizeof

C ++ 11では、次のように、配列初期化構文を使用してベクトルを初期化できます。

vector<int> numbers = {2, 4, 6, 8};

他のすべては同じままです(ここのデモを参照してください)。

于 2013-01-16T03:28:05.880 に答える
2

プレーンな古いCコンテナー使用して、ループにイテレーター構文を使用することもできます。

#include <iostream>

int main()
{
    int numbers[] = {2, 4, 6, 8};
    int *numbers_end = numbers + sizeof(numbers)/sizeof(numbers[0]);
    for (int *it = numbers; it != numbers_end; ++it)
        std::cout << "the current number is " << *it << std::endl;

    return 0;
}
于 2016-02-16T13:50:59.897 に答える
1

私は答えの中にそれを見ませんでしたが、これはそれを行うための最良の方法です:範囲ベースのforループ

安全であり、実際、ジェネリックコードでは、参照の転送に控除を使用することをお勧めします:
for(auto && var:sequence)。

ミニマリストと実例:

#include <list>
#include <iostream>

int main()
{
    std::list<int> numbers = {2, 4, 6, 8};
    for (const int & num : numbers)
        std::cout << num << "  ";
    std::cout << '\n';
    return 0;
}
于 2018-12-22T16:27:29.967 に答える
0

「numbers」はクラスではないため、メンバー関数「size」はありません。この方法で配列のサイズを取得することはできません。配列を知る(または計算する)か、クラスを使用して数値を格納する必要があります。

于 2013-01-16T03:32:44.833 に答える
0

私の意見では、それを行う最も簡単な方法は、スパンを使用することです。

#include <cstdlib>
#include <iostream>
#include <gsl/span>

int main() {
    int numbers[] = {2, 4, 6, 8};
    for(auto& num : gsl::span(numbers)) {
            cout << "the current number is " << num;
    }

    system("pause");
}

ノート:

  • スパンはGSLライブラリの一部です。それらを使用するには、ここからライブラリをダウンロードし、ダウンロードパスをコンパイルコマンドに追加します。g++ -o foo foo.cpp -I/path/to/gsl
  • C ++ 20では、spanが標準の一部になるため、とを使用するだけstd::spanです#include <span>
于 2018-12-17T21:53:38.620 に答える
0

番号のリストが固定されている場合は、次のように書くことができることに注意してください。

#include <iostream>
#include <initializer_list>

int main()
{
    for (int i : {2, 4, 6, 8})
        std::cout << i << std::endl;
    return 0;
}
于 2021-10-29T08:14:59.170 に答える