如果我想将已知或未知大小的数组作为函数参数传递,我对使用哪种语法感到困惑。
假设我有这些变体用于此目的:
void func1(char* str) {
//print str
}
void func2(char str[]) {
//print str
}
void func3(char str[10]) {
//print str
}
使用其中每一种的优点和缺点是什么?
所有这些变体都是相同的。 C 只是允许您使用替代拼写,但即使是用数组大小显式注释的最后一个变体也会衰减为普通指针。
也就是说,即使使用最后一个实现,您也可以使用 any 大小的数组调用该函数:
void func3(char str[10]) { }
func("test"); // Works.
func("let's try something longer"); // Not a single f*ck given.
不用说,这应该不被使用:它可能会给用户一种错误的安全感(“哦,这个函数只接受长度为10的数组,所以我不需要自己检查长度”)。
正如 Henrik 所说,在 C++ 中的正确方法是使用强类型缓冲区。根据您的用例和参数的实际含义,这可以是字符串类型(例如
std::string
1或std::string_view
)、字节缓冲区(std::vector<char>
1或迭代器) -分隔范围)或固定宽度范围或切片(std::array<char, N>
、std::span<char, N>
)。
1通常作为(
const
)参考
请注意,在 C++ 中,如果在编译时已知数组的长度(例如,如果传递了字符串文字),则实际上可以获得其大小:
template<unsigned int N>
void func(const char(&str)[N])
{
// Whatever...
}
int main()
{
func("test"); // Works, N is 5
}
在 C++ 中,使用
void func4(const std::string& str)
。
这些在功能上都是相同的。当您将数组传递给 C 中的函数时,数组会隐式转换为指向数组第一个元素的指针。因此,这三个函数将打印相同的输出(即指向
char
的指针的大小)。
void func1(char* str) {
printf("sizeof str: %zu\n", sizeof str);
}
void func2(char str[]) {
printf("sizeof str: %zu\n", sizeof str);
}
void func3(char str[10]) {
printf("sizeof str: %zu\n", sizeof str);
}
此转换仅适用于数组的第一维。
char[42][13]
会转换为 char (*)[13]
,不是 char **
。
void func4(char (*str_array)[13]) {
printf("sizeof str_array: %zu\n"
"sizeof str_array[0]: %zu\n", sizeof str_array, sizeof str_array[0]);
}
char (*)[13]
是 str_array
的类型。这就是“指向 13 个 char
数组的指针”的写法。这也可以写成 void func4(char str_array[42][13]) { ... }
,尽管 42 在功能上没有意义,正如您通过实验将不同大小的数组传递到 func4
中看到的那样。
在 C99 和 C11(但不是 C89 或 C++)中,您可以将指向不同大小的数组的指针传递到函数中,方法是随其传递数组的大小,并将大小标识符包含在
[square brackets]
中。例如:
void func5(size_t size, char (*str_array)[size]) {
printf("sizeof str_array: %zu\n"
"sizeof str_array[0]: %zu\n", sizeof str_array, sizeof str_array[0]);
}
这声明了一个指向 size
char
数组的指针。请注意,您必须先取消引用 pointer,然后才能访问该数组。在上面的示例中, sizeof str_array[0]
计算的是数组的大小,而不是第一个元素的大小。例如,要访问第 11 个元素,请使用 (*str_array)[11]
或 str_array[0][11]
。
在 C 中,前两个定义是等效的。第三个定义本质上是相同的,但它给出了关于数组大小的想法。
如果打印
str
是您的意图,那么您可以安全地使用它们中的任何一个。本质上,所有三个函数都传递了 char*
类型的参数,正是 printf()
需要打印字符串。以免您不这样做不知道,不管看起来如何,C 中的所有参数传递都是在 pass-by-value
模式下完成的。
编辑:看来从今以后我必须非常严格地选择单词。好吧,在第三种情况下,它不知道数组传递到的函数的大小因为最终它会被简化为
char*
类型,就像前两种情况一样。我的意思是说,它有点告诉阅读它的人数组的大小是 10。而且,在 C 中这不是错误/非法的。但是对于程序,这样做就像没用一样。它根本不知道传递给函数的数组大小。Downvoter 先生,感谢您指出 SO 不容忍随意的态度和疏忽。
在一维数组中,编译器对它们的处理方式相同。然而,对于二维或更多维数组(例如
myArray[10][10]
),它很有用,因为它可用于确定数组的行/列长度。
补充,分点描述。
1)正如大家所说,都是一样的。
2) 数组在函数参数中传递时会退化为指针。
3)根本问题可能是在函数中查找数组的大小。为此,我们可以使用类似的宏。
#define noOfElements(v) sizeof(v)/sizeof(0[v])
int arr[100]
myfunction ( arr, noOfElements(arr))
0[v] 或 v[0] 都可以在宏中使用,其中第一个用于避免将用户定义的数据类型传递给 noOfElements。
希望这有帮助。