C中是否有一个标准函数可以返回数组的长度?

时间:2022-05-06 16:47:55

Is there a standard function in C that would return the length of an array?

C中是否有一个标准函数可以返回数组的长度?

6 个解决方案

#1


59  

Often the technique described in other answers is encapsulated in a macro to make it easier on the eyes. Something like:

通常,在其他答案中描述的技术被封装在一个宏中,以使它更容易被眼睛看到。喜欢的东西:

#define COUNT_OF( arr) (sizeof(arr)/sizeof(0[arr]))

Note that the macro above uses a small trick of putting the array name in the index operator ('[]') instead of the 0 - this is done in case the macro is mistakenly used in C++ code with an item that overloads operator[](). The compiler will complain instead of giving a bad result.

注意,上面的宏使用了一个小技巧,将数组名放在索引操作符('[]')中,而不是0——这是为了防止在c++代码中错误地使用该宏,并在一个项中重载操作符[]()。编译器将会抱怨而不是给出糟糕的结果。

However, also note that if you happen to pass a pointer instead of an array, the macro will silently give a bad result - this is one of the major problems with using this technique.

但是,还要注意,如果您碰巧传递的是一个指针而不是一个数组,那么宏将会悄无声息地给出一个糟糕的结果——这是使用这种技术的主要问题之一。

I have recently started to use a more complex version that I stole from Google Chromium's codebase:

我最近开始使用从谷歌Chromium的代码基中偷来的一个更复杂的版本:

#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))

In this version if a pointer is mistakenly passed as the argument, the compiler will complain in some cases - specifically if the pointer's size isn't evenly divisible by the size of the object the pointer points to. In that situation a divide-by-zero will cause the compiler to error out. Actually at least one compiler I've used gives a warning instead of an error - I'm not sure what it generates for the expression that has a divide by zero in it.

在这个版本中,如果一个指针被错误地作为参数传递,编译器会在某些情况下抱怨——特别是当指针的大小不能被指针指向的对象的大小平均分割的时候。在这种情况下,二分法将导致编译器出错。实际上,我使用过的至少一个编译器给出了一个警告而不是一个错误——我不确定它为表达式生成了什么,其中包含一个除以0的表达式。

That macro doesn't close the door on using it erroneously, but it comes as close as I've ever seen in straight C.

这个宏并没有关闭错误使用它的大门,但是它是我在直C中所见过的最接近的。

If you want an even safer solution for when you're working in C++, take a look at Compile time sizeof_array without using a macro which describes a rather complex template-based method Microsoft uses in winnt.h.

如果您希望在c++中使用更安全的解决方案,那么可以在不使用宏的情况下查看编译时sizeof_array,该宏描述了Microsoft在winnt.h中使用的相当复杂的基于模板的方法。

#2


14  

No, there is not.

不,没有。

For constant size arrays you can use the common trick Andrew mentioned, sizeof(array) / sizeof(array[0]) - but this works only in the scope the array was declared in.
sizeof(array) gives you the size of the whole array, while sizeof(array[0]) gives you the size of the first element.
See Michaels answer on how to wrap that in a macro.

对于常量大小的数组,您可以使用Andrew提到的常见技巧sizeof(数组)/ sizeof(数组[0])—但是这只在数组声明的范围内有效。sizeof(数组)给出了整个数组的大小,而sizeof(数组[0])给出了第一个元素的大小。参见Michaels回答如何在宏中包装它。

For dynamically allocated arrays you either keep track of the size in an integral type or make it 0-terminated if possible (i.e. allocate 1 more element and set the last element to 0).

对于动态分配的数组,您可以在整数类型中跟踪大小,也可以在可能的情况下使其以0结尾(例如,再分配一个元素并将最后一个元素设置为0)。

#3


5  

sizeof array / sizeof array[0]

#4


3  

The number of elements in an array x can be obtained by:

数组x中的元素数可通过:

sizeof(x)/sizeof(x[0])

You need to be aware that arrays, when passed to functions, are degraded into pointers which do not carry the size information. In reality, the size information is never available to the runtime since it's calculated at compile time, but you can act as if it is available where the array is visible (i.e., where it hasn't been degraded).

您需要注意的是,当数组传递给函数时,数组被分解为指针,不携带大小信息。实际上,由于在编译时计算大小信息,所以运行时永远无法获得大小信息,但是您可以将它当作在数组可见的地方可用(例如)。,在那里它没有被降级。

When I pass arrays to a function that I need to treat as arrays, I always ensure two arguments are passed:

当我将数组传递给一个我需要处理为数组的函数时,我总是确保通过了两个参数:

  • the length of the array; and
  • 数组的长度;和
  • the pointer to the array.
  • 指向数组的指针。

So, whilst the array can be treated as an array where it's declared, it's treated as a size and pointer everywhere else.

