Metadata

  • 📅 Date :: 12-06-2025
  • 🏷️ Tags :: cpp

Notes

Passing Structs to Functions in C++

In C++, structs are user-defined data types that allow us to group different types of data under one name. These data types can be passed to functions as arguments. However, when passing a struct to a function, there are some key considerations regarding how data is passed—by value or by reference. In this section, we’ll explore how to pass structs to functions, demonstrating both the pass-by-value and pass-by-reference techniques, and why you might choose one over the other. Let’s break down the concepts with detailed explanations and examples.

1. Definition of Struct

A struct in C++ is a composite data type that allows grouping different variables (called members) under one entity. In this case, we’ll define a struct called Car that contains information about different attributes of a car, such as the model, year, and color.

Example of defining a struct:

struct Car {
    std::string model;
    int year;
    std::string color;
};
 

Here, the struct Car contains three members:

  • model (a string representing the car’s model),
  • year (an integer representing the year of the car),
  • color (a string representing the car’s color).

2. Creating Instances of Structs

Once you’ve defined a struct, you can create instances (variables) of that struct. For instance, you can create two car instances car1 and car2:

Car car1;
Car car2;
 

You can assign values to the members of these car objects. For example:

car1.model = "Mustang";
car1.year = 2023;
car1.color = "Red";
 
car2.model = "Corvette";
car2.year = 2022;
car2.color = "Blue";
 

3. Passing Structs to Functions

When you pass a struct to a function, there are two main ways of passing it:

  • Pass-by-Value (the default behavior)
  • Pass-by-Reference (using pointers or references)

Let’s explore both methods with examples.

4. Passing by Value

By default, structs are passed by value in C++. This means when you pass a struct to a function, a copy of the struct is created, and the function works with this copy rather than the original struct.

Example of a function that accepts a Car struct by value:

void printCar(Car car) {
    std::cout << "Model: " << car.model << std::endl;
    std::cout << "Year: " << car.year << std::endl;
    std::cout << "Color: " << car.color << std::endl;
}
 

In this function, car is passed by value, meaning a copy of the Car struct is created inside the printCar function. Any changes made to the copy will not affect the original struct.

Testing the pass-by-value behavior:

int main() {
    Car car1 = {"Mustang", 2023, "Red"};
    std::cout << "Address of car1: " << &car1 << std::endl;
    printCar(car1);
    return 0;
}
 

Output:

Address of car1: 0x7ffee122b3a0
Model: Mustang
Year: 2023
Color: Red

Notice that the address of car1 printed in main is different from the address of the car parameter inside the printCar function. This demonstrates that a copy of the struct is passed.

5. Pass-by-Reference (using pointers or references)

To work with the original struct (and not a copy), you can pass the struct by reference or by using pointers. This allows the function to modify the original struct.

Using References:

When you pass a struct by reference, the function receives a reference to the original struct. This means any changes made to the struct inside the function will affect the original struct.

Example of passing by reference using references:

void printCar(Car& car) {
    std::cout << "Model: " << car.model << std::endl;
    std::cout << "Year: " << car.year << std::endl;
    std::cout << "Color: " << car.color << std::endl;
}
 

The & after Car signifies that car is passed by reference. If you modify car inside the function, the changes will affect the original car object in main.

Using Pointers:

You can also pass a struct by pointer, which means the function works directly with the memory address of the struct.

Example using pointers:

void printCar(Car* car) {
    std::cout << "Model: " << car->model << std::endl;
    std::cout << "Year: " << car->year << std::endl;
    std::cout << "Color: " << car->color << std::endl;
}
 

Here, car is a pointer, and -> is used to access members of the struct.

Testing pass-by-reference and pointers:

int main() {
    Car car1 = {"Mustang", 2023, "Red"};
    std::cout << "Address of car1: " << &car1 << std::endl;
 
    // Passing by reference
    printCar(car1); // No copy is made, the original car1 is modified if needed
 
    // Passing by pointer
    Car* carPtr = &car1;
    printCar(carPtr); // Also operates on the original car1
 
    return 0;
}
 

6. Modifying Members Inside the Function

When a struct is passed by value, any changes made inside the function will not affect the original struct. However, when you pass by reference (or pointer), changes made to the struct inside the function will modify the original struct.

Example of modifying a struct member:

Let’s say you want to change the color of a car inside a function. You can create a function paintCar() to modify the car’s color.

void paintCar(Car& car, const std::string& newColor) {
    car.color = newColor;
}
 

Here, Car& car means we’re passing the car by reference, and we modify its color inside the function.

Testing the modification:

int main() {
    Car car1 = {"Mustang", 2023, "Red"};
    printCar(car1); // Prints original color: Red
 
    paintCar(car1, "Silver");
    printCar(car1); // Prints new color: Silver
 
    return 0;
}
 

Output:

Model: Mustang
Year: 2023
Color: Red

Model: Mustang
Year: 2023
Color: Silver

Notice how the color is successfully changed because we passed the struct by reference.

7. Efficiency Considerations

  • Pass-by-Value: When you pass large structs by value, a copy of the entire struct is made, which can be inefficient, especially if the struct contains many members or is large in size.
  • Pass-by-Reference (or Pointers): This method is more efficient because no copy is made. Instead, the function works directly with the original struct.

As a general rule, if you don’t need to modify the struct and it is large, it’s better to pass it by constant reference (const Car& car). This ensures you don’t make a copy and prevents accidental modification of the original struct.

8. Conclusion

To summarize, C++ allows us to pass structs to functions either by value or by reference. Pass-by-value creates a copy of the struct, while pass-by-reference works with the original struct. Depending on whether you need to modify the original struct or not, and based on performance considerations, you can choose the appropriate method.

  1. Pass by Value: Good for small structs or when you don’t need to modify the original.
  2. Pass by Reference (or Pointer): More efficient for larger structs or when you need to modify the original.

Lastly, always ensure you choose the appropriate method based on whether you need to alter the struct or just need to read its members.


References