如何在C++中遍历数字列表

8

如何遍历数字列表,有哪些不同的方法可以做到?

我认为会起作用的方式:

#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循环行上遇到了一个错误:

请求访问非类类型“int [4]”的“numbers”成员“size”


1
你有一个列表的数组... - chris
1
数组没有size成员函数,你的编辑使你的问题无效。列表不再存在! - billz
抱歉,我已经修复了代码,恢复到最初的状态!并且我更新了错误信息。 - Dbz
9个回答

29

与许多现代语言不同,普通的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
}

C++11(新标准)还带来了新的和时髦的基于范围的for循环,它应该适用于任何提供.begin().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 还有一个有趣的特性:它可以用于原始数组。这意味着你可以在数组和非数组之间使用相同的迭代语义(但你应该仍然优先选择标准类型而不是原始数组):

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;
    }
}

这个列表并不全面,但是你可以看到有很多方法来对集合进行迭代。通常情况下,除非有充分的理由,否则最好使用迭代器。


6
将您的for循环更改为
 for(i=0; i< sizeof(numbers)/sizeof(int);i++){

简单来说,sizeof(numbers) 表示数组中元素的数量乘以 int 类型的大小,因此你需要除以 sizeof(int) 才能得到元素的数量。

为什么我要将 sizeof(numbers) 除以 sizeof(int) - Dbz

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) { ... }

3
如果您的数字列表是固定的,请注意您可以直接编写以下代码:
#include <iostream>
#include <initializer_list>

int main()
{
    for (int i : {2, 4, 6, 8})
        std::cout << i << std::endl;
    return 0;
}

这个问题为什么一年来一直没有人投票,还排在最底下?o_O - P i

3

我没有在答案中看到,但我认为这是最好的方法:范围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;
}

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;
}

2

在“普通”的C风格数组中,没有size函数。如果您想使用size,则需要使用std::vector或通过sizeof计算大小。

在C++11中,您可以使用数组初始化语法来初始化向量,如下所示:

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

其他所有内容都保持不变(请在此处查看演示)。


0

没有"size"成员函数,因为"numbers"不是一个类。你不能用这种方式获取数组的大小,你必须要么知道它(或计算它),要么使用一些类来存储你的数字。


0

在我看来,最简单的方法是使用span

#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");
}

备注:

  • Spans是GSL库的一部分。要使用它们,请从此处下载库,并将下载路径添加到编译命令中,例如g++ -o foo foo.cpp -I/path/to/gsl
  • 在C++20中,span将成为标准的一部分,因此您只需使用std::span#include <span>即可。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接