内部函数的范围错误 我在C++中有一点麻烦。我试图用它来显示和int数组(int[])上的元素,当我在主函数上这样做时,它完全可以正常工作,如: int main(int argc, char const *argv[]) { int v[] = {3, 4, 6, 9, 2, 1}; for (auto a : v) { std::cout << a << " "; } std::cout << std::endl; return 0; }

内部函数的范围错误 我在C++中有一点麻烦。我试图用它来显示和int数组(int[])上的元素,当我在主函数上这样做时,它完全可以正常工作,如: int main(int argc, char const *argv[]) { int v[] = {3, 4, 6, 9, 2, 1}; for (auto a : v) { std::cout << a << " "; } std::cout << std::endl; return 0; },c++,arrays,ranged-loops,C++,Arrays,Ranged Loops,但当我尝试在函数中使用range for时,事情变得有点奇怪,例如,我对以下代码有一个问题: void printList(int *v); int main(int argc, char const *argv[]) { int v[] = {3, 4, 6, 9, 2, 1}; printList(v); return 0; } void printList(int *v) { for (auto a : v) { std::cout << a

但当我尝试在函数中使用range for时,事情变得有点奇怪,例如,我对以下代码有一个问题:

void printList(int *v);

int main(int argc, char const *argv[]) {

  int v[] = {3, 4, 6, 9, 2, 1};

  printList(v);

  return 0;
}

void printList(int *v) {
  for (auto a : v) {
    std::cout << a << " ";
  }
  std::cout << std::endl;
}

为什么会这样?有没有不使用模板格式的简单解决方案?是否有一种方法可以使用参数作为传递数组和隐式大小信息的方法?

对于
循环,这样的
使用
开始
结束
成员函数来确定序列的开始和结束位置

例如,
std::vector
确实有这些函数,因此支持这种迭代。实际上,指针仅仅是表示内存地址的整数,没有这些函数,因此不可能以这种方式对指针进行迭代(指针本身没有多大意义)

您可以像这样进行迭代:

void printList(int *begin, int *end) {
    for(; begin < end; ++begin)
        std::cout << *begin;
    std::cout << std::endl;
}
void打印列表(int*begin,int*end){
对于(;开始<结束;++开始)

数组和指针之间有很大的区别

您可以使用基于范围的for迭代数组,因为数组的大小在编译时是已知的。但是,您传递给函数的是指向数组第一个元素的指针。在这一步中,大小是未知的,这就是基于范围的for失败的原因

在关于模板的第二个示例中,问题是,您忘记了
printList
的定义中的
template
,因此您有两个不同的函数,模板化函数和非模板化函数,称为


在这种情况下-我建议使用更现代的
std::array

main
中的数组具有已知大小

一旦传递到
printList
函数,它就会衰减为指向
int
s的指针,因此会出现错误

“我认为这可能发生的原因是,因为我是 数组的指针表示某些信息丢失,但原因是什么 这个信息丢失了,我不知道。”

是的。数组很容易衰减为指针,指针不知道数组长度。从数据类型计算
begin()
end()
需要基于范围的for循环。
我的建议是避免使用C样式的数组,而是使用
std::array

#include <iostream>
#include <array>

void printList(std::array<int,6> const& v);

int main(int argc, char const *argv[]) {

  std::array<int,6> v{{3, 4, 6, 9, 2, 1}};
  printList(v);

  return 0;
}

void printList(std::array<int,6> const& v) {
  for (auto a : v) {
    std::cout << a << " ";
  }
  std::cout << std::endl;
}
#包括
#包括
无效打印列表(标准::数组常量&v);
int main(int argc,char const*argv[]{
std::数组v{{3,4,6,9,2,1};
印刷品清单(五);
返回0;
}
无效打印列表(标准::数组常量&v){
用于(自动a:v){

STD::CUT> P>当将数组传递给函数时,它会衰变为指针,因此它失去了与STD::START和STD::Endo:ToME一起使用的能力。一种现代的方法来使用你想要的是使用STD:::Calpod(如果可能的话,你不应该在C++中使用C样式数组):

#包括
#包括
模板
无效打印列表(常量标准::数组和v)
{
用于(自动a:v){
标准::cout
获取了
int[6]
,而
int*v
的类型。其类型是
int*
。您可以使用指向int的指针访问数组,但它不包含有关该数组大小的信息。 您可以像这样传递数组,但要根据数组的大小来限制自己:

void foo(int (&p)[6])
或制作模板:

template <std::size_t size> void foo( int (&p)[size] )
template <int size>
void printList(int (&v)[size]) {
    for (auto& a : v) {
        std::cout << a << " ";
    }
}
模板void foo(int&p)[size])

如果出于某种原因,您不能使用automic for()循环(例如,为了便于移植到C++11\14支持不可靠的平台),您需要使用std::array\std::vector或pass pointer and size of array

您可以将固定大小的数组传递给函数:

void printList(int (&v)[6]) {        // pass by reference
    for (auto& a : v) {              // use reference to avoid making a copy
        std::cout << a << " ";
    }
}
印刷品:

3 4 6 9 2 1

基于范围的for循环本质上只不过是语法上的糖,即从

for(range\u声明:range\u表达式)loop\u语句(直到C++20

for(init语句(可选)range\u声明:range\u表达式)loop\u语句

在功能上等同于以下各项:

{
自动范围=范围表达式;
对于(自动开始=开始执行,结束=结束执行;
__开始!=\uuu结束;++\uu开始){
范围\声明=*\开始;
循环语句
}
}
或者,如果您使用c++17或更高版本,它有效地允许使用不同类型的
\uu begin
\uu end

{
    init-statement // only since C++20
    auto && __range = range_expression ;
    auto __begin = begin_expr ;
    auto __end = end_expr ;
    for ( ; __begin != __end; ++__begin) {
        range_declaration = *__begin;
        loop_statement
    }
}
其中
begin_expr
end_expr
的格式如下

  • 如果range_expression是数组类型的表达式,那么begin_expr是_range,end_expr是(_range+_bound),其中_bound是数组中的元素数(如果数组大小未知或类型不完整,则程序格式不正确)

  • 如果range_expression是一个C类类型的表达式,其成员名为begin和/或end(无论该成员的类型或可访问性如何),则begin_expr是u range.begin(),end_expr是u range.end()

  • 否则,begin_expr是begin(_range),end_expr是end(_range),它们是通过参数相关查找找到的(不执行非ADL查找)


  • 让我们看看这如何适用于您的案例:

    在第一种情况下,
    v
    肯定是数组类型的表达式,或者确切地说是类型
    int(&)[6]
    ,因此我们使用案例(1),其中
    \uu-bound=6
    等(为了简洁起见,省略完全的扣除替换)

    在第二种情况下,当您有一个函数时,
    v
    的类型为
    int*
    ,并且由于它不是数组类型,指针也没有成员,因此我们默认使用案例(3),该案例用于确定调用
    begin(\uu范围)的函数
    这不会产生指针类型的结果,因此编译器会抱怨
    错误:“begin”未在此范围内声明
    <
    int v[] = {3, 4, 6, 9, 2, 1};
    
    void foo(int (&p)[6])
    
    template <std::size_t size> void foo( int (&p)[size] )
    
    void printList(int (&v)[6]) {        // pass by reference
        for (auto& a : v) {              // use reference to avoid making a copy
            std::cout << a << " ";
        }
    }
    
    template <int size>
    void printList(int (&v)[size]) {
        for (auto& a : v) {
            std::cout << a << " ";
        }
    }
    
    int main() {
        int v[] = {3, 4, 6, 9, 2, 1};
        printList(v); 
    }
    
    3 4 6 9 2 1
    
    {
        init-statement // only since C++20
        auto && __range = range_expression ;
        auto __begin = begin_expr ;
        auto __end = end_expr ;
        for ( ; __begin != __end; ++__begin) {
            range_declaration = *__begin;
            loop_statement
        }
    }
    
    template <std::size_t len>
    void printList(int (&v)[len]);
    
    int main(int argc, char const *argv[]) {
      int v[] = {3, 4, 6, 9, 2, 1};
      printList(v);
      return 0;
    }
    
    template <std::size_t len>
    void printList(int (&v)[len]) {
      for (int a : v) {
        std::cout << a << " ";
      }
      std::cout << std::endl;
    }