Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 什么时候需要将数组的大小作为参数传递_C++_C_Arrays_Parameters - Fatal编程技术网

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++中传递时,只传递其地址。这就是为什么第二种情况非常常见,其中第二个参数是数组中的元素数。函数不知道,只是通过查看数组的地址,它应该包含多少元素。您可以编写

我对在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]);