7.4a — Returning values by value, reference, and address

In the three previous lessons, you learned about passing arguments to functions by value, reference, and address. In this section, we’ll consider the issue of returning values back to the caller via all three methods.

As it turns out, returning values from a function to its caller by value, address, or reference works almost exactly the same way as passing parameters to a function does. All of the same upsides and downsides for each method are present. The primary difference between the two is simply that the direction of data flow is reversed. However, there is one more added bit of complexity -- because local variables in a function go out of scope and are destroyed when the function returns, we need to consider the effect of this on each return type.

Return by value

Return by value is the simplest and safest return type to use. When a value is returned by value, a copy of that value is returned to the caller. As with pass by value, you can return by value literals (e.g. 5), variables (e.g. x), or expressions (e.g. x+1), which makes return by value very flexible.

Another advantage of return by value is that you can return variables (or expressions) that involve local variables declared within the function without having to worry about scoping issues. Because the variables are evaluated before the function returns, and a copy of the value is returned to the caller, there are no problems when the function’s variable goes out of scope at the end of the function.

Return by value is the most appropriate when returning variables that were declared inside the function, or for returning function arguments that were passed by value. However, like pass by value, return by value is slow for structs and large classes.

When to use return by value:

  • When returning variables that were declared inside the function
  • When returning function arguments that were passed by value

When not to use return by value:

  • When returning a built-in array or pointer (use return by address)
  • When returning a large struct or class (use return by reference)

Return by address

Returning by address involves returning the address of a variable to the caller. Similar to pass by address, return by address can only return the address of a variable, not a literal or an expression (which don’t have addresses). Because return by address just copies an address from the function to the caller, return by address is fast.

However, return by address has one additional downside that return by value doesn’t -- if you try to return the address of a variable local to the function, your program will exhibit undefined behavior. Consider the following example:

As you can see here, value is destroyed just after its address is returned to the caller. The end result is that the caller ends up with the address of non-allocated memory (a dangling pointer), which will cause problems if used. This is a common mistakes that new programmers make. Many newer compilers will give a warning (not an error) if the programmer tries to return a local variable by address -- however, there are quite a few ways to trick the compiler into letting you do something illegal without generating a warning, so the burden is on the programmer to ensure the address they are returning will be to a valid variable after the function returns.

Return by address is often used to return dynamically allocated memory to the caller:

This works because dynamically allocated memory does not go out of scope at the end of the block in which it is declared, so that memory will still exist when the address is returned back to the caller.

When to use return by address:

  • When returning dynamically allocated memory
  • When returning function arguments that were passed by address

When not to use return by address:

  • When returning variables that were declared inside the function (use return by value)
  • When returning a large struct or class that was passed by reference (use return by reference)

Return by reference

Similar to pass by address, values returned by reference must be variables (you can not return a reference to a literal or an expression). When a variable is returned by reference, a reference to the variable is passed back to the caller. The caller can then use this reference to continue modifying the variable, which can be useful at times. Return by reference is also fast, which can be useful when returning structs and classes.

However, just like return by address, you should not return local variables by reference. Consider the following example:

In the above program, the program is returning a reference to a value that will be destroyed when the function returns. This would mean the caller receives a reference to garbage. Fortunately, your compiler will probably give you a warning or error if you try to do this.

Return by reference is typically used to return arguments passed by reference to the function back to the caller. In the following example, we return (by reference) an element of an array that was passed to our function by reference:

This prints:


When we call getElement(array, 10), getElement() returns a reference to the array element with index 10. main() then uses this reference to assign that element the value 5.

Although this is somewhat of a contrived example (because you can access array[10] directly), once you learn about classes you will find a lot more uses for returning values by reference.

When to use return by reference:

  • When returning a reference parameter
  • When returning an element from an array that was passed into the function
  • When returning a large struct or class that will not be destroyed at the end of the function (e.g. one that was passed in)

When not to use return by reference:

  • When returning variables that were declared inside the function (use return by value)
  • When returning a built-in array or pointer value (use return by address)

Mixing return references and values

Although a function may return a value or a reference, the caller may or may not assign the result to a value or reference accordingly. Let’s look at what happens when we mix value and reference types.

In case A, we’re assigning a reference return value to a non-reference variable. Because value isn’t a reference, the return value is copied into value, as if returnByReference() had returned by value.

In case B, we’re trying to initialize reference ref with the copy of the return value returned by returnByValue(). However, because the value being returned doesn’t have an address (it’s an r-value), this will cause a compile error.

In case C, we’re trying to initialize const reference ref with the copy of the return value returned by returnByValue(). Because const references can bind to r-values, there’s no problem here. Normally, r-values expire at the end of the expression in which they are created -- however, when bound to a const reference, the lifetime of the r-value (in this case, the return value of the function) is extended to match the lifetime of the reference (in this case, cref)


Most of the time, return by value will be sufficient for your needs. It’s also the most flexible and safest way to return information to the caller. However, return by reference or address can also be useful, particularly when working with dynamically allocated classes or structs. When using return by reference or address, make sure you are not returning a reference to, or the address of, a variable that will go out of scope when the function returns!

Quiz time

Write function prototypes for each of the following functions. Use the most appropriate parameter and return types (by value, by address, or by reference), including use of const where appropriate.

1) A function named sumTo() that takes an integer parameter and returns the sum of all the numbers between 1 and the input number.

Show Solution

2) A function named printEmployeeName() that takes an Employee struct as input.

Show Solution

3) A function named minmax() that takes two integers as input and returns the smaller and larger number as separate parameters.

Show Solution

4) A function named getIndexOfLargestValue() that takes an integer array (as a pointer) and an array size, and returns the index of the largest element in the array.

Show Solution

5) A function named getElement() that takes an integer array (as a pointer) and an index and returns the array element at that index (not a copy). Assume the index is valid, and the return value is const.

Show Solution

7.5 -- Inline functions
7.4 -- Passing arguments by address

128 comments to 7.4a — Returning values by value, reference, and address

  • KnowMore

    Alex, I was revisiting some of the basics of C++, and, I found that when a variable is passed to a function’s reference parameter, it doesn’t show the effect of the reference in the variable on the same line being called ! What I’m trying to say is this :-

    operator(<<) executes in -> style,  not in <- ! So, It Should have updated the value of x accordingly, but, It Didn’t!
    Is this behaviour due to Side-Effects?
    Waiting for your reply……
    Thanks In Advance 🙂

  • John Halfyard

    The mystery deepens… if I //comment out all the code and add a token command (see code) the application file reappears in the ‘debug’ folder.  When I reverse the process, the application file disappears.

    • Alex

      It’s possible your virus scanner or malware detector is interfering. You might try disabling them and see if that fixes your issue… Outside of that, I’m as perplexed as you.

  • John Halfyard

    Update::  I checked out my earlier Projects from Chapters 1-6 (which run fine).  Noticed in the "Debug" folder there is an applications file.  But in the Chapter 7_4a_Q1 there is no applications file.  Not sure what I did here.

    • Alex

      Not clear on whether you were able to resolve this. Your code compiles fine for me, so something in your project must have gotten messed up. Easiest thing to do is just create a new one from scratch and paste your code in.

      • John Halfyard

        Alex… see my last comment.  Following your suggestion, I pasted the code into a new solution (naming it something else) and still my *.exe application is not being placed into the debug folder and I get the same error.

        I can run past chapter questions fine and when I check the application file is in the debug folder.

  • John Halfyard

    I get the following runtime error.  I don’t think there’s anything wrong with the code but this prompt happened after I mistakenly named a file "Chapter_7.4a_Q1".  When I deleted that folder and started over I get the following error:  "XXXXX.exe" is not recognized as an internal or external command.  

    Here’s my code - was attempting Q1 in Section 7.4a

  • Viraj

    Hey Alex, really enjoying the tutorial so far! You’ve done some great work. 🙂
    Just a question:
    In the quiz question 4’s answer,

    Is it necessary to put a const before the second int parameter? (Since we’re passing it by value wouldn’t it be kind of pointless to?)

    And if it’s been done to ensure that length does not accidentally get changed in the function, why, in the answer to the third question (given below) is the same not done to x and y?

    Thanks for all the help!

    • Alex

      It’s not necessary, but it is considered a best practice. It signals to other programmers (or our future self) that we don’t intend for this value to change inside the function, and enlists the compiler’s help in making sure we don’t change it. Understanding what might change and what won’t makes the purpose of the parameter, and the function itself, easier to understand.

      In the other example, x and y should similarly be made const for consistency with best practices. I’ve updated the answers accordingly. Thanks for pointing this out!

  • Mor

    Shouldn’t the answer to 3 be

    Since otherwise you won’t have anything to put into minOut and maxOut, unless you declare static variables in the function/return reference to global variables/allocate dynamic memory for the reference.

    • Alex

      Nope. I see what you’re thinking. However, remember that assigning to a reference doesn’t change the reference, it only changes the value that’s being referenced.

      So when we say:

      We’re not setting minOut to reference (local) variable x or y (which would be bad, as you noted), we’re setting the value of the argument passed in for minOut to the value of x or y (which is fine).

  • :|

    What is the int& for? i dont understand the syntax for the functions, they have to be inside the parameter like (*array, &y) or they have to be out of the parameter and in the function declaration (int& functionName?) or both?

    What is the syntax for return values with adressess and references?

  • Alan

    Hello , Alex
    I have some problem with the return by address and reference

    Case 1

    int* allocateArray(int size)
        return new int[size];
        // why do u say the dynamically allocated memory does not goes out of the scope at the end of the block
           in which it is declared since it do really goes out of block of the the function allocateArray which means the pointer containing the address of dynamically allocated memory should be destroy resulting in undefined result?

    int main()
        int *array = allocateArray(25);

        // do stuff with array

        delete[] array;
        return 0;

    Case 2

    // Returns a reference to the index element of array
    int& getElement(std::array<int, 25> &array, int index)
        // we know that array[index] will not be destroyed when we return to the caller (since the caller
           passed in the array in the first place!)
        // so it’s okay to return it by reference
        return array[index];

    int main()
        std::array<int, 25> array;

        // Set the element of array with index 10 to the value 5
        getElement(array, 10) = 5;
        std::cout << array[10] << ‘n’;

        return 0;

        what does it mean by (since the caller passed in the array in the first place)?Wont it reference to a garbage value when the block is exited?

    Your help is greatly appreciated.

    • Alex

      1) Dynamically allocated memory persists until explicitly deleted by the programmer.
      2) No, because the caller passed in the array, we can reasonably assume that when a result from the array is returned back to the caller that it will still exist.

  • Zoran

    Hello, Alex,
    In this lesson you say:

    When to use return by reference:

      *  When returning a large struct or class that has scope outside of the function

    Shouldn’t it actually be:

      *  When returning a large struct or class that has duration outside of the function

    So, isn’t the correct word there "duration", not "scope"?
    I might not be right, as I’m just learning C++ (although not new in programming). But if I got everything right after I had read the tutorial up to this point, it should be "duration".


  • jenifer

    It must print some garabage value, but how it works?

    • Alex

      Returning a reference (or pointer) to a local variable results in undefined behavior. That “undefined behavior” can manifest in any number of ways: It may work fine all of the time. It may work fine some of the time and not others. It may cause your program to crash. It may look like it’s working but mess up something else. It may work on some compilers and not others. It may work until you change some other line of code. With a little digging, we could probably determine why this particular case is working like it is, but it’s not worth it. You’re violating the rules of C++, and understanding how it’s working in unsupported cases isn’t a good use of our time. 🙂

  • David

    On number 5 and 6 of the quiz, why was ‘const int’ not used for length and index? Since the functions would not modify these values, shouldn’t const be preferred?

    • Alex

      Yes, slightly preferred, since then we can enlist the compiler to assist in ensuring we don’t accidentally change these inside the function.

      However, because these are pass by value parameters, even if the function does change them, the argument won’t be changed, so the risk is pretty minimal. Nevertheless, I’ll update the reference answers.

  • Milos

    Can you explain a little bit question number 5 in quiz? Thanks Alex!

    • Alex

      Is there something in particular you find confusing?

      • Milos

        I made some effort and now i understand all the quiz questions. But Alex, at part "Mixing return references and values" in example B and C, what do you mean by "rvalue", and in C how can a const variable extend the life of return value, btw how can references hold literal values?
        A lot of awkward questions but i truly want to understand this part, so Alex i hope u can help me with it. Thanks!

        • Alex

          > what do you mean by “rvalue”

          An rvalue is a literal or a temporary/anonymous value or something that doesn’t have a permanent memory address.

          > in C how can a const variable extend the life of return value,

          The scope of the returned value is extended so that it doesn’t go out of scope until the reference does.

          > btw how can references hold literal values?

          Const references have special logic that let them point to literals and other rvalues. Without this, references would be a pain because you’d only be able to pass lvalues to them, never a literal or temporary result of some expression…

  • Martin

    I have a question concerning the quizzes. In almost all examples the int parameter is passed without the const, e.g. the length in 4) and 5).
    Why is that so? Wouldn’t it be safer to add the const keyword to prevent the programmer from actually changing it?

    Thanks in advance for the answer.

    • Alex

      Yes. If you don’t expect the function to change the value of the parameter, it’s safer to make the parameter const.

      This is particularly important for pointer and reference parameters, because inadvertently modifying the parameter can modify the underlying argument.

      However, in practice, use of const is often omitted for variables passed by value, since in the worst case, if the function changes the value, it’s only changing a copy. There’s no benefit to not using const in such a case, it’s just bad habit that tends to be of low consequence.

  • Anonymous

    I have a question about this line in your tutorial --

    int main()
        int value = returnByReference(); // case A -- ok, treated as return by value
        int &ref = returnByValue(); // case B -- compile error
        const int &cref = returnByValue(); // case C -- ok, the lifetime of return value is extended to the lifetime of cref
    In case A, we’re assigning a reference return value to a non-reference variable. Because value isn’t a reference, the return value is copied into value, as if returnByReference() had returned by value.

    Now my question is -- Since The reference of x returned "is copied" into value -- will modifying "value" in the program modify "x" the variable?

  • Perry Frimpong Mensah

    I am making a program for riddles and say if the answer to a riddle is age, not everyone would write age. Some might write Age or even AGE. How do I make all of these answers valid and not just one of them

    • Alex

      Generally the best thing to do in such a case is convert the user input to lower case before checking against the correct answer (which should also be lower case).

  • Happy Holidays, everyone!

    I am finding this C++ tutorial site very useful. Complex concepts are explained very lucidly, and the exercises reinforce the core material.

    My only suggestion would to perhaps provide a page that links to various chapters/sections in the course, and serves as a fast-track for people who already know programming in another language.

    I use this site with AdBlocker, so the ads don’t compete for my attention. I have chosen to support Alex directly, and encourage others to do so.

    Thank you, Alex!

  • Gajendra Gulgulia

    i come from a mechanical engineering background from India and have enrolled for computational science engineering at the Technical University of Munich. We have a course in advanced programming which considers that one already knows the basics of C++ and further advanced topics in C++ are to be built upon in the advanced course.

    Without any precursor, the course started dealing with Classes, pointers and what not in OOP using C++ , and I sat like a dumbass through the lectures, until in one of the tutorials, the tutor mentioned in the slides to learn from

    Here I am already through this section and hope to catch up with the missed programming tutorials in a few weeks.

    Thanks so much for saving my ass! 🙂

  • Matt

    Under section "Return by address", second paragraph, you wrote:

    "However, returning by address has one additional downside that pass by reference doesn’t -- you can not return local variables to the function by address."

    I think it would be better if you replaced "function" with "caller".

  • Kılıçarslan

    I have two questions.Returning local variables by reference or by address never gives me a compile error,it(VS) only warns me about it.Doest it mean processing system still didn’t allocate a memory for the now empty memory,so it doesn’t give me a compile error?

    Second question is how

    differs from

    I tried nearly every possible combination to get an error where "const" is used for function definitons or declarations.

    • Alex

      1) I don’t understand what you are asking about re: returning local references or addresses.
      2) The top example returns a const reference whereas the bottom example returns a non-const reference. So in the top case, you couldn’t do something like this:

      But in the bottom case you could.

      • Kılıçarslan

        Thanks for clarifying me about second one.For the first one,consider this:

        Now if I compile,compiler only warns me about returning address of local variable but in run-time I never get an error if I use that returned reference of local variable.Does this mean,system has nothing placed in the memory address of the variable?

        • Alex

          It means that the reference returned by function doubleValue() is aliasing memory that is no longer allocated for variable value.

          Accessing that reference will therefore have an undefined result -- it might work for a little while. It might stop working after a little while (perhaps when another function is called and the memory is reused). It might crash your program.

  • Amol

    Hi Alex,

    This is a wonderful site! I am really enjoying learning C++ thanks to you!

    I have one question though.

    I am not sure why I am getting below output for the give code:
    From what you explained above, I shouldn’t have gotten correct answer, but I do get correct answer every time I run this code.
    And what’s more surprising is that the pointer named ‘yPtr’ is pointing to different address before and after returning the value!
    Can you please provide your insights?


    • Alex

      I didn’t say you wouldn’t get the correct answer. I said the result would be undefined. It might work, or it might not, depending on what C++ is doing behind the scenes, and what else your program is doing, and any number of other things.

      You’re not getting the same address because you’re not printing the address of the same variable. In function doubleit2(), you’re printing the address of doubleit2’s variable y (through the pointer yPtr). In function main(), you’re printing the address of main’s variable y.

      • Amol

        Ok. Thanks Alex.

        But they both are pointing to the same value (i.e. 6) in memory right?

        Also, is there any tool or something which can help us visualize memory allocation in c++ ?

        • Alex

          They may or may not. As I said, the results are undefined.

          When you did this:

          You’re saying “instantiate a new variable named y and initialize it with a copy of the value that the pointer returned from function doubleIt2 is pointing to”.

          If the pointer returned from doubleIt() was pointing at value 6, that value 6 would get copied into main’s variable y. In that case, both y’s have value 6, but they do not occupy the same memory address.

          However, because you’re returning a pointer to a value that’s goes out of scope before you dereference it, who knows what value will actually be returned. Probably 6, but it’s possible that when doubleIt2() goes out of scope and local variable y is destroyed that some other value could be put in that memory address.

          There may be tools to help visualize such things but I’m not aware of them.

  • Rahul Choubey

    Hi Alex,

    I tried passing an address of local variable from a function. And it compiles fine (no warning) and runs fine in Visual Studio 2015:

    I thought,  this will not work as local variable die out and deferencing should give some garbage value, if not some runtime exception. What’s wrong?

    • Alex

      Just because the compiler will let you do something doesn’t mean you should do it.

      You’re right, this will not work, because the local variable will be destroyed, so the memory address returned will be left as a dangling pointer. Accessing that memory address will have undefined results (sometimes it might work, sometimes it might crash, sometimes you might get a different value back, etc…)

  • Anonymous


      In the example that was mentioned (Case A, Case B and Case C), can it be thought of as implicit type conversion done by the compiler?

    const int (high)
    int &   (low)  

    Assuming the compiler implicitly converts to the type above (if need be), and the reason for error being the compiler could not convert it implicitly (in Case B).

    Just like in the case of :

    long double (high)
    unsigned long long
    long long
    unsigned long
    unsigned int
    int (low) // * taken from chapter 4.4

    Does it work that way?

    • Alex

      Not really, no. 🙂 It’s more that the language has specific rules about what happens when you mix (const/non-const) references and non-references.


    I’m curious about function declaration and return syntax of reference.

    When it come to return by value you wrote,

    From function declaration, ‘int’ means this function would return int type value. In the function local variable ‘value’ is an int type variable.(which is returned)

    However when it comes to return by reference it seems little bit strange. You wrote,

    From function declaration, "int&" means this function would return reference type. However inside the function you returned "static int" type variable ‘x’. So could you return "int" type as a "reference"??

    Shouldn’t we have to add another variable y which is an reference variable and return y? which looks like this.

    • Alex

      Remember that a reference is just an alias for a variable. So when we return x and the return type is a reference to an int, the compiler knows that we’re intending to return a reference to that local x variable. We don’t explicitly have to declare a reference version of x first and return that.

  • Chris


    i think we should return built-in array by address because at return by reference section you said don’t return by reference built-in array, but at the above example at return by reference section and quiz number 5 you use return by reference for returning built-in array element. i am confuse with that, so we should use return by address or return by reference?

    Thank you.

    • Alex

      C-style arrays decay into pointers, so when we pass the entire array (either to a function, or as a return value), we typically do so by address.

      However, when dealing with individual array elements, it’s easier to pass or return them by reference. Remember that operator[] (which you typically use to get the specific element of the array) does an implicit dereference, so you have an actual value to pass or return, not a pointer to it.

  • mrlinh

    I thank admin, knowledge is too wonderful for beginners, let me ask how original do so?

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter