A function that returns a function that adds x to its argument

S

Sathyaish

In a thread on JoS, Quickie asked,

"Write a function in C that returns a function that adds x to its
argument."

http://discuss.fogcreek.com/joelonsoftware/default.asp?cmd=show&ixPost=146457

Here's my go at it. It compiles, links, but prints junk. So it
basically doesn't do what it was supposed to do. Comments welcome.

Code:
/*Write a function in C that returns a 
function that adds x to its argument

  x in this case is 2
*/

#include <stdio.h>

int Add2(int);
typedef int(*fnptr)(int);
int (*fn(void))(int);


int main(void)
{
    int (*fnptr)(int);
    fnptr=fn;
    printf("%d", (*fnptr)(3));
}

    
int Add2(int a)
{
    return a+2;
}

fnptr fn(void)
{
    return &Add2;
}
 
B

Barry Schwarz

In a thread on JoS, Quickie asked,

"Write a function in C that returns a function that adds x to its
argument."

http://discuss.fogcreek.com/joelonsoftware/default.asp?cmd=show&ixPost=146457

Here's my go at it. It compiles, links, but prints junk. So it
basically doesn't do what it was supposed to do. Comments welcome.

How can you claim it compiles when it has a syntax error?
Code:
/*Write a function in C that returns a 
function that adds x to its argument

x in this case is 2
*/

#include <stdio.h>

int Add2(int);
typedef int(*fnptr)(int);
int (*fn(void))(int);[/QUOTE]

fn is a function that takes no arguments and returns ...
[QUOTE]
int main(void)
{
int (*fnptr)(int);[/QUOTE]

fnptr is a pointer to a function that takes one argument (of type int)
and returns ...
[QUOTE]
fnptr=fn;[/QUOTE]

fn is not the correct type to be assigned to fnptr.
[QUOTE]
printf("%d", (*fnptr)(3));
}


int Add2(int a)
{
return a+2;
}

fnptr fn(void)
{
return &Add2;
}



<<Remove the del for email>>
 
J

Jack Klein

In a thread on JoS, Quickie asked,

"Write a function in C that returns a function that adds x to its
argument."

[snip]

The author of this question is ignorant of C. It is not possible to
return a function in C.
 
C

Chris Dollin

Jack said:
In a thread on JoS, Quickie asked,

"Write a function in C that returns a function that adds x to its
argument."

[snip]

The author of this question is ignorant of C. It is not possible to
return a function in C.

You're just pickier than the author about the difference between a
function and a function pointer. Or perhaps the author (or the OP)
made a typo. In any case, your pickiness allows you to avoid the
real and interesting question and its near variations. Was that
your intent?

[My answer is "insufficnet detail in the question - the obvious
general question has the answer "no" in C, but there are various
restricted forms that might serve."]
 
N

Nick Austin

In a thread on JoS, Quickie asked,

"Write a function in C that returns a function that adds x to its
argument."

Assuming that reads "...returns a pointer to a function...".

Also forget using typedefs as that makes it more complex.

#include <stdio.h>

static int Add2(int);
static int (*fn(void))(int);

int main(void)
{
printf("%d", fn()(3));
return 0;
}

int Add2(int a)
{
return a+2;
}

int (*fn(void))(int)
{
return Add2;
}

Nick.
 
M

Malcolm

Nick Austin said:
Also forget using typedefs as that makes it more complex.
No. I think the OP should write a non-typedefed version to learn the syntax,
but C function pointer syntax is so difficult to read that a typedef makes
things simpler.

callbackfunc foo( int bar );

is a lot easier on the eye than

int (*foo(int bar))(int baz);
 
J

Jack Klein

Jack said:
In a thread on JoS, Quickie asked,

"Write a function in C that returns a function that adds x to its
argument."

[snip]

The author of this question is ignorant of C. It is not possible to
return a function in C.

You're just pickier than the author about the difference between a
function and a function pointer.

I have read the C standard, have you?

<begin quote>

6.7.5.3 Function declarators (including prototypes)

Constraints

1 A function declarator shall not specify a return type that is a
function type or an array type.

<end quote>
 
S

Stephen Hooper

On Thu, 10 Jun 2004 18:09:28 -0700, Sathyaish wrote:

I am probably misunderstanding the question, but the most elegant I could
come up with was:

<code>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>

/*
The "add the two numbers" together function
Should never be called by its lonesome
*/
int addit(int i, ...){
va_list args;
static int set;
static int x;
int y = 0;

if(!set && i == 0) {
va_start(args,i);
y = va_arg(args,int);
if(y != 0)
x = y;
va_end(args);
set = 1;
}

return (i + x);
}

/*
Set's x, and returns a function pointer to addit
*/
void *setadd(int x) {
addit(0,x); /*Sets x (also returns i + x, but doesn't matter)*/
return &addit;
}

/*
Should work (keeping my fingers X'd)
*/
int main(int argc, char **argv) {
int ( *addem)(int,...);

/* first set is permanent */
the_fp = setadd(17);
printf("%i\n",addem(3));
printf("%i\n",addem(0));

/* is set so we can't reset :( */
the_fp = setadd(10);
printf("%i\n",addem(3));
return EXIT_SUCCESS;
}
</code>

It would be simpler to declare a global static variable, and use it
instead. That gives the benefit of being resettable, and allowing a zero
to be added without any of the hoops being jumped through here.

Still, unless I am misinterpreting, I think this better fulfills the
spirit of your question :}

