在C ++中对太多元素进行循环循环时

时间:2019-06-14 17:29:03

标签: c++ arrays function count definition

运行代码时,我得到所有这些数字作为输出,这意味着我的while循环似乎遍历了不应跳过的元素。为什么会这样呢? 就上下文而言,我目前正在学习C ++,并且对C ++进行了了解,我对指针和引用感到非常困惑。

这是我获得代码的地方: Buggy code in "A Tour of C++" or non-compliant compiler?

int counter(int* arr,int c){
    int counter = 0;
    while(*arr){
    cout << *arr<<"\n";
    if(*arr == c){
        ++counter;
    }
    ++arr;
    }
    return counter;
}

int main()
{
    int arr[3] = {1,2,3};
    int count = counter(arr,1);
    cout<< count;
}

示例运行:

/Users/benediktschesch/CLionProjects/untitled/cmake-build-debug/untitled
1
2
3
-945684358
-1153026697
-280532248
32766
1839025881
32767
1839025881
32767
1
Process finished with exit code 0

3 个答案:

答案 0 :(得分:3)

这非常类似于不为将用作字符串的字符数组提供空终止符。

while(*arr) 

表示找到零时停止。

int arr[3] = {1,2,3};

不提供零,因此您无法控制循环何时停止。

TL; DR解决方案:

使用Library container。 std :: vector或std::array在这里非常合适,std::countthe <algorithm> librarythe <iterator> librarystd::beginstd::end也是如此。 / p>

#include <iostream>
#include <iterator>
#include <algorithm>

int main()
{
    int arr[] = { 1, 2, 3 };
    int count = std::count(std::begin(arr), std::end(arr), 1);
    std:: cout << count;
}

说明:

您可以提供零

int arr[] = {1,2,3,0};

请注意,我删除了显式数组的大小。不需要,因为编译器可以从Initializer中的元素数量中得知。

还要注意,这将在到达第一个零时停止,因此

int arr[] = {1,2,3,0,1,2,3,0};

只会发现1。这使0成为终止整数列表的非常差的值,除非确保输入中没有0。

要扫描整个阵列并且仅扫描阵列,需要提供阵列的大小。可以通过传入size参数来完成

int counter(int* arr, size_t len, int c)
{
    int counter = 0;
    while (len--)
    {
        std::cout << *arr << "\n";
        if (*arr == c)
        {
            ++counter;
        }
        ++arr;
    }
    return counter;
}

int main()
{
    int arr[3] = { 1, 2, 3 };
    int count = counter(arr, std::size(arr), 1);
    std:: cout << count;
}

,但是Modern C ++中的首选解决方案是使用容器代替数组。容器知道它们的大小,并提供了各种各样的其他工具,以使编写代码更容易且更不易出错。

#include <iostream>
#include <vector>

int counter(const std::vector<int> & arr, int c)
{
    int counter = 0;
    for (const auto & val: arr)
    {
        std::cout << val << "\n";
        if (val == c)
        {
            ++counter;
        }
    }
    return counter;
}

int main()
{
    std::vector<int> arr = { 1, 2, 3 };
    int count = counter(arr, 1);
    std:: cout << count;
}

请注意使用range-based for loop来简化代码。 const auto & valvalarr的内容推导auto的类型。该值不会因循环而更改,因此我们将其声明为const以防止意外并使其成为引用,因为编译器可能会产生一些额外的优化伏都教。此外,如果容器或容器中的数据类型发生了更改,则可以继续重用此确切的语句,而无需进行任何更改。这样可以防止以后在维护代码时出错。

您还可以使用std::array并使counter成为模板化函数,以在此处检测std::array的大小,但在这一点上要花很多钱。

下一个改进是利用<algorithm>库。

#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
    std::vector<int> arr = { 1, 2, 3 };
    int count = std::count(arr.begin(), arr.end(), 1);
    std:: cout << count;
}

在这种情况下,将使用迭代器而不是指定长度。这使您可以轻松地扫描容器的子集。

这使我们可以通过使用std::beginstd::end将数组变成一对迭代器来重新使用香草数组:

#include <iostream>
#include <iterator>
#include <algorithm>

int main()
{
    int arr[] = { 1, 2, 3 };
    int count = std::count(std::begin(arr), std::end(arr), 1);
    std:: cout << count;
}

这使我们可以使用TL; DR解决方案。

答案 1 :(得分:3)

我建议使用std::arrayrange based for loops

#include <array>
#include <iostream>

int counter(const std::array<int, 3> &arr, int c){
    int counter = 0;
    for (auto const a : arr) {
        std::cout << a << "\n";
        if(a == c){
            ++counter;
        }
    }
    return counter;
}

int main()
{
    std::array<int, 3> arr = {1,2,3};
    int count = counter(arr,1);
    std::cout << count;
}

出现问题的原因是在行

while(*arr){

声明

*arr

被评估为布尔值。 *arr == 0为false,其他情况为true。在您的代码中,您需要获取数组的大小或值为0的最后一个元素的大小。有不同的方法。您可以将最后一个元素添加为0,也可以将大小传递给函数。但是C ++标准提供了stl容器,可以解决您的问题而不会产生开销。 std::array是一个包含数据和数组大小的容器。这是一个模板类,因此大小不需要任何额外的数据。首先,您应该学习如何使用语言提供的工具,例如stl容器和算法。稍后,您将学习如何使用底层函数和数据类型。

答案 2 :(得分:1)

除了包含字符串的字符数组以外,其他所有数组(如果您不故意使用标记值)都不包含表示数组结尾的零元素。因此,如果数组不包含等于0的元素(如您的情况),则您的函数可以调用未定义的行为。

因此,通常,您的函数应该再有一个参数,用于指定数组中元素的数量,并且看起来应该像

size_t counter( const int *arr, size_t n, int value )
{
    size_t count = 0;

    for ( const int *p = arr; p != arr + n; ++p )
    {
        if ( *p == value ) ++count;
    }

    return count;
}

并称呼为

int main()
{
    int arr[] = { 1, 2, 3 };
    const size_t N = sizeof( arr ) / sizeof( *arr );

    size_t count = counter( arr, N, 1 );

    std::cout << count << '\n';
}

如果编译器支持C ++ 17,则可以在标头sizeof( arr ) / sizeof( *arr )中声明标准函数std::size()而不是表达式<iterator>,例如std::size( arr )

否则,可以使用表达式代替表达式sizeof( arr ) / sizeof( *arr )

std::extent<decltype( arr )>::value

提供了标头<type_traits>

请注意,标头std::count中声明了执行相同任务的标准算法<algorithm>。这是一个演示程序

#include <iostream>
#include <iterator>
#include <algorithm>

int main()
{
    int arr[] = { 1, 2, 3 };

    auto count = std::count( std::begin( arr ), std::end( arr ), 1 );

    std::cout << count << '\n';
}