【问题标题】:How is C++ array recognized?如何识别 C++ 数组?
【发布时间】:2020-02-19 18:11:55
【问题描述】:

在 C++ 中传递数组时,它们会作为指针传递。所以我们必须明确地传递该数组的大小。

// This will not work.
int GetSize(int* arr){
  return sizeof(arr)/size(int);
}

但是如果我们不使用函数来获取它的大小并在初始化数组的同一个函数中使用“sizeof”,那么现在我们会得到正确的结果。

int main(){
  int arr[5];
  int size = sizeof(arr)/sizeof(int);
  cout << size << endl;
}

那么我是否可以将数组视为一个带有指针、其大小和元素类型的类?

现在我想了想,如果只是像指针一样处理它,我不确定 C++ 如何知道后面代码中数组的大小。

【问题讨论】:

  • 当你有一个“正确的”数组时,编译器知道它,因为它必须跟踪所有变量及其类型。当你有一个指针时,编译器无法知道指针来自哪里或指向什么,因为它可以在运行时决定。
  • 建议:不要使用 C 风格的数组。请改用std::arraystd::vector
  • 了解指针和数组是不相关的不同类型很重要。感知到的联系来自数组必须非常容易地转换为指向其第一个元素的指针的能力。知道数组从哪里开始并不足以知道它在哪里结束。
  • int size = sizeof(arr)/sizeof(int); --> const auto size = std::size(arr);
  • “那么我是否可以将数组视为一个带有指针的类、它的大小和其中元素的类型?”简单的回答:绝对不是!指针是指针而不是数组。指向数组的指针中没有任何内容可以保存任何附加信息。任何数组在用作函数参数时都会自动转换为指向第一个元素的指针,这很简单。如果您想将其作为模板实例类型,在类型(而不是实例)中保留大小信息,请使用 std::array。如果您想要运行时大小信息,请使用 std::vector

标签: c++ arrays sizeof


【解决方案1】:

那么我是否可以将数组视为一个带有指针、其大小和元素类型的类?

不,因为它不是。 C 风格的数组只是一块连续的内存,其中包含给定类型的元素,仅此而已。

现在我想了想,如果只是像指针一样处理它,我不确定 C++ 如何知道后面代码中数组的大小。

数组不是这样处理的。

在您的第一个示例中,该函数只接受一个指针,它不关心该指针来自哪里。传入一个数组会将数组衰减为指向第一个元素的指针。所有大小信息都丢失了,无法仅从指针确定数组的大小。这就是sizeof(arr) 在这种情况下不起作用的原因。它只知道指针本身的大小,而不知道指针来自的数组的大小。

在您的第二个示例中,实际数组在使用 sizeof() 的范围内。编译器知道数组的声明,所以sizeof(arr)可以知道数组的实际字节大小。

如果你真的想知道函数中传递的数组的大小,并且不想显式地将大小作为参数传递,那么通过引用而不是pointer 所以数组的大小不会丢失:

template<size_t N>
int GetSize(int (&arr)[N]){
  return N;
}

【讨论】:

    【解决方案2】:

    在我正确理解的第一种情况下,您使用的是 int* 类型的大小,它是一个指向 int 的指针,在大多数情况下,它将产生 4 个字节(取决于架构和可能的其他因素)。

    在第二种情况下,编译器还具有计算 sizeof(arr) 所需的所有信息,因为 int arr[5] 定义的 int 明确给出了 5 个元素;因此在大多数情况下将等于 4 个字节 * 5 个元素,20 个字节

    【讨论】:

      【解决方案3】:

      声明

      int *arr; // arr = ptr to int
      

      与声明不同

      int arr[5];  // arr = base ptr to array of 5 ints
      

      请注意,arr 在每种情况下都解析为一个地址 (ptr),但在第二种情况下,编译器可以将 arr 解析为 5 个int 的数组的基本 ptr。如果第二个声明是针对函数参数的,事情会变得有点棘手:

      void foo(int arr[5]) { ... }
      

      那么这真的和

      没有什么不同
      void foo(int *arr) { ... }
      void foo(int arr[]) { ... }
      

      即只传递一个ptr,sizeof(arr)将返回一个ptr中的字节数。

      【讨论】:

      • 数组不是指针。 int arr[5]; 是数组而不是指针
      • 我没记错,完成你的想法,除非它是例如void foo(int(&arr)[5]),那么它可以解决并且它不等于上面的int *arr和arr[]?
      • @cplusogl 你在声明 arr 是对 5 个 int 数组的引用,是的,元素的数量可以静态解析。
      • @idclev463035818 你是对的,但在幕后arr 符号仍然解析为地址。
      • 在底层,数组仍然是数组而不是指针。数组在某些情况下会衰减为指针,但这仍然不能使它们成为指针
      【解决方案4】:
      1. 为什么sizeof() 在同一范围内? - 这是因为编译器看到你声明了int arr[5],它在编译时得到大小为5。 sizeof() 在编译时计算。
      2. 为什么当数组作为指针传递时它不起作用? - 这是因为一个数组在这里衰减为一个指针。因此,它丢失了大小信息。事实上,sizeof(arr) 会在此处为您提供系统上指针的大小 - 64 位机器为 8 字节,32 位机器为 4 字节。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-12
        • 1970-01-01
        • 1970-01-01
        • 2013-11-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多