如何通过指针获取数组的大小?

3
在以下场景中,我如何通过指针 c 获取数组 a 的大小(3)?解决这种问题的模式是什么?
struct struct_point {
  int x;
  int y;
  int z;
};

typedef struct struct_point point;

int test_void_pointer () {
  point a[3] = {{1, 1, 1}, {2, 2, 2}};
  void * b;
  point * c;
  b = a;
  c = b;
  /* get_size_p (c) */
}

你对数组的大小是以字节还是元素数量为单位感兴趣? - haccks
3个回答

7
你无法这样做。指针只是一个地址,一个数字,它没有保存除类型之外关于其所指向的数据的任何信息。
顺便说一下:这就是为什么他们称“数组退化为指针”。它们“退化”是因为从根本上来说,指针保存的信息比数组少。
正如nims在评论中指出的那样,当将数组传递给函数时,它会自动退化为对第一个元素的指针-在函数中执行sizeof不会产生预期的结果。恰好也有一篇关于此的C FAQ

2
只是补充一下:这就是为什么在将数组作为参数传递给函数时无法确定其大小。 - Natan Streppel
@cnicutar的nims指针似乎很有用 - 我认为你应该将它添加到你的答案中。 - exexzian

4
在C语言中,数组的大小信息并不会存储在数组内。如果要安全地使用它,您必须知道它的大小。
有一些技巧可以解决这个问题。如果数组在当前作用域中以静态方式声明,您可以按以下方式确定其大小:
size_t size = (sizeof(a) / sizeof(a[0]);

这很有用,如果你不想每次添加元素时都更新大小:
struct point a[] = {{1, 1, 1}, {2, 2, 2}};
size_t size = (sizeof(a) / sizeof(a[0));

但是,如果你有一个任意数组,这个数组从其他地方传递进来的,或者像你的例子一样被转换为指针,你需要某种方式来确定它的大小。通常的做法是将大小与数组一起传递(可以作为单独的参数,也可以作为包含数组的结构体),或者如果该数组是可以包含哨兵值(给定类型的无效值)的类型,则可以分配比实际需要的数组大一号的数组,并向数组末尾添加一个哨兵值来确定何时到达数组的末尾。
以下是将长度作为单独参数传递的示例:
struct point myfunction(struct point array[], size_t n) {
    for (size_t i = 0; i < n; ++i) {
        struct point p = array[i];
        // do something with p ...
    }
}

或者作为包含长度信息的结构体:

struct point_array {
    size_t n;
    struct point elems[];
}
struct point myfunction(struct point_array a) {
    for (size_t i = 0; i < a.n; ++i) {
        struct point p = a.elems[i];
        // do something with p ...
    }
}

对于一个struct point数组,直接使用哨兵值可能会比较困难,因为没有明显的无效值可以保持相同的类型,但是它们通常用于字符串(以'\0'字符结尾的char数组)和以空指针结尾的指针数组。我们可以通过将指向结构体的指针存储在数组中而不是内联存储来将其应用于struct point

struct point *myfunction(struct point *a[]) {
    for (size_t i = 0; a[i] != NULL; ++i) {
        struct point *p = a[i];
        // do something with p ...
    }
}

0
有一种方法可以确定数组的长度,但需要在数组末尾标记另一个元素(例如-1)。然后只需要遍历数组并查找该元素。该元素的位置就是数组的长度。

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