所以,虽然数组可以被当作一个数组来声明,但是在其他地方它被当作一个大小和指针。

I tend to have code like:

我倾向于这样的代码:

#define countof(x) (sizeof(x)/sizeof(x[0]))
: : :
int numbers[10];
a = fn (countof(numbers),numbers);

then fn() will have the size information available to it.

然后fn()将有可用的大小信息。

Another trick I've used in the past (a bit messier in my opinion but I'll give it here for completeness) is to have an array of a union and make the first element the length, something like:

我过去使用过的另一个技巧(在我看来有点混乱,但我在这里给出它的完整性)是拥有一个联合数组,并使第一个元素的长度,类似于:

typedef union {
    int len;
    float number;
} tNumber;
tNumber number[10];
: : :
number[0].len = 5;
a = fn (number);

then fn() can access the length and all the elements and you don't have to worry about the array/pointer dichotomy.

然后fn()可以访问长度和所有元素,您不必担心数组/指针二分法。

This has the added advantage of allowing the length to vary (i.e., the number of elements in use, not the number of units allocated). But I tend not to use this anymore since I consider the two-argument array version (size and data) better.

这有一个额外的优势,允许长度变化(例如。,使用的元素数量,而不是分配的单元数量)。但是我不再使用它,因为我认为双参数数组版本(大小和数据)更好。

#5


2  

The simple answer, of course, is no. But the practical answer is "I need to know anyway," so let's discuss methods for working around this.

答案当然是否定的。但实际的答案是“无论如何我都需要知道”,所以让我们讨论解决这个问题的方法。

One way to get away with it for a while, as mentioned about a million times already, is with sizeof():

一种暂时摆脱它的方法是使用sizeof():

int i[] = {0, 1, 2};
...
size_t i_len = sizeof(i) / sizeof(i[0]);

This works, until we try to pass i to a function, or take a pointer to i. So what about more general solutions?

这是可行的,直到我们尝试把i传递给一个函数,或者指向i的指针,那么更一般的解呢?

The accepted general solution is to pass the array length to a function along with the array. We see this a lot in the standard library:

已接受的通用解决方案是将数组长度与数组一起传递给函数。我们在标准库中经常看到:

void *memcpy(void *s1, void *s2, size_t n);

