Arrays (C++)

Started by
8 comments, last by alvaro 15 years, 4 months ago
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?
Advertisement
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.

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.
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.
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.
NextWar: The Quest for Earth available now for Windows Phone 7.
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.
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]
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 << " ";	}}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;}
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);}
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.

This topic is closed to new replies.

Advertisement