Skip to main content
GameDev.net gamedev.net
🔒 Locked

Finding array length -- C++

Started by skulldrudgery Sep 16, 2005 at 9:02 PM 24 replies 149.3k views
Original Post
skulldrudgery
skulldrudgery
Do I HAVE to use a vector? I prefer to use them only when it is necessary. Is there a way to find the length of an array that is passed to a function? I thought I could use something like
while(array) i++;
but that is obviously wrong. (It worked with strings so I figured "oh, what the hell?"). When I create an array inside the same function I can find the size using sizeof(array) / sizeof(char) but I already know the size in that situation.
skulldrudgery--A tricky bit of toil
SiCrane
SiCrane
No you can't know. Pass the length along with the array or use a vector.
skulldrudgery
skulldrudgery
Okie doke. Thanks.

EDIT: How do they find the length with a vector? Just wondering.
skulldrudgery--A tricky bit of toil
Fruny
Fruny
Quote:
Original post by skulldrudgery
EDIT: How do they find the length with a vector? Just wondering.


They don't "find" it. They keep track of it. A typical vector implementation would keep a pointer to the beginning of the vector, to the end of the vector (one past the last element) and to the end of the allocated block (one past the last valid address in the block).

The length of the vector would then simply be pEnd - pBegin, and its capacity pEndBlock - pBegin.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
skulldrudgery
skulldrudgery
So...In other words, shut my uppity n00b mouth and just use the stinking vector.[grin]

Thanks for the info.
skulldrudgery--A tricky bit of toil
Satan666
Satan666
#include <vector>int main(){vector<char>Size;Size.push_back('a'); //Size[0] = 'a'Size.push_back('b'); //Size[1] = 'b'Size.push_back('c'); //Size[2] = 'c'int SizesSize = Size.size();//3}

Roboguy
Roboguy
Quote:
Original post by Anonymous Poster
Quote:

while(array) i++;


Step back for a second. Why does this work for strings and not for other arrays? (Hint: It doesn't work for char arrays. What's the difference between a char array and a string?) Once you figure that out, it may be possible to adapt that solution to your needs.


It should work on a null-terminated char array.
Fruny
Fruny
Quote:
Original post by Anonymous Poster
Note that this only works for char arrays and, for a string, will give a different answer from strlen(array). A more robust version is (sizeof array / sizeof *array).


I must voice my disagreement here. (sizeof array / sizeof *array), just like (sizeof array / sizeof char) both suffer from the fatal flaw that they will silently return an erroneous result if array isn't an array name, but a pointer. And given how 'easy' it is for an array to decay to a pointer...

In C++, a safe solution is the following template function:

template size_t N dimension_of(T (&)[N]) { return N; }

or, if you need a version that provides a result at compile-time:

template<size_t N> struct dimension_of_hs { char dummy[N]; };template<class T, size_t N> dimension_of_hs<N> dimension_of_hfn(T (&)[N]);#define dimension_of(X) (sizeof dimension_of_hfn(X))


Both versions will cause a compiler error if you try to pass them pointers.

Usage: dimension_of(array)
Result: The number of elements of the array.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Polymorphic OOP
Polymorphic OOP
Quote:
Original post by Fruny
template<size_t N> struct dimension_of_hs { char dummy[N]; };template<class T, size_t N> dimension_of_hs<N> dimension_of_hfn(T (&)[N]);#define dimension_of(X) (sizeof dimension_of_hfn(X))


Both versions will cause a compiler error if you try to pass them pointers.

Usage: dimension_of(array)
Result: The number of elements of the array.

Actually, technically that wouldn't necessarily work because of padding (the struct size isn't guaranteed to be the size of the array). Instead of returning the array encapsulated in a struct, have the return-type be a reference to an array of char:

template<typename T, ::std::size_t N> char (&dimension_of_hfn(T (&)[N]))[N];
Fruny
Fruny
Ooops, my bad.

"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Mxz
Mxz
Heres a slight variation which avoids the need for the struct, and keeps the safety of not compiling if X is only a pointer.

