0

I am trying to use an array of structs to create a symbol table. This is what I have so far, but I am having trouble allocating memory in the create function, is what I have so far correct?

I want something like this as my final result for arr { {"sym1"; 1}, {"sym2"; 2}, {"sym3"; 3} }

struct str_id {
  char* s;
  int id;
}

struct symbol_table {
  int count;
  struct str_id** arr;
}

struct symbol_table *symbol_table_create(void) {
  struct symbol_table *stt = malloc(sizeof(struct symbol_table));
  stt->count = 1;
  stt->arr =  malloc(sizeof(struct str_id*) * stt->count);
  return stt;

}
  • `struct symbol_table { int count = 1; ... }` is illegal. You cannot initialize `struct` fields in the type declaration in C. – Dai Apr 04 '20 at 23:43
  • yes sorry, I fixed that. Is the rest fine? –  Apr 04 '20 at 23:46
  • how is it undefined if I set it to one in the create functions –  Apr 04 '20 at 23:47
  • oh I see what you mean, I forgot to do stt->count. Thanks –  Apr 04 '20 at 23:51

1 Answers1

1
  • Use descriptive names for identifiers, not cryptic short names (like s and str_id).
  • Avoid Systems Hungarian Notation (i.e. naming or prefixing identifiers after their type or what-they-are as opposed to what-they-mean).
    • In your case, I assume str_id is an abbreviation for struct_id (or string_id) - which is a bad name because it's already immediately obvious that it's a struct (or contains a string).
    • It was popular right until the 1990s when programmers started using more powerful editors and IDEs that kept track of variable types - it just isn't needed today.
    • *
  • Always check if a heap allocation succeeded or failed by comparing calloc and malloc's return values to NULL. This can be done with if( some_pointer ) abort().
    • Don't use assert( some_pointer ) because assertions are only enabled in debug builds, use abort instead as it signifies abnormal program termination compared to exit.
  • Pass a size_t parameter so consumers can specify the size of the symbol table.
  • Quantities of objects held in memory should be expressed as size_t (e.g. array indexers). Never use int for this!
  • You need to put a semi-colon at the end of each struct definition.
  • Are you sure you want an array-of-pointers-to-structs and not just an array-of-structs? In this case you can use inline structs and use a single allocation for the array, instead of allocating each member separately.
  • Because you're performing custom allocation, you must also define a destructor function.
struct symbol_table_entry {
  char* symbolText;
  int   id;
};

struct symbol_table {
  size_t count;
  struct symbol_table_entry** entries;
};

struct symbol_table* create_symbol_table( size_t count ) {
    struct symbol_table* stt = malloc( sizeof(struct symbol_table) );
    if( !stt )
    {
        abort();
    }
    stt->count = count;
    stt->entries = calloc( count, sizeof(struct symbol_table_entry) );
    if( !stt->entries ) {
        free( stt );
        abort();
    }
    // Note that calloc will zero-initialize all entries of the array (which prevents debuggers showing garbage string contents) so we don't need to do it ourselves.
    return stt;
}

void destroy_symbol_table( struct symbol_table* stt, bool free_strings ) {
    if( stt->entries ) {
        if( free_strings ) {
            for( size_t i = 0; i < stt->count; i++ ) {
                free( stt->entries[i]->symbolText );
            }
        }
        free( stt->entries );
    }
    free( stt );
}
Dai
  • 141,631
  • 28
  • 261
  • 374
  • 1
    Wrong allocation with `stt->entries = calloc( count, sizeof(struct symbol_table_entry) );`. Suggest `stt->entries = calloc( count, sizeof stt->entries[0]);` to avoid getting the type wrong. – chux - Reinstate Monica Apr 05 '20 at 00:22
  • @chux-ReinstateMonica Thank you for the improvements, I've removed the guard around `free`. As for `sizeof`, I don't think using `sizeof( stt->entries[0] )` over `sizeof(struct symbol_table_entry)` presents much of an advantage in this situation though. – Dai Apr 05 '20 at 00:46
  • 1
    Dai, `sizeof(struct symbol_table_entry)` is the [wrong size](https://stackoverflow.com/questions/61036202/using-an-array-of-strings-to-implement-a-symbol-table-in-c/61036346?noredirect=1#comment107981784_61036346). `sizeof(struct symbol_table_entry*)` would have been correct. `sizeof( stt->entries[0] )` is more likely to be coded right (it avoids the original coding mistake of the wrong type, hence the advantage), easier to review and maintain. – chux - Reinstate Monica Apr 05 '20 at 02:08