在C语言中将数组作为参数传递

3

我(认为我)理解,只有在编译时在堆栈上声明数组时,才能使用sizeof检索数组的大小,例如:

int my_array[] = {1,2,3};
sizeof(my_array) == 3;

一旦你开始使用指针,就会失去数组的长度信息。

例如,如果你将一个 int 指针作为函数参数传递,以获取一个 int 数组到函数中,你就不能再像这样使用 sizeof(),它只会返回用于存储指针的字节数。

显然,知道你的数组有多长非常重要。

那么,在传递数组时我应该使用以下哪个选项呢?

  1. Pass a pointer and an accompanying length parameter

    int my_func(int *my_array, size_t len_my_array)

  2. Create my own vector struct

    struct vector {
       int *my_array;
       size_t len;
    }
    
    int my_func(struct vector *my_vector)
    
  3. Use someone elses vector implementation. (Is there a default implementation for C as there is for C++?)

  4. Another approach which I've missed?

我目前正在使用第一种选项,但它有些笨重,我很想知道这是否被认为是糟糕的编程实践。


2
sizeof(my_array) == 3; => sizeof(my_array)/sizeof(int) == 3; sizeof(my_array)/sizeof(int) == 3; - BLUEPIXY
5个回答

7

你错过的一种方法是在数组末尾放置一个终止元素,有点像'\0'标记char*的结尾。

这和将数组的长度作为不同参数传递是常用的方法。


我可以看到在决定终止元素的值时存在问题。 - bph
@Hiett,对于char*和其他类型,这个方法是可行的。当然,在您的情况下,您应该选择最适合您的方式。 - Luchian Grigore

5

标准方法是使用第一种方法,特别是当您希望其他人重复使用您的代码时,请传递指针和大小。


3
在现代 C 语言(又称 C99)中,我认为最简单的方法是使用数组符号。
int my_func(size_t len, int my_array[len]);

这与您所做的几乎相同,但是先确定大小。之所以按照这个顺序进行操作,是因为这对于多维数组的扩展非常有效。

int my_func(size_t n, size_t m, int my_array[n][m]);

这样,您就可以在函数内正确地进行索引计算,而不会遇到任何额外的困难。

您需要确保的唯一事情是:

  • 在数组之前将列表中的大小写好,这样在声明数组时就知道大小了
  • 在原型中使用与定义后使用完全相同的声明(维度符号等),否则会让用户感到困惑

这看起来很整洁,但是my_array[len]中的第二个len是否真的起作用?例如,以下三者是否等效:int my_array[len]int my_array[]int *my_array - bph
1
不,在第一个例子中,这只是一种语法糖,但很好地表达了期望,我觉得。对于第二个例子,这真的改变了事情。否则你就无法做像my_array[i][j]这样的操作。 - Jens Gustedt
1
我注意到你提到的语法在C99中是有效的,但在C90中是无效的。 - Robᵩ
@Rob,没错,我有时候会忘记还有人对古老的文本感兴趣。我会加上的。 - Jens Gustedt
那么将数组参数声明为int my_array[len],使得sizeof my_array能正确地返回数组的大小? - Ferdi265
1
@Ferdi265,不幸的是,第一维仍然只是一个指针。但是第二维是可以的,在我第二个示例代码中,sizeof(*myarray)会给你一行的正确大小。 - Jens Gustedt

1

没有被广泛接受的答案,这意味着你唯一可以依赖的方式就是第一个。特别是,除非你自己编写所有的代码(即,从不使用任何库),否则你几乎可以肯定,你自己定义的vector结构与其他人使用的任何东西都不同,所以在代码库之间的“边界”处,无论如何你都需要使用第一种方法。他们可能有自己内部使用的vector类型。你可能有自己内部使用的类型 - 但是当两者彼此交流时,它们将不得不将该类型“解开”为其各个组件。


0
这个有点复杂,但我刚刚在阅读关于数组和指针的内容,你可以考虑使用sizeof来确定总字节数,然后除以数组包含的数据类型的字节大小,从而得到数组的长度...

1
是的,我见过定义宏来实现这个功能,但是我不清楚它适用于哪些情况——因为指向int的指针并不知道它所指向的数组有多长。 - bph
其实,仔细想想,你说得对 - 指针必须始终知道它指向多少字节,否则free()怎么能工作呢?它只接受一个参数,即指针的名称,并成功释放堆上正确数量的内存... - bph
所以这样应该可以 - #define sizearray(a) (sizeof(a) / sizeof((a)[0])) - bph
1
这样不行,对于数组参数的 sizeof 返回指针类型的大小。指针永远不会存储大小信息。大部分操作系统在内部存储动态分配内存区域的大小以便于 free() 的工作,但是没有(可移植的)方法来提取它。 - osvein
@osvein 你所说的只有在sizeof的参数是一个指针时才成立,因为你将一个已经衰变为指针的函数参数传递给它:https://dev59.com/sHVD5IYBdhLWcg3wQZQg - Lover of Structure

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接