Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

Functions and Return statement in C

  1. May 3, 2017 #1
    Hello,
    In C (or C++), a function is a body of instructions. Functions can be classified as functions that

    1) receive inputs and produce outputs
    2) receive no inputs and produce no outputs
    3) receive inputs and produce no outputs
    4) receive no inputs and produce outputs

    For case 1) and 4), the function body must alwaysinclude the instruction return, correct? The argument of return is the output of the function. What if the function needed to produce more than one output? Can the return instruction handle more than just one output?

    Thanks
     
  2. jcsd
  3. May 3, 2017 #2

    Borg

    User Avatar
    Gold Member

    You can return a class that encompasses all of the data that you wish to return.
     
  4. May 3, 2017 #3

    DrClaude

    User Avatar

    Staff: Mentor

    You can always return output through arguments.
     
  5. May 3, 2017 #4

    jedishrfu

    Staff: Mentor

    Yes, 1 and 4 require return statements. The compiler determines this from the function signature. So if you say you're returning an integer value then the compiler expects you to have a return statement to return that type of value.

    In C you can't return more than one piece of data so when a function needs to return more, you would define a struct with the information to be returned, fill it in and then return that struct reference.

    Here's a simple example:

    https://cboard.cprogramming.com/c-programming/149372-returning-struct-function.html

    As @DrClaude says you can return values through some arguments if they are defined as pointers or array references. I tend not to do that because its more difficult to implement well without potential side effects.

    Here's a more detailed discussion on it:

    http://www.yukselgunal.org/c/pointers_in_func_args.pdf
     
  6. May 3, 2017 #5

    Mark44

    Staff: Mentor

    Not mentioned already is that functions of type 2 or 3 are called void functions. Their prototypes (or declarations) would look like this:
    Code (C):
    void func2(void); // Type 2 -- no parameters
    void func3(...);  // Type 3 -- nonempty parameter list
    These functions can have a return statement, but it would be an error if the return keyword were followed by an expression, as in return some_value;
     
  7. May 3, 2017 #6

    ChrisVer

    User Avatar
    Gold Member

    as far as I know, not in general, at least not in the same way python can...
    In general one way I've seen people using C++ to return more than 1 outputs is by using the "pass-by-reference" in the functions' arguments.... that way you can change the value of a variable within the function by accessing the variable's address.
    This effectively acts as returning multiple outputs...since the function will have (or may not have) a single return , but in its body it will be able to update/change additional variables (so producing new outputs out of them). The bad thing is that your initial variables are going to be lost (?) but this may not be a problem if you create them just for that purpose...

    for example, ROOT TH1 class gives the ability to calculate the integral and its error by the TH1::IntegralAndError() method (https://root.cern.ch/doc/master/classTH1.html#ace3e72fc1df4a16db0d3c86230b39502).
    This method can 3 arguments: the first bin, the last bin (for your integration) and a variable that keeps the error. So you could get two values of it: the integral and its error...
    Code (C):

    Double_t err(0.0);
    Double_t Integral;
    //calculates the integral of the histogramTH1 (a TH1 histogram object) from bin=0 to bin=5.
    Integral= histogramTH1.IntegralAndError( 0, 5 , err );
    //err is passed by reference here
    // so chances are it's going to be changed within this method/function.
    // err is not going to be 0.0 now if there's error to calculate...
    std::cout << "Integral  = " << Integral << " +/- " << err <<std::endl;
     
    In general when you see some argument passed as reference in C++, it means that either the variable you give is going to be modified or you want to avoid copying it (that's what pass-by-value does). The second is often the case when you have large objects, where copying them costs extra time. If I sent you in a city, and told you "can you check whether the street numbers add up to 1000", it would be better for you to go and have a look in the city itself rather than building an identical city and summing its street numbers. On top of that, in this case, you should pass your object with const (to ensure and let others know, you don't intend to change it).
     
    Last edited: May 3, 2017
  8. May 4, 2017 #7

    Mark44

    Staff: Mentor

    But technically, the function isn't "returning" multiple values when it alters arguments that have been passed by reference. A C or C++ function can still return only one thing (which might be a structure with multiple members).
     
  9. May 4, 2017 #8

    ChrisVer

    User Avatar
    Gold Member

    well, yes, but effectively it's a multiple return, since you have a function that returns several outputs (without using the return statement).
    The rest is all about semantics and about what one means by "return"... Is it just what's written after the return statement or the actual manipulated variables? (afterall that's the main reason to use functions).
     
  10. May 4, 2017 #9

    Mark44

    Staff: Mentor

    I think that most would call what's returned by a function the expression that comes in the function's return statement. Others might fudge a bit, and phrase things as "after the function returns, the variables x, y, and z have their values changed." Strictly speaking, in my view, anyway, the function doesn't "return" x, y, and z.
     
  11. May 4, 2017 #10

    Mark44

    Staff: Mentor

    You can also have a parameter that is a constant reference, as in const int& param. In this case, the programming is saying that even though param is passed by reference, the code won't change its value.
    Right, and the reason for this is that what is passed is the address of the object that is referred to. At least that's the way pass-by-reference is implemented in Visual Studio. I'd be surprised to find it implemented differently in another compiler.
    What I found was that exactly the same code was emitted by the compiler for a parameter that was a reference parameter or for a parameter that was a pointer. The only difference between the two ways is the semantics of declaring the parameters in the function's parameter list, and how the function is called.
     
  12. May 4, 2017 #11

    jedishrfu

    Staff: Mentor

    In general, I am not a fan of arguments that can be changed by the calling routine. In the early days of Fortran IV, I was burned by a most mysterious bug. I was using some calcomp plot functions to draw floor plans (that's what I told my boss, but the real reason was to draw a poster sized Star Trek Enterprise which never happened).

    I called a library function in which the examples all showed variables as the arguments and I used a literal 3 in one of the arguments. 2 was used to lower the plotter pen and 3 was used to raise it. The program ran but only some portion of the plot came out and there were lines everywhere.

    Eventually I tracked it down to that one function which changed the 3 to some other number and because the Fortran of the time consolidated all literals in memory i.e. there was one and only one 3 value in the pool, the change effectively changed everywhere the literal 3 was used.

    What a mess! In changing the 3, I was no longer able to raise the pen when I called the plot function with a 3 hence the massive mess of lines.

    Fortran IV used "call by reference" for variables and for literals as arguments to a function and was probably the leading reason for why other languages started passing literals as call by value. The machine instruction set allows for it but the Fortran calling scheme used addressing registers to locate argument values which meant call by value was out.

    Here's a little more context on this issue:

    https://everything2.com/title/Changing+the+value+of+5+in+FORTRAN
     
  13. May 4, 2017 #12

    Mark44

    Staff: Mentor

    Makes it hard to write something as simple as a swap() function to swap the values of two variables. Of course, you could pass in a struct that contains the two variables, and return the altered struct, but that seems like a lot of extra work to go to.

    I've been writing C code for 30+ years, and C++ for not quite as long, so pointer parameters are second nature to me by now.
     
  14. May 5, 2017 #13

    ChrisVer

    User Avatar
    Gold Member

    I agree, that's why I also said "On top of that, in this case, you should pass your object with const (to ensure and let others know, you don't intend to change it)."

    I don't think this is compiler dependent? Except for if the compiler affects how variables are treated in memory... Referencing seems like a "memory" thing to me.

    Again, I think the const keyword is strong in this case, since it wouldn't change your value... If the program intended to change that variable, then you must have used a wrong package - or you should have hacked it...
    To me it's really convenient especially for cases when values of a variable need to be updated for any sort of a reason, or for making the program even more modular than normal... eg a user prompt input could be used in a different function or method and the user input can be read anywhere afterwards because you passed them as refs.
     
  15. May 5, 2017 #14

    jedishrfu

    Staff: Mentor

    Last edited: May 5, 2017
  16. May 5, 2017 #15

    ChrisVer

    User Avatar
    Gold Member

    I wasn't even thinking in FORTRAN... I am happy I was done with it as a freshman in my bachelor...
     
  17. May 5, 2017 #16
    The value returned is the result of the function, a function does not have various results.
    However, the value returned can be a pointer to a memory location, and that location can be the starting address for as much data as you like.
     
Know someone interested in this topic? Share this thread via Reddit, Google+, Twitter, or Facebook

Have something to add?
Draft saved Draft deleted