Will copy n bytes from s1 to s2, allowing us to use n to ensure that our buffers never overflow. This is a good strategy - it has low overhead, and it actually generates some efficient code (compare to strcpy(), which has to check for the end of the string and has no way of "knowing" how many iterations it must make, and poor confused strncpy(), which has to check both - both can be slower, and either could be sped up by using memcpy() if you happen to have already calculated the string's length for some reason).

将从s1复制n个字节到s2,允许我们使用n来确保缓冲区不会溢出。这是一个很好的策略——低开销,它生成一些高效的代码(strcpy()进行比较,检查结束的字符串并无法“知道”它必须多少迭代,和穷人困惑strncpy(),已检查都——都可以慢,,要么可以通过使用加速memcpy()如果你碰巧已经计算字符串的长度由于某种原因)。

Another approach is to encapsulate your code in a struct. The common hack is this:

另一种方法是将代码封装在结构体中。最常见的技巧是:

typedef struct _arr {
  size_t len;
  int arr[0];
} arr;

If we want an array of length 5, we do this:

如果我们想要一个长度为5的数组,我们这样做:

arr *a = malloc(sizeof(*a) + sizeof(int) * 5);
a->len = 5;

However, this is a hack that is only moderately well-defined (C99 lets you use int arr[]) and is rather labor-intensive. A "better-defined" way to do this is:

然而,这是一种只有适度定义的技巧(C99允许您使用int arr[]),并且是相当劳动密集型的。一种“更好定义”的方式是:

typedef struct _arr {
  size_t len;
  int *arr;
} arr;

But then our allocations (and deallocations) become much more complicated. The benefit of either of these approaches is, of course, that now arrays you make will carry around their lengths with them. It's slightly less memory-efficient, but it's quite safe. If you chose one of these paths, be sure to write helper functions so that you don't have to manually allocate and deallocate (and work with) these structures.

但是我们的分配(和交易)变得更加复杂。当然,这两种方法的好处是,现在您所创建的数组将携带它们的长度。它的内存效率略低,但很安全。如果您选择了其中的一条路径,请确保编写帮助函数,这样您就不必手动分配和分配(并处理)这些结构。

#6


0  

If you have an object a of array type, the number of elements in the array can be expressed as sizeof a / sizeof *a. If you allowed your array object to decay to pointer type (or had only a pointer object to begin with), then in general case there's no way to determine the number of elements in the array.

如果您有一个数组类型的对象a,那么数组中的元素数可以表示为sizeof a / sizeof *a。如果允许数组对象衰减到指针类型(或者开始只有一个指针对象),那么通常情况下,无法确定数组中的元素数量。

#1


59  

Often the technique described in other answers is encapsulated in a macro to make it easier on the eyes. Something like:

通常,在其他答案中描述的技术被封装在一个宏中,以使它更容易被眼睛看到。喜欢的东西:

#define COUNT_OF( arr) (sizeof(arr)/sizeof(0[arr]))

Note that the macro above uses a small trick of putting the array name in the index operator ('[]') instead of the 0 - this is done in case the macro is mistakenly used in C++ code with an item that overloads operator[](). The compiler will complain instead of giving a bad result.

注意,上面的宏使用了一个小技巧,将数组名放在索引操作符('[]')中,而不是0——这是为了防止在c++代码中错误地使用该宏,并在一个项中重载操作符[]()。编译器将会抱怨而不是给出糟糕的结果。

However, also note that if you happen to pass a pointer instead of an array, the macro will silently give a bad result - this is one of the major problems with using this technique.

但是,还要注意,如果您碰巧传递的是一个指针而不是一个数组,那么宏将会悄无声息地给出一个糟糕的结果——这是使用这种技术的主要问题之一。

I have recently started to use a more complex version that I stole from Google Chromium's codebase:

我最近开始使用从谷歌Chromium的代码基中偷来的一个更复杂的版本:

#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))

In this version if a pointer is mistakenly passed as the argument, the compiler will complain in some cases - specifically if the pointer's size isn't evenly divisible by the size of the object the pointer points to. In that situation a divide-by-zero will cause the compiler to error out. Actually at least one compiler I've used gives a warning instead of an error - I'm not sure what it generates for the expression that has a divide by zero in it.

在这个版本中,如果一个指针被错误地作为参数传递,编译器会在某些情况下抱怨——特别是当指针的大小不能被指针指向的对象的大小平均分割的时候。在这种情况下,二分法将导致编译器出错。实际上,我使用过的至少一个编译器给出了一个警告而不是一个错误——我不确定它为表达式生成了什么,其中包含一个除以0的表达式。

That macro doesn't close the door on using it erroneously, but it comes as close as I've ever seen in straight C.

这个宏并没有关闭错误使用它的大门,但是它是我在直C中所见过的最接近的。

If you want an even safer solution for when you're working in C++, take a look at Compile time sizeof_array without using a macro which describes a rather complex template-based method Microsoft uses in winnt.h.

如果您希望在c++中使用更安全的解决方案,那么可以在不使用宏的情况下查看编译时sizeof_array,该宏描述了Microsoft在winnt.h中使用的相当复杂的基于模板的方法。

#2


14  

No, there is not.

不,没有。

For constant size arrays you can use the common trick Andrew mentioned, sizeof(array) / sizeof(array[0]) - but this works only in the scope the array was declared in.
sizeof(array) gives you the size of the whole array, while sizeof(array[0]) gives you the size of the first element.
See Michaels answer on how to wrap that in a macro.

对于常量大小的数组,您可以使用Andrew提到的常见技巧sizeof(数组)/ sizeof(数组[0])—但是这只在数组声明的范围内有效。sizeof(数组)给出了整个数组的大小,而sizeof(数组[0])给出了第一个元素的大小。参见Michaels回答如何在宏中包装它。

For dynamically allocated arrays you either keep track of the size in an integral type or make it 0-terminated if possible (i.e. allocate 1 more element and set the last element to 0).

对于动态分配的数组,您可以在整数类型中跟踪大小,也可以在可能的情况下使其以0结尾(例如,再分配一个元素并将最后一个元素设置为0)。

#3


5  

sizeof array / sizeof array[0]

#4


3  

The number of elements in an array x can be obtained by:

数组x中的元素数可通过:

sizeof(x)/sizeof(x[0])

You need to be aware that arrays, when passed to functions, are degraded into pointers which do not carry the size information. In reality, the size information is never available to the runtime since it's calculated at compile time, but you can act as if it is available where the array is visible (i.e., where it hasn't been degraded).

您需要注意的是,当数组传递给函数时,数组被分解为指针,不携带大小信息。实际上,由于在编译时计算大小信息,所以运行时永远无法获得大小信息,但是您可以将它当作在数组可见的地方可用(例如)。,在那里它没有被降级。

When I pass arrays to a function that I need to treat as arrays, I always ensure two arguments are passed:

当我将数组传递给一个我需要处理为数组的函数时,我总是确保通过了两个参数:

  • the length of the array; and
  • 数组的长度;和
  • the pointer to the array.
  • 指向数组的指针。

So, whilst the array can be treated as an array where it's declared, it's treated as a size and pointer everywhere else.

所以,虽然数组可以被当作一个数组来声明,但是在其他地方它被当作一个大小和指针。

