Sign in to follow this  
openglJunkie

Arrays (C++)

Recommended Posts

openglJunkie    100
Murry Crimas Everybody I'm making a function that accepts an integer array, but I can't get the correct size of the array from within my function. This is because I know that a pointer points to the first object in the array, but I'm doing the same thing in the main function and it gets correct results:
void ArraySwap(int *pInt)
{

   // Returns the size of the first element as expected
   int size = sizeof(pInt);

   // Returns the size of the first element divided by the first element
   // which equals one.
   size = sizeof(pInt)/sizeof(pInt[0]);
}

int main()
{
   int num[] = { 10, 20, 30, 40, 50, 60 };
   
   // This works, but I didn't want to have a need to call it here.
   int numCount = sizeof(num)/sizeof(num[0];

   ArraySwap(num);

return 0;
}
I have tried going through all the elements in the array and incrementing a counter each time, but int arrays apparently don't have a terminating NULL character like character arrays do. Is it possible to get the size of it without doing so in the main function?

Share this post


Link to post
Share on other sites
alvaro    21263
No, you can't do that. You'll have to either pass the number of elements or a pointer to the end of the array (one past the last element).

If you are using C++, you can use std::vector instead of an array, and vectors know how many element they hold.

Share this post


Link to post
Share on other sites
rip-off    10979
There is no way, arrays are not first class types in C++. You cannot pass them to functions nor return them from functions. You can pass a reference to a specific sized array, but that generally isn't what you want.

There are a few ways of approximating this.

1) std::vector:

#include <vector>

void foo(std::vector<int> &arg)
{
int size = arg.size()

// ...
}


2) templates (a.k.a generate a function per array size)

template<int N>
void foo(int (&arg)[N])
{
// size == N

// ...
}


3) templated forwarding:

template<class Function, int N>
void call_with_size(int (&a)[N], Function f)
{
f(a,N);
}

void foo(int *, int size)
{
// ...
std::cout << "size " << size << '\n';
}

int main()
{
int array[5];

call_with_size(array,foo);
}


I actually kind of like the last one. With a bit more work it could be extended to include return values and any type. Then again, boost probably has a similar function.

Share this post


Link to post
Share on other sites
openglJunkie    100
An array is just a pointer to the first element so how is the sizeof(num) returning the size of the entire array, but sizeof(pInt) doesn't?

Quote:

You can pass a reference to a specific sized array.


I see... Well, I suppose the only way would be to pass its size. I'm trying to do so without a call to "standard" functions created by the std library or boost and templates seem like a bit overkill for such a small feature. I haven't really used templates much maybe that's why.

Share this post


Link to post
Share on other sites
Sc4Freak    643
Quote:
Original post by openglJunkie
An array is just a pointer to the first element so how is the sizeof(num) returning the size of the entire array, but sizeof(pInt) doesn't?

No, an array is an array. In your main function, array is of type int[6]. That's why your sizeof works. But when you pass it to ArraySwap, it degenerates into a pointer to the first element (ie. it is type converted into an int*), and so your sizeof takes the size of the pointer.

Share this post


Link to post
Share on other sites
rip-off    10979
Quote:
Original post by openglJunkie
An array is just a pointer to the first element so how is the sizeof(num) returning the size of the entire array, but sizeof(pInt) doesn't?


Arrays aren't pointers.

Quote:
Quote:

You can pass a reference to a specific sized array.


I see... Well, I suppose the only way would be to pass its size. I'm trying to do so without a call to "standard" functions created by the std library or boost and templates seem like a bit overkill for such a small feature. I haven't really used templates much maybe that's why.


Well, the last example uses templates to automagically pass the correct size. This way you don't have the problem of mismatching the actual size with an error.

Another example:

template<int N, class T>
void array_size(T (&)[N])
{
return N;
}

void foo(int *, int size)
{
// ...
std::cout << "size " << size << '\n';
}

int main()
{
int array[42];

foo(array,array_size(array));
}


This just reduces the amount of typing required on the calling code. No more sizeof(array) / sizeof(array[0]).

The other benefit is maintenance: if you change the array to a pointer then the templated code will refuse to compile. The sizeof() method will just silently compile and produce problems at runtime.

Share this post


Link to post
Share on other sites
DevFred    840
Quote:
Original post by openglJunkie
An array is just a pointer to the first element

No. Where did you get that idea?

Quote:
Original post by openglJunkie
I'm making a function that accepts an integer array

Impossible, because:
1. C++ does not support passing arrays by value.
2. Passing an array by reference only works if the size is statically known.
(in other words: "an integer array" is not a built-in C++ type)

Quote:
Original post by openglJunkie
but int arrays apparently don't have a terminating NULL character like character arrays do.

Character arrays do not have a null terminator either! Here is a perfectly fine character array without a null:

char days_per_month[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

What you are talking about are string literals. They always have a null terminator. (If you use a string literal to initialize a character array, then that null is copied into the array, of course.)

I highly recommend you forget about all that low-level issues and start using std::vector.

[Edited by - DevFred on December 18, 2008 5:04:48 PM]

Share this post


Link to post
Share on other sites
openglJunkie    100
Thanks for all the very informative replies. I like the idea of using the template because if of what rip-off mentioned: if you change the array to a pointer, the compiler refuses to compile it. I used another approach, though, this was just to learn about pointers:


void ArraySwap(int *pInt, int count)
{
count -= 1;

int iPos = 0;
int *pFirst = pInt;
int *pSecond = pFirst+count;
int temp;

while(iPos<count)
{
// If in the middle of the array, break.
if(pFirst>pSecond)
break;

// Perform Swap
temp = *pFirst;
*pFirst = *pSecond;
*pSecond = temp;

// Update Variables For Next Swap
iPos++;
pFirst += iPos;
pSecond -= iPos;
}

delete pFirst;
delete pSecond;

pFirst = 0;
pSecond = 0;
}

void DispArray(int *pInt, int count)
{
for(int i=0; i<count; i++)
{
cout << pInt[i] << " ";
}
}

int main()
{
int num[] = { 10, 20, 30, 40, 50, 60 };
int count = sizeof(num)/sizeof(num[0]);

cout << "Array Before: ";
DispArray(num, count);
cout << endl;

ArraySwap(num, count);

cout << "Array After: ";
DispArray(num, count);

return 0;
}

Share this post


Link to post
Share on other sites
DevFred    840
Why are you deleting pFirst and pSecond? They don't point to dynamically allocated data. Welcome to undefined behavior land!

Anyway, here is the equivalent C++ program:

#include <algorithm>
#include <iostream>
#include <iterator>

int main()
{
int num[] = { 10, 20, 30, 40, 50, 60 };
int count = sizeof num / sizeof num[0];

std::copy(num, num + count, std::ostream_iterator<int>(std::cout, " "));
std::endl(std::cout);

std::reverse(num, num + count);
std::copy(num, num + count, std::ostream_iterator<int>(std::cout, " "));
std::endl(std::cout);
}

Share this post


Link to post
Share on other sites
alvaro    21263
Here's another C++ implementation:
#include <iostream>
#include <vector>
#include <algorithm>

void print(std::vector<int> const &v) {
for(std::vector<int>::const_iterator it=v.begin(), end=v.end();
it!=end; ++it)
std::cout << *it << ' ';
std::cout << std::endl;
}

int main() {
static int const num_i[] = { 10, 20, 30, 40, 50, 60 };
std::vector<int> num(num_i, num_i + sizeof (num_i) / sizeof (*num_i));

print(num);
std::reverse(num.begin(), num.end());
print(num);
}



I think the original question was how to pass an array to a function, and this shows it.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this