Thread: Storing function pointers in generic pointers

  1. #1
    Registered User
    Join Date
    Jun 2008
    Posts
    54

    Storing function pointers in generic pointers

    Hi, I'm having trouble storing a function pointer in a generic pointer. Apparently I'm causing a screw up in the memory locations for one reason or another.

    The program causes a segmentation fault when I attempt to call the function via the new pointer, and when I checked it with a debugger, it was indeed not pointing to the correct place in memory. I'm not sure what I should do to fix the problem, though.

    Here is the program:
    http://pastebin.com/f3e1f4dde
    It's supposed to implement a really basic LIFO data stack.

    Here is what my output looks like:
    Code:
    ./cstackdemo
    Hello there.
    27
    Segmentation fault
    If you want to try to compile this piece of crap (bless your heart), I have a makefile for it that you can download here:
    http://github.com/pipingcats/cstack/tree/master
    Last edited by Boxknife; 08-01-2009 at 01:46 AM.

  2. #2
    Making mistakes
    Join Date
    Dec 2008
    Posts
    476
    I'm not sure, but the standard doesn't guarantee that function pointers can be stored in void *s.
    The second problem is that you're reallocating just one byte for each void *, whereas it should be sizeof(void *) * stack->items.

    Quick note: As far as I see, a cstack ** is redundant. just use a cstack *. And check if the stack is empty in cpop.

  3. #3
    Registered User
    Join Date
    Jan 2008
    Posts
    290
    What Brafil said, plus:
    Code:
    cpush(&data, &printyay, sizeof(fp));
    This doesn't do what you think it does. &printyay is exactly the same as printyay (without the &) in this context.

    In other words, you are passing a pointer to a function when instead you should be passing a pointer to a pointer to a function.

    [edit]
    Try this:
    Code:
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    typedef struct cstack {
      void** stack;
      int items;
    } cstack;
    
    void cpush(cstack* stackp, void* data, int size)
    {
       stackp->items++;
       stackp->stack=realloc(stackp->stack, stackp->items * sizeof(void*));
       stackp->stack[stackp->items-1] = malloc(size);
       memcpy((stackp->stack)[stackp->items-1], data, size);
    }
    
    void* cpop(cstack* stackp)
    {
       void* data=NULL;
       stackp->items--;
       data=(stackp->stack)[stackp->items];
       
       if(stackp->items==0)
       {
          free(stackp->stack);
          stackp->stack=NULL;
       }
       else
          stackp->stack=realloc(stackp->stack, stackp->items * sizeof(void*));
       
       return data;
    }
    
    void printyay()
    {
       printf("Yay\n");
    }
    
    int main()
    {
       cstack *data=malloc(sizeof(cstack));
       typedef void (*fp)();
    
       fp *callme=NULL;
       fp yayfunc = printyay;
    
       char buf[50], *message=NULL;
       int num=27,*newnum=NULL;
    
       sprintf(buf, "Hello there.\n");
    
       /* Push data into stack */
       cpush(data, &yayfunc, sizeof(fp));
       cpush(data, &num, sizeof(int));
       cpush(data, &buf, sizeof(char)* 50);
    
       /* Pop from data */
       message=(char*)cpop(data);
       newnum=(int*)cpop(data);
       callme=(fp*)cpop(data);
    
       printf("%s%d\n", message, *newnum);
       (*callme)();
    
       free(callme);
       free(message);
       free(newnum);
       free(data);
       return 0;
    }
    [/edit]
    Last edited by arpsmack; 08-01-2009 at 02:26 AM.

  4. #4
    Registered User
    Join Date
    Jun 2008
    Posts
    54
    Thanks; good calls. I'm not sure what I was thinking with the extraneous indirection for cstack, and I just plain missed the realloc size mistakes.

    In other words, you are passing a pointer to a function when instead you should be passing a pointer to a pointer to a function.
    Correct me if I'm wrong, but do you mean that by doing what I'm doing, I'm getting the addresses of the function arguments instead of the location of the actual printyay()?

    I'm trying to feed the data in using a pointer to a pointer now, but so far I'm getting the same results. Gah.

    Edit:

    Alright, awesome, your code works.
    Last edited by Boxknife; 08-01-2009 at 02:29 AM.

  5. #5
    Registered User
    Join Date
    Jan 2008
    Posts
    290
    I mean you are getting the address of the function. For example:
    Code:
    fp pointerA = &printyay;
    fp pointerB = printyay;
    Both pointerA and pointerB contain the exact same thing, the address of the beginning of the printyay function.

    Your stack however, expects to be passed a pointer to what you are storing. If you are storing an int, then you pass int*. If you are storing a fp, then you need to pass a fp* (a pointer to a function pointer). Memcpy will then copy the contents of the fp into the memory that the stack allocates.

    When you pop the function pointer off the stack, you receive a fp*. It is then your job to dereference this in order to call the function. You do the exact same thing when retrieving an int, you dereference the pointer that you receive back before you pass it to printf.

    Making any more sense yet?

    [edit]
    Alternatively, you might try something like this:

    I made a modification to your stack. When you pass a size of 0, it doesn't malloc any memory and instead just copies the passed in pointer directly into the stack. This will allow you to pass in function pointers without a problem.

    Unfortunately, now you won't know whether you need to free the pointer that you get back from cpop (unless you keep track of it yourself).
    Code:
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    typedef struct cstack {
      void** stack;
      int items;
    } cstack;
    
    void cpush(cstack* stackp, void* data, int size)
    {
       stackp->items++;
       stackp->stack=realloc(stackp->stack, stackp->items * sizeof(void*));
       
       if (size > 0)
       {
          stackp->stack[stackp->items-1] = malloc(size);
          memcpy((stackp->stack)[stackp->items-1], data, size);
       }
       else
          stackp->stack[stackp->items-1] = data;
    }
    
    void* cpop(cstack* stackp)
    {
       void* data=NULL;
       stackp->items--;
       data=(stackp->stack)[stackp->items];
       
       if(stackp->items==0)
       {
          free(stackp->stack);
          stackp->stack=NULL;
       }
       else
          stackp->stack=realloc(stackp->stack, stackp->items * sizeof(void*));
       
       return data;
    }
    
    void printyay()
    {
       printf("Yay\n");
    }
    
    int main()
    {
       cstack *data=malloc(sizeof(cstack));
       typedef void (*fp)();
    
       fp callme=NULL;
    
       char buf[50], *message=NULL;
       int num=27,*newnum=NULL;
    
       sprintf(buf, "Hello there.\n");
    
       /* Push data into stack */
       cpush(data, &printyay, 0);
       cpush(data, &num, sizeof(int));
       cpush(data, &buf, sizeof(char)* 50);
    
       /* Pop from data */
       message=(char*)cpop(data);
       newnum=(int*)cpop(data);
       callme=(fp)cpop(data);
    
       printf("%s%d\n", message, *newnum);
       callme();
    
       free(message);
       free(newnum);
       free(data);
       return 0;
    }
    [/edit]
    Last edited by arpsmack; 08-01-2009 at 02:48 AM.

  6. #6
    Registered User
    Join Date
    Jun 2008
    Posts
    54
    Alright, that makes perfect sense. Thanks.

  7. #7
    Registered User
    Join Date
    Jun 2008
    Posts
    54
    Alternatively, you might try something like this:

    I made a modification to your stack. When you pass a size of 0, it doesn't malloc any memory and instead just copies the passed in pointer directly into the stack. This will allow you to pass in function pointers without a problem.

    Unfortunately, now you won't know whether you need to free the pointer that you get back from cpop (unless you keep track of it yourself).
    This is a pretty good idea, I think.

    I might be able to store the size data in an array in the structure, but I don't think it'll be a huge deal because I'll probably be using this code in places where I know exactly what I'll be passing. Like the last thing I'll push onto the stack will be an enum that describes the "format" of the rest of the data on the stack.
    Last edited by Boxknife; 08-01-2009 at 01:39 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. state machine using function pointers
    By meena_selvam in forum C Programming
    Replies: 1
    Last Post: 10-25-2008, 02:09 PM
  2. doubt in c parser coding
    By akshara.sinha in forum C Programming
    Replies: 4
    Last Post: 12-23-2007, 01:49 PM
  3. Game Pointer Trouble?
    By Drahcir in forum C Programming
    Replies: 8
    Last Post: 02-04-2006, 02:53 AM
  4. <Gulp>
    By kryptkat in forum Windows Programming
    Replies: 7
    Last Post: 01-14-2006, 01:03 PM
  5. Array of function pointers?
    By The V. in forum C++ Programming
    Replies: 3
    Last Post: 10-16-2001, 08:37 PM