Call by value:
void foo( int x ) {
cout << x << endl;
x = 4;
}
int someVar = 5;
foo( someVar );
The value 5 is pushed onto the stack and foo is called. Inside foo(), 5 is popped off the stack and output. x = 4 modifies the stack copy, which is then thrown away when the function returns.
void foo( int& x ) {
cout << x << endl;
x = 4;
}
int someVar = 5;
foo( someVar );
The address of someVar is pushed onto the stack and foo is called. Inside foo, the address is popped off the stack and the integer stored at that address is output. x = 4 modifies the memory referred to by the address, which means that when foo() returns, someVar now has the value 4.
Contrast the above code to
void foo( int* x ) {
cout << *x << endl;
*x = 4;
}
int someVar = 5;
foo( &someVar );
This code does the exact same thing as my reference example, it's just the syntax is a bit different: note the &someVar where foo is called, and note the *x in foo() to refer to the integer value.