It compiles with gcc -ansic -Wall, and gives me the right results.
 
S

Stephen Hooper

the_fp = setadd(17);
the_fp = setadd(10);

should be
addem = setadd(17);
addem = setadd(10);

Changing "the_fp" to "addem" should make it work. Sorry.
It compiles with gcc -ansic -Wall, and gives me the right results.

Oops! I promise it was an unintentional lie.
 
C

Chris Torek

I am probably misunderstanding the question, but ...

Yes, you are. :)

If C had the feature that was being referred to originally --
denoted below by explicit "magic" -- one might write something like
this:

/* T_adder is a pointer to a function that takes one int argument
(say "i") and returns i+k for some constant k, but k is not
determined until later. */
typedef int (*T_adder)(int);

static int doit(int);

/* new_adder makes a new adder that adds k */
T_adder new_adder(int k) {
/* this is the part that doesn't work: */
T_adder ret;

ret = doit;
magic(ret)->saved_val = k; /* but there is no magic! */
return ret;
}

static int doit(int i) {
magic int k = magic()->saved_val; /* magically recover the saved val */
return i + k;
}

With the above in a module (say adder.c, and adder.h for the one
"typedef" line), we could then write, as our entire main() program:

#include <stdio.h>
#include <stdlib.h>
#include "adder.h"

int main(int argc, char **argv) {
T_adder a1, a2, a3;
int x;

a1 = new_adder(1); /* now a1(x) returns x+1 */
a2 = new_adder(99); /* and a2(x) returns x+99 */
if (argc >= 2)
a3 = new_adder(atoi(argv[1]));
else
a3 = new_adder(0); /* a3(x) returns x+k or x */
if (argc >= 3)
x = atoi(argv[2]);
else
x = 42;
printf("a1(%d) = %d\n", x, a1(x));
printf("a2(%d) = %d\n", x, a2(x));
printf("a3(%d) = %d\n", x, a3(x));
return EXIT_SUCCESS;
}

When run with no parameters, the output would be:

a1(42) = 43
a2(42) = 141
a3(42) = 42

and when run with one or two parameters the output would change.

The "magic" that is missing in C, but does exist in other languages,
is something that those languages usually call a "closure". A
closure allows you to capture the values of local variables and
save them away, then have the magically "resurrect" later. C has
no magic, so if you want to save away one or more values, you
have to do so explicitly -- and then the fact that there are saved
values becomes clear to the caller. We might rewrite adder.h as
follows:

typedef struct adder T_adder;
struct adder {
int k;
int (*run)(T_adder *, int);
};

Now adder.c looks like this:

static int doit(T_adder *, int);

T_adder *new_adder(int k) {
T_adder *ret;

ret = malloc(sizeof *ret);
if (ret == NULL)
panic("out of memory in new_adder()");
ret->k = k;
ret->run = doit;
return ret;
}

static int doit(T_adder *closure, int i) {
return closure->k + i;
}

and of course main.c has to change:

int main(int argc, char **argv) {
T_adder a1, a2, a3;

a1 = new_adder(1); /* now a1->run(a1, x) returns x+1 */
...
printf("a1(%d) = %d\n", x, a1->run(a1, x));
printf("a2(%d) = %d\n", x, a2->run(a2, x));
printf("a3(%d) = %d\n", x, a3->run(a3, x));
return EXIT_SUCCESS;
}

The magic has now been removed: the closure is explicitly available
in each "new_adder"-created adder, and when one calls the functions
associated with that adder (in this case just the one function named
"run"), one has to provide the environment holding that closure.

Those familiar with C++ should now comprehend how to fake closures
in C++. :)
 
R

Richard Tobin

Chris Torek said:
Those familiar with C++ should now comprehend how to fake closures
in C++. :)

Indeed. Another way to put it is the observation that a closure is
very like an object with a method, in that both are a combination of a
function and an object. This is very clear in the different idioms
used for callbacks in various languages: in Lisp you would pass a
closure, in Java an object (some specific method of which is called),
and in C typically a function pointer and a void * argument.

-- Richard
 
C

Chris Dollin

[much leading quoting]

Jack said:
Jack said:
On 10 Jun 2004 18:09:28 -0700, (e-mail address removed)
(Sathyaish) wrote in comp.lang.c:

In a thread on JoS, Quickie asked,

"Write a function in C that returns a function that adds x to its
argument."

[snip]

The author of this question is ignorant of C. It is not possible to
return a function in C.

You're just pickier than the author about the difference between a
function and a function pointer.

I have read the C standard, have you?

Enough of it for this point, yes.
1 A function declarator shall not specify a return type that is a
function type or an array type.

Yes, I know. Makes no difference. You're *still* just [possibly] being
pickier than the author on the difference. Just because the language
is the language of the Standard doesn't avoid that.

The usage may be made in ignorance, or it may be a typo, or it may be
sloppiness; but in any of those cases, it's *still* possible to
supply an illuminating answer to the question, rather than drive the
car off the cliff and into the swamp - as Chris Torek, for one, has
demonstrated.
 

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

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,527
Members
45,000
Latest member
MurrayKeync

Latest Threads

Top