6.3.3. Pass-By-Reference

Time: 00:03:19 | Download: Large, Large (CC) Small | Streaming, Streaming (CC) | Slides (PDF)

The C++ implementation of pass-by-reference is without parallel in Java, making this section especially important for programmers transitioning from Java to C++. Paradoxically, it's easy for programmers to use pass-by-reference but relatively more difficult to understand it. The following figures illustrate the pass-by-reference syntax and behavior, but three preliminary observations facilitate the discussion and clarify the examples.

Clarifying Terminology

Confusingly, the meaning of the term pass-by-reference varies from one programming language to another. In compiler theory and most programming languages, pass-by-reference describes the passing technique we called "pass-by-pointer" in the previous section.

Fischer and LeBlanc2 state, "Reference parameters represent the address of an actual parameter" (1988, p. 485). The Edpresso Team3 explicitly joins the two terms: "Pass by reference (also called pass by address) means to pass the reference of an argument in the calling function to the corresponding formal parameter of the called function so that a copy of the address of the actual parameter is made in memory..." Their statement suggests that a "reference" is an address, which explains the terms "dereference operator" and "dereferencing a variable."

Alternatively, IBM4 titled one of its z/OS documentation pages "Pass by reference (C++ only)," suggesting that the documented concepts and examples apply only to C++. (I highly recommend studying this short page.) The following description of pass-by-reference applies only to C++ and represents the meaning used throughout this textbook.

Observing the same procedure as the previous sections, the following figures demonstrate pass-by-reference by comparing a simple program with its effects on memory, articulating key operations with specific memory changes. The address of a, 0x12, is arbitrary and plays no significant role in the program. In these examples, the compiler simply maps the parameter p to the same memory address as the argument a - p is, in the truest sense, an alias for a while the functions are active.

Passing Simple Data By Reference

As in the two previous sections, simple data are any of the fundamental, built-in data types like char, int, or double. This example uses data of type int, but the behavior is the same for all fundamental types.

void func(int& p);

int main()
{	
	int  a = 5;	// step 1

	func(a);	// step 2
}

void func(int& p)
{
	p = p + 1;	// step 3
}			// step 4
A single square represents variable a, and during steps 2 and 3, it also represents variable b. Any change made to a must also change b because there is only one variable - it just has two names.
Pass by reference with simple data.
  1. The variable a is defined and initialized to 5
  2. Function func is called and while it is active, p refers to or labels the same memory location as a
  3. The function increments the value located at p, which is exactly the same as incrementing variable a since the variables map to the same memory location
  4. The function ends, the variable p goes out of scope, but the value in variable a is changed from 5 to 6

Passing Structured Data By Reference

The structured data is an object - an instance of a structure or class.

struct part
{	char	type;
	int	id;
};

void func(part& p);

int main()
{	
	part  a = { 'd', 10 };	// step 1

	func(a);		// step 2
}

void func(part& p)
{
	p.id = 1000;		// step 3
}				// step 4
A single square represents variable a, and during steps 2 and 3, it also represents variable b. Any change made to a must also change b because there is only one variable - it just has two names. So when the <kbd>p</kbd>'s <kbd>id</kbd> field is updated, <kbd>a</kbd>'s <kbd>id</kbd> field is also updated.
Pass by reference with structured data.
  1. The fields of variable a are defined and initialized to 'd' and 10 respectively
  2. The program calls function func and while it's active, the name p refers to the same memory location as a
  3. The id field in structure p is modified, assigning 1000 to it, but a and p refer to the same memory location, so any change to p is also a change to a
  4. The function ends and the value in the id field of a is changed from 10 to 1000

Pass-By-Reference: Advantages and Disadvantages

