This question already has an answer here:
这个问题在这里已有答案:
- How can I get the size of an array from a pointer in C? 13 answers
- 如何从C中的指针获取数组的大小? 13个答案
For the following scenario, how can I get the size (3) of the array a
via the pointer c
? What is the pattern for solving this sort of problems?
对于以下场景,如何通过指针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) */
}
3 个解决方案
#1
4
In C, no information about the size of the array is stored with the array. You have to know how big it is to work with it safely.
在C中,没有关于数组大小的信息与数组一起存储。你必须知道安全地使用它有多大。
There are a few techniques for working around this. If the array is declared statically in the current scope, you can determine the size as:
有一些解决这个问题的技巧。如果在当前范围内静态声明数组,则可以将大小确定为:
size_t size = (sizeof(a) / sizeof(a[0]);
This is useful if you don't want to have to update the size every time you add an element:
如果您不希望每次添加元素时都必须更新大小,这将非常有用:
struct point a[] = {{1, 1, 1}, {2, 2, 2}};
size_t size = (sizeof(a) / sizeof(a[0));
But if you have an arbitrary array, that has been passed in from somewhere else, or converted to a pointer as in your example, you'll need some way of determining its size. The usual ways to do this are to pass the size in along with the array (either as a separate parameter, or as a struct containing the array), or if the array is of a type which can contain a sentinel value (a value of the given type that is not valid), you can allocate an array one bigger than you need add a sentinel to the end of the array and use that to determine when you've reached the end.
但是如果你有一个任意数组,从其他地方传入,或者像你的例子那样转换为指针,你需要某种方法来确定它的大小。通常的方法是将大小与数组一起传递(作为单独的参数,或作为包含数组的结构),或者如果数组的类型可以包含sentinel值(值为如果给定的类型无效),您可以分配一个比您需要的更大的数组,将一个标记添加到数组的末尾,并使用它来确定何时到达最后。
Here's how you might pass in a length as a separate argument:
以下是您可以将长度作为单独的参数传递的方式:
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 ...
}
}
Or as a structure containing the length:
或者作为包含长度的结构:
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 ...
}
}
It would probably be hard to use sentinel values with an array of struct point
directly, as there is no obvious invalid value that is still of the same type, but they are commonly used for strings (arrays of char
which are terminated by a '\0'
character), and arrays of pointers which are terminated by a null pointer. We can use that with struct point
by storing pointers to our structures rather than storing them inline in the array:
可能很难直接使用具有结构点数组的sentinel值,因为没有明显的无效值仍然是相同的类型,但它们通常用于字符串(char的数组以''终止0'字符),以及由空指针终止的指针数组。我们可以通过存储指向结构的指针而不是将它们内联存储在数组中来使用结构点:
struct point *myfunction(struct point *a[]) {
for (size_t i = 0; a[i] != NULL; ++i) {
struct point *p = a[i];
// do something with p ...
}
}
#2
7
You can't. The pointer is just an address, a number, and it doesn't hold any information about the data it points to except its type.
你不能。指针只是一个地址,一个数字,它不包含任何有关它指向的数据的信息,除了它的类型。
Side note: that's why they say "arrays decay to pointers". They "decay" because inherently a pointer holds less information compared to an array.
旁注:这就是他们说“数组衰减到指针”的原因。它们“衰减”,因为与数组相比,指针本身保存的信息较少。
As nims points out in the comments when passing an array to a function, it automatically decays to a pointer to the first element - and doing sizeof
in the function doesn't yield the expected result. Incidentally there's also a C FAQ about this.
当nims在将数组传递给函数时在注释中指出,它会自动衰减到指向第一个元素的指针 - 并且在函数中执行sizeof不会产生预期的结果。顺便说一下,还有一个关于这个问题的C FAQ。
#3
0
There's a way to determine the length of an array, but for that you would have to mark the end of the array with another element, such as -1. Then just loop through it and find this element. The position of this element is the length.
有一种方法可以确定数组的长度,但为此你必须用另一个元素标记数组的结尾,例如-1。然后循环遍历它并找到这个元素。该元素的位置是长度。
#1
4
In C, no information about the size of the array is stored with the array. You have to know how big it is to work with it safely.
在C中,没有关于数组大小的信息与数组一起存储。你必须知道安全地使用它有多大。
There are a few techniques for working around this. If the array is declared statically in the current scope, you can determine the size as:
有一些解决这个问题的技巧。如果在当前范围内静态声明数组,则可以将大小确定为:
size_t size = (sizeof(a) / sizeof(a[0]);
This is useful if you don't want to have to update the size every time you add an element:
如果您不希望每次添加元素时都必须更新大小,这将非常有用:
struct point a[] = {{1, 1, 1}, {2, 2, 2}};
size_t size = (sizeof(a) / sizeof(a[0));
But if you have an arbitrary array, that has been passed in from somewhere else, or converted to a pointer as in your example, you'll need some way of determining its size. The usual ways to do this are to pass the size in along with the array (either as a separate parameter, or as a struct containing the array), or if the array is of a type which can contain a sentinel value (a value of the given type that is not valid), you can allocate an array one bigger than you need add a sentinel to the end of the array and use that to determine when you've reached the end.
但是如果你有一个任意数组,从其他地方传入,或者像你的例子那样转换为指针,你需要某种方法来确定它的大小。通常的方法是将大小与数组一起传递(作为单独的参数,或作为包含数组的结构),或者如果数组的类型可以包含sentinel值(值为如果给定的类型无效),您可以分配一个比您需要的更大的数组,将一个标记添加到数组的末尾,并使用它来确定何时到达最后。
Here's how you might pass in a length as a separate argument:
以下是您可以将长度作为单独的参数传递的方式:
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 ...
}
}
Or as a structure containing the length:
或者作为包含长度的结构:
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 ...
}
}
It would probably be hard to use sentinel values with an array of struct point
directly, as there is no obvious invalid value that is still of the same type, but they are commonly used for strings (arrays of char
which are terminated by a '\0'
character), and arrays of pointers which are terminated by a null pointer. We can use that with struct point
by storing pointers to our structures rather than storing them inline in the array:
可能很难直接使用具有结构点数组的sentinel值,因为没有明显的无效值仍然是相同的类型,但它们通常用于字符串(char的数组以''终止0'字符),以及由空指针终止的指针数组。我们可以通过存储指向结构的指针而不是将它们内联存储在数组中来使用结构点:
struct point *myfunction(struct point *a[]) {
for (size_t i = 0; a[i] != NULL; ++i) {
struct point *p = a[i];
// do something with p ...
}
}
#2
7
You can't. The pointer is just an address, a number, and it doesn't hold any information about the data it points to except its type.
你不能。指针只是一个地址,一个数字,它不包含任何有关它指向的数据的信息,除了它的类型。
Side note: that's why they say "arrays decay to pointers". They "decay" because inherently a pointer holds less information compared to an array.
旁注:这就是他们说“数组衰减到指针”的原因。它们“衰减”,因为与数组相比,指针本身保存的信息较少。
As nims points out in the comments when passing an array to a function, it automatically decays to a pointer to the first element - and doing sizeof
in the function doesn't yield the expected result. Incidentally there's also a C FAQ about this.
当nims在将数组传递给函数时在注释中指出,它会自动衰减到指向第一个元素的指针 - 并且在函数中执行sizeof不会产生预期的结果。顺便说一下,还有一个关于这个问题的C FAQ。
#3
0
There's a way to determine the length of an array, but for that you would have to mark the end of the array with another element, such as -1. Then just loop through it and find this element. The position of this element is the length.
有一种方法可以确定数组的长度,但为此你必须用另一个元素标记数组的结尾,例如-1。然后循环遍历它并找到这个元素。该元素的位置是长度。