473,386 Members | 1,720 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

Small question about return statements...

int divide (int a, int b)
{
int r;
r=a/b;
return (r);
}
int main ()
{
int result = divide (20,4);
cout << result
return 0;
}
--------------

I understand the use of the return statement as exemplified in the
example above. However, I was wondering what was the proper way for a
function to return more than one value and subsequently store those
values in their own independent variables. For instance, if the above
function were to return two different results, how would I assign them
each to their own variable by means of the return statement?

I figured I could achieve this by declaring the variables in the main
function and then passing them by reference to the function so they
could be changed within (This would work without the use of the return
function ofcourse), but something tells me this method is not exactly
kosher?

What do you guys think, whats the proper way of doing it?

Jan 27 '07 #1
18 1694
SpiralCorp wrote:
int divide (int a, int b)
{
int r;
r=a/b;
return (r);
}
int main ()
{
int result = divide (20,4);
cout << result
return 0;
}
--------------

I understand the use of the return statement as exemplified in the
example above. However, I was wondering what was the proper way for a
function to return more than one value and subsequently store those
values in their own independent variables. For instance, if the above
function were to return two different results, how would I assign them
each to their own variable by means of the return statement?

I figured I could achieve this by declaring the variables in the main
function and then passing them by reference to the function so they
could be changed within (This would work without the use of the return
function ofcourse), but something tells me this method is not exactly
kosher?

What do you guys think, whats the proper way of doing it?
It is kosher and is a fine way to return multiple values from a
function. Another way is to define a struct that contains multiple
values, and use the struct as the function's return.

--
Scott McPhillips [VC++ MVP]

Jan 27 '07 #2


On Jan 27, 12:25 pm, "Scott McPhillips [MVP]" <org-dot-mvps-at-
scottmcpwrote:
SpiralCorp wrote:
int divide (int a, int b)
{
int r;
r=a/b;
return (r);
}
int main ()
{
int result = divide (20,4);
cout << result
return 0;
}
--------------
I understand the use of the return statement as exemplified in the
example above. However, I was wondering what was the proper way for a
function to return more than one value and subsequently store those
values in their own independent variables. For instance, if the above
function were to return two different results, how would I assign them
each to their own variable by means of the return statement?
I figured I could achieve this by declaring the variables in the main
function and then passing them by reference to the function so they
could be changed within (This would work without the use of the return
function ofcourse), but something tells me this method is not exactly
kosher?
What do you guys think, whats the proper way of doing it?It is kosher and is a fine way to return multiple values from a
function. Another way is to define a struct that contains multiple
values, and use the struct as the function's return.

--
Scott McPhillips [VC++ MVP]
Good to know. I'll keep using the reference method as I'm not so
familiar with structs yet, but I'll make a note for when I am. Thanks
for the help.

---
SpiralCorp

Jan 27 '07 #3
On 27 Jan 2007 07:47:40 -0800, "SpiralCorp" <sp***************@gmail.com>
wrote:
>int divide (int a, int b)
{
int r;
r=a/b;
return (r);
}
int main ()
{
int result = divide (20,4);
cout << result
return 0;
}
--------------

I understand the use of the return statement as exemplified in the
example above. However, I was wondering what was the proper way for a
function to return more than one value and subsequently store those
values in their own independent variables. For instance, if the above
function were to return two different results, how would I assign them
each to their own variable by means of the return statement?

I figured I could achieve this by declaring the variables in the main
function and then passing them by reference to the function so they
could be changed within (This would work without the use of the return
function ofcourse), but something tells me this method is not exactly
kosher?

What do you guys think, whats the proper way of doing it?
It's kosher, and it's traditionally done, although it's not pretty.

Then there is the "return a struct" where the returned value is actually a
data structure:

struct Retval
{
Retval(int a, int b): a(a), b(b) {}
int a;
int b;
};

Retval fn()
{
return Retval(1, 2);
}

