tags:

views:

415

answers:

7

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

+4  A: 
sizeof array / sizeof array[0]
Andrew Medico
You should explain that this only works for fixed size arrays where the size is known at compile time.
John Kugelman
+9  A: 

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

Georg Fritzsche
Note that `sizeof(array)/sizeof(array[0])` only works in the same scope that the array was declared. We can't pass `array` to a function and expect that code to work.
Chris Lutz
Of course, thanks. Added that.
Georg Fritzsche
Not only it works for constant size arrays, but also for variable length arrays in C99. In that case, though, the `sizeof` is evaluated at runtime.
Johannes Schaub - litb
A: 

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.

AndreyT
Er... Any explanations for the downvote?
AndreyT
+10  A: 

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 http://stackoverflow.com/questions/1500363/compile-time-sizeofarray-without-using-a-macro/1500917#1500917 which describes a rather complex template-based method Microsoft uses in winnt.h.

Michael Burr
+1 for the interesting chromium version.
Georg Fritzsche
+1 both for the Chromium version and the small trick of using 0[x].
Danilo Piazzalunga
A: 

This is a bit out of the scope of your question, but the 'info libc' has a lot of examples that use struct arrays, which they keep dynamic. By ending the array with a certain value, they can then iterate through the array and stop when they hit the mark.

struct textstruct { char *astring; char *bstring; };
textstruct array = {"foo", "bar", 0};

This way you don't get the problem with scopes and/or pointers

Masse
+1  A: 

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.

Chris Lutz
"Struct hack" is a hack, but there's no reason to make it more hackish than it needs to be. Arrays of size 0 were (and are) always explictly illegal in C. The proper struct declaration for "struct hack" uses array of size 1. The size for `malloc` is traditionally calculated as `offsetof(arr, arr) + n * sizeof(int)` (so it doesn't matter what size is used in the array declaration).
AndreyT
They are illegal, but many older C compilers supported them (from laziness, no doubt), and I've seen `arr[0]` many times (with cringes). I've never seen the size calculated with `offsetof()` though that is a nice way to ensure it. And I disagree. Hacks should loudly scream "This is a hack! Please improve this code when you get the chance!"
Chris Lutz
Well, I'd say that the beauty of "struct hack" is that it doesn't violate any constraints. The program must compile fine. "Struct hack" always relied on practical "definedness" of theoretical undefined behavior. And, as we all know, life often makes us rely on that. Which is why we love and cherish that "struct hack". But the `[0]` version make a drastic qualitative change to all that. It introduces a constraint violation, leading to the possible compilation failure. It is hard to love something that doesn't even compile. (Yes, I know that some compilers allowed and still allow `[0]` arrays.)
AndreyT
The "hack" is legal in C99, with a much more hack-y looking syntax. And though I agree that legal hacks are good, if they're fully legal, they're not really hacks. (And for what it's worth, the `int arr[0]` compiles on GCC 4.0 with -Wall -Werror -Wextra without a peep. It can't be _that_ illegal.)
Chris Lutz
Chris Lutz: try -pedantic as well, arr[0] as the last member of a struct is a documented GCC extension :)
Zack
+1  A: 

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.

paxdiablo
That `union` trick is neat, but I'd much rather use the `struct` hack (or a non-hack version of the same idea).
Chris Lutz