传递数组、固定大小数组和数组基址作为函数参数的区别

问题描述 投票:0回答:7

如果我想将已知或未知大小的数组作为函数参数传递,我对使用哪种语法感到困惑。

假设我有这些变体用于此目的:

void func1(char* str) {
    //print str
}

void func2(char str[]) {
    //print str
}

void func3(char str[10]) {
    //print str
}

使用其中每一种的优点和缺点是什么?

c++ arrays pointers
7个回答
96
投票

所有这些变体都是相同的。 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
)参考


27
投票

请注意,在 C++ 中,如果在编译时已知数组的长度(例如,如果传递了字符串文字),则实际上可以获得其大小:

template<unsigned int N>
void func(const char(&str)[N])
{
    // Whatever...
}

int main()
{
    func("test"); // Works, N is 5
}

12
投票

在 C++ 中,使用

void func4(const std::string& str)


12
投票

这些在功能上都是相同的。当您将数组传递给 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]


2
投票

在 C 中,前两个定义是等效的。第三个定义本质上是相同的,但它给出了关于数组大小的想法。

如果打印

str
是您的意图,那么您可以安全地使用它们中的任何一个。本质上,所有三个函数都传递了
char*
类型的参数,正是
printf()
需要打印字符串。以免您不这样做不知道,不管看起来如何,C 中的所有参数传递都是在
pass-by-value
模式下完成的。

编辑:看来从今以后我必须非常严格地选择单词。好吧,在第三种情况下,它不知道数组传递到的函数的大小因为最终它会被简化为

char*
类型,就像前两种情况一样。我的意思是说,它有点告诉阅读它的人数组的大小是 10。而且,在 C 中这不是错误/非法的。但是对于程序,这样做就像没用一样。它根本不知道传递给函数的数组大小。Downvoter 先生,感谢您指出 SO 不容忍随意的态度和疏忽。


1
投票

在一维数组中,编译器对它们的处理方式相同。然而,对于二维或更多维数组(例如

myArray[10][10]
),它很有用,因为它可用于确定数组的行/列长度。


1
投票

补充,分点描述。

1)正如大家所说,都是一样的。

2) 数组在函数参数中传递时会退化为指针。

3)根本问题可能是在函数中查找数组的大小。为此,我们可以使用类似的宏。

   #define noOfElements(v) sizeof(v)/sizeof(0[v])

   int arr[100]
   myfunction ( arr, noOfElements(arr))

0[v] 或 v[0] 都可以在宏中使用,其中第一个用于避免将用户定义的数据类型传递给 noOfElements。

希望这有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.