Home > Software design >  What is causing this Segmentation Fault in C?
What is causing this Segmentation Fault in C?

Time:10-21

I'm working on a program for a course of mine, so I'd appreciate it if answers were kept abstract. I am working on a key-value hash table in C that stores a string for a key and an int for the value. I'm getting a segmentation fault on the helper function for the put() method. Below is the problematic code. I've changed it slightly for academic honesty purposes, and I've only included the parts that lead up to the error. I've tried adjusting how I dereference or don't dereference table[index]->symbol, but to no avail. I'm thinking that that line that the SEGFAULT is happening on probably isn't the culprit, but I'm struggling to find where it might otherwise appear. Any help on this matter would be greatly appreciated, be it GDB hints, high-level explanations, etc. I just ask that code snippets be kept vague so that I actually learn, rather than just being told an answer. Thank you!

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
 
typedef struct elem_t elem_t;
struct elem_t {
    const char* symbol;
    void* data;
    elem_t* next;
};
 
typedef struct {
    size_t length;
    size_t size;
    elem_t** table;
} table_t;
 
static unsigned int hash(const char *str) {
    const unsigned int p = 16777619;
    unsigned int hash = 2166136261u;
    while (*str) {
        hash = (hash ^ *str) * p;
        str  = 1;
    }
    hash  = hash << 13;
    hash ^= hash >> 7;
    hash  = hash << 3;
    hash ^= hash >> 17;
    hash  = hash << 5;
    return hash;
}
 
 
void *createTable(int sizeHint) {
    table_t* table;
    table = malloc(sizeof(table));
    if (table == NULL) {
        return NULL;
    }
    table->length = 0;
    table->size = sizeHint * 2;
 
    table->table = calloc(table->size, sizeof(elem_t*));
    if (table->table == NULL) {
        free(table);
        return NULL;
    }
 
    return table;
}

static const char* putHelper(elem_t** table, size_t size, const char* symbol, void* data, size_t* length) {
    unsigned int hashVal = hash(symbol);
    size_t index = (size_t)(hashVal & (unsigned int)(size - 1));
 
    while (table[index]->symbol != NULL) { // !!! SEGFAULT HERE !!!
        if (strcmp(symbol, table[index]->symbol) == 0) { // collision
            elem_t* cur = table[index];
            while (table[index]->next != NULL) { // separate chaining
                cur = cur->next;
            }
            elem_t* newElem = (elem_t*)malloc(sizeof(elem_t)); // make new element to hang at the end of the chain
            cur->next = newElem;
            newElem->data = data;
            newElem->symbol = symbol;
            newElem->next = NULL;
            return newElem->symbol;
        }
        index  ;
        if (index >= size) {
            index = 0;
        }
    }
 
    if (length != NULL) {
        symbol = strdup(symbol);
        if (symbol == NULL) {
            return NULL;
        }
        (*length)  ;
    }
    table[index]->symbol = (char*)symbol;
    table[index]->data = data;
    return symbol;
}
 
int put(void *tableHandle, const char *symbol, void *data) {
    table_t* table = (table_t*)tableHandle;
    if (data == NULL) {
        return 0;
    }
 
    table->length  ;
    const char* result = putHelper(table->table, table->size, symbol, data, &table->length);
    if (result != NULL) {
        return 1;
    } else {
        return 0;
    }
}
 
 
int main() {
    table_t* table = createTable(200);
    int result = put(table, "t1", 25);
    if (result == 0) {
        printf("put failed");
        return 1;
    }
}

CodePudding user response:

You allocated an array of null pointers

table->table = calloc(table->size, sizeof(elem_t*));

and then you are using null pointer tp access memory

while (table[index]->symbol != NULL) { // !!! SEGFAULT HERE !!!
       ^^^^^^^^^^^^^^^^^^^^

So the program crashes.

And as @bbbbbbbbb pointed out you allocated memory only for a pointer

table = malloc(sizeof(table));

CodePudding user response:

You by the least need to change this:

    table_t* table;
    table = malloc(sizeof(table));

To this:

    table_t* table;
    table = malloc(sizeof(*table));

Or to this:

    table_t* table;
    table = malloc(sizeof(table_t));
  • Related