template<class T, size_t N> T decay_array_to_subtype(T (&a)[N]);#define dimension_of(X) (sizeof(X)/sizeof(decay_array_to_subtype(X)))
Fruny
Fruny
Sure, it's a bit more complicated, and vectors are preferable in many cases. But it is the safe solution to getting an array's length. And no, it's not possible to get around using a macro, since it's not possible to define new operators in C++. Given that the expression has properly been parenthesed and that the input parameter only appears once in the expression, that code (at least my version, though the sizeof should absorb any function call and thus eliminate side effects in both versions) is safe.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Cacks
Cacks
Here is a simple example:

//CODE
int arr[10];
cout << sizeof(arr)/sizeof(int);

sizeof(arr) - returns the size in bytes off the entire array.
sizeof(int) - returns the number of bytes required for one element of the array.
Thus dividing gives the number of elements.

Hope that helps you!
Reject the basic asumption of civialisation especially the importance of material possessions
Cocalus
Cocalus
Quote:
Original post by Cacks
Here is a simple example:

//CODE
int arr[10];
cout << sizeof(arr)/sizeof(int);

sizeof(arr) - returns the size in bytes off the entire array.
sizeof(int) - returns the number of bytes required for one element of the array.
Thus dividing gives the number of elements.

Hope that helps you!


That can break really easily.

#include <iostream>using namespace std;int size(int arr[]){ //I don't work, I always return 1   return sizeof(arr)/sizeof(*arr);}  int main(){    int arraytest[10];    cout << "This works: " << sizeof(arraytest)/sizeof(*arraytest) << endl;    cout << "This doesn't: " << size(arraytest) << endl;    int *dynamicarray = new int[20];    cout << "This doesn't either: " << sizeof(dynamicarray)/sizeof(*dynamicarray) << endl;    delete dynamicarray;    cin.get();}
Cacks
Cacks
Yeah, I see now. I forgot that even when declaring a parameter in the form 'arr[]' - 'arr' is a pointer. So using sizeof(arr)/sizeof(type) is basically useless if it only works for statically allocated arrays. Could some1 explain:

//CODE
template T decay_array_to_subtype(T (&a)[N]);
#define dimension_of(X) (sizeof(X)/sizeof(decay_array_to_subtype(X)))


How can this give a compile error if X is only a pointer?


Maybe wrapping an array in a new class with a getLength() function could be a good solution?
Reject the basic asumption of civialisation especially the importance of material possessions
Mxz
Mxz
Quote:
Original post by Cacks
Yeah, I see now. I forgot that even when declaring a parameter in the form 'arr[]' - 'arr' is a pointer. So using sizeof(arr)/sizeof(type) is basically useless if it only works for statically allocated arrays. Could some1 explain:

//CODE
template T decay_array_to_subtype(T (&a)[N]);
#define dimension_of(X) (sizeof(X)/sizeof(decay_array_to_subtype(X)))


How can this give a compile error if X is only a pointer?


Maybe wrapping an array in a new class with a getLength() function could be a good solution?



It gives a compiler error because an array and a pointer are two distinct types.

A pointer is a variable which contains an address of an element of type T (which may or may not exist).

An array is a contiguous block of N elements of type T.

A variable declared to be a T&, that is “reference to type T”, can only be initialized by an object of type T or by an object that can be converted into a T.

There are no available conversions from type T* (pointer to type T) to type T [N] (array of N elements of type T), so the decay_array_to_subtype function cannot compile when called with a pointer.

JohnBolton
JohnBolton
Quote:
Original post by Anonymous Poster
Anyone got one without the "evil" #define? [looksaround]

This works for me.
    template < typename T, size_t N >    size_t elementsof( T const (&a)[N] )    {        return N;    } 
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Fruny
Fruny
Quote:
Original post by JohnBolton
This works for me.
    template < typename T, size_t N >    size_t elementsof( T const (&a)[N] )    {        return N;    } 


int a[10]; int b[elementsof(a)]; will not compile, nor can us use elementsof(a) as a template argument.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
-=HM=-
-=HM=-
_countof(x) implementation in Visual Studio is very similar to what's been posted on this thread already; from memory it looks like this:

template <typename T, std::size_t N> char (* helper(T(&)[N]))[N];
#define _countof(x) (sizeof (*helper(x)) + 0)


I remember it well because I could never figure out what is that +0 supposed to be doing.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.