473,378 Members | 1,680 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,378 software developers and data experts.

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

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/joelonso...&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.

Expand|Select|Wrap|Line Numbers
  1. /*Write a function in C that returns a
  2. function that adds x to its argument
  3.  
  4. x in this case is 2
  5. */
  6.  
  7. #include <stdio.h>
  8.  
  9. int Add2(int);
  10. typedef int(*fnptr)(int);
  11. int (*fn(void))(int);
  12.  
  13.  
  14. int main(void)
  15. {
  16. int (*fnptr)(int);
  17. fnptr=fn;
  18. printf("%d", (*fnptr)(3));
  19. }
  20.  
  21.  
  22. int Add2(int a)
  23. {
  24. return a+2;
  25. }
  26.  
  27. fnptr fn(void)
  28. {
  29. return &Add2;
  30. }
  31.  
Nov 14 '05 #1
11 1404
On 10 Jun 2004 18:09:28 -0700, Vi****************@yahoo.com
(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/joelonso...&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?

Expand|Select|Wrap|Line Numbers
  1. /*Write a function in C that returns a
  2. function that adds x to its argument
  3.   x in this case is 2
  4. */
  5. #include <stdio.h>
  6. int Add2(int);
  7. typedef int(*fnptr)(int);
  8. int (*fn(void))(int);
  •  
  • fn is a function that takes no arguments and returns ...
  • int main(void)
  • {
  •     int (*fnptr)(int);
  •  
  • fnptr is a pointer to a function that takes one argument (of type int)
  • and returns ...
  •     fnptr=fn;
  •  
  • fn is not the correct type to be assigned to fnptr.
  •     printf("%d", (*fnptr)(3));
  • }
  • int Add2(int a)
  • {
  •     return a+2;
  • }
  • fnptr fn(void)
  • {
  •     return &Add2;
  • }


  • <<Remove the del for email>>
    Nov 14 '05 #2
    On 10 Jun 2004 18:09:28 -0700, Vi****************@yahoo.com
    (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/~a...FAQ-acllc.html
    Nov 14 '05 #3
    Jack Klein wrote:
    On 10 Jun 2004 18:09:28 -0700, Vi****************@yahoo.com
    (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-newsgrou...mp.lang.c.html
    C welcome: http://www.angelfire.com/ms3/bchambl...me_to_clc.html
    Nov 14 '05 #4
    On 10 Jun 2004 18:09:28 -0700, Vi****************@yahoo.com
    (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.

    Nov 14 '05 #5

    "Nick Austin" <ni***@r-e-m-o-v-e.nildram.co.uk> 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);

    Nov 14 '05 #6
    On Fri, 11 Jun 2004 10:00:02 +0100, Chris Dollin <ke**@hpl.hp.com>
    wrote in comp.lang.c:
    Jack Klein wrote:
    On 10 Jun 2004 18:09:28 -0700, Vi****************@yahoo.com
    (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/~a...FAQ-acllc.html
    Nov 14 '05 #7
    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.
    Nov 14 '05 #8
    > 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.
    Nov 14 '05 #9
    In article <pa****************************@email.arizona.ed u>
    Stephen Hooper <sc******@email.arizona.edu> 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.
    Nov 14 '05 #10
    In article <ca*********@news3.newsguy.com>,
    Chris Torek <no****@torek.net> 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
    Nov 14 '05 #11
    [much leading quoting]

    Jack Klein wrote:
    On Fri, 11 Jun 2004 10:00:02 +0100, Chris Dollin <ke**@hpl.hp.com>
    wrote in comp.lang.c:
    Jack Klein wrote:
    > On 10 Jun 2004 18:09:28 -0700, Vi****************@yahoo.com
    > (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-newsgrou...mp.lang.c.html
    C welcome: http://www.angelfire.com/ms3/bchambl...me_to_clc.html
    Nov 14 '05 #12

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

    Similar topics

    10
    by: Ron_Adam | last post by:
    I'm trying to figure out how to test function arguments by adding a decorator. @decorate def func( x): # do something return x This allows me to wrap and replace the arguments with my own,...
    2
    by: | last post by:
    OK: Purpose: Using user's input and 3 recursive functions, construct an hour glass figure. Main can only have user input, loops and function calls. Recursive function 1 takes input and displays...
    7
    by: | last post by:
    How to call a function with variable argument list from another function again with variable argument list? Example : double average ( int num, ... ); double AFunct1 ( int num, ... ); double...
    2
    by: laredotornado | last post by:
    Hello, I am looking for a cross-browser way (Firefox 1+, IE 5.5+) to have my Javascript function execute from the BODY's "onload" method, but if there is already an onload method defined, I would...
    4
    by: ey.markov | last post by:
    Greetings, I have an A2K application where for a report the user enters a month-end date, and the system must gather transactions for that month. No problem, I thought, I'll just use the DateAdd...
    30
    by: bnp | last post by:
    Hi, Is possible to use functions in conditional operator as ashown below. ..... ..... int fun1() { // body }
    4
    by: anonymous | last post by:
    Thanks your reply. The article I read is from www.hakin9.org/en/attachments/stackoverflow_en.pdf. And you're right. I don't know it very clearly. And that's why I want to understand it; for it's...
    17
    by: Charles Sullivan | last post by:
    The library function 'qsort' is declared thus: void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *)); If in my code I write: int cmp_fcn(...); int...
    21
    by: globalrev | last post by:
    i have a rough understanding of lambda but so far only have found use for it once(in tkinter when passing lambda as an argument i could circumvent some tricky stuff). what is the point of the...
    1
    by: CloudSolutions | last post by:
    Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
    0
    isladogs
    by: isladogs | last post by:
    The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
    0
    by: ryjfgjl | last post by:
    In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
    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: aa123db | last post by:
    Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
    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...
    0
    by: Hystou | last post by:
    There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

    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.