Arrays as parameters

I'm having trouble passing arrays as function parameters and I'm pretty sure I'm doing everything correct.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//  Always returns a value of 1
int array_size (int ip_array[])
 {
    int size = sizeof( ip_array ) / sizeof(ip_array[0]);
    return size;
 }

void print_array(int ip_array [])
{
    int i;
    for (i=0;i< ( sizeof(ip_array) / sizeof(ip_array[0]) ); i++)
    // reads i to be less than 1 so this only runs once
    {
        cout << "+" << ip_array[i] << endl;
    }
}


I'm not sure what the problem is and it also compiles but the array only runs once. The array i'm working with contains about 8 elements so the value of 8 should be returned. Any help is appreciated.
Last edited on
Try this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>

using namespace std;

void print_array(int ip_array[], int n) {
  for (int i=0;i<n; i++)
    cout << "+" << ip_array[i] << endl;
}

main() {
  int x[8], n=sizeof(x)/sizeof(x[0]);

  for ( int i=0; i<n; ++i )
    x[i] = i;

  print_array( x, n );
}


When you pass the array in as int[], it becomes like an int*, so inside print_array(), sizeof( ip_array )==8 in a 64-bit OS, but outside, sizeof( x ) is 32 (8 x 4bytes).

Now, you would think that if you changed the parameter code:

1
2
3
4
void print_array(int ip_array[8]) {  // makes a difference?  apparently, no...
  for (int i=0;i<sizeof(ip_array)/sizeof(ip_array[0]); i++)     // nope - doesn't work
    cout << "+" << ip_array[i] << endl;
}

ip_array is really like a pointer to your original array - if you modify it, you will be modifying x.
However, because it's a pointer now and not an array, the compiler does not do sizeof() as you expect.

Check here:

http://www.cplusplus.com/doc/tutorial/arrays/

So for array_size you may want:
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))

Of course, you'd want to call the macro while x is still an array and hasn't been turned into a pointer.

It is not possible to compute the size of an array at runtime. Of cause there are a few exceptions like c style arrays. These are zero terminated string literals. This means, if your array has a special character at the end you can loop through the array to get it's size, or to compute the array.

sizeof(ip_array) / sizeof(ip_array[0] This means in fact divide the size of the pointer ip_array by the size of an integer. If you want to use arrays as function arguments you normally want to pass the size of the array as a second parameter.

Thus the function declaration would look like this:
void funcName(T array[], const int arraySize);

You can think of an array as an bunch of pointers which are stored beneath each other in the memory. Here is an example:
1
2
3
4
5
6
int array[10] = {1,2,3,4,5,6,7,8,9,10};
  // array is the pointer to the 0 element of the array. You could write *array instead of array[0]
  // *(array+1) = array[1]
  // *(array+2) = array[2]
  // ...
  // it is clear that sizeof(array) therefore returns the size of an pointer to an int. 



So for array_size you may want:
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))

Of course, you'd want to call the macro while x is still an array and hasn't been turned into a pointer.

Sorry, but x never really is an array. x is always an pointer to the first element in the array. Arrays are just a convenient feature of pointer arithmetic. You could do it all with pointers, which would be hard to read code. Therefore arrays are part of the language. But under the hood they are simply pointers.
@Darokthar
Arrays are not pointers. As such, sizeof(array) will produce sizeof(int)*10 in your example.
However, arrays can be cast to a pointer to their first element, which happens implicitly when writing *(array+1).
this code is also a popular way to get the array length
template<class T, size_t size> size_t len(T(&)[size]){return size;}

I guess the only option here is to pass the array length to the function just like Darokthar said, or put the array in global scope.

Athar+1, yeah I believe arrays are not pointers. but kinda..
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>

using namespace std;

void foo( int y[10] ) {
  cerr << "PARAMETER = " << sizeof( y ) << " bytes " << endl;
}

int main() {
  int x[10];

  cerr << "AUTOMATIC VARIABLE = " << sizeof( x ) << " bytes " << endl;
  foo( x );
}


AUTOMATIC VARIABLE = 40 bytes 
PARAMETER = 8 bytes

This result would be somewhat surprising to most people, as suggested by the OP. Note that if I change y, I will also change x, as I have allocated no new memory. OTOH, if I had used vector<int> y as a parameter, I would get new memory so changing y would have no effect on x.

I wonder if it is an artifact of the early C days where you could never push an array on a stack (as a parameter) because it would overflow. In that context, it is obvious that you would always pass a pointer and never an array.

These days, C++ could care less if you wanted to pass a large object onto the stack as a parameter - it would happily copy construct it for you. BTW, there is no absolute reason why the code should behave like the way it does above, except it has been set that way as a standard. I mean, the compiler clearly knows the sizeof() that chunk of memory at that memory address!!!

The bottom line? According to sizeof() and assignment-behavior, x is an array (has its own contiguous memory) but y is a pointer (refers to memory allocated elsewhere).
Last edited on
Thanks guys. This makes alot of sense. I spent immense time googling the answer with no luck. Thank you. :)
There is an article about this in our article database. I'm surprised that you were not able to find anything with a google search. C++ is an object oriented language. c-arrays are from the c-language and do not have copy construction or assignment operator built in. The vector is the c++ array. You can also embed a c-array within a struct since a struct has a default copy constructor and assignment operator. Since the c-array does not only the pointer to the first element can be copied. I guess they could have made c-arrays have copy construction but the designers of the language gave us a new set of tools instead. Those tools are the sequence container types, vector, deque, list. Unfortunately they screwed up a bit and didn't make using the sequence containers convenient enough. They have improved that in the next standard but by then many programmers will have already developed bad habits due to the limitations of the existing tools.
Actually I did read the article on this site about passing arrays as functions because I thought maybe I was screwing up.

This is an interesting point you bring up about C++ arrays being vectors. I don't know what my teacher didn't tell us about vectors. We are learning C++ so atleast she should have introduced us to vectors.... But it just seems to me that you can do more with vectors and there are a plethora of functions available for them. For example, to get the size of a vector you just do identifier.size(). Alot simpler and results in cleaner code.
C++ vectors are part of STL (Standard Template Library) containers:

http://www.cplusplus.com/reference/stl/

There are programmers who really love STL iterators and the way it has been designed. I personally think the design is too academic and needlessly complex/wordy (debuggers still spew out difficult to interpret error messages when there is an STL problem), but at least STL code is efficient. STL also doesn't mesh well with smart_ptrs and some other newer C++ features:

http://ootips.org/yonat/4dev/smart-pointers.html

However, it is the standard, and you should learn how to use them - I personally use vector and map quite a lot.
I personally think the design is too academic and needlessly complex/wordy (debuggers still spew out difficult to interpret error messages when there is an STL problem)


That's not really a problem with the the library so much as it's a problem with template errors.

STL also doesn't mesh well with smart_ptrs and some other newer C++ features


AFAIK, the only one it doesn't work with is auto_ptr, but they work great with other kinds of smart pointers.
I will need to look further into STL. My understanding of STL so far was that it's just the standard libraries (minus the template part). So my understanding was that iostream.h was part of the standard library but its not because it's not a template. Correct?
It's not part of the standard because it ends with ".h" That is the old, pre-standard header. The one in the standard is just "iostream." I think you might be confusing the standard library and the standard template library; the STL is a subset of the standard library.
Topic archived. No new replies allowed.