为什么数组的维是其类型的一部分?


14

在阅读C ++ Primer书籍时,我遇到了这样的说法:“数组中元素的数量是数组类型的一部分。” 因此,我想使用以下代码进行查找:

#include<iostream>

int main()
{
    char Array1[]{'H', 'e', 'l', 'p'};
    char Array2[]{'P', 'l', 'e', 'a', 's', 'e'};

    std::cout<<typeid(Array1).name()<<std::endl;        //prints  A4_c
    std::cout<<typeid(Array2).name()<<std::endl;        //prints  A6_c

    return 0;
}

有趣的是,两个数组上的typeid结果表明它们有所不同。

  • 幕后发生了什么事?
  • 为什么数组必须具有包含其大小的类型?仅仅是因为它的大小不应该改变吗?
  • 这将如何影响比较数组?

只是希望能够深刻理解这个概念。


3
并非一定要在类型中包含大小信息,但这很有用
byxor19

任何有关数组的教程都将说明(1)。我不确定(3)是什么意思,因为没有内置的比较数组的方法。
HolyBlackCat

Answers:


20

幕后发生了什么事?

根据定义,非动态分配的是固定大小的同类元素容器。N类型的元素数组T作为N类型的对象的连续序列布置在内存中T


为什么数组的类型必须包含其大小?

我不认为数组的类型包含它的大小是“必要的”-实际上,您可以使用指针来引用连续的T对象序列。这样的指针将丢失有关数组的大小信息。

但是,这是一件有用的事情。它提高了类型安全性,并在编译时对有用的信息进行了编码,可以以多种方式使用。例如,您可以使用引用数组来重载不同大小的数组

void foo(int(&array)[4]) { /* ... */ }
void foo(int(&array)[8]) { /* ... */ }

或找出数组的大小作为常数表达式

template <typename T, std::size_t N>
constexpr auto sizeOf(const T(&array)[N]) { return N; }

这将如何影响比较数组?

确实不是。

您不能以比较两个数字(例如int对象)的相同方式比较C样式的数组。您将必须编写某种词典比较,并确定对不同大小的集合意味着什么。std::vector<T>提供,并且可以将相同的逻辑应用于数组。


奖励: C ++ 11和更高版本提供std::array,它是带有容器状接口的C样式数组的包装。应该首选C风格的数组,因为它与其他容器(例如std::vector<T>)更加一致,并且还支持开箱即用的词典编目比较


2
“您将必须编写某种词典比较,并确定这对于不同大小的集合意味着什么。” 您可以使用std::equal(通过std::beginstd::end为数组定义)。在这种情况下,不同大小的数组是不相等的。
Stu

3
可能值得注意的是,基于范围的for循环的范围是一个数组,需要在编译时读取数组的大小-这有点微妙,因为(非常感谢!)在此示例中,从未写出数组的类型,但似乎比基于大小的重载要多得多。
米洛·布兰特

8

创建对象时分配给对象的空间量完全取决于其类型。我所说的分配不是来自new或的分配malloc,而是分配的空间,以便您可以运行构造函数并初始化对象。

如果您将结构定义为(例如)

struct A { char a, b; }; //sizeof(A) == 2, ie an A needs 2 bytes of space

然后,当您构造对象时:

A a{'a', 'b'};

您可以将构造对象的过程视为一个过程:

  • 分配2个字节的空间(在堆栈上,但是对于本示例而言,无关紧要)
  • 运行对象的构造函数(在这种情况下,复制'a''b'到对象)

重要的是要注意,所需的2个字节的空间完全由对象的类型决定,函数的参数无关紧要。因此,对于数组,处理过程是相同的,除了现在所需的空间量取决于数组中元素的数量。

char a[] = {'a'}; //need space for 1 element
char b[] = {'a', 'b', 'c', 'd', 'e'}; //need space for 5 elements

所以类型的ab必须反映一个事实,a需要有足够的空间1个char和b需要足够的空间,5个字符。这确实意味着这些数组的大小不能突然改变,一旦创建了5个元素的数组,它始终是5个元素的数组。为了拥有大小可能变化的类似“数组”的对象,您需要动态的内存分配,这应该在您的书中有所介绍。


0

这是运行库的内部原因。例如,如果考虑以下语句:

unsigned int i;
unsigned int *iPtr;
unsigned int *iPtrArr[2];
unsigned int **iPtrHandle;

这样就可以清楚地知道问题出在哪里:例如,的寻址unsigned int *必须与的sizeof operator或寻址有关unsigned int

对于您在此处看到的其余内容,有更详细的说明,但这主要是对Kernighan和Ritchie 的C编程语言第二版中涉及打印声明类型的纯语言文本的程序的概括。串。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.