0

So I'm having a problem where I have an array of char*s (declared as) char** where the array is dynamically allocated (by calloc), but the char*s within it are static.

This works fine for me until I attempt to free the array (during resizing), at which point I get

*** glibc detected *** ./hash_table_test: free(): invalid next size (normal): 0x0891f028 ***

I tried setting all of the ptrs in the array to NULL, but then I got the error

*** glibc detected *** ./hash_table_test: double free or corruption (!prev): 0x0815b028 ***

Here is the relevant code:

Table struct:

struct string_hash_table {

//Array of c-strings
char** table;
//number of elements in the table
int num_elements;
//size of table
int table_size;

//Primes
int *primes;
//Current position in primes array
int primes_index;
//the size of the primes array
int primes_size;
};
//TypeDefs--------------------------------
typedef struct string_hash_table HashTable;

Rehash Function (source of errors)

void rehash_string(HashTable *table) {

int prev_size = table->table_size;
int i;

table->table_size = table->table_size * 2;

//create new array
char** new_table = calloc(table->table_size, sizeof(char*));
printf("new table created\n");
int index;
printf("before loop prev_size is %d\n", prev_size);
//add all elements to new_table
for (i = 0; i < prev_size; i++) {
    printf("on %d\n", i);
    index = find_spot_string(new_table, table->table_size, table->table[i]);
    printf("after find_spot_string\n");
    if (index != -1) {
        table->table[index] = table->table[i];
    }
}

//free and swap
printf("before free\n");
empty_string_array(table->table, table->table_size);
free(table->table);
table->table = new_table;

Initialization of HashTable struct:

//Takes a HashTable and initializes it
void init_hash_table(HashTable *table) {

table->primes_index = 0;
table->num_elements = 0;
table->primes_size = 297;
table->primes = prime_list;

table->table_size = table->primes[0];
table->table = calloc(table->table_size, sizeof(char*));
}

declarations of static strings within:

    char* temp = "hello";
add_hash_table_string(table, temp);

temp = "luck";
add_hash_table_string(table, temp);

temp = "stuck";
add_hash_table_string(table, temp);

temp = "buck";
add_hash_table_string(table, temp);

temp = "muck";
add_hash_table_string(table, temp);

temp = "much";
add_hash_table_string(table, temp);

Currently I'm just testing my code here, everything works except for the rehashing function above. Anyone have any ideas? or leads I should follow?

EDIT: adding code for add_hash_table_string

void add_hash_table_string(HashTable *table, char* element) {

    //if non-null element, and element is not in the HashTable
    if (element != NULL && contains_hash_table_string(table, element) == 1) {

        //if the table is full
        if (table->table_size / 2 < table->num_elements) {

            rehash_string(table);
        }

        int index = find_spot_string(table->table, table->table_size, element);

        table->table[index] = element;
        table->num_elements++;
    }
}

EDIT2:

forgot to be precise, the error is occurring at the line with free(table->table) in the rehash function

Ethan
  • 1,206
  • 3
  • 21
  • 39
  • 2
    You're using a function `add_hash_table_string()` and we're supposed to guess what it does and how your code goes wrong? You need to provide an SSCCE ([Short, Self-Contained, Correct Example](http://sscce.org/)) so that people can help. Or you should consider using [`valgrind`](http://valgrind.org/). – Jonathan Leffler Dec 02 '12 at 21:21
  • Only the table was dynamically allocated, so what does `empty_string_array()` suppose to do? – Arjor Dec 02 '12 at 21:24
  • So my guess is that your `add_hash_table_string()` just takes the char-pointer (2nd arg) and puts it somewhere in a list and later deletes this pointers, which will fail because they are never allocated in the heap, because they reside in the const-string-pool. – pbhd Dec 02 '12 at 21:26
  • @arjor empty_string_array() just sets all of the ptrs in the table to NULL. I haven't quite figured out all of the nuances of how free works yet.. I thought it might help..it didn't lol – Ethan Dec 02 '12 at 21:32
  • @pbhd I don't free the individual elements in the array, just the array. – Ethan Dec 02 '12 at 21:32

1 Answers1

3

One possible problem, you free the old table with the new size

empty_string_array(table->table, table->table_size);

Another one might be

index = find_spot_string(new_table, table->table_size, table->table[i]);
printf("after find_spot_string\n");
if (index != -1) {
    table->table[index] = table->table[i];

If this is supposed to copy the entries to the new_table, it doesn't AFAICS. When index is greater than prev_size, you write beyond the end of table.

Olaf Dietsche
  • 72,253
  • 8
  • 102
  • 198
  • oh damn good eye!! I fixed that however and I still get the same segfault & error – Ethan Dec 02 '12 at 21:30
  • you sir are the man! The line table->table[index] = table->table[i]; is a typo! it's supposed to be new_table[index] = table->table[i]; Thanks for the help!! – Ethan Dec 02 '12 at 21:46