0

I've grinding away at this one problem for a couple of days now, and can't quite work out what's going wrong. My code passes check50. The output is fine. I'm relatively happy with how quickly it runs.

I can't however, manage to free 1 remaining 568 byte block of memory.

Here is what valgrind says:

==13511== 
==13511== HEAP SUMMARY:
==13511==     in use at exit: 568 bytes in 1 blocks
==13511==   total heap usage: 143,093 allocs, 143,092 frees, 8,014,232 bytes allocated
==13511== 
==13511== 568 bytes in 1 blocks are still reachable in loss record 1 of 1
==13511==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13511==    by 0x4EA537C: __fopen_internal (iofopen.c:73)
==13511==    by 0x40132E: load (dictionary.c:99)
==13511==    by 0x400A0D: main (speller.c:45)
==13511== 
==13511== LEAK SUMMARY:
==13511==    definitely lost: 0 bytes in 0 blocks
==13511==    indirectly lost: 0 bytes in 0 blocks
==13511==      possibly lost: 0 bytes in 0 blocks
==13511==    still reachable: 568 bytes in 1 blocks
==13511==         suppressed: 0 bytes in 0 blocks
==13511== 
==13511== For counts of detected and suppressed errors, rerun with: -v
==13511== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Here's my load function:

bool load(const char* dictionary)
{
// open dictionary from file
FILE* dicptr = fopen(dictionary,"r");

if (dicptr == NULL)
{
    printf("Couldn't open dictionary.\n");
    return false;
}

// set all node pointers in hashTable array to NULL
for (int i = 0; i < HASH_TABLE_SIZE; i ++)
{
    hashTable[i] = NULL;
}

// loop until end of end of dictionary file
while(!feof(dicptr))
{
    // create pointer to node on the heap and set its 'next' pointer to NULL
    node* newNode = malloc(sizeof(node));
    newNode->next = NULL;

    // load string from dictionary into newNode->word and check for end of dictionary file
    if (fscanf(dicptr, "%s", newNode->dicWord) != 1)
    {   
        // if end of dictionary file, free newNode and return true
        free(newNode);
        return true;
    }
    // store index returned from hash function as int
    int hashIndex = hashFunction(newNode->dicWord);

    // set hashTable[hashIndex] to newNode if that array entry is null
    if (hashTable[hashIndex] == NULL)
    {
        hashTable[hashIndex] = newNode;
    }

    // else set next pointer to previous head of linked list and make newNode the new head of the list
    else 
    {
        node* head = hashTable[hashIndex];
        newNode->next = head;
        head = newNode;
        hashTable[hashIndex] = head;
    }

    // update dictionary word count
    wordCount ++;
}
return true;

}

And here's my unload function:

bool unload(void)
{
for (int i = 0; i < HASH_TABLE_SIZE; i ++)
{
    // initialise a new node pointer that will traverse the list and set it to index 'i' of hash table
    node* trav = hashTable[i];

    // traverse through list freeing nodes until reaching a null pointer
    while (trav != NULL)
    {
        node* temp = trav;
        trav = trav->next;
        free(temp);
    }

    // ensure that index 'i' of the hash table is set to null
    hashTable[i] = NULL;
}
return true;

}

According to valgrind, my load function is allocating 2 more blocks of memory than there are words in the dictionary.

I can understand 1 of those - the code allocates memory for a new node before checking if it has reached the end of the dictionary file, but I then subsequently free that memory block. So where is this other block being created and how do I free it? It's driving me insane.

A huge thank you to anyone that can help!

7

Hmmm..... 568 bytes in 1 block.... sounds like a file pointer.

Did we forget to close an open file somewhere???? ;-)

Side note: valgrind usually tells you how you can get more information, with something like

For counts of detected and suppressed errors, rerun with: -v

If this answers your question, please click on the check mark to accept. Let's keep up on forum maintenance. ;-)

1
  • Argghhh! That was so annoyingly simple. Thanks so much. You just saved me a few more hours working through dbg. I salute you!
    – tom-p-uk
    Aug 25 '16 at 3:55
0

I solved it with a fclose([dictionary pointer name]); at the end of the load function:

bool load(const char *dictionary)
{
    FILE* dicp = fopen(dictionary, "r");
    ...

    fclose(dicp);
    return true;
}

[EDIT: Formatting and Unrelated solution code removed for Honor Code compliance.]

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .