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

Discussion in 'C Programming' started by Sathyaish, Jun 11, 2004.

  1. Sathyaish

    Sathyaish Guest

    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;
    }
    
     
    Sathyaish, Jun 11, 2004
    #1
    1. Advertising

  2. On 10 Jun 2004 18:09:28 -0700,
    (Sathyaish) wrote:

    >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);[/color]
    
    fn is a function that takes no arguments and returns ...
    [color=blue]
    >
    >
    >int main(void)
    >{
    >    int (*fnptr)(int);[/color]
    
    fnptr is a pointer to a function that takes one argument (of type int)
    and returns ...
    [color=blue]
    >    fnptr=fn;[/color]
    
    fn is not the correct type to be assigned to fnptr.
    [color=blue]
    >    printf("%d", (*fnptr)(3));
    >}
    >
    >    
    >int Add2(int a)
    >{
    >    return a+2;
    >}
    >
    >fnptr fn(void)
    >{
    >    return &Add2;
    >}
    >




    <<Remove the del for email>>
     
    Barry Schwarz, Jun 11, 2004
    #2
    1. Advertising

  3. Sathyaish

    Jack Klein Guest

    On 10 Jun 2004 18:09:28 -0700,
    (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.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
     
    Jack Klein, Jun 11, 2004
    #3
  4. Sathyaish

    Chris Dollin Guest

    Jack Klein wrote:

    > On 10 Jun 2004 18:09:28 -0700,
    > (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. 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."]

    --
    Chris "Lisp, Pop11, Smalltalk[ish] can all do the general case" Dollin
    C FAQs at: http://www.faqs.org/faqs/by-newsgroup/comp/comp.lang.c.html
    C welcome: http://www.angelfire.com/ms3/bchambless0/welcome_to_clc.html
     
    Chris Dollin, Jun 11, 2004
    #4
  5. Sathyaish

    Nick Austin Guest

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

    >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.
     
    Nick Austin, Jun 11, 2004
    #5
  6. Sathyaish

    Malcolm Guest

    "Nick Austin" <> wrote in message
    >
    > 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);
     
    Malcolm, Jun 11, 2004
    #6
  7. Sathyaish

    Jack Klein Guest

    On Fri, 11 Jun 2004 10:00:02 +0100, Chris Dollin <>
    wrote in comp.lang.c:

    > Jack Klein wrote:
    >
    > > On 10 Jun 2004 18:09:28 -0700,
    > > (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?

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

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
     
    Jack Klein, Jun 12, 2004
    #7
  8. 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.
     
    Stephen Hooper, Jun 12, 2004
    #8
  9. > 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.
     
    Stephen Hooper, Jun 12, 2004
    #9
  10. Sathyaish

    Chris Torek Guest

    In article <>
    Stephen Hooper <> writes:
    >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++. :)
    --
    In-Real-Life: Chris Torek, Wind River Systems
    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    email: forget about it http://web.torek.net/torek/index.html
    Reading email is like searching for food in the garbage, thanks to spammers.
     
    Chris Torek, Jun 12, 2004
    #10
  11. In article <>,
    Chris Torek <> wrote:

    >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
     
    Richard Tobin, Jun 12, 2004
    #11
  12. Sathyaish

    Chris Dollin Guest

    [much leading quoting]

    Jack Klein wrote:

    > On Fri, 11 Jun 2004 10:00:02 +0100, Chris Dollin <>
    > wrote in comp.lang.c:
    >
    >> Jack Klein wrote:
    >>
    >> > On 10 Jun 2004 18:09:28 -0700,
    >> > (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.

    --
    Chris "electric hedgehog" Dollin
    C FAQs at: http://www.faqs.org/faqs/by-newsgroup/comp/comp.lang.c.html
    C welcome: http://www.angelfire.com/ms3/bchambless0/welcome_to_clc.html
     
    Chris Dollin, Jun 14, 2004
    #12
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Steven Knight
    Replies:
    0
    Views:
    448
    Steven Knight
    Nov 7, 2003
  2. Reckoner
    Replies:
    11
    Views:
    704
    Steven D'Aprano
    Jan 19, 2009
  3. thunk
    Replies:
    1
    Views:
    316
    thunk
    Mar 30, 2010
  4. thunk
    Replies:
    0
    Views:
    490
    thunk
    Apr 1, 2010
  5. thunk
    Replies:
    14
    Views:
    629
    thunk
    Apr 3, 2010
Loading...

Share This Page