int main()
{
Retval retval = fn();
int my_a = retval.a;
int my_b = retval.b;
}

They're both ugly and kludgy. For a more elegant solution, see boost.tuple. It
lets you write code like this:

#include "boost/tuple.hpp"

using boost::tuples::tuple;
using boost::tuples::make_tuple;
using boost::tuples::tie;

tuple<int, intfn()
{
return make_tuple(1, 2);
}

int main()
{
int my_a;
int my_b;
tie(my_a, my_b) = fn(); // Assigns values to my_a and my_b
}
Jan 27 '07 #4
SpiralCorp wrote:
int divide (int a, int b)
{
int r;
r=a/b;
return (r);
}
int main ()
{
int result = divide (20,4);
cout << result
return 0;
}
--------------

I understand the use of the return statement as exemplified in the
example above. However, I was wondering what was the proper way for
a function to return more than one value and subsequently store
those values in their own independent variables. For instance, if
the above function were to return two different results, how would
I assign them each to their own variable by means of the return
statement?
It's not really "proper" for a function to return more than value. :-)

Usually one function should have one purpose only, and return the result of
it's computations, if any.

If you really need to return two or more connected values, they will often
be stored in a structure anyway, because they belong together. If so, you
can return the structure.
>
I figured I could achieve this by declaring the variables in the
main function and then passing them by reference to the function so
they could be changed within (This would work without the use of
the return function ofcourse), but something tells me this method
is not exactly kosher?
It works, when you need to do that. But don't do it, if you don't have to.
>
What do you guys think, whats the proper way of doing it?
The proper way is not having to do it at all. :-)

Bo Persson
Jan 27 '07 #5
SpiralCorp wrote:
int divide (int a, int b)
{
int r;
uninitialized variable is wrong way, at least set "r" to zero
int r=0;
r=a/b;
return (r);
}
int main ()
{
int result = divide (20,4);
cout << result
return 0;
}
--------------

I understand the use of the return statement as exemplified in the
example above. However, I was wondering what was the proper way for a
function to return more than one value and subsequently store those
values in their own independent variables. For instance, if the above
function were to return two different results, how would I assign them
each to their own variable by means of the return statement?
If your function change several variables make class as data structure +
functions for them.

--
Maksim A Polyanin
Jan 27 '07 #6
On Sat, 27 Jan 2007 17:33:14 +0100, "Bo Persson" <bo*@gmb.dkwrote:
>It's not really "proper" for a function to return more than value. :-)

Usually one function should have one purpose only, and return the result of
it's computations, if any.

If you really need to return two or more connected values, they will often
be stored in a structure anyway, because they belong together. If so, you
can return the structure.
Some functions intrinsically return more than one value that is not easily
encapsulated in a class. For example, the following function declaration often
appears in embedded systems:

enum ErrorCode { ERROR_OK, ERROR_DEVICE_ERROR /* ... */ };

ErrorCode getBufferContents(
void* buffer, // in: buffer to hold the data
unsigned long maxLength, // in: max. bytes that can fit
// in the buffer
unsigned long* bytesRetrieved // out: number of bytes retrieved
unsigned long* bytesRemaining // out: number of bytes remaining
// in the device's internal
// buffer
);

void fn()
{
static const unsigned long bufferLength = 100;
static unsigned char buffer[bufferLength];

unsigned long bytesRetrieved = 0;
unsigned long bytesRemaining = 0;
ErrorCode errorCode = getBufferContents(buffer, bufferLength,
&bytesRetrieved, &bytesRemaining);

if (errorCode == ERROR_OK)
{
// Use data
}
}

You can technically return one struct, but ofter it's easier to break the
items out so they can be used quickly.

I know, I know, return a std::vector, use exceptions, etc. However, in
embedded systems speed is essential, dynamic memory allocation (due to vector)
or anomalous execution times (due to exception handling) are undesirable, and
this method works wonderfully.

-dr
Jan 27 '07 #7
On Sat, 27 Jan 2007 11:05:13 -0600, Dave Rahardja wrote:
On Sat, 27 Jan 2007 17:33:14 +0100, "Bo Persson" <bo*@gmb.dkwrote:
>>It's not really "proper" for a function to return more than value. :-)

Usually one function should have one purpose only, and return the result of
it's computations, if any.

If you really need to return two or more connected values, they will often
be stored in a structure anyway, because they belong together. If so, you
can return the structure.

Some functions intrinsically return more than one value that is not easily
encapsulated in a class. For example, the following function declaration often
appears in embedded systems:

enum ErrorCode { ERROR_OK, ERROR_DEVICE_ERROR /* ... */ };

ErrorCode getBufferContents(
void* buffer, // in: buffer to hold the data
unsigned long maxLength, // in: max. bytes that can fit
// in the buffer
unsigned long* bytesRetrieved // out: number of bytes retrieved
unsigned long* bytesRemaining // out: number of bytes remaining
// in the device's internal
// buffer
);

void fn()
{
static const unsigned long bufferLength = 100;
static unsigned char buffer[bufferLength];

unsigned long bytesRetrieved = 0;
unsigned long bytesRemaining = 0;
ErrorCode errorCode = getBufferContents(buffer, bufferLength,
&bytesRetrieved, &bytesRemaining);

if (errorCode == ERROR_OK)
{
// Use data
}
}
That looks very much like C code. The C++ equivalent would probably be to
have the function take references rather than pointers... which you seem to
have dismissed in a previous reply in this thread as "not pretty". How is
the above code prettier?
You can technically return one struct, but ofter it's easier to break the
items out so they can be used quickly.

I know, I know, return a std::vector, use exceptions, etc.
Um, surely std::vector would not be appropriate here - as you are
obviously aware of, as in a previous reply you mentioned using
boost::tuple (std::pair would be ok too, I guess).

Are you actually two different people? ;)
However, in
embedded systems speed is essential, dynamic memory allocation (due to
vector) or anomalous execution times (due to exception handling) are
undesirable, and this method works wonderfully.
I imagine a half-decent optimising compiler would eliminate any overheads
in the struct/boost::tuple/std::pair solutions (ok, that may not be a good
argument for embedded systems). Also, I'm not sure exceptions would be
necessary/appropriate, depending on how you view an "error
condition". But you might just as well return your error code as
part of your struct/tuple.

--
Lionel B
Jan 27 '07 #8
Dave Rahardja wrote:
>
I know, I know, ... use exceptions, etc. However, in
embedded systems speed is essential
I think "embedded" property of system is not a cause here, because "error
during transfer" often is one of examples when error is one of correct
states, awaiting state of transfer and not suitable for C++ exceptions.

High-level functions that only return correct data can throw, but low-level
functions must expect the situation and to resolve the errors can, for
example, declare recovering interface to up level.

--
Maksim A Polyanin
Jan 27 '07 #9
Grizlyk wrote:
SpiralCorp wrote:
>>int divide (int a, int b)
{
int r;


uninitialized variable is wrong way, at least set "r" to zero
int r=0;
No, just use

int r=a/b;

--
Ian Collins.
Jan 27 '07 #10
On Sat, 27 Jan 2007 17:31:28 GMT, Lionel B <me@privacy.netwrote:
>That looks very much like C code. The C++ equivalent would probably be to
have the function take references rather than pointers... which you seem to
have dismissed in a previous reply in this thread as "not pretty". How is
the above code prettier?
Yes, the example is very much C code. I personally prefer the tuple
implementation for its convenience (i.e. it can be a struct (tuple) if you
want, or fill in individual variables (tie) if you want, or a mixture of
both).

I guess having worked in the embedded world for so long has caused me to
prematurely optimize at the very low level. ;-) Shame on me.
>Um, surely std::vector would not be appropriate here - as you are
obviously aware of, as in a previous reply you mentioned using
boost::tuple (std::pair would be ok too, I guess).

Are you actually two different people? ;)
I used to have multiple personalities, but we're fine now. ;-)

I'm the software architecture lead on a reasonably large project, and I have
to constantly switch between very high-level architectural concerns and high
frequency, low-level bit-twiddling behavior that can cripple the system with
inefficiency. I've managed to stay pure to good OOA/OOD principles over the
vast majority of the design, but every now and then Mr. Hyde pops out and I
want to optimize! Bad Mr. Hyde.
>I imagine a half-decent optimising compiler would eliminate any overheads
in the struct/boost::tuple/std::pair solutions (ok, that may not be a good
argument for embedded systems). Also, I'm not sure exceptions would be
necessary/appropriate, depending on how you view an "error
condition". But you might just as well return your error code as
part of your struct/tuple.
You are correct.

As a side note, Using C++ exceptions in a real-time system (like mine is)
makes me uneasy because of its timing concerns and its ambiguous semantics
(with respect to my application domain). In my project, every error is
expected by definition, and any unexpected error (exception) is
short-circuited to either unexpected() or terminate(), which causes the system
to reset to a safe state.

-dr
Jan 27 '07 #11
Dave Rahardja wrote:
They're both ugly and kludgy. For a more elegant solution, see boost.tuple. It
lets you write code like this:

#include "boost/tuple.hpp"

using boost::tuples::tuple;
using boost::tuples::make_tuple;
using boost::tuples::tie;

tuple<int, intfn()
{
return make_tuple(1, 2);
}

int main()
{
int my_a;
int my_b;
tie(my_a, my_b) = fn(); // Assigns values to my_a and my_b
}
While this is one of the more elegant solutions, I still find it a bit
"kludgy". Specifically the variables that receive the return values
have to be default constructed, which is annoying for types that do
something non-trivial in their constructor (or types that don't even
have a default constructor).

Unfortunately I think this might be the closest we can get with a pure
library solution.

--
Alan Johnson
Jan 27 '07 #12
On Sat, 27 Jan 2007 12:50:57 -0800, Alan Johnson <aw***@yahoo.comwrote:
>Dave Rahardja wrote:
>They're both ugly and kludgy. For a more elegant solution, see boost.tuple. It
lets you write code like this:

#include "boost/tuple.hpp"

using boost::tuples::tuple;
using boost::tuples::make_tuple;
using boost::tuples::tie;

tuple<int, intfn()
{
return make_tuple(1, 2);
}

int main()
{
int my_a;
int my_b;
tie(my_a, my_b) = fn(); // Assigns values to my_a and my_b
}

While this is one of the more elegant solutions, I still find it a bit
"kludgy". Specifically the variables that receive the return values
have to be default constructed, which is annoying for types that do
something non-trivial in their constructor (or types that don't even
have a default constructor).

Unfortunately I think this might be the closest we can get with a pure
library solution.
Actually, you can do this:

int main()
{
tuple<int, intresult = fn();
int my_a = result.get<0>;
int my_b = result.get<1>;
}

With the appropriate using statements, etc.

-dr
Jan 28 '07 #13
Dave Rahardja wrote:
On Sat, 27 Jan 2007 12:50:57 -0800, Alan Johnson <aw***@yahoo.comwrote:
>Dave Rahardja wrote:
>>They're both ugly and kludgy. For a more elegant solution, see boost.tuple. It
lets you write code like this:

#include "boost/tuple.hpp"

using boost::tuples::tuple;
using boost::tuples::make_tuple;
using boost::tuples::tie;

tuple<int, intfn()
{
return make_tuple(1, 2);
}

int main()
{
int my_a;
int my_b;
tie(my_a, my_b) = fn(); // Assigns values to my_a and my_b
}
While this is one of the more elegant solutions, I still find it a bit
"kludgy". Specifically the variables that receive the return values
have to be default constructed, which is annoying for types that do
something non-trivial in their constructor (or types that don't even
have a default constructor).

Unfortunately I think this might be the closest we can get with a pure
library solution.

Actually, you can do this:

int main()
{
tuple<int, intresult = fn();
int my_a = result.get<0>;
int my_b = result.get<1>;
}

With the appropriate using statements, etc.

-dr
Now you have superfluous copy construction instead. Perhaps:

tuple<T1, T2result = fn() ;
T1 & a = result.get<0>() ;
T2 & b = result.get<1>() ;

Though this is still annoyingly verbose. This seems like something the
language should take care of for me. Something like:

[T1, T2] fn()
{
return [T1(), T2()] ;
}

int main()
{
[T1 a, T2 b] = fn() ;
}

--
Alan Johnson.
Jan 28 '07 #14
SpiralCorp wrote:
>>
>>>What do you guys think, whats the proper way of doing it?

It is kosher and is a fine way to return multiple values from a
function. Another way is to define a struct that contains multiple
values, and use the struct as the function's return.
- - >>Scott McPhillips [VC++ MVP]

Good to know. I'll keep using the reference method as I'm not so
familiar with structs yet, but I'll make a note for when I am. Thanks
for the help.
---
SpiralCorp
'struct' and 'class' are very useful tools. I'll give you a short example:

#include <iostream>

struct Thing{ // same as "class Thing{ public:"
int Num;
char Ch;
}; // note semicolon at end

void Func( Thing &Th ){
Th.Num = 42;
Th.Ch = 'Z';
return;
}

int main(){
Thing Mine;
Func( Mine );
std::cout<<"Mine: Num="<<Mine.Num<<" Ch="
<<Mine.Ch<<std::endl;

int A( Mine.Num );
char B( Mine.Ch );
std::cout<<"int A="<<A<<" char B="<<B<<std::endl;

return 0;
}

That's only the very tip of the iceberg. <G>
Bob R
POVrookie

