【问题标题】:Using C++11's begin() and end() function to determine array dimension by parameter使用 C++11 的 begin() 和 end() 函数通过参数确定数组维度
【发布时间】:2016-06-19 13:05:53
【问题描述】:

所以我目前正在学习 C++(以前在 Java 和 JavaScript 方面有经验),就我而言,你不能像在 Java 中那样在 C++ 中将数组作为参数传递。但是您可以将指针传递给数组中的第一个元素。所以我可以像这样遍历一个数组:

bool occurs(int* arrInt, int length, int sought, int& occurrences)
{
    for (int i = 0; i <= length; ++i)
    {
        if (arrInt[i] == sought)
            occurrences++;
    }

    // if occurences > 0 return true, else false
    return occurrences;
}

整个函数基本上应该返回一个布尔值,告诉我给定的 int (sought) 是否在数组 (arrInt) 中找到。我还通过参考 (occurrences) 提供了一个小计数器。 但让我烦恼的是length 参数。 C++11 提供了那些花哨的 std::begin / cbegin() 和 std::end / cend() 函数来获取数组的第一个和最后一个元素:

int arr[] = {1,2,3,4} // arr is basically a pointer to an int, just as the
                      // function parameter of ocurs(int*,int,int,int&)
auto end = std::end(arr); // end points to one past last element

但是为什么我不能使用我的arrInt 参数作为该函数的参数呢?然后我可以摆脱长度参数:

bool occurs(int* arrInt, int sought, int& occurences)
{
    for (auto it = std::begin(arrInt); it != std::end(arrInt); ++it)
    {
        if (*it == sought)
            occurences++;
    }

    // if occurences > 0 return true, else false
    return occurences;
}

我在这里遗漏了一个主要概念吗?提前致谢

【问题讨论】:

  • 看看std::vector和/或std::array
  • @rettichschnidi 感谢您的链接,但我知道那个类,使用 vector::iterator 太容易了,如果我没有选择矢量怎么办? :)
  • 然后 a) 在问题中说明这一点,然后 b) 看看 std::count
  • “我是否遗漏了一个重要概念?” - 是的。 std::vector 为您做这件事。这是使用数组的面向对象的方式。你想要一个数组?使用向量。
  • @NiklasVest 听起来很有趣,但确实如此。根据标准,std::vector 管理一个 动态 数组。如果你使用像C 这样的过程 语言,你必须记住指针和长度。面向对象的方法是将指针和长度存储在一个对象内——一个抽象数据类型。它可以执行除内部之外的所有操作。而且,因为C++ 所有的访问都是通过inline 被编译器完全剥离的琐碎函数。因此,它就像您以C 方式完成所有操作一样快速

标签: c++ arrays c++11


【解决方案1】:

首先,请注意数组不是指针。所以在这个示例代码中:

int arr[] = {1,2,3,4} // arr is basically a pointer to an int, just as the
                      // function parameter of ocurs(int*,int,int,int&)

... cmets 完全是错误的。

但是,在 C 和 C++ 中,数组类型表达式衰减为指针类型,结果是指向第一项的指针,在需要指针的上下文中。一个不属于这种上下文的示例是通过引用传递数组的地方。另一个例子是当它被用作sizeof 的参数时。


arrInt 声明为

int* arrInt

它只是一个指针,没有关于它是指向单个 int 还是指向数组中某个位置的信息,等等

std::end(arrInt)

无法推断出数组大小。通常它从参数的数组类型中推断出来。或者来自容器的sizeend 成员(未指定其实现方式,相同的信息可通过多种方式获得)。


一种可能性是改变你的功能设计,例如将其更改为接受两个指针(或通用迭代器),例如 std::find

另一种可能性是在你的函数中使用std::find

您可以这样做,因为给定一个起始指针和一个数组大小,您可以简单地计算数组的结束指针,用作std::find 的参数。

【讨论】:

    【解决方案2】:

    在你的第一个例子中:

    int arr[] = {1,2,3,4} // arr is basically a pointer to an int, just as the
                          // function parameter of ocurs(int*,int,int,int&)
    auto end = std::end(arr); // end points to one past last element
    

    arrNOT “基本上是指向 int 的指针”。 arr 的类型为 int[4]。请注意,长度是类型的一部分。因此,编译器可以很容易地确定“最后一个元素”在哪里。只需添加长度即可。

    可能会引起混淆的地方是arr 可转换为(您有时会听到衰减为)int*。但它不仅仅是一个指针。


    在你的第二个例子中:

    bool occurs(int* arrInt, int sought, int& occurences)
    {
        for (auto it = std::begin(arrInt); it != std::end(arrInt); ++it) {
            ...
        }
        ...
    }
    

    arrInt 只是一个指针。因此,您怎么知道end() 在哪里?这里没有信息。这就是为什么你需要那个额外的长度参数。

    您可以改为传递完整的数组,但您必须通过引用来完成(您不能通过值传递数组,感谢 C!)。为此,您必须将其设为函数模板:

    template <size_t N>
    bool occurs (int (&arrInt)[N], int sought, int& occurrences) {
        ...
    }
    

    这里,arrInt 是一个数组 - 其长度以类型 (N) 编码。所以你可以写std::end(arrInt)


    occurs() 基本上是在重写std::count,所以你可以改用它:

    int arr[] = {1, 2, 3, 3, 8};
    int occurrences = std::count(std::begin(arr), std::end(arr), 3); // yields 2
    

    或者,更简单的是,使用std::vector&lt;int&gt;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-17
      • 1970-01-01
      • 2019-05-19
      • 2012-05-10
      • 1970-01-01
      • 2016-11-26
      • 1970-01-01
      • 2016-01-04
      相关资源
      最近更新 更多