I tend to have code like:

我倾向于这样的代码:

#define countof(x) (sizeof(x)/sizeof(x[0]))
: : :
int numbers[10];
a = fn (countof(numbers),numbers);

then fn() will have the size information available to it.

然后fn()将有可用的大小信息。

Another trick I've used in the past (a bit messier in my opinion but I'll give it here for completeness) is to have an array of a union and make the first element the length, something like:

我过去使用过的另一个技巧(在我看来有点混乱,但我在这里给出它的完整性)是拥有一个联合数组,并使第一个元素的长度,类似于:

typedef union {
    int len;
    float number;
} tNumber;
tNumber number[10];
: : :
number[0].len = 5;
a = fn (number);

then fn() can access the length and all the elements and you don't have to worry about the array/pointer dichotomy.

然后fn()可以访问长度和所有元素,您不必担心数组/指针二分法。

This has the added advantage of allowing the length to vary (i.e., the number of elements in use, not the number of units allocated). But I tend not to use this anymore since I consider the two-argument array version (size and data) better.

这有一个额外的优势,允许长度变化(例如。,使用的元素数量,而不是分配的单元数量)。但是我不再使用它,因为我认为双参数数组版本(大小和数据)更好。

#5


2  

The simple answer, of course, is no. But the practical answer is "I need to know anyway," so let's discuss methods for working around this.

答案当然是否定的。但实际的答案是“无论如何我都需要知道”,所以让我们讨论解决这个问题的方法。

One way to get away with it for a while, as mentioned about a million times already, is with sizeof():

一种暂时摆脱它的方法是使用sizeof():

int i[] = {0, 1, 2};
...
size_t i_len = sizeof(i) / sizeof(i[0]);

This works, until we try to pass i to a function, or take a pointer to i. So what about more general solutions?

这是可行的,直到我们尝试把i传递给一个函数,或者指向i的指针,那么更一般的解呢?

The accepted general solution is to pass the array length to a function along with the array. We see this a lot in the standard library:

已接受的通用解决方案是将数组长度与数组一起传递给函数。我们在标准库中经常看到:

void *memcpy(void *s1, void *s2, size_t n);

Will copy n bytes from s1 to s2, allowing us to use n to ensure that our buffers never overflow. This is a good strategy - it has low overhead, and it actually generates some efficient code (compare to strcpy(), which has to check for the end of the string and has no way of "knowing" how many iterations it must make, and poor confused strncpy(), which has to check both - both can be slower, and either could be sped up by using memcpy() if you happen to have already calculated the string's length for some reason).

将从s1复制n个字节到s2,允许我们使用n来确保缓冲区不会溢出。这是一个很好的策略——低开销,它生成一些高效的代码(strcpy()进行比较,检查结束的字符串并无法“知道”它必须多少迭代,和穷人困惑strncpy(),已检查都——都可以慢,,要么可以通过使用加速memcpy()如果你碰巧已经计算字符串的长度由于某种原因)。

Another approach is to encapsulate your code in a struct. The common hack is this:

另一种方法是将代码封装在结构体中。最常见的技巧是:

typedef struct _arr {
  size_t len;
  int arr[0];
} arr;

If we want an array of length 5, we do this:

如果我们想要一个长度为5的数组,我们这样做:

arr *a = malloc(sizeof(*a) + sizeof(int) * 5);
a->len = 5;

However, this is a hack that is only moderately well-defined (C99 lets you use int arr[]) and is rather labor-intensive. A "better-defined" way to do this is:

然而,这是一种只有适度定义的技巧(C99允许您使用int arr[]),并且是相当劳动密集型的。一种“更好定义”的方式是:

typedef struct _arr {
  size_t len;
  int *arr;
} arr;

But then our allocations (and deallocations) become much more complicated. The benefit of either of these approaches is, of course, that now arrays you make will carry around their lengths with them. It's slightly less memory-efficient, but it's quite safe. If you chose one of these paths, be sure to write helper functions so that you don't have to manually allocate and deallocate (and work with) these structures.

但是我们的分配(和交易)变得更加复杂。当然,这两种方法的好处是,现在您所创建的数组将携带它们的长度。它的内存效率略低,但很安全。如果您选择了其中的一条路径,请确保编写帮助函数,这样您就不必手动分配和分配(并处理)这些结构。

#6


0  

If you have an object a of array type, the number of elements in the array can be expressed as sizeof a / sizeof *a. If you allowed your array object to decay to pointer type (or had only a pointer object to begin with), then in general case there's no way to determine the number of elements in the array.

如果您有一个数组类型的对象a,那么数组中的元素数可以表示为sizeof a / sizeof *a。如果允许数组对象衰减到指针类型(或者开始只有一个指针对象),那么通常情况下,无法确定数组中的元素数量。