简体   繁体   中英

Passing an array of structs by reference in C++

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.

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.

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])

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)

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
}

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)
{
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM