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 (also sometimes called an exit code, or rarely a return 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

172 comments to 2.2 — Function return values

  • Lesommeil

    Don't repeat yourself.
    Don't repeat yourself.
    Don't repeat yourself.
    Don't repeat yourself.
    Don't repeat yourself.
    Don't repeat yourself.
    Don't repeat yourself.
    Don't repeat yourself.
    Don't repeat yourself.
    Don't repeat yourself.

  • Manuel Calzadillas

    Great lesson,
    Learning a lot
    Thanks Alex

  • Xuan

    What are differences between

    and

    ?

    • Alex

      Parenthesis prioritize a subexpression for evaluation. Braces create an object using list-initialization.

      In this simple case, there is likely no difference between the two.

  • dave dave dave

    i'm getting an error c2084 (function int maint already has a body) but it's showing on line 23 when there's only 19 lines of code. and it went away when i built the project. is that something wrong in my setting or what?   //and thank you so much for these tutorials. i made an attempt to learn C++ way back in the early 00's but it was NOTHING like it is now. i got my butt kicked and had it in my head that c++ was some unlearnable mythical beast but now it practically writes itself. you guys are a major part of that. thank you.

  • Pls help. Why won't my code work? There's a compilation error that says:

    main.cpp: In function ‘int main();
    main.cpp:15:36: error: cannot convert ‘double (*)()’ to ‘double’ in initialization
         double finalPrice {getOrigPrice};

    P.S. I only use an online compiler btw
    Also I have a follow-up question. Does the main function always have to be integer type? or can we use double or float type as main function?

    UPDATE: NVM HAHAH For those who are curious as well, I forgot to put ( ) after the function name in main function that's why it didn't run. Do not ever underestimate those two parentheses XD.

    Here is my code:

    • Hits

      Hey, at the line double finalPrice{getOrigPrice} you need to call it as getOrigPrice() because it is a function!
      I have rewritten the same code as this:
      #include <iostream>

      double getOrigPrice()
      {
          std::cout << "Please enter the price of your selected item: \n";
          double price{};
          std::cin >> price;
          return price;
      }

      int main()
      {
          double finalPrice{getOrigPrice()};
          std::cout << "We have a 50% discount promo.\n";
          std::cout << "The final price of your selected item is " << finalPrice / 2 << "!\n";
          return 0;
      }

  • Armando I G

    Is it wrong to declare main as void, like "void main()"? What would be the problem or disadvantage to not get a run successful value?

    • Li

      I'm not sure if there would be a disadvantage but running it in my code led to a compiler error that states the following;

      pos_or_neg.cpp:32:1: error: 'main' must return 'int'
      void main()
      ^~~~
      int

      Hope this helps

      P.S. I'm using the compiler associated with VisualStudo Code

      • Armando I G

        That is right I didn't test it...
        I asked because several years ago I learnt a little of C and main was always declared as "void main (void)", but I see C++ has a different story about main.

        Thank you!

  • jacklit7

    Can anyone tell me why d works, I thought nothing would print if the function type was void

    • Mick Arundell

      void is the return type
      The function doesn't need to return anything, it can print and then exit

    • D works because it is a void function , it doesnt return anything.
      You are probably confused about why D works while E doesnt

      std::cout needs a value to print and we give him "printA()" which doesnt return any value (cuz its void), in D we dont use std::cout , we directly use the function itself thats why there is no error

  • Apres

    I know how to fix, but I dont understand why this way of code dont give me the double number
    PS: I've used setLocale, to set UTF-8

  • Anonymous

    I think the comment on line 4 under Return values doesn't make sense regarding "return isn't specified here" but it literally says "return 5.." and specified in comments returns back 5 to caller

  • German

    "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)." What about all the times we printed something to the screen using cout in int main?

  • German

    I dont understand the "return input" part, why is it necessary?

  • atobots

    if you return an int but init the function with 'char', will it return the int as a string?

    char doSomething()
    {
    return 3;
    }

    is the type of 3 now 'char' or string, or is it an int?
    (intentionally leaving out main function as it doesn't relate to the question)

    • Forhad Rahman

      What does the compiler say? I guess it'll throw an error since you are trying to returning an integer while declare 'char' as the function's data type.

    • Robert Warner

      No, it will convert the returned int into a char (character). If you look at an ASCII table, the decimal value of 'j' is 106. I re-wrote your code to return 106, the ASCII decimal value for the letter j, and wrote a small program to call it. The output was the letter j (the std::cin snippet was to just freeze the output):

  • Forhad Rahman

    Hi,
    This also works shown in 'Fixing our challenge program'. Though you can't put the ``num << " doubled is: " `` here(just print the result), but it reduces that extra num variable.

    So, is there any problem if I calculate the function directly if I can??

  • Cesar

    So the purpose of void to make it Clear is:

    To let you create a function with any pointer like int/char ect.. and integer(int) function is just when you dealing with numbers?

    is Void is basically like a Blank Piece of paper for pointers?

    we can start a Function with any pointer like

    I'm having a hard time understanding its real purpose and what makes it different from "int" i don't know if i answered my own question, but correct me please.

    • Robert Warner

      No, void is for when you DON'T want a return value. If you specify a return value, then you have to create a variable to store the return value. Instead of simply calling the function, you have to write code as x = function.
      Would you rather code doPrint(); or int x = doPrint(); when all you want to do is output something to the screen? If you don't need int x, why create it?

  • nav

    is correct ? int number{ getValueFromUser()*2 };
    int x{2*2};

  • Luca Della Sciucca

    In this example

    Doesn t the program print A when void type function printA() is called from main and std::cout printA() is executed inside the printA() function?
    I thought it was obvious but the solution didn t agree xD I m a beginner so i m guessing i m missing something, i just can t find it

    • GabRio Blu

      PrintA() doesn't return a value, instead it prints out A. The

      function is trying to print the return value of the

      function, but it doesn't return anything!

      • Luca Della Sciucca

        mmmm i see. So in this program:

        "enter an integer" gets actually printed, in the getValueFromUser function, in the results because the program is compilable (even tho it doesn t work), while in the previous example the program gave a compiler error and no solution is actually printed.   Is that it?!
        The word print when nothing is actually printed (visible as output) confuses the heck out me!

        • Weetou

          the function "getValueFromUser()" doesn't return anything because it is declared as void. If you want to get the value stored in "value" and store it into "num" you have to return "value" as an integer. your code should look like this :

  • Anonymous

    When I did this, on debug configuration in latest Visual Studio Community, it gave me an error //C4716 'returnFive': must return a value// and zero warnings. I tried doing the same after

    a) turning off "treat all errors as warnings"
    b) turning warning level down to zero

    and still got the compiler error. Is this specific to Visual Studio or is this now treated as an error?

    Also is there some way to check what kind of undefined behaviour will occur if the return statement is absent?

    • nascardriver

      Functions that don't return cause undefined behavior, but no compiler errors, this didn't change.
      VS promotes this specific warning to an error by default.

      https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-1-c4716?view=vs-2019
      "This warning is automatically promoted to an error. If you wish to modify this behavior, use #pragma warning."

      Undefined behavior is undefined, anything can happen. If you want to predict what will happen, you need to read the assembly generated by your compiler.

      • Anonymous

        Thank you!

        > Undefined behavior is undefined, anything can happen. If you want to predict what will happen, you need to read the assembly generated by your compiler.

        I meant it more as is there anyway to see the undefined behaviour in action in VisualStudio without it showing an error. For example in lesson 1.6, one way was shown to bypass the error/warning for uninitialized variables in VS:

        > If your compiler won’t let you compile and run the above program for this reason, here is a possible solution to get around this issue:

        Is there a similar way to do this for absent return statements?

  • Anonymous

    I used the EXIT_SUCCESS and EXIT_FAILURE status codes as return values *after* commenting out #include <cstdlib> and the program ran just fine, did any changes happen?

    Also, what is meant by "status code of 0 means the program executed successfully"? Does it have something do with error messages? I am imagining something like using conditional statements to return 0 for successful execution and 1 etc. for errors. Am I right?

    I tried changing the return value of main() to 5 and -5 and the program ran just fine, is this something that is not relevant to beginners?

    • nascardriver

      https://www.learncpp.com/cpp-tutorial/header-files/#missing_include_but_works

      > status code of 0 means the program executed successfully
      Other programs can use the exit code of your program to determine if it was successful. eg. if your program wants to load a file but that file doesn't exist, it can exit with a non-zero code and the other program will know that your program failed.

      > I tried changing the return value of main() to 5 and -5
      You can return whatever you want. It's up to the executor of your program to use and interpret the exit code. Look up how to see exit codes on your OS.

  • RobN-Hood

    You said that C++ disallows calling the main function explicitly, but this program compiles without error (just a warning):

    Why does it work if it isn't allowed?

  • Samoxx

    This would be the option without using return types (except in main of course).
    When is it appropriate or better to utilize return types other than void rather than variables initialized outside of functions?

    • nascardriver

      What you did is never appropriate. I won't try to list the reasons why it's bad, you'll notice it yourself as you write more code.

    • Anonymous

      See:

      https://www.learncpp.com/cpp-tutorial/global-constants-and-inline-variables/

      https://www.learncpp.com/cpp-tutorial/why-global-variables-are-evil/

  • One question about void return type functions: do they return any symbolic information or they really return nothing?

Leave a Comment

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