-1

i have written this little program to explain my point and my variable a remains unchanged it prints 4. I later learned that I need to use pointers or references; why is that?

#include <iostream>

void setToTen(int x) { x = 10; }

int main(){  
    int a = 4;
    setToTen(a);
    std::cout << a << std::endl;
}
einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • 4
    By definition in the rules of the language, variables are passed by value or copy to a function, unless they are references. – Thomas Matthews Jul 19 '17 at 20:44
  • You need to declare `x` as by reference. That is `int&` instead of `int`. – Aluan Haddad Jul 19 '17 at 20:44
  • 3
    This isn't the problem, but do you really need the extra stuff that `std::endl` does? `'\n'` ends a line. – Pete Becker Jul 19 '17 at 20:45
  • 2
    Possible duplicate of [How do I use Reference Parameters in C++?](https://stackoverflow.com/questions/2564873/how-do-i-use-reference-parameters-in-c) – Justin Jul 19 '17 at 20:46
  • Given that the `setToTen()` function receives an integer as argument, it can be invoked as `setToTen(4);`. In fact, this is how it is invoked in your code too, just that `4` is not hardcoded but it comes from a memory location usually known as a "variable". – axiac Jul 19 '17 at 20:46
  • I would give you the tip to delete this question and read more into whatever you are following. Learn something about pointers and references in C++, if you then need help, ask. – Hannes Hauptmann Jul 19 '17 at 20:47
  • 2
    Questions should not be downvoted because they are basic or beginner questions. This question states the expected behavior, the observed behavior and provides a [MCVE]. It is well asked, if lacking in research. Specially for a new user. – François Andrieux Jul 19 '17 at 20:47
  • @PeteBecker good point. I looked it up and what you suggest is mentioned in [C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#slio50-avoid-endl) – Aluan Haddad Jul 19 '17 at 20:47
  • @Thomas Matthews "unless they are references" - nitpick: or pointers (well, the *pointer* is passed by value, but you can access what it *points to*). – Jesper Juhl Jul 19 '17 at 20:56

3 Answers3

4

In C++ arguments to functions are passed by value. This means that when you write

setToTen(a);

the parameter int x in setToTen is given a copy of the value stored in the variable a. In other words, you're not actually handing off the variable a into the setToTen function. Instead, you're giving a copy of that value to setToTen, so the changes made in that function affect the copy rather than the original.

On the other hand, if you change setToTen so that it takes its parameter by reference, like this:

void setToTen(int& x) {
    x = 10;
}

the story is different. Here, calling setToTen(a) essentially hands the variable a into the function setToTen, rather than a copy of the value. That means that changes made to the parameter x in setToTen will change the variable a.

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
3

Your code requests a copy of x by having the signature void setToTen(int x).

Being able to take things by copy means that reasoning about the behavior of a function is far easier. This is true both for you, and for the compiler.

For example, imagine this:

int increase_some( int x, int y, int z ) {
  for (int i = 0; i < y; ++i )
    x+=z;
  return x;
}

because x y and z are copies, you can reason about what this does. If they where references to the values "outside" of increase_some, the bit where you x+=z could change y or z and things could get crazy.

But because we know they are copies, we can say increase_some returns x if y<=0, and otherwise returns x+y*z.

Which means that the optimizer could change it to exactly that:

int increase_some( int x, int y, int z ) {
  if (y<=0) return x;
  return x + y*z;
}

and generate that output.

This is a toy example, but we took a complex function and turned it into a simple one. Real optimizers do this all the time with pieces of your complex function.

Going one step further, by taking things by immutable value, and never touching global state, we can treat your code as "functional", only depending on its arguments. Which means the compiler can take repeated calls to a function and reduce them to one call.

This is so valuable that compilers will transform code that doesn't have immutable copies of primitive data into code that does before trying to optimize -- this is known as static single assignment form.

In theory, a complex program with lots of functions taking things by reference could be optimized this same way, and nothing be lost. But in practice that gets hard, and it is really easy to accidentally screw it up.

That is the other side; making it easier to reason about by people.

And all you have to embrace is the idea of taking arguments by value.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
0

Function parameters are function local variables that are not alive after exiting function.

You can imagine the function definition and its call

int a = 4;
setToTen(a);

//...

void setToTen(int x) { x = 10; }

the following way

int a = 4;
setToTen(a);

//...

void setToTen( /* int x */ ) { int x = a; x = 10; }

As it is seen within the function there is declared a local variable x which is initialized by the argument a. Any changes of the local variable x do not influence on the original argument a.

If you want to change the original variable itself you should pass it by reference that is the function will deal with a reference to the variable. For example

void setToTen(int &x) { x = 10; }

In this case you can imagine the function definition and its call the following way

int a = 4;
setToTen(a);

//...

void setToTen( /* int x */ ) { int &x = a; x = 10; }

As you see the reference x is as usual local. But it references the original argument a. In this case the argument will be changed through the local reference.

Another way is to declare the parameter as pointer. For example

void setToTen(int *x) { *x = 10; }

In this case you have to pass the original argument indirectly by its address.

int a = 4;
setToTen( &a );
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335