3

So I'm still rather new to programming/C++, and still trying to wrap my head around pointers and passing by reference and everything. A program I'm trying to figure out now needs to pass an array of structs to another function. I've gotten it working by just passing the array directly there. It seems to work fine. However, what I'm concerned about is that I believe I'm passing it by value, and I understand that it's better to pass structs by reference, so you're not making a copy of the struct every time...

Anyway, here's a basic example of what I'm doing:

struct GoldenHelmet {
    int foo;
    string bar;
    };

void pass (GoldenHelmet ofMambrino[], int size);

int main () {
    GoldenHelmet ofMambrino[10];
    int size = sizeof(ofMambrino) / sizeof(ofMambrino[0]);
    ofMambrino[1].foo = 1;
    pass(ofMambrino, size);
    cout << ofMambrino[2].foo << endl;
    return 0;
}

void pass (GoldenHelmet ofMambrino[], int size) {
    ofMambrino[2].foo = 100;
    ofMambrino[2].bar = "Blargh";
}

From what I understand, it works because arrays are already pointers, right? But the way I have that configured, am I still passing a copy of the struct and everything to the pass() function? I've tried to pass it by reference, but it doesn't seem to want to work any way I've tried.

Nate
  • 925
  • 2
  • 12
  • 23
  • 4
    Arrays are not pointers. Repeat this to yourself until you faint, then come back to this site to read the answers that will have been posted by then. – Kerrek SB Jan 10 '12 at 04:13
  • 3
    @NiklasBaumstark No, the answer will be in C++ :) – Sergey Kalinichenko Jan 10 '12 at 04:14
  • @Kerrek SB Thanks for clarifying. I was reading [this post](http://forums.devshed.com/c-programming-42/how-to-passing-arrays-of-structures-61159.html) and it seemed to imply that arrays are pointers. I guess I need to keep looking into it. Anyway, going to read the responses now, thanks for the help everyone. – Nate Jan 10 '12 at 04:20
  • @Nate: Instead of reading that, you should have read the article that proved beyond doubt that you must send me all your money... anyway, don't believe everything you hear on the internet. If in doubt, pick up a good book, or check in the language standard (free from GitHub) once you're comfortable enough with the language. – Kerrek SB Jan 10 '12 at 04:21
  • What Kerrek is trying to say is that this is a common misunderstanding, and there are a *lot* of common misunderstandings when it comes to learning C++. But picking up one of the books on [this list](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) that have been vetted and recommended by experts, you can't go wrong. – Cody Gray - on strike Jan 10 '12 at 04:25
  • @Kerrek: I'm currently taking a C++ course, and have a decent book on it as well. I've just recently started on pointers, so I had no reason to think otherwise. Anyway, good point, and I'm going to continue trying to learn more. – Nate Jan 10 '12 at 04:25
  • 1
    @Nate: Personal opinion: If you're just starting to learn C++, you shouldn't have any business with pointers at all. Those should be left for much later, either when you implement your own memory management, unformatted I/O, or in a discussion of historical oddities. – Kerrek SB Jan 10 '12 at 04:28

5 Answers5

7

The C++ way:

#include <array>

typedef std::array<GoldenHelmet, 10> Helmets;

void pass(Helmets &);

int main()
{
   Helmets h;
   h[1].foo = 1;
   pass(h);
   //...
}

void pass(Helmets & h)
{
   h[2].foo = 100;
   // ...
}

Indeed, we pass the array by reference.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
5

This syntax:

void pass (GoldenHelmet ofMambrino[], int size)

is actually quite confusing. Because you are not passing an array, you are passing a pointer. They are not the same thing though, don't get confused. This oddity only applies to function parameters. The above is exactly identical to this:

void pass (GoldenHelmet * ofMambrino, int size)

It's actually impossible to pass an array by value, unless it is a sub-object of another object. You can pass them by reference, you need to include the size though, but you can do that using a template:

template<int N>
void pass (GoldenHelmet (&ofMambrino)[N])
Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274
  • 1
    Why do we need a template? What's wrong with `void pass(GoldenHelmet (&h)[10])`? – Kerrek SB Jan 10 '12 at 04:19
  • @Kerrek: I didn't say you need a template. I said "you need to include the size, but you can do that using a template". You chose to be explicit about it[the size], I chose to use a template. – Benjamin Lindley Jan 10 '12 at 04:22
  • 1
    @Benjamin Thanks, that's beginning to make a bit more sense. So if I'm passing a pointer and not the entire array, do I really need to be worried about passing it by reference? If I was, say, just passing a struct alone, I can see the benefit of passing by reference. But if I'm just passing the pointer is their really any benefit to passing by reference? – Nate Jan 10 '12 at 04:23
  • @Nate: 1) The calling syntax is simpler. No need to calculate the size, just pass the array. Template type deduction figures out the size for you. 2) It's much much harder to get the size wrong. 3) It's much harder to pass an invalid argument. (e.g. you can't just pass NULL) – Benjamin Lindley Jan 10 '12 at 04:34
4

These are all possible, but none of them are pass by value. Just think of ofMambrino as being the address of the beginning of the array, and that is what you are passing.

void pass (GoldenHelmet ofMambrino[], int size)
void pass (GoldenHelmet ofMambrino[10], int size)
void pass (GoldenHelmet *ofMambrino, int size)
void pass (GoldenHelmet (&ofMambrino)[10], int size)
Jesse Good
  • 50,901
  • 14
  • 124
  • 166
  • Perfect, that clears up a lot. It also explains why I need to pass the size, because if I'm just pointing to the address for the beginning of the array, I need to keep track of how long the array is. – Nate Jan 10 '12 at 04:31
  • @Nate: Exactly, when I first started learning I always wondered why nobody told me that "its just the address". – Jesse Good Jan 10 '12 at 04:39
1

Arrays are represented and passed as pointers, so you are not copying anything here. In contrast, if you were passing a single struct, it would be passed by value.

Below is a code snippet to illustrate this last point:

void passByVal (GoldenHelmet ofMambrino) {
    ofMambrino.foo = 100;
    ofMambrino.bar = "Blargh";
}

void passByRef (GoldenHelmet& ofMambrino) {
    ofMambrino.foo = 100;
    ofMambrino.bar = "Blargh";
}

int main() {
    GoldenHelmet h;
    passByVal(h); // h does not change
    passByRef(h); // fields of h get assigned in the call
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
0

First of all array is not pointers. We refer this as a pointer in the argument list because when we use

int x[ ]

x is actually const pointer that points the beginning of the array. And when you pass this to a function you send the adress of the memory that is beginning of the array. Thats why when you make a change in your function, you make change in the adress of your variable in the caller section actually. This is actualy simulated call by reference not call by reference. But effect is same with call by reference because you are working on memory locations. For this reason when you send array of your struct you pass actually adress of your array of structs. Thats why when you change value on this, you actually change your structs.

To use call by reference, one thing you must to do is to define your function prototype like

void f(int &param)

and when calling function, it is same with the others.

To summarize:

int main()
{
     int x;

     // simulated call by reference that use adress of variable, 
     // lets say adress of x is 19ff 
     f(&x);     // actually you send 19ff

     f(x);      // call by reference that use reference of variable

}

// simulated call by reference
void f(const int *y)
{
    // when you use like *y=10, you are writing on memory area 19ff, you actually 
    // change memory area that is belong to x in the main

}

// call by reference
void f(const int &y)
{
}
oldTimes
  • 259
  • 3
  • 4
  • 13