Search

2.2 — Function return values

Consider the following program:

This program is composed of two conceptual parts: First, we get a value from the user. Then we tell the user what double that value is.

Although this program is trivial enough that we don’t need to break it into multiple functions, what if we wanted to? Getting an integer value from the user is a well-defined job that we want our program to do, so it would make a good candidate for a function.

So let’s write a program to do this:

While this program is a good attempt at a solution, it doesn’t quite work.

When function getValueFromUser is called, the user is asked to enter an integer as expected. But the value they enter is lost when getValueFromUser terminates and control returns to main. Variable num never gets initialized with the value the user entered, and so the program always prints the answer 0.

What we’re missing is some way for getValueFromUser to return the value the user entered back to main so that main can make use of that data.

Return values

When you write a user-defined function, you get to determine whether your function will return a value back to the caller or not. To return a value back to the caller, two things are needed.

First, your function has to indicate what type of value will be returned. This is done by setting the function’s return type, which is the type that is defined before the function’s name. In the example above, function getValueFromUser has a return type of void, and function main has a return type of int. Note that this doesn’t determine what specific value is returned -- only the type of the value.

Second, inside the function that will return a value, we use a return statement to indicate the specific value being returned to the caller. The specific value returned from a function is called the return value. When the return statement is executed, the return value is copied from the function back to the caller. This process is called return by value.

Let’s take a look at a simple function that returns an integer value, and a sample program that calls it:

When run, this program prints:

5
7

Execution starts at the top of main. In the first statement, the function call to returnFive is evaluated, which results in function returnFive being called. Function returnFive returns the specific value of 5 back to the caller, which is then printed to the console via std::cout.

In the second function call, the function call to returnFive is evaluated, which results in function returnFive being called again. Function returnFive returns the value of 5 back to the caller. The expression 5 + 2 is evaluated to produce the result 7, which is then printed to the console via std::cout.

In the third statement, function returnFive is called again, resulting in the value 5 being returned back to the caller. However, function main does nothing with the return value, so nothing further happens (the return value is ignored).

Note: Return values will not be printed unless the caller sends them to the console via std::cout. In the last case above, the return value is not sent to std::cout, so nothing is printed.

Fixing our challenge program

With this in mind, we can fix the program we presented at the top of the lesson:

When this program executes, the first statement in main will create an int variable named num. When the program goes to initialize num, it will see that there is a function call to getValueFromUser, so it will go execute that function. Function getValueFromUser, asks the user to enter a value, and then it returns that value back to the caller (main). This return value is used as the initialization value for variable num.

Compile this program yourself and run it a few times to prove to yourself that it works.

Void return values

Functions are not required to return a value. To tell the compiler that a function does not return a value, a return type of void is used. Let’s look at the doPrint() function from the previous lesson:

This function has a return type of void, indicating that it does not return a value to the caller. Because it does not return a value, no return statement is needed (trying to return a specific value from a function with a void return type will result in a compilation error).

Here’s another example of a function that returns void, and a sample program that calls it:

In the first function call to function returnNothing, the function prints “Hi” and then returns nothing back to the caller. Control returns to main and the program proceeds.

The second function call to function returnNothing won’t even compile. Function returnNothing has a void return type, meaning it doesn’t return a value. However, this statement is trying to send the return value of returnNothing to std::cout to be printed. std::cout doesn’t know how to handle this (what value would it output?). Consequently, the compiler will flag this as an error. You’ll need to comment out this line of code in order to make your code compile.

A void return type (meaning nothing is returned) is used when we want to have a function that doesn’t return anything to the caller (because it doesn’t need to). In the above example, the returnNothing function has useful behavior (it prints “Hi”) but it doesn’t need to return anything back to the caller (in this case, main). Therefore, returnNothing is given a void return type.

Returning to main

You now have the conceptual tools to understand how the main function actually works. When the program is executed, the operating system makes a function call to main. Execution then jumps to the top of main. The statements in main are executed sequentially. Finally, main returns an integer value (usually 0), and your program terminates. The return value from main is sometimes called a status code, as it is used to indicate whether the program ran successfully or not.

By definition, a status code of 0 means the program executed successfully.

Best practice

Your main function should return 0 if the program ran normally.

A non-zero status code is often used to indicate failure (and while this works fine on most operating systems, strictly speaking, it’s not guaranteed to be portable).

For advanced readers

The C++ standard only defines the meaning of 3 status codes: 0, EXIT_SUCCESS, and EXIT_FAILURE. 0 and EXIT_SUCCESS both mean the program executed successfully. EXIT_FAILURE means the program did not execute successfully.

EXIT_SUCCESS and EXIT_FAILURE are defined in the <cstdlib> header:

If you want to maximize portability, you should only use 0 or EXIT_SUCCESS to indicate a successful termination, or EXIT_FAILURE to indicate an unsuccessful termination.

C++ disallows calling the main function explicitly.

For now, you should also define your main function at the bottom of your code file, below other functions.

A few additional notes about return values

First, if a function has a non-void return type, it must return a value of that type (using a return statement). Failure to do so will result in undefined behavior. The only exception to this rule is for function main(), which will assume a return value of 0 if one is not explicitly provided. That said, it is best practice to explicitly return a value from main, both to show your intent, and for consistency with other functions (which will not let you omit the return value).

Best practice

Always explicitly provide a return value for any function that has a non-void return type.

Warning

Failure to return a value from a function with a non-void return type (other than main) will result in undefined behavior.

Second, when a return statement is executed, the function returns back to the caller immediately at that point. Any additional code in the function is ignored.

Third, a function can only return a single value back to the caller each time it is called. However, the value doesn’t need to be a literal, it can be the result of any valid expression, including a variable or even a call to another function that returns a value. In the getValueFromUser() example above, we returned a variable holding the number the user typed.

Finally, note that a function is free to define what its return value means. Some functions use return values as status codes, to indicate whether they succeeded or failed. Other functions return a calculated or selected value. Other functions return nothing. What the function returns and the meaning of that value is defined by the function’s author. Because of the wide variety of possibilities here, it’s a good idea to document your function with a comment indicating what the return values mean.

For example:

Reusing functions

Now we can illustrate a good case for function reuse. Consider the following program:

While this program works, it’s a little redundant. In fact, this program violates one of the central tenets of good programming: “Don’t Repeat Yourself” (often abbreviated “DRY”).

Why is repeated code bad? If we wanted to change the text “Enter an integer:” to something else, we’d have to update it in two locations. And what if we wanted to initialize 10 variables instead of 2? That would be a lot of redundant code (making our programs longer and harder to understand), and a lot of room for typos to creep in.

Let’s update this program to use our getValueFromUser function that we developed above:

This program produces the following output:

Enter an integer: 5
Enter an integer: 7
5 + 7 = 12

In this program, we call getValueFromUser twice, once to initialize variable x, and once to initialize variable y. That saves us from duplicating the code to get user input, and reduces the odds of making a mistake. Once we know getValueFromUser works for one variable, it will work for as many of them as we need.

This is the essence of modular programming: the ability to write a function, test it, ensure that it works, and then know that we can reuse it as many times as we want and it will continue to work (so long as we don’t modify the function -- at which point we’ll have to retest it).

Best practice

Follow the DRY best practice: “don’t repeat yourself”. If you need to do something more than once, consider how to modify your code to remove as much redundancy as possible. Variables can be used to store the results of calculations that need to be used more than once (so we don’t have to repeat the calculation). Functions can be used to define a sequence of statements we want to execute more than once. And loops (which we’ll cover in a later chapter) can be used to execute a statement more than once.

Conclusion

Return values provide a way for functions to return a single value back to the function’s caller.

Functions provide a way to minimize redundancy in our programs.

Quiz time

Question #1

Inspect the following programs and state what they output, or whether they will not compile.

1a)

Show Solution

1b)

Show Solution

1c)

Show Solution

1d)

Show Solution

1e)

Show Solution

1f)

Show Solution

1g)

Show Solution

1h) Extra credit:

Show Solution

Question #2


What does “DRY” stand for, and why is it a useful practice to follow?

Show Solution


2.3 -- Introduction to function parameters and arguments
Index
2.1 -- Introduction to functions

97 comments to 2.2 — Function return values

  • Suyash Mallik

    EDIT: I read ahead and found the answer.. It seems that initializing a variable with a function's return value does call that function.

    Hi! I want to ask whether defining a function calls it as well? For instance, when I compile the following code:

    The console prints out oops5.. but I did not call the get5 function anywhere? Does initializing the variable x with the return value of get5 call it as well?

  • What's up with the weird curly braces when initializing a variable? Using VS Code on Mac with Clang compiler just throws errors. Replacing int x{ someFunction()} by int x = someFunction() solves the problem.

    some googling give something about scalars and I was lost. Can you explain this notation because I don't understand.

    • Okay I’ll answer my own post ;-P Off course I didn’t read the chapter about variables otherwise I would have known it’s a C+11 addition. some further digging provided me information Clang compiler on macOS defaults to C++98. So likely I have to add a parameter to config.

      I didn’t read cause I started with the Pluralsight’s C++ for beginners but I don’t like it. I makes huge jumps from functions to Object oriented programming and instructor is talking in a video for 17mins without any practice exercises then next video. W the F?! I would like to compliment you guys with the thorough and baby steps approach of this website. Takes probably 4 times as long to “learn C++” but with a proper grasp. Thanks in advance!

      • nascardriver

        Since you've probably skipped more than just the lesson about initialization, please read lesson 0.10-0.12. Otherwise you'll run into more problems.

        • Thanks for the pointer. Apparently I had read majority of that chapter. I use VS Code.

          For others; configuration VS Code C++ you can find at https://code.visualstudio.com/docs/cpp/customize-default-settings-cpp

  • Hi all,

    Regarding the last question of the above quiz. Could someone please explain why the c++ compiler
    does not throw an error:

    {code}
    #include <iostream>

    int returnFive()
    {
        return 5;
    }

    int main()
    {
        std::cout << returnFive << '\n';

        return 0;
    }

    {code}

    for undefined reference to returnFive variable in main function or

    for missing the () when calling returnFive function from main?

    Nikos

  • Shakib

    From Void Return Values:

    -I added #include <iostream> ; though I am getting this error-
    1>------ Build started: Project: Draft1, Configuration: Debug x64 ------
    1>Draft1.cpp
    1>MSVCRTD.lib(exe_main.obj) : error LNK2019: unresolved external symbol main referenced in function "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ)
    1>C:\Users\USER\source\repos\Draft1\x64\Debug\Draft1.exe : fatal error LNK1120: 1 unresolved externals
    1>Done building project "Draft1.vcxproj" -- FAILED.
    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

  • Failure to return a value

    "Failure to return a value from a function with a non-void return type (other than main) will result in undefined behavior."

    When I tried the following, I got compile-time error not undefined behaviour.

    • nascardriver

      You got a warning, because `sum` doesn't return a value.
      You're treating warnings as errors, so the warning turned into an error (That's a good setting).

      If you were to disable "Treat warnings as errors", you could compile your function and experience undefined behavior.

  • Where does a return value is being stored

    I have a question:

    Where does a return value is being stored exactly after a function is done executing and before its return value is stored in a variable in a caller function? Is it going to be stored in a temporary storage like a register or in a unnamed memory storage?

    Thank you.

    • nascardriver

      That's not standardized. Most commonly, return values are stored in the `ax` (`rax` on 64-bit, `eax` on 32 bit) register.

  • internet_laser

    After deciding to learn C++ I did some YouTube tutorials but wasn't learning things at a deep enough level. Then I discovered this website and found exactly what I've been looking for! You've answered every question I've had and things are very clear for me after going through these tutorials. I'm going through every example, step by step, testing everything & trying to really retain the information being offered here. Thanks for doing this for so many years!

    Seeing other people making calculators in the comments inspired me to make my own calculator. It hasn't been covered but I used if/else and figured out how to use a loop (that was my extra credit challenge).

    I realize that this calculator program can break so many ways if a user enters invalid information, looking forward to learning how to control the information that's entered, I'm sure this is in a future lesson.

    Code below. This is my first program!

  • Miloš Radović

    Hi! Might be a stupid question since I'm new to programming, but in the solution to our problem, was there a need to create a new variable num? Couldn't we just call the function getValueFromUser in the std::cout statement and multiply it with two?

    • Niasty

      From what I see, the variable num is used in the code two times. If you would replace these two instances of this variable with function calls, the user could type a different value the second time, which could cause the result to be wrong. If you planned on using the value only once, then this would be ok, but if you want to reuse it, you need to create a new variable for it.

  • David Slaughter

    Why is the main function an integer type and not a bool type?

    Firstly, we care about it being one of two things, a success or a failure.

    Secondly, why can we return EXIT_SUCCESS or EXIT_FAILURE, which are strings, not integers, when the main function is defined to be of type integer. If EXIT_SUCCESS and EXIT_FAILURE are integers, what integers are they?

    To me, it seems that the main function should be of type bool, and return either 0 or 1.

    • EganJ

      (Warning: new to c++, so might be entirely wrong).

      I think the reason it returns an int instead of a boolean is to give more detail- with an integer, you can have as many codes as you like to tell you exactly how it crashed.

      EXIT_SUCCESS and EXIT_FAILURE are macros, kind of like variables that c++ has already defined. When I ran my program, EXIT_SUCCESS had the integer value of 0, and EXIT_FAILURE had the value of 1. You can even do math with them, they work just like other ints. I'm not sure if they change value based on system or compiler.

  • Luis

    Hi! Sorry if ask a fool question.
    In the "this program doesn´t work".
    Why it pint always 0 if you use:

    int num{};

    I tested it and yes, always retiunr 0, but I suppoused will be retunr any nonsense number casue num value will be garbaged being not initialized.

    Thanks.

    • nascardriver

      `num` is initialized to 0. num2 is uninitialized. Empty curly braces initialize to a safe default value (For numbers, 0), one of the reasons why list initialization is superior to the other forms of initialization. We can use them for all kinds of types, as you'll discover later.

  • ColdCoffee

    Assume that the void printHi() function has a statement that prints "hi" and has some statements in the main() function, which we ignore for a while ...Since printHi() returns nothing, what was the point of printing the "hi" statement in that function? Consuming memory !!

  • phil

    If I enter a number with 10 digits larger than around 1073700000, I get a negative number printed.

    #include <iostream>

    int userInput()
    {
        std::cout << "Enter an integer: "; //user to enter a value
        int input {};                      //initialise variable input
        std::cin >> input;                 //user value is assigned to input
        return input;                      //return user value input to the

    main function
    }

    int main()
    {
        int num {userInput()};             //initialise num with return value from userInput
        std::cout << num << " doubled is " << num *2 << '\n'; //double the number from the user
        return 0;
    }

    • Alex

      Yes, this is due to you entering a larger number than the int can hold. We discuss this further in the lesson on integer types (4.4).

  • It's Me

    I just want to say thank you
    I'm learning a lot because of this Web

  • Max

    Why can't you use void main()

    • Josh

      Hi max,

      Sorry, I'm just learning as well, but I believe you can't use void main() because the main() function requires a return value of 0 to act as a status code to let the program know it was successfully completed. Since void marks a function as not needing a return value, the program wouldn't get it's required status code upon completion.

  • Ryan

    At the top; "Getting an integer value from the user is well-defined job"- missing an 'a' as in 'a well-defined job'. Also, this may be negligible; the plural of 'parenthesis' is 'parentheses'.

  • Vitaliy Sh.

    Hi Sires!

Leave a Comment

Put all code inside code tags: [code]your code here[/code]