【问题标题】:Correct way of looping through C++ arrays循环遍历 C++ 数组的正确方法
【发布时间】:2013-12-12 15:33:08
【问题描述】:

最近我发现了很多例子,其中大部分是关于 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的价值:香蕉
a的值:橙色

分段错误

一切正常,除了最后的分段错误。

我的问题是,这个数组/循环是否做得很好?我正在使用 C++ 11,所以想确保它符合标准并且不能做得更好?

【问题讨论】:

  • 只需使用std::array 及其size() 函数。

标签: c++ arrays loops c++11


【解决方案1】:

在 C/C++ 中sizeof。总是给出整个对象的字节数,数组被视为一个对象。注意:sizeof 指针——指向数组的第一个元素或单个对象——给出指针的大小,而不是指向的对象。无论哪种方式,sizeof 确实 not 给出了数组中元素的数量(它的长度)。要获得长度,您需要除以每个元素的大小。例如,

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;

这让编译器可以计算出您需要多少次迭代。

编辑:正如其他人所指出的,std::array 在 C++11 中优于原始数组;但是,其他答案都没有解决为什么 sizeof 会失败,所以我仍然认为这是更好的答案。

【讨论】:

  • 为了更简单,试试for(auto &amp; text : texts)
  • @edA-qamort-ora-y 甚至更好:for(auto &amp;&amp;text: texts)
  • 第一种方式,这不是只有在所有字符串长度相同的情况下才有效吗?
  • @tmath 我的数学应该适用于 OP 的示例,因为每个 string 对象实际上是一个恒定大小,而与封装字符串的长度无关。特别是string 对象本质上只是一个结构体,它带有一个指向数据的指针,以及一些其他固定大小的元数据。
  • 注意,这可能适用于 C++,但在 C 中使用是危险的。它在 C 中适用于堆栈上的静态声明数组,但不适用于函数。在函数中,sizeof 运算符不知道整个数组,而是返回指针的大小。
【解决方案2】:
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;
    }
}

Live example


您可能会问,std::array 比 ol' C 数组更好吗?答案是它具有其他标准库容器的额外安全性和功能,大多与std::vector 非常相似。此外,答案是它没有衰减到指针从而丢失类型信息的怪癖,一旦丢失原始数组类型,就不能使用 range-for 或 std::begin/end

【讨论】:

  • 注意:他们仍然可以在原始数组中使用基于范围的循环。
  • 我不喜欢std::array 方法,因为我需要自己计算元素。以传统方式,编译器会为我创建正确大小的数组。
【解决方案3】:

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

【讨论】:

  • 嘿,这太棒了!但可能应该解释它的含义以及它是如何工作的。
【解决方案4】:

您需要了解 std::array::size 和 sizeof() 运算符之间的区别。如果你想以传统方式循环到数组元素,那么你可以使用 std::array::size。这将返回数组中元素的数量,但如果你热衷于使用 C++11,那么更喜欢下面的代码

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

【讨论】:

    【解决方案5】:

    给数组添加一个停止值:

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

    【讨论】:

    • 这是不正确的。 texts[a].length() 是索引 a 处单词的长度。不是数组的长度。
    • @htellez 是的,这就是重点。当遇到长度为零的字符串时,循环退出。
    • 啊!我没听懂。
    • 代码运行良好,感谢它也解决了我的问题,但string texts[] 如何声明数组?为什么我的没有?我正在使用代码块 minGW 17.12
    【解决方案6】:

    如果您想要处理的元素列表非常短,您可以使用 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;
    }
    

    【讨论】:

      【解决方案7】:

      sizeof(texts) 在我的系统上评估为 96:数组及其字符串实例所需的字节数。

      正如在其他地方提到的,sizeof(texts)/sizeof(texts[0]) 将给出您期望的值 3。

      【讨论】:

        【解决方案8】:

        怎么样:

        #include <iostream>
        #include <array>
        #include <algorithm>
        
        int main ()
        {
            std::array<std::string, 3> text = {"Apple", "Banana", "Orange"};
            std::for_each(text.begin(), text.end(), [](std::string &string){ std::cout << string << "\n"; });
        
            return 0;
        }
        

        编译和使用 C++ 11 并且没有“原始”循环:)

        【讨论】:

          【解决方案9】:

          你可以这样做:

          #include < iostream >
          
          using namespace std;
          
          int main () {
          
             string texts[] = {"Apple", "Banana", "Orange"};
          
             for( unsigned int a = 0; a < sizeof(texts) / 32; a++ ) { // 32 is the size of string data type
          
                 cout << "value of a: " << texts[a] << endl;
          
             }
          
          
             return 0;
          
          }
          

          【讨论】:

          • 32 并不是任何时候任何时候字符串数据类型的大小。
          猜你喜欢
          • 2017-05-13
          • 2011-01-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-08-09
          • 2013-05-15
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多