C++ 什么时候需要将数组的大小作为参数传递
我对在C/C++中传递数组有点困惑。我看到一些案例的签名是这样的C++ 什么时候需要将数组的大小作为参数传递,c++,c,arrays,parameters,C++,C,Arrays,Parameters,我对在C/C++中传递数组有点困惑。我看到一些案例的签名是这样的 void f(int arr[]) void f(int arr[], int size) 有些是这样的 void f(int arr[]) void f(int arr[], int size) P>是否有人详细说明了它的区别和使用方法, < P>当数组在C或C++中传递时,只传递其地址。这就是为什么第二种情况非常常见,其中第二个参数是数组中的元素数。函数不知道,只是通过查看数组的地址,它应该包含多少元素。您可以编写
void f(int arr[])
void f(int arr[], int size)
有些是这样的
void f(int arr[])
void f(int arr[], int size)
<> P>是否有人详细说明了它的区别和使用方法, < P>当数组在C或C++中传递时,只传递其地址。这就是为什么第二种情况非常常见,其中第二个参数是数组中的元素数。函数不知道,只是通过查看数组的地址,它应该包含多少元素。您可以编写
void f( int *arr, int size )
另外,使用后者(大小)允许在读取/写入时不超出数组边界第一个签名只是通过数组,无法判断数组的大小,并可能导致出现越界错误和/或安全缺陷的问题\ 第二个签名是一个更安全的版本,因为它允许函数检查数组的大小,以防止第一个版本的缺陷
除非这是家庭作业,否则原始数组有点过时。改用std::vector。它允许在不需要手动传递大小的情况下传递向量,因为它可以为您传递大小。数组的大小不会与数组本身一起传递。因此,如果另一个函数需要这个大小,它将把它作为一个参数 问题是,有些函数隐式地理解数组具有一定的大小。所以他们不需要显式地指定它。例如,如果您的函数在3个浮点数组上运行,则不需要用户告诉您它是3个浮点数组。就拿一个数组 还有一些函数(我们称它们为“可怕的”,因为它们是)将用任意数据填充数组,直到数据定义的某个点<代码>sprintf可能是“最好”的例子。它将继续将字符放入该数组中,直到完成写入。这非常糟糕,因为用户和函数之间对于数组的大小没有明确或隐含的一致意见
sprintf
将写入一些字符,但用户无法确切知道写入了多少字符(一般情况下)
这就是为什么你应该永远不要使用
sprintf
;使用snprintf
或\u snprintf
,具体取决于您的编译器。任何时候您需要知道数组的大小,都需要提供它。传递数组本身的两种形式没有什么特别之处;第一个参数在两种方式中都是相同的。第二种方法只提供了解数组大小所需的信息,而第一种方法不提供
不过,有时数组本身保存有关其大小的信息。例如,在第一个示例中,可能将arr[0]
设置为数组的大小,实际数据从arr[1]
开始。或者考虑C字符串的情况…您只提供了一个char[]
,并且假定数组在第一个元素处结束,该元素等于\0
。在您的示例中,负值可能充当类似的哨兵。或者,函数根本不关心数组的大小,只会假设它足够大
这种方法本质上是不安全的,尽管。。。很容易忘记设置
arr[0]
或意外覆盖空终止符。然后,f
突然无法知道它有多少可用空间。始终倾向于显式提供大小,可以通过您显示的size
参数,也可以使用指向数组末尾的第二个指针。后者是C++中标准库函数所采用的方法。不过,你仍然有提供错误大小的问题,这就是为什么C++不推荐你首先使用这样的数组…使用一个实际的容器为您跟踪该信息。首先,传递给函数的数组实际上会传递指向数组第一个元素的指针,例如,如果您有
int a[] = { 1, 2, 3 };
f(a);
然后,f()
获取传递给它的&a[0]
。因此,在编写函数原型时,以下内容是等效的:
void f(int arr[]);
void f(int *arr);
这意味着数组的大小丢失,并且通常f()
无法确定大小。(这就是为什么我更喜欢void f(int*arr)
form而不是void f(int arr[])
)
有两种情况下,f()
不需要这些信息,在这两种情况下,不需要额外的参数也可以
首先,在arr
中有一些特殊的、一致的值,调用者和f()
都认为这意味着“结束”。例如,可以同意值0
表示“完成”
然后你可以写:
int a[] = { 1, 2, 3, 0 }; /* make sure there is a 0 at the end */
int result = f(a);
并定义如下内容:
int f(int *a)
{
size_t i;
int result = 0;
for (i=0; a[i]; ++i) /* loop until we see a 0 */
result += a[i];
return result;
}
显然,只有当调用者和被调用者都同意约定并遵循约定时,上述方案才有效。例如C库中的strlen()
函数。它通过查找0
来计算字符串的长度。如果你在最后传递了一个没有0
的东西,那么所有的赌注都被取消,你处于未定义的行为领域
第二种情况是当您没有真正的数组时。在本例中,f()
获取指向对象的指针(int
)。因此:
与
很好:
f()
无论如何都不会在数组上运行。区别在于第二个数组包含一个指示数组大小的参数。逻辑上的结论是,如果不使用这样的参数,函数就不知道数组的大小。事实证明确实如此。事实上,它不知道你有一个数组。事实上,调用函数不需要数组
此处的数组语法没有指定大小
void toto(double A[23]);
void toto(double *A);
void toto(double A[static 23]);
void toto(double A[const 23]);
void toto(double A[23][7]);
void toto(double (*A)[7]);
void toto(size_t n, size_t m, double A[n][m]);