在函数声明中,传递一个固定大小的数组意味着什么?

11

这感觉像是一个非常愚蠢的问题,但我有个正在上编程课的人向我求助他的一项任务,我在他的代码中看到了这样的东西(请勿对匈牙利命名法进行评价):

void read_dictionary( string ar_dictionary[25], int & dictionary_size ) {...

作为一名主要使用C#的程序员(我在大学里学习了C和C ++),我甚至不知道你可以这样做。 我一直被告知,并且后来也读到过,你应该有

void read_dictionary( string ar_dictionary[], int ar_dictionary_size, int & dictionary_size ) {...

有人告诉我教授给了他们这个并且它起作用,那么像这样声明一个固定大小的数组意味着什么?C++没有本地方法知道传递给它的数组的大小(即使我认为最新的规范可能已经改变了这一点)。


它有一种本地方法可以知道数组的大小:这个方法。如果你告诉它数组有多大,它就会相信它的大小。 - user529758
2
参数声明中的“25”被编译器忽略了。它与“string ar_dictionary []”相同。 - Cody Gray
1
@H2CO3 这个函数无法处理那个数字,编译器也无法检查传递给它的大小是否正确。 - cost
@CodyGray 噢,是这样吗?考虑到我对 C++ 的了解,这似乎是最有意义的。我甚至从未尝试过那种语法,我以为编译器会报错。你能在回答中说一下吗,这样我就可以将其标记为答案了吗? - cost
让我给你一个技巧:如果您使用void func(int (&myarr)[25]);,大小不为25的数组将被拒绝。GCC的错误消息是:error: invalid initialization of reference of type 'int (&)[25]' from expression of type 'int [3]' - v.oddou
有趣的是,七年前回答这个问题的人现在将其标记为重复,七年后。 - cost
3个回答

13

在一维数组中,这个值没有意义,编译器会忽略它。在二维或更高维度的数组中,它可以很有用,并被函数用作确定矩阵(或多维数组)行长度的一种方式。例如:

int 2dArr(int arr[][10]){
   return arr[1][2];
}

根据指定的长度,此函数将知道arr[1][2]的地址,而且编译器不应该接受这个函数中不同大小的数组 -

int arr[30][30];
2dArr(arr);

这是不被允许的操作,会导致编译器报错(g++):

error: cannot convert int (*)[30] to int (*)[10]

函数怎么可能知道地址? - cost
1
访问位于[x][y]的数组意味着访问位于第y行和第x列的元素。为此,您必须知道该行的长度。arr[1][2]arr[2*10 + 1]相同。 - WeaselFox

6
在参数声明中的“25”将被编译器忽略。这与您编写了“string ar_dictionary[]”是相同的。这是因为数组类型的参数声明会隐式调整为元素类型的指针。
因此,以下三个函数声明是等效的:
void read_dictionary(string ar_dictionary[25], int& dictionary_size)
void read_dictionary(string ar_dictionary[],   int& dictionary_size)
void read_dictionary(string *ar_dictionary,    int& dictionary_size)

即使在第一个函数中,数组的大小明确声明,sizeof(ar_dictionary) 返回的值与 sizeof(void*) 相同。
请参见Codepad上的示例
#include <string>
#include <iostream>

using namespace std;

void read_dictionary(string ar_dictionary[25], int& dictionary_size)
{
    cout << sizeof(ar_dictionary) << endl;  
    cout << sizeof(void*) << endl;  
}

int main()
{
    string test[25];
    int dictionary_size = 25;
    read_dictionary(test, dictionary_size);

    return 0;
}

输出(确切的值当然取决于实现,这只是为了举例):

4
4

1
WeaselFox的回答对你有意义吗?如果它只是衰变为指针,那么他所说的就不应该是真的。我有点困惑。 - cost
在第一个中,sizeof(ar_dictionary)也会返回sizeof(void*)吗? - Spidey
1
具有多个维度的数组与单个维度的数组工作方式不同。我不确定这与任何事情有关; 问题只涉及一维数组。@cos - Cody Gray
@Spidey:是的。我在我的回答中添加了一个例子。 - Cody Gray
这里实际上有两个不同的规则。其中一个是,在大多数情况下,数组类型的表达式会被隐式转换为(“衰减”为)指向数组第一个元素的指针。另一个是,数组类型的参数声明将被“调整”为元素类型的指针。语言本来可以只有其中一条规则而没有另一条,但它同时拥有两者。它们共同作用于——嗯,引起混乱。 - Keith Thompson

2

我一直认为传递固定大小的C++数组是C++中“半成品”的功能。例如,忽略大小匹配或只能指定第一个索引大小等等... 直到最近我学到了这个习惯用法:

template<size_t N1, size_t N2> // enable_if magic can be added as well
function(double(&m)[N1][N2]){
  ... do something with array m...knowing its size!
}

参考: 有人能解释一下这个模板代码如何获取数组的大小吗?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接