微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何从函数访问数组的元素

如何解决如何从函数访问数组的元素

如果被迭代的数组来自一个参数并在另一个作用域中声明,则 foreach 循环类型不起作用。

// C++ program to demonstrate use of foreach 

#include <iostream> 
using namespace std; 
void display(int arr[])
{
    for (int x : arr) 
        cout << x << endl; 
}
int main() 
{ 
    int arr[] = { 10,20,30,40 }; 
    display(arr);
} 

错误如下:

Here's what the error looks like

什么是开始和结束? 导致此错误的幕后发生了什么? for 循环是否在运行前隐式更改为迭代器声明?这是因为 C 风格的数组不是容器对象,因此没有开始和结束吗?如果这是真的,那么为什么这段代码有效:

#include <iostream> 
using namespace std;
int main() 
{ 
    int arr[] = { 10,40 }; 
    for (int x : arr) 
        cout << x << endl;
} 

作为参数传递时是否会发生一些信息衰减?

解决方法

那个 for 循环被称为基于范围的 for 循环。编译器正在将该代码转换为其他内容。您可以在此处查看所有详细信息 https://en.cppreference.com/w/cpp/language/range-for(C++11、C++17 和 C++20 不同)。

但是,原则上,你的代码变成这样:

{
  auto && __range = arr;
  auto __begin = begin_expr;
  auto __end = end_expr;
  for ( ; __begin != __end; ++__begin) {
    x = *__begin;
    cout << x << endl;
  }
}

这里的问题是 begin_exprend_expr 可以是不同的东西。如果 arr 是一个数组,如 int arr[3]__range 将是 __range + 3。如果 arr 是一个具有成员 begin()end() 的类,它将是 __range.begin()。否则,它将是 begin(__range)

最后一种情况是您的代码正在登陆,因为 arr 不是数组而是指向 int 的指针(int [] arr 表示 int* arr)。并且 begin() 没有 end()int*

它在这里有效,因为在这个例子中,arr 是一个包含 4 个整数的数组:

int arr[] = { 10,20,30,40 }; 
for (int x : arr) 
   cout << x << endl; 

有不同的方法可以做到这一点。这是我更喜欢自己做的方式:

template <typename T>
void display(std::vector<T> const & arr)
{
    for (int x : arr) 
        cout << x << endl; 
}

int main() 
{ 
    std::vector<int> arr { 10,40 };
    display(arr);
}

您可以检查 https://cppinsights.io/ 以了解编译器如何转换您的代码(在某种程度上)。例如,你的代码变成这样(注意,如果代码不编译它就不起作用,所以我不得不注释掉循环):

#include <iostream> 
using namespace std; 

void display(int * arr)  // <-- notice int*
{
}


int main()
{
  int arr[4] = {10,40};  // <-- notice int[4]
  display(arr);
}

如果你使用这个代码:

int main() 
{ 
    int arr[] = { 10,40 }; 
    for (int x : arr) 
       cout << x << endl; 
}

结果如下:

int main()
{
  int arr[4] = {10,40};
  {
    int (&__range1)[4] = arr;
    int * __begin1 = __range1;
    int * __end1 = __range1 + 4L;
    for(; __begin1 != __end1; ++__begin1) 
    {
      int x = *__begin1;
      std::cout.operator<<(x).operator<<(std::endl);
    }
    
  }
}
,

当你给一个函数一个 C 风格的数组时,你还需要给出它的大小,因为函数不知道数组的大小。数组参数 int x[] 被视为数组第一个元素上的指针(因此类似于 int* x)。因此,该函数无法判断数组有多大,因为它只有指针(第一个元素的地址)。您需要指定函数从提供的地址中读取多少个 int(或其他类型)以获得有效元素。

#include <iostream>
using namespace std;

void display(int arr[],int nsize)
{
    int i=0;
    while (i < nsize){
        cout << *arr << endl;
        // you move the pointer to the next element to be read
        arr++;
        i++;
    }
}

int main()
{
    int arr[] = { 10,40 };
    int n= sizeof(arr)/sizeof(int);
    display(arr,n);
}

,

第一段代码不起作用,因为

void display(int arr[])

实际上相当于

void display(int *arr)

并且您不能使用单个指针进行迭代,因为它没有任何长度信息。另见What is array to pointer decay


第二段代码有效,因为基于范围的 for 中的范围表达式必须是

表示合适序列的任何表达式(数组或定义了开始和结束成员函数或自由函数的对象,见下文)或花括号初始化列表。

Source

所以代替不存在的成员函数arr.begin()arr.end(),它可以使用重载的自由函数std::begin()std::end()用于数组。

,

首先,让我建议您像@Ted 在评论中提到的那样编辑您的问题。

我必须承认错误信息不是很直观。缺失 beginend 的出现源于 range-based for loop 的定义。如您所见,您将一个未知大小的数组作为 range_expression 传递,对吗?链接页面对此案有进一步说明:

如果 range_expression 是数组类型的表达式,则 begin_expr 是 __range 和 end_expr 是 (__range + __bound),其中 __bound 是数组中元素的数量(如果数组大小未知或者是 类型不完整,程序格式错误)

你的第二个代码片段实际上使用了一个已知大小的数组,因为它的使用与它的初始化在同一范围内。 Array initialization 表示:

初始化一个未知大小的数组时,最大下标为 指定的初始化程序决定了数组的大小 正在声明。

让我为您提供一个标准库模板,以便更好地掌握数组。这是.. 错误.. std::array :)。你得到的基本上是值语义和与其他类型的一致性:

  • 按值接受参数会复制整个内容,
  • 通过(常量)引用接受参数具有熟悉的语法,
  • 传递数组对象时不会隐式丢失大小信息。

所以你的代码会看起来像这样:

#include <array>
#include <iostream> 
using namespace std; 
void display(const array<int>& arr)
{
    for (int x : arr) 
        cout << x << endl; 
}
int main() 
{ 
    std::array arr{ 10,40 }; 
    display(arr);
} 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。