Superficially, pass-by-reference and by-pointer seem quite similar. Specifically, both passing methods allow passing data into and out of a function through the function call arguments. Consequently, they share some advantages and disadvantages, but the fundamental difference in their respective implementations guarantees they have unique benefits and drawbacks.

  1. (Advantage) Like pass-by-pointer, the execution time required to pass data by reference is independent of the data's size. Pass-by-pointer achieves independence by passing a relatively small, fixed-size address. Alternatively, pass-by-reference achieves independence by not passing data at all but by temporarily mapping the parameter name to the argument's memory address.
  2. (Advantage) Quite unlike pass-by-pointer, pass-by-reference requires a single, simple syntactical change: adding the ampersand, &, to all reference parameters in the function definition and prototypes. This overloaded use of the ampersand is in addition to its use as the address-of operator and the logical and bitwise AND operators.
  3. (Disadvantage) Pass-by-reference only allows l-value arguments - typically a variable name - rather than than the more general expressions pass-by-value permits.
  4. (Disadvantage) Pass-by-reference is only possible within a programm5, preventing programmers from using it to pass data to functions defined in independently-compiled programs.
  5. (Depends) The parameter name of data passed-by-reference is a function-scope alias for the original data. Changes the function makes to the parameter (i.e., the alias) change the original data. This operation is beneficial if programmers want to return data through the arguments, but it is a drawback if they expect the function to protect the data, preventing change. Programmers can make the parameters const to prevent the function from changing pass-by-reference parameters.
Advantages and disadvantages of pass-by-reference.

Pass-By-Reference Vs. Pass-By-Pointer

part&	my_part = t;	// okay

part&	my_part;	// error
my_part = t;
part*	my_part = &t;	// okay

part*	my_part;	// okay
my_part = &t;
(a)(b)
void func(part& p)
{
	p.id = 1000;
}
	. . .
part p = { 'd', 10 };
func(p);
cout << "Output: " << p.id << endl;
void func(part* p)
{
	p->id= 1000;
}
	. . .
part p = { 'd', 10 };
func(&p);
cout << "Output: " << p.id << endl;
Output: 1000
Output: 1000
(c)(d)
void func(part& p)
{
	p = new part { 'd', 1000 };
}
	. . .
part p = { 'd', 10 };
func(p);
cout << "Output: " << p.id << endl;
void func(part* p)
{
	p = new part { 'd', 1000 };
}
	. . .
part p = { 'd', 10 };
func(&p);
cout << "Output: " << p.id << endl;
Output: 1000
Output: 10
(e)(f)
Programming examples: references vs. pointers. C++ overloads the & operator to denote reference variables. The compiler distinguishes between a reference, the address-of operator, and the logical and bitwise AND operators by the operator's context (where the program uses it).
  1. Used in a variable definition, the & creates a reference variable and C++ requires programs to initialize them in the defining statement. The & appears on the left-hand side of the assignment operator.
  2. The address-of operator, in conjunction with a variable name, forms an expression that is the variable's address. The & appears on the right-hand side of the assignment operator.
  3. Programmers use the dot operator to access the fields or members of reference objects. Functions propagate changes made through reference variables back to the call.
  4. Programmers dereference and select object fields with the arrow operator. Calls must pass an address. Functions propagate changes made through pointer variables back to the call.
  5. C++ allows a program to return a new object through a reference parameter.
  6. C++ cannot return a new object through a pointer parameter.


  1. Referring to The complete C++ compilation process, the compiler component processes the individual source code (i.e., .cpp) files one at a time, producing object code files. The linker or loader joins the individual object files, library functions, and a system runtime file, creating an executable program. Matching the addresses of functions defined in one source code file to function calls made in different files is a primary task of the linker or loader. Consequently, functions can pass data by reference within a single executable program but not between different programs.
  2. Fischer, C. N., & LeBlanc, R. J., Jr. (1988). Crafting a compiler. Menlo Park, CA: The Benjamin/Cummings Publishing Company, Inc.
  3. Edpresso Team. Pass by value vs. pass by reference. (n.d.). Retrieved from https://www.educative.io/edpresso/pass-by-value-vs-pass-by-reference
  4. Pass by reference (C++ only). (n.d.). Retrieved from https://www.ibm.com/docs/en/zos/2.4.0?topic=calls-pass-by-reference-c-only
  5. Although not covered in introductory courses, it is possible to have systems of separate programs running concurrently, sharing data, and cooperating to solve a problem. If the programs run on the same computer, they can share data through addresses or pointers. For example, the operating system is nothing more than a program, exchanging data with our programs through system calls using pass-by-value and pointer. Other examples include programs interfacing with database management systems or other server programs.