Search code examples
cmemory-managementstaticdynamic-memory-allocationcalloc

Declare a pointer to structure in const expression


I am new to C and can't yet freely navigate trough my program memory. Anyways, I am creating a static memory data type (gc_menu) that should hold a pointer to created at execution time structure (mcl_items).

For simplicity mcl_items structure have one virtual method (push) that is going to be run inside of gc_menu_add_item and also assigned to the gc_menu static space. push saves an menu item name (letter) and method to mcl_item virtual object.

mcl_items.h code:

[...]

typedef struct Items_t {
  int8_t size;
  char names[64];
  void (*methods[64])();
  // Interface
  void (*push)(struct Items_t *self, char c, void (*method)());
}mcl_items;

mcl_items *new_mcl_items();
void mcl_items_push(mcl_items *self, char c, void (*method)());

mcl_items.c code:

[...]
#include "mcl_items.h"

mcl_items *new_mcl_items() {
  fprintf(stderr, "MCL_Items: Generating a new set of mcl_items..");
  // Build a virtual object
  mcl_items *items    = calloc(1, sizeof(struct Items_t));
  items->push         = mcl_items_push;
  // Set data
  items->size         = 0;
  return items;
}

void mcl_items_push(mcl_items *self, char c, void (*method)()) {
  fprintf(stderr, "MCL_Items: pushing a new item..");
  self->names[self->size] = c;
  self->methods[self->size] = method;
  self->size ++;
}

gc_menu.h code:

#include "items.h"

typedef struct {
  // Interface
  void (*add_item)(char c, void (*method)());
  // Data
  mcl_items *items;
}__gc_menu;

extern __gc_menu const gc_menu;

gc_menu.c code:

static void gc_menu_add_item(char c, void (*method)) {
  fprintf(stderr, "GC_Menu: Passing an new item..");
  fprintf(stderr, "length = %i\n", gc_menu.items->size);
  gc_menu.items->push(gc_menu.items, c, method);
}

__gc_menu const gc_menu = {gc_menu_add_item,    // Virtual methods
                           new_mcl_items};      // Data

After callng gc_menu.add_item the segmentation fault occurs and gc_menu.items->size is equal to 72, not 0 as is defined in the definition of new_mcl_items.

main.c code:

gc_menu.add_item('q', xw->end(xw));
GC_Menu: Passing an new item..length = 72
[1]    66021 segmentation fault (core dumped)  ./3D_scean

So what am I doing wrong? Why is there such a weird data written to instances of my gc_menu.items?


Solution

  • You've initialized gc_menu.items to new_mcl_items, i.e. a pointer to the function new_mcl_items (which should give you a warning since it is of type mcl_items *(*)(void) and not mcl_items *).

    It looks like what you want is to actually call the function new_mcl_items() and set gc_menu.items to the value that new_mcl_items() returns. You can't do this with an initializer; initializers of global or static objects must be known at compile or link time. Standard C doesn't have "constructors".

    So you'll have to remove the const from the declaration and definition of gc_menu, and add code to main (or some function called by main, etc) to initialize gc_menu.items at run time.

    gc_menu.h:

    extern __gc_menu gc_menu;
    

    gc_menu.c:

    __gc_menu gc_menu = { 
        gc_menu_add_item,
        NULL // or whatever else you like
    };
    

    main.c or whatever you have called it:

    int main(void) {
        // ...
        gc_menu.items = new_mcl_items();
        // ...
    }