Returning values from a function

M

Materialised

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?
 
W

WW

Materialised said:
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.
 
E

Eric Sosman

Materialised said:
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
Frequently Asked Questions (FAQ) list

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

Martin Ambuhl

Materialised said:
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;
}
 
M

Materialised

WW said:
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();
 
A

Artie Gold

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

....and please reread the suggestions elsethread.

HTH,
--ag
 
D

Dan Pop

In said:
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
 
D

Default User

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
 
C

Christopher Benson-Manica

In comp.lang.c Dan Pop said:
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?
 
K

Keith Thompson

Materialised said:
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:

#include yadda yadda

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
something like your randomise() function.
 
M

Materialised

Materialised said:
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)
 
K

Karl Heinz Buchegger

Materialised said:
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.
 
D

Dan Pop

In said:
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
 
?

=?iso-8859-1?Q?Andr=E9_P=F6nitz?=

In alt.comp.lang.learn.c-c++ Dan Pop said:
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'
 
D

Dan Pop

In said:
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
 
?

=?iso-8859-1?Q?Andr=E9_P=F6nitz?=

In alt.comp.lang.learn.c-c++ Dan Pop said:
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'
 
M

Martijn Lievaart

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
 
M

Martijn Lievaart

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
 
A

Arthur J. O'Dwyer

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,733
Messages
2,569,439
Members
44,829
Latest member
PIXThurman

Latest Threads

Top