对于传递二维(或更高的多维)数组,请在此处查看我的其他答案:How to pass a multidimensional array to a function in C and C++
在 C(和 C++)中将一维数组作为函数参数传递
1。 C 中的标准数组使用,具有从数组到 ptr 的自然类型衰减(调整)
@Bo Persson 在他的精彩回答here 中正确陈述:
当将数组作为参数传递时,this
void arraytest(int a[])
意思完全一样
void arraytest(int *a)
让我添加一些 cmets 以使这两个代码 sn-ps 更加清晰:
// param is array of ints; the arg passed automatically "adjusts" (frequently said
// informally as "decays") from `int []` (array of ints) to `int *`
// (ptr to int)
void arraytest(int a[])
// ptr to int
void arraytest(int *a)
不过,我还要补充一点,以上两种形式也有:
-
意思完全一样
// array of 0 ints; automatically adjusts (decays) from `int [0]`
// (array of zero ints) to `int *` (ptr to int)
void arraytest(int a[0])
-
意思完全一样
// array of 1 int; automatically adjusts (decays) from `int [1]`
// (array of 1 int) to `int *` (ptr to int)
void arraytest(int a[1])
-
意思完全一样
// array of 2 ints; automatically adjusts (decays) from `int [2]`
// (array of 2 ints) to `int *` (ptr to int)
void arraytest(int a[2])
-
意思完全一样
// array of 1000 ints; automatically adjusts (decays) from `int [1000]`
// (array of 1000 ints) to `int *` (ptr to int)
void arraytest(int a[1000])
-
等等
在上面的每一个数组示例中,正如下面代码中的示例调用所示,输入参数类型调整(衰减)为int *,并且可以是即使打开了构建选项-Wall -Wextra -Werror,调用时也没有警告和错误(有关这三个构建选项的详细信息,请参阅my repo here),如下所示:
int array1[2];
int * array2 = array1;
// works fine because `array1` automatically decays from an array type
// to a pointer type: `int *`
arraytest(array1);
// works fine because `array2` is already an `int *`
arraytest(array2);
事实上,此处数组参数中的“大小”值([0]、[1]、[2]、[1000] 等)显然只是出于审美/自我记录目的,并且可以是您想要的任何正整数(我认为是size_t 类型)!
然而,在实践中,您应该使用它来指定您希望函数接收的数组的最小大小,以便在编写代码时可以轻松跟踪和验证。 @ 987654324@ 标准 (buy/download the 236-pg 2012-version PDF of the standard for £15.00 here) 甚至声明(强调):
规则 17.5 对应于声明为数组类型的参数的函数参数应具有适当数量的元素。
...
如果将参数声明为具有指定大小的数组,则每个函数调用中的相应参数应指向一个对象,该对象至少具有与该数组一样多的元素。
...
对函数参数使用数组声明器比使用指针更清楚地指定函数接口。函数期望的最小元素数量已明确说明,而指针则无法做到这一点。
换句话说,他们建议使用显式大小格式,尽管 C 标准在技术上并未强制执行它——它至少有助于向作为开发人员的您以及使用代码的其他人阐明,什么函数期望你传入的大小数组。
2。在 C 中强制数组类型安全
(不推荐(更正:sometimes recommended, especially for fixed-size multi-dimensional arrays),但可能。请参阅我最后反对这样做的简短论点。另外,对于我的多维数组[例如:二维数组]版本,请参阅@987654327 @.)
正如@Winger Sendon 在我的答案下方的评论中指出的那样,我们可以强制 C 根据数组 size 将数组 type 视为不同! p>
首先,您必须认识到,在我上面的示例中,像这样使用int array1[2];:arraytest(array1); 会导致array1 自动衰减为int *。但是,如果您使用 array1 的地址并调用 arraytest(&array1),则会得到完全不同的行为!现在,它不会衰减为 int *!这是因为如果您将的地址 设为一个数组,那么您已经 具有指针类型,并且指针类型不会适应其他指针类型。只有数组类型才能适应指针类型。因此,&array1 的类型是 int (*)[2],这意味着 “指向大小为 2 的 int 数组的指针”,或 “指向int 类型的大小为 2 的数组”,或者也称为 “指向 2 个 int 数组的指针”。 因此,您可以通过将显式指针传递给数组来强制 C 检查数组的类型安全性,如下所示:
// `a` is of type `int (*)[2]`, which means "pointer to array of 2 ints";
// since it is already a ptr, it can NOT automatically decay further
// to any other type of ptr
void arraytest(int (*a)[2])
{
// my function here
}
这种语法很难阅读,但类似于function pointer。在线工具cdecl 告诉我们int (*a)[2] 的意思是:“将a 声明为指向int 数组2 的指针”(指向2 数组ints 的指针)。不要将此与不带括号的版本混淆:int * a[2],这意味着:“将 a 声明为指向 int 的指针的数组 2”(AKA:2 个指针到int,又名:2 个数组 int*s)。
现在,这个函数需要你像这样使用地址运算符 (&) 调用它,使用指向正确大小的数组的指针作为输入参数!:
int array1[2];
// ok, since the type of `array1` is `int (*)[2]` (ptr to array of
// 2 ints)
arraytest(&array1); // you must use the & operator here to prevent
// `array1` from otherwise automatically decaying
// into `int *`, which is the WRONG input type here!
然而,这会产生一个警告:
int array1[2];
// WARNING! Wrong type since the type of `array1` decays to `int *`:
// main.c:32:15: warning: passing argument 1 of ‘arraytest’ from
// incompatible pointer type [-Wincompatible-pointer-types]
// main.c:22:6: note: expected ‘int (*)[2]’ but argument is of type ‘int *’
arraytest(array1); // (missing & operator)
你可以test this code here。
要强制 C 编译器将此警告转换为错误,因此您必须始终仅使用大小正确的输入数组调用 arraytest(&array1);和(在本例中为 int array1[2]; ),将-Werror 添加到您的构建选项中。如果在 onlinegdb.com 上运行上面的测试代码,请单击右上角的齿轮图标并单击“Extra Compiler Flags”以输入此选项。现在,此警告:
main.c:34:15: warning: passing argument 1 of ‘arraytest’ from incompatible pointer type [-Wincompatible-pointer-types]
main.c:24:6: note: expected ‘int (*)[2]’ but argument is of type ‘int *’
会变成这个构建错误:
main.c: In function ‘main’:
main.c:34:15: error: passing argument 1 of ‘arraytest’ from incompatible pointer type [-Werror=incompatible-pointer-types]
arraytest(array1); // warning!
^~~~~~
main.c:24:6: note: expected ‘int (*)[2]’ but argument is of type ‘int *’
void arraytest(int (*a)[2])
^~~~~~~~~
cc1: all warnings being treated as errors
请注意,您还可以创建指向给定大小的数组的“类型安全”指针,如下所示:
int array[2]; // variable `array` is of type `int [2]`, or "array of 2 ints"
// `array_p` is a "type safe" ptr to array of size 2 of int; ie: its type
// is `int (*)[2]`, which can also be stated: "ptr to array of 2 ints"
int (*array_p)[2] = &array;
...但我并不一定推荐这个(在 C 中使用这些“类型安全”的数组),因为它让我想起了很多用于在任何地方强制类型安全的 C++ 滑稽动作,在语言语法复杂性、冗长性和难以构建代码的异常高成本,我不喜欢这些,并且之前曾多次抱怨过(例如:参见"My Thoughts on C++" here)。
有关其他测试和实验,另请参阅下面的链接。
参考文献
请参阅上面的链接。另外:
- 我的代码在线实验:https://onlinegdb.com/B1RsrBDFD
另见:
- 我对多维数组(例如:二维数组)的回答对上述内容进行了阐述,并在有意义的情况下对多维数组使用了“类型安全”方法:How to pass a multidimensional array to a function in C and C++