• Advertisement
Sign in to follow this  

Finding array length - with a pointer

This topic is 4177 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey, In a project I'm doing I have a method that takes quite a lot of arguments so in order to make things a bit smaller I decided to cut out unnecessary arguments. One of these arguments was the amount of elements in an array. The array itself is passed by reference to the method - that is, the method takes a pointer to the array as argument. I decided to cut off the 'numElements' argument because I figured this would also work:
/* Original function (simplified, just to show the problem) */
void SomeMethod ( HWND * hwnd, int numArgs )
{
    for ( int i = 0; i < numArgs; i++ )
    {
        DoSomethingWithWindow ( (*hwnd) );
    }
}

/* Function with less arguments */
void SomeMethod ( HWND * hwnd )
{
    int numArgs = sizeof(hwnd)/sizeof(HWND);
    for ( int i = 0; i < numArgs; i++ )
    {
        DoSomethingWithWindow ( (*hwnd) );
    }
}

Of course, this failed in many ways because 'sizeof(hwnd)' returns only the size of the pointer, not the array to which it points... Is it possible to leave the numArgs argument out of the parameter list of said function and still calculate the correct number of elements by only using the pointer to the first element of the array?

Share this post


Link to post
Share on other sites
Advertisement
Simple answer is you can't. Unless you pass in the array length, or determine it at runtime, your SOL. You could do the following extremely unsafe code to accomplish what I think you want

void SomeMethod( HWND * hwnd)
{
int curHwnd = 0;
while(hwnd[curHwnd] != null)
{
DoSomethingWithWindow((*hwnd));
curHwnd++;
}

This will give you the total count of HWNDs in the array ( in the value curHwnd ). With two caveats. First off, you probrably just as well off passing in the length. Second, you should make sure the hwnd array has been memset to 0 when created or all kinds of neat things can happen.

Share this post


Link to post
Share on other sites
Thanks for your replies, I think I'll just go with the extra argument and see if I can cut some others off. I'd hate to think of what'd happen when someone else uses that method and forgets to ZeroMemory or memset the HWND array to 0... [grin]

Share this post


Link to post
Share on other sites
I'm going to go with ToohrVyk on this one and recommend a std::vector (assuming c++). This will not only solve your problem but save headaches in the future.

Share this post


Link to post
Share on other sites
Well yeah, I could do that, but I think it's a bit of an overkill for the purpose that it serves. A simple array suits me fine here, it was only a question of including the number of elements or not...

Share this post


Link to post
Share on other sites
Quote:
Original post by rogierpennink
Hey,

In a project I'm doing I have a method that takes quite a lot of arguments so in order to make things a bit smaller I decided to cut out unnecessary arguments. One of these arguments was the amount of elements in an array. The array itself is passed by reference to the method - that is, the method takes a pointer to the array as argument.

I decided to cut off the 'numElements' argument because I figured this would also work:

*** Source Snippet Removed ***

Of course, this failed in many ways because 'sizeof(hwnd)' returns only the size of the pointer, not the array to which it points...
Is it possible to leave the numArgs argument out of the parameter list of said function and still calculate the correct number of elements by only using the pointer to the first element of the array?


For static arrays:

template<class T, size_t N>
size_t size(T[N]) { return N; }



The above is only for static arrays, (i.e. Foo foo[12];) This will only work with direct static arrays, not with pointers to static arrays.

For dynamic arrays:

std::vector<Element> elements;
size_t size = elements.size();



Really, there isn't much of an excuse for not using vectors for dynamic arrays (assuming you aren't doing something too funky with pointers).

Share this post


Link to post
Share on other sites
When you discover how many other places around the system you have to pass an array and a length count around "together", you'll probably come to rethink that :)

Share this post


Link to post
Share on other sites

Use std::vector or list, it will save you from much of headache. And believe me, it isn't overkill. It is just code that somebody made and tested pretty well.

The amount of code needed to use std::vector is pretty much the same as you'd need for an array anyway.

At least, if you don't want to mess with std, write your own array wrapper template with some bound checking.

Cheers !

Share this post


Link to post
Share on other sites
Thanks for your reply agi_shi. As you said, there is not much of an excuse for not using vectors if the array is dynamic. In my case the array isn't dynamic however. It's a global array that contains the windowhandles of each window that my future game engine should render to. As such, the number of elements is only needed for the creation of a swapchain. This use is so trivial that I didn't bother with std::vector ;)

Share this post


Link to post
Share on other sites
Quote:
Original post by agi_shi
I decided to cut off the 'numElements' argument because I figured this would also work:

template<class T, size_t N>
size_t size(T[N]) { return N; }



Actually, it should be

template<class T, size_t N>
size_t size(T (&) [N]) { return N; }


Taking the parameter by reference isn't optional: it's what prevents the array from decaying to a pointer.

Share this post


Link to post
Share on other sites
One possibility if you wish to reduce the number of arguments passed to a function would be to pass a structure as required, instead. For example instead of

void someFunc( HWND* hWnds, int numHWnds );

you could have

typedef struct someFuncArgs
{
HWND* hWnds;
int numHWnds;
} someFuncArgs;

void someFunc( someFuncArgs& args );

... though obviously you wouldn't bother for something with only two arguments. You'll see Windows and other Microsoft code doing this sort of thing very frequently.

Share this post


Link to post
Share on other sites
OTOH, if taking two arguments isn't a problem, you can give yourself a lot more flexibility at basically no cost, by accepting an iterator range instead:


template <typename HWNDIterator>
void SomeMethod(HWNDIterator begin, HWNDIterator end) {
// Of course you could also use std::for_each for this trivial example :)
for (HWNDIterator i = begin; i != end; ++i) {
// By the way, you should not dereference the pointer before subscripting,
// in your original code. Subscripting already implies a dereference;
// foo is equivalent to *(foo + i).
DoSomethingWithWindow(*i);
}
}

// Passing an array:
SomeMethod(array, array + sizeof(array) / sizeof(array[0]));
// You might want to use the inline function taking an array reference to
// simplify that.

// Passing a std::vector, *or any other standard library container*
// (except std::(multi)map, because its iterators yield key-value pairs):
SomeMethod(container.begin(), container.end());

// Passing a single element:
SomeMethod(&thing, &thing + 1);

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement