# Returning values from a function

Discussion in 'C Programming' started by Materialised, Oct 20, 2003.

1. ### MaterialisedGuest

I am writing a simple function to initialise 3 variables to pesudo
random numbers.

I have a function which is as follows

int randomise( int x, int y, intz)
{
srand((unsigned)time(NULL));
x = rand();
y = rand();
z = rand();

}
And I call this function with

randomise(a,b,c);

However a,b,c do not contain the randomised integers, I understand this
is a problem with the return value of my function,
I have tried
return x,y,z;
But this doesnt work either.

Can anyone point out where my problem is?

Materialised, Oct 20, 2003

2. ### WWGuest

Materialised wrote:
> I am writing a simple function to initialise 3 variables to pesudo
> random numbers.
>
> I have a function which is as follows
>
> int randomise( int x, int y, intz)
> {
> srand((unsigned)time(NULL));
> x = rand();
> y = rand();
> z = rand();
>
> }
> And I call this function with
>
> randomise(a,b,c);
>
> However a,b,c do not contain the randomised integers, I understand
> this is a problem with the return value of my function,
> I have tried
> return x,y,z;
> But this doesnt work either.
>
> Can anyone point out where my problem is?

Ehem. The first one is that you try to program in C++ without a good
textbook. :-(

First of all, your program has not return value. You do not return
anything. There is no return statement.

The second: how do you expect to return 3 integers in one?

The third: as you wrote the function definition (signature) it takes the
arguments by value, so x,y and z (which you have clearly typed wrong) is a
*copy* of a b and c. Writing into them will write into the copy.

You can take the arguments by reference, then you will be able to change
them. *If* you work in C++. If you do work in C, you will need to take
pointers to them.

--
WW aka Attila

WW, Oct 20, 2003

3. ### Eric SosmanGuest

Materialised wrote:
>
> I am writing a simple function to initialise 3 variables to pesudo
> random numbers.
>
> I have a function which is as follows
>
> int randomise( int x, int y, intz)
> {
> srand((unsigned)time(NULL));
> x = rand();
> y = rand();
> z = rand();
>
> }
> And I call this function with
>
> randomise(a,b,c);
>
> However a,b,c do not contain the randomised integers, I understand this
> is a problem with the return value of my function,
> I have tried
> return x,y,z;
> But this doesnt work either.
>
> Can anyone point out where my problem is?

These are Questions 4.8 and 20.1 in the comp.lang.c

http://www.eskimo.com/~scs/C-faq/top.html

--

Eric Sosman, Oct 20, 2003
4. ### Martin AmbuhlGuest

Materialised wrote:

> I am writing a simple function to initialise 3 variables to pesudo
> random numbers.
>
> I have a function which is as follows
>
> int randomise( int x, int y, intz)
> {
> srand((unsigned)time(NULL));
> x = rand();
> y = rand();
> z = rand();
>
> }
> And I call this function with
>
> randomise(a,b,c);
>
> However a,b,c do not contain the randomised integers, I understand this
> is a problem with the return value of my function,
> I have tried
> return x,y,z;
> But this doesnt work either.
>
> Can anyone point out where my problem is?

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void randomise(int *x, int *y, int *z)
{
srand((unsigned) time(NULL));
*x = rand();
*y = rand();
*z = rand();
}

int main(void)
{
int a, b, c;
randomise(&a, &b, &c);
printf("%d %d %d\n", a, b, c);
return 0;
}

--
Martin Ambuhl

Martin Ambuhl, Oct 20, 2003
5. ### MaterialisedGuest

WW wrote:
> Materialised wrote:
>
>>I am writing a simple function to initialise 3 variables to pesudo
>>random numbers.
>>
>>I have a function which is as follows
>>
>>int randomise( int x, int y, intz)
>>{
>>srand((unsigned)time(NULL));
>>x = rand();
>>y = rand();
>>z = rand();
>>
>>}
>>And I call this function with
>>
>>randomise(a,b,c);
>>
>>However a,b,c do not contain the randomised integers, I understand
>>this is a problem with the return value of my function,
>>I have tried
>>return x,y,z;
>>But this doesnt work either.
>>
>>Can anyone point out where my problem is?

>
>
> Ehem. The first one is that you try to program in C++ without a good
> textbook. :-(
>
> First of all, your program has not return value. You do not return
> anything. There is no return statement.
>
> The second: how do you expect to return 3 integers in one?
>
> The third: as you wrote the function definition (signature) it takes the
> arguments by value, so x,y and z (which you have clearly typed wrong) is a
> *copy* of a b and c. Writing into them will write into the copy.
>
> You can take the arguments by reference, then you will be able to change
> them. *If* you work in C++. If you do work in C, you will need to take
> pointers to them.
>

Thanks for your help, I realised my error right after posting

int randomise()
{
int x;
srand((unsigned)time(NULL));
x = rand();
return x;
}

and in main

a = randomise();
b = randomise();
c = randomise();

Materialised, Oct 20, 2003
6. ### Artie GoldGuest

Materialised wrote:
> WW wrote:
>
>> Materialised wrote:
>>
>>> I am writing a simple function to initialise 3 variables to pesudo
>>> random numbers.
>>>
>>> I have a function which is as follows
>>>
>>> int randomise( int x, int y, intz)
>>> {
>>> srand((unsigned)time(NULL));
>>> x = rand();
>>> y = rand();
>>> z = rand();
>>>
>>> }
>>> And I call this function with
>>>
>>> randomise(a,b,c);
>>>
>>> However a,b,c do not contain the randomised integers, I understand
>>> this is a problem with the return value of my function,
>>> I have tried
>>> return x,y,z;
>>> But this doesnt work either.
>>>
>>> Can anyone point out where my problem is?

>>
>>
>>
>> Ehem. The first one is that you try to program in C++ without a good
>> textbook. :-(
>>
>> First of all, your program has not return value. You do not return
>> anything. There is no return statement.
>>
>> The second: how do you expect to return 3 integers in one?
>>
>> The third: as you wrote the function definition (signature) it takes the
>> arguments by value, so x,y and z (which you have clearly typed wrong) is a
>> *copy* of a b and c. Writing into them will write into the copy.
>>
>> You can take the arguments by reference, then you will be able to change
>> them. *If* you work in C++. If you do work in C, you will need to take
>> pointers to them.
>>

> Thanks for your help, I realised my error right after posting
>
> int randomise()
> {
> int x;
> srand((unsigned)time(NULL));
> x = rand();
> return x;
> }
>
> and in main
>
> a = randomise();
> b = randomise();
> c = randomise();
>

No, you don't want to do that either.
Calling `srand()' multiple times like that (i.e. for each call to
`rand()') will not make the numbers any more random, and may do
exactly the opposite.

Call srand() once...

HTH,
--ag

--
Artie Gold -- Austin, Texas
Oh, for the good old days of regular old SPAM.

Artie Gold, Oct 20, 2003
7. ### Dan PopGuest

In <bn11p3\$rv6a4\$-berlin.de> Materialised <> writes:

>I am writing a simple function to initialise 3 variables to pesudo
>random numbers.
>
>I have a function which is as follows
>
>int randomise( int x, int y, intz)
>{
>srand((unsigned)time(NULL));
>x = rand();
>y = rand();
>z = rand();
>
>}
>And I call this function with
>
>randomise(a,b,c);
>
>However a,b,c do not contain the randomised integers, I understand this
>is a problem with the return value of my function,
>I have tried
>return x,y,z;
>But this doesnt work either.
>
>Can anyone point out where my problem is?

Sure, both your favourite C book and the FAQ can.

The *right* way of solving this problem in C is by using a structure:

struct random { int x, y, z; };

struct random randomise(void)
{
struct random t;
srand((unsigned)time(NULL)); /* this function call doesn't belong
here, unless you call this function exactly once */
t.x = rand();
t.y = rand();
t.z = rand();
return t;
}

Ignore any advice recommending the usage of three pointers in the
function's interface. Such interfaces are evil, in general, even if, in
this particular case, there is no big deal. Functions should not use
their parameters as a way of returning back information to the caller.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email:

Dan Pop, Oct 20, 2003
8. ### Default UserGuest

WW wrote:

> Ehem. The first one is that you try to program in C++ without a good
> textbook. :-(

C++

Default User, Oct 20, 2003
9. ### Default UserGuest

WW wrote:

> You can take the arguments by reference, then you will be able to change
> them. *If* you work in C++. If you do work in C, you will need to take
> pointers to them.

Where did the OP say he was working in C++?

Brian Rodenborn

Default User, Oct 20, 2003
10. ### Christopher Benson-ManicaGuest

In comp.lang.c Dan Pop <> wrote:

> Ignore any advice recommending the usage of three pointers in the
> function's interface. Such interfaces are evil, in general, even if, in
> this particular case, there is no big deal. Functions should not use
> their parameters as a way of returning back information to the caller.

Why is this? In what circumstances can pointers lead to tragedy?

--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome.

Christopher Benson-Manica, Oct 20, 2003
11. ### Keith ThompsonGuest

Materialised <> writes:
[...]
> Thanks for your help, I realised my error right after posting
>
> int randomise()
> {
> int x;
> srand((unsigned)time(NULL));
> x = rand();
> return x;
> }
>
> and in main
>
> a = randomise();
> b = randomise();
> c = randomise();

As someone else pointed out, you don't want to call srand() more than
once in your program. You can either call it once in your main
program, or use a static variable in randomise() to allow randomise()
to call srand() only the first time. Calling it in main() is the
simplest approach, but putting the srand() call inside randomise()
might be better in terms of program organization.

Also, the way your randomise() function is now written, the variable x
is unnecessary. Assuming you call srand() from main(), randomise()
could look like this:

int randomise(void)
{
int x;
x = rand();
return x;
}

which is equivalent to this:

int randomise(void)
{
return rand();
}

which means you probably might as well eliminate the randomise() function
altogether:

int main(void)
{
srand((unsigned)time(NULL));
a = rand();
b = rand();
c = rand();
...
}

A couple more things to note:

C library implementations of rand() are often of poor quality; there
might be a system-specific routine that gives you better random
numbers.

The values return by rand() are in the range 0 .. RAND_MAX (defined in
<stdlib.h>). You probably want some range that you specify; see
question 13.16 in the C FAQ for details.

Given these complications, getting a useful random number is going to
involve more than just calling rand(), and you probably do want

--
Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://www.sdsc.edu/~kst>
Schroedinger does Shakespeare: "To be *and* not to be"

Keith Thompson, Oct 20, 2003
12. ### MaterialisedGuest

Materialised wrote:
> I am writing a simple function to initialise 3 variables to pesudo
> random numbers.
>
> I have a function which is as follows
>
> int randomise( int x, int y, intz)
> {
> srand((unsigned)time(NULL));
> x = rand();
> y = rand();
> z = rand();
>
> }
> And I call this function with
>
> randomise(a,b,c);
>
> However a,b,c do not contain the randomised integers, I understand this
> is a problem with the return value of my function,
> I have tried
> return x,y,z;
> But this doesnt work either.
>
> Can anyone point out where my problem is?
>

I would like to thank everyone for their input on this matter.

I have been given a few solutions, using pointers, eliminating the
random function altogether, using a structure, etc, etc.

My question now is which of these solutions would be more efficient?
Or is this compiler dependent and considered OT?
(Dont wanna be flamed)

Materialised, Oct 21, 2003
13. ### Karl Heinz BucheggerGuest

Materialised wrote:
>
>
> I have been given a few solutions, using pointers, eliminating the
> random function altogether, using a structure, etc, etc.
>
> My question now is which of these solutions would be more efficient?
> Or is this compiler dependent and considered OT?
> (Dont wanna be flamed)

Sorry. Can't resist.
Why is it that newbies who are berely able to write a correct
To say it clearly: Forget about efficiency for now at this level.
Write your program correct, make it work. Then watch your
program. If it is fast enough: don't do anything. If not: profile!
and figure out where time is spent. Only after you know where your
program uses up the time you care about efficiency.

--
Karl Heinz Buchegger

Karl Heinz Buchegger, Oct 21, 2003
14. ### Dan PopGuest

In <bn18om\$pmb\$> Christopher Benson-Manica <> writes:

>In comp.lang.c Dan Pop <> wrote:
>
>> Ignore any advice recommending the usage of three pointers in the
>> function's interface. Such interfaces are evil, in general, even if, in
>> this particular case, there is no big deal. Functions should not use
>> their parameters as a way of returning back information to the caller.

>
>Why is this? In what circumstances can pointers lead to tragedy?

In most cases, using pointer arguments this way results in less readable
and maintainable code. It's not clear whether the callee will use the
existing values of the pointed-to objects or whether it will
unconditionally change them. When encountering such a function call,
you *must* study its definition, to see what exactly is happening.
Functions not taking pointers to scalars as their arguments don't raise
such issues, you can safely ignore their definitions if they are not
directly relevant to the issue you're currently investigating.

To be more clear, I'm talking about returning back scalar information to
the caller. It is perfectly OK to do it for arrays. So, in the case of
the OP, another valid solution would be

void randomise(int *array);

where the caller is passing the address of the first int in an array
of three int's.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email:

Dan Pop, Oct 21, 2003
15. ### =?iso-8859-1?Q?Andr=E9_P=F6nitz?=Guest

In alt.comp.lang.learn.c-c++ Dan Pop <> wrote:
> In most cases, using pointer arguments this way results in less readable
> and maintainable code. It's not clear whether the callee will use the
> existing values of the pointed-to objects or whether it will
> unconditionally change them. When encountering such a function call,
> you *must* study its definition, to see what exactly is happening.
> Functions not taking pointers to scalars as their arguments don't raise
> such issues, you can safely ignore their definitions if they are not
> directly relevant to the issue you're currently investigating.
>
> To be more clear, I'm talking about returning back scalar information to
> the caller. It is perfectly OK to do it for arrays. So, in the case of
> the OP, another valid solution would be
>
> void randomise(int *array);
>
> where the caller is passing the address of the first int in an array
> of three int's.

And how do you tell on the caller side that the function
(a) does not use the values in *array, *(array + 1), *(array + 2)
(b) puts something in there
(c) uses three items?

This solution is as good or as bad as passing three separate pointers.
I'd even argue it is worse as (c) is non-obvious.

Andre'

=?iso-8859-1?Q?Andr=E9_P=F6nitz?=, Oct 21, 2003
16. ### Dan PopGuest

In <bn36ou\$re0\$-chemnitz.de> =?iso-8859-1?Q?Andr=E9_P=F6nitz?= <> writes:

>In alt.comp.lang.learn.c-c++ Dan Pop <> wrote:
>> In most cases, using pointer arguments this way results in less readable
>> and maintainable code. It's not clear whether the callee will use the
>> existing values of the pointed-to objects or whether it will
>> unconditionally change them. When encountering such a function call,
>> you *must* study its definition, to see what exactly is happening.
>> Functions not taking pointers to scalars as their arguments don't raise
>> such issues, you can safely ignore their definitions if they are not
>> directly relevant to the issue you're currently investigating.
>>
>> To be more clear, I'm talking about returning back scalar information to
>> the caller. It is perfectly OK to do it for arrays. So, in the case of
>> the OP, another valid solution would be
>>
>> void randomise(int *array);
>>
>> where the caller is passing the address of the first int in an array
>> of three int's.

>
>And how do you tell on the caller side that the function
> (a) does not use the values in *array, *(array + 1), *(array + 2)
> (b) puts something in there
> (c) uses three items?

The function's prototype clearly suggests that the function is using the
pointer in write mode. And, if the array is not already initialised,
it is a (relatively) safe bet that it ignores the existing contents.

If this is not enough for your immediate needs, you can always check the
function definition.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email:

Dan Pop, Oct 21, 2003
17. ### =?iso-8859-1?Q?Andr=E9_P=F6nitz?=Guest

In alt.comp.lang.learn.c-c++ Dan Pop <> wrote:
>>> To be more clear, I'm talking about returning back scalar information to
>>> the caller. It is perfectly OK to do it for arrays. So, in the case of
>>> the OP, another valid solution would be
>>>
>>> void randomise(int *array);
>>>
>>> where the caller is passing the address of the first int in an array
>>> of three int's.

>>
>>And how do you tell on the caller side that the function
>> (a) does not use the values in *array, *(array + 1), *(array + 2)
>> (b) puts something in there
>> (c) uses three items?

>
> The function's prototype clearly suggests that the function is using the
> pointer in write mode.

I see no particular difference between

void func(int *item1, int *item2, int *item3);

void foo()
{
int i1, i2, i3;
func(&i1, &i2, &i3);
}

and

void func(int *arr);

void foo()
{
int arr[3];
func(arr);
}

at least noct to a degree to call the seond version "safer".

> And, if the array is not already initialised,
> it is a (relatively) safe bet that it ignores the existing contents.

So when I debug code and see the caller side I have to assume it is
correct to make a guess on how the function works?

This is not different from the original proposal.

> If this is not enough for your immediate needs, you can always check the
> function definition.

I thought your main point was that your solution makes checking the
definition unnecessary.

I am still not convinced and still maintain that your solution is not
better than the original. But maybe I simply don't

Andre'

--
Those who desire to give up Freedom in order to gain Security, will not have,
nor do they deserve, either one. (T. Jefferson or B. Franklin or both...)

=?iso-8859-1?Q?Andr=E9_P=F6nitz?=, Oct 21, 2003
18. ### Martijn LievaartGuest

On Tue, 21 Oct 2003 10:03:24 +0200, Karl Heinz Buchegger wrote:

>
>
> Materialised wrote:
>>
>>
>> I have been given a few solutions, using pointers, eliminating the
>> random function altogether, using a structure, etc, etc.
>>
>> My question now is which of these solutions would be more efficient?
>> Or is this compiler dependent and considered OT?
>> (Dont wanna be flamed)

>
> Sorry. Can't resist.
> Why is it that newbies who are berely able to write a correct
> program always care about efficiency.
> To say it clearly: Forget about efficiency for now at this level.
> Write your program correct, make it work. Then watch your
> program. If it is fast enough: don't do anything. If not: profile!
> and figure out where time is spent. Only after you know where your
> program uses up the time you care about efficiency.

And nine out of ten, the speedup comes from rewriting algorithms, not
technical details.

I'm not saying technical details can't make a difference, just that they
are in the order of a few percent most of the time.

M4

Martijn Lievaart, Oct 21, 2003
19. ### Martijn LievaartGuest

On Tue, 21 Oct 2003 10:49:58 +0000, Dan Pop wrote:

> To be more clear, I'm talking about returning back scalar information to
> the caller. It is perfectly OK to do it for arrays. So, in the case of
> the OP, another valid solution would be
>
> void randomise(int *array);
>
> where the caller is passing the address of the first int in an array
> of three int's.

I'ld always do this as

void randomise(int *array, int size);

HTH,
M4

Martijn Lievaart, Oct 21, 2003
20. ### Arthur J. O'DwyerGuest

On Tue, 21 Oct 2003, Dan Pop wrote:
>
> Christopher Benson-Manica <> writes:
> >In comp.lang.c Dan Pop <> wrote:
> >
> >> Ignore any advice recommending the usage of three pointers in the
> >> function's interface. Such interfaces are evil, in general, even if, in
> >> this particular case, there is no big deal. Functions should not use
> >> their parameters as a way of returning back information to the caller.

> >
> >Why is this? In what circumstances can pointers lead to tragedy?

>
> In most cases, using pointer arguments this way results in less readable
> and maintainable code.

While this is true, I must respectfully disagree with most of the
rest of what you're saying.

> It's not clear whether the callee will use the
> existing values of the pointed-to objects or whether it will
> unconditionally change them. When encountering such a function call,
> you *must* study its definition, to see what exactly is happening.

....unless the pointer parameters have 'const' attached to them in
the right places, so you can tell they're not being changed. If
they're *not* constified, then it's almost always better to assume
they *will* be changed. (No guarantees, though.)

> To be more clear, I'm talking about returning back scalar information to

s/returning back/returning/

> the caller. It is perfectly OK to do it for arrays. So, in the case of
> the OP, another valid solution would be
>
> void randomise(int *array);
>
> where the caller is passing the address of the first int in an array
> of three int's.

I think this is worse than the original for *several* reasons.

void foo(int *bar);

is the accepted idiom for "bar is an array of int," with no constness
guarantees either way; it's rare IME to see

void foo(const int *bar);

So just by looking at the prototype, the client can't tell as reliably
whether the value of *bar will be changed.

void foo(const int bar[3]);

would be preferable in this case, since it specifies that we need to
pass exactly 3 integers in the array -- not 2, not 4, but 3. Doesn't
help the compiler, but it can help the client.

Finally, I think that the average programmer is likely to find the
array-based solution simply too clumsy. It takes time and LOC to
initialize an array that would be slightly less annoying to do with
single ints. Unless, of course, the parameters are part of a larger
"chunk" of information (say, the XYZ coordinates of a point), in
which case it probably makes more sense to pass around a (pointer to
a) 'struct'.

When I see

int a, b, c;
...
foo(&a, &b, &c);

it's pretty obvious that something is going to get changed inside
foo. In contrast, when I see

int r[3];
...
foo(r);

I can't even tell without checking types again that r *is* getting
"passed by pointer." I think that's more of a disadvantage than
whatever advantages you see to the lack of & operators -- I consider
&s a red flag!

Just for completeness, what do you think of

void foo(int (*bar)[3]);

int r[3];
...
foo(&r);

?
(I think it's unnecessarily ugly and restrictive, myself.)

-Arthur

Arthur J. O'Dwyer, Oct 21, 2003