Functions and Return statement in C

  • Context:
  • Thread starter Thread starter fog37
  • Start date Start date
  • Tags Tags
    Functions
Click For Summary

Discussion Overview

The discussion revolves around the behavior of functions and return statements in C and C++. Participants explore how functions can return values, the limitations of returning multiple outputs, and various methods to achieve similar outcomes, such as using structures or pass-by-reference techniques.

Discussion Character

  • Exploratory
  • Technical explanation
  • Debate/contested

Main Points Raised

  • Some participants classify functions based on their input and output capabilities, identifying four types.
  • It is suggested that functions requiring outputs must include a return statement, with the return value being the function's output.
  • One participant proposes that a class can be returned to encompass multiple outputs.
  • Another participant mentions that outputs can also be returned through arguments, particularly when using pointers or references.
  • Some participants argue that in C, a function cannot return more than one piece of data directly, suggesting the use of structures to encapsulate multiple values.
  • There is a discussion about using pass-by-reference in C++ to effectively return multiple outputs by modifying the original variables passed to the function.
  • Some participants express differing views on whether modifying passed arguments constitutes returning multiple values, with a focus on semantics.
  • Concerns are raised about potential side effects when using pass-by-reference, with some preferring to avoid this practice.
  • Participants discuss the implementation details of pass-by-reference and its efficiency compared to pass-by-value.

Areas of Agreement / Disagreement

Participants generally agree on the classification of functions and the necessity of return statements for certain types. However, there is disagreement regarding the semantics of returning multiple values and the implications of modifying arguments passed by reference.

Contextual Notes

Some limitations include the dependence on definitions of return behavior, unresolved nuances in the use of pass-by-reference, and varying interpretations of what constitutes a return value in the context of function outputs.

fog37
Messages
1,566
Reaction score
108
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
 
Technology news on Phys.org
fog37 said:
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
You can return a class that encompasses all of the data that you wish to return.
 
  • Like
Likes   Reactions: QuantumQuest and jedishrfu
You can always return output through arguments.
 
  • Like
Likes   Reactions: rbelli1 and jedishrfu
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
 
  • Like
Likes   Reactions: QuantumQuest, Borg and jim mcnamara
fog37 said:
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
Not mentioned already is that functions of type 2 or 3 are called void functions. Their prototypes (or declarations) would look like this:
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;
 
  • Like
Likes   Reactions: jedishrfu
fog37 said:
What if the function needed to produce more than one output? Can the return instruction handle more than just one output?
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:
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::count << "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:
ChrisVer said:
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
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).
 
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).
 
ChrisVer said:
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).
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.
 
  • Like
Likes   Reactions: QuantumQuest
  • #10
ChrisVer said:
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).
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.
ChrisVer said:
The second is often the case when you have large objects, where copying them costs extra time.
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.
 
  • #11
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
 
  • #12
jedishrfu said:
In general, I am not a fan of arguments that can be changed by the calling routine.
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.
 
  • #13
Mark44 said:
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.
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)."

Mark44 said:
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.
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.

jedishrfu said:
Fortran IV was 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.
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
I wasn't even thinking in FORTRAN... I am happy I was done with it as a freshman in my bachelor...
 
  • #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.
 

Similar threads

  • · Replies 15 ·
Replies
15
Views
2K
  • · Replies 10 ·
Replies
10
Views
2K
  • · Replies 12 ·
Replies
12
Views
2K
  • · Replies 30 ·
2
Replies
30
Views
7K
  • · Replies 2 ·
Replies
2
Views
3K
Replies
31
Views
4K
  • · Replies 2 ·
Replies
2
Views
1K
  • · Replies 9 ·
Replies
9
Views
2K
  • · Replies 3 ·
Replies
3
Views
2K
  • · Replies 17 ·
Replies
17
Views
4K