Is there a standard function in C that would retur

2019-01-02 18:26发布

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

标签: c arrays
6条回答
与风俱净
2楼-- · 2019-01-02 18:37
sizeof array / sizeof array[0]
查看更多
后来的你喜欢了谁
3楼-- · 2019-01-02 18:41

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.

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:

#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.

That macro doesn't close the door on using it erroneously, but it comes as close as I've ever seen in straight 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.

查看更多
闭嘴吧你
4楼-- · 2019-01-02 18:45

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.

查看更多
永恒的永恒
5楼-- · 2019-01-02 18:50

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

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.

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.

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.

查看更多
余生请多指教
6楼-- · 2019-01-02 18:53

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.

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).

查看更多
闭嘴吧你
7楼-- · 2019-01-02 18:53

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():

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?

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).

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:

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:

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.

查看更多
登录 后发表回答