Jan 28 '07 #15
Ian Collins wrote:
Grizlyk wrote:
>>SpiralCorp wrote:
>>>int divide (int a, int b){
int r;

uninitialized variable is wrong way, at least set "r" to zero
int r=0;

No, just use

int r=a/b;
No, just use:

int r( a/b );

<G>

......next....

Bob <GR
POVrookie

Jan 28 '07 #16
In article <SR*********************@bgtnsc05-news.ops.worldnet.att.net>,
wo**@worldnet.att.net says...
Ian Collins wrote:
Grizlyk wrote:
>SpiralCorp wrote:

int divide (int a, int b){
int r;

uninitialized variable is wrong way, at least set "r" to zero
int r=0;
No, just use

int r=a/b;

No, just use:

int r( a/b );
Or just 'return a/b;'

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jan 28 '07 #17

On 1/27/07 9:08 PM, in article MP************************@news.sunsite.dk,
"Jerry Coffin" <jc*****@taeus.comwrote:
In article <SR*********************@bgtnsc05-news.ops.worldnet.att.net>,
wo**@worldnet.att.net says...
>Ian Collins wrote:
>>Grizlyk wrote:
SpiralCorp wrote:

int divide (int a, int b){
int r;

uninitialized variable is wrong way, at least set "r" to zero
int r=0;

No, just use

int r=a/b;

No, just use:

int r( a/b );

Or just 'return a/b;'
None of these implementations are satisfactory because none answer the
question: what is divide()'s intended behavior when b == 0?

Several possible ways for divide() to handle divide-by-zero:

A) does not handle division-by-zero. (Callers must ensure b != 0)

int divide( int a, int b )
{
assert( b != 0 );
...

B) throws exception

int divide( int a, int b )
{
if ( b == 0 )
throw std::invalid_argument("divide by zero");
...

C) evaluates to 0 (emulates PowerPC behavior)

int divide( int a, int b )
{
if (b == 0)
return 0;
...

Currently, divide()'s de-facto behavior for division-by-zero is undefined.
But without an assert documenting divide's b != 0 precondition, there is no
way of being certain whether the undefined behavior in this case reflects an
intentional design decision or an accidental oversight.

Greg

Jan 28 '07 #18


On Jan 27, 11:10 pm, BobR <w...@worldnet.att.netwrote:
SpiralCorp wrote:
>>What do you guys think, whats the proper way of doing it? >>
>>It is kosher and is a fine way to return multiple values from a
>function. Another way is to define a struct that contains multiple
values, and use the struct as the function's return.
- - >>Scott McPhillips [VC++ MVP]
Good to know. I'll keep using the reference method as I'm not so
familiar with structs yet, but I'll make a note for when I am. Thanks
for the help.
---
SpiralCorp'struct' and 'class' are very useful tools. I'll give you a short example:

#include <iostream>

struct Thing{ // same as "class Thing{ public:"
int Num;
char Ch;
}; // note semicolon at end

void Func( Thing &Th ){
Th.Num = 42;
Th.Ch = 'Z';
return;
}

int main(){
Thing Mine;
Func( Mine );
std::cout<<"Mine: Num="<<Mine.Num<<" Ch="
<<Mine.Ch<<std::endl;

int A( Mine.Num );
char B( Mine.Ch );
std::cout<<"int A="<<A<<" char B="<<B<<std::endl;

return 0;
}

That's only the very tip of the iceberg. <G>
Bob R
POVrookie

Indeed they are. I'm reading up on them now. And man this group is
responsive, its nice to see so many useful answers.

By the way, to everyone correcting the code up there it was just a
random example for regular use of the return statement. It was copied
from cplusplus.com's tutorial on functions.
>Though this is still annoyingly verbose. This seems like something the
language should take care of for me. Something like:

[T1, T2] fn()
{
return [T1(), T2()] ;

}

int main()
{
[T1 a, T2 b] = fn() ;

}

--
Alan Johnson.
Heh, this is exactly what I was trying to do. It really should be a
language feature in my opinion, its a very reasonable situation.

Jan 28 '07 #19

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

220
by: Brandon J. Van Every | last post by:
What's better about Ruby than Python? I'm sure there's something. What is it? This is not a troll. I'm language shopping and I want people's answers. I don't know beans about Ruby or have...
54
by: Brandon J. Van Every | last post by:
I'm realizing I didn't frame my question well. What's ***TOTALLY COMPELLING*** about Ruby over Python? What makes you jump up in your chair and scream "Wow! Ruby has *that*? That is SO...
24
by: sureshjayaram | last post by:
In some functions where i need to return multiple error codes at multiple places, I use multiple return statements. Say for ex. if (Found == 1) { if (val == -1) return error1; } else { if...
74
by: lovecreatesbeauty | last post by:
My small function works, but I have some questions. And I want to listen to you on How it is implemented? 1. The function does not check if parameter x is larger or smaller than parameter y. ...
0
by: Gary Herron | last post by:
Ohad Frand wrote: There is no way you can consider 'elif', 'else', 'except', and 'from' statements. However, as someone pointed out, the kwlist from the keyword module is the closest thing we...
0
by: Ohad Frand | last post by:
Hi Thanks a lot for your reply I think the main uses for it is to study the language and to see that I didn't miss anything else or that something is changed from one version to another. The...
58
by: Don Li | last post by:
I've tried <body style="font-family:Verdana,Arial,Helvetica;font-size:0.8em;"> or <body style="font-family:Verdana,Arial,Helvetica;font-size:11pct;"> or <body...
16
by: scholz.lothar | last post by:
I want to add some extension features to my program and this would require that i bundle a small c compiler with my program. On Unix it seems that tiny-c can do this, but i don't know about windows.
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.