0
// Implements a dictionary's functionality #include <ctype.h> #include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include "dictionary.h" // Represents a node in a hash table typedef struct node { char word[LENGTH + 1]; struct node *next; } node; // Number of buckets in hash table const unsigned int N = 26; // Create counter for size int counter = 0; // Hash table node *table[N]; // Returns true if word is in dictionary, else false bool check(const char *word) { // Create node for use in searching through linked list node *cursor = malloc(sizeof(node)); int temp_word = hash(word); cursor = table[temp_word]; while (cursor != NULL) { if (strcasecmp(cursor->word, word) == 0) { return true; free(cursor); } cursor = cursor->next; } free(cursor); return false; } // Hashes word to a number unsigned int hash(const char *word) { // Hash function return toupper(word[0]) - 'A'; } // Loads dictionary into memory, returning true if successful, else false bool load(const char *dictionary) { // Open required file FILE *source = fopen(dictionary, "r"); if (source == NULL) { return false; } // Read each string within the file char buffer[LENGTH + 1]; while (fscanf(source, "%s", buffer) != EOF) { // Create new node and assign read string node *n = malloc(sizeof(node)); if (n == NULL) { return false; } strcpy(n->word, buffer); n->next = NULL; // Carry out hash function int temp_answer = hash(buffer); if (table[temp_answer] == NULL) { table[temp_answer] = n; n->next = NULL; } else { n = table[temp_answer]->next; table[temp_answer] = n; } counter++; } fclose(source); return true; } // Returns number of words in dictionary if loaded, else 0 if not yet loaded unsigned int size(void) { return counter; } // Unloads dictionary from memory, returning true if successful, else false bool unload(void) { // Create nodes to allow freeing memory without disrupting links node *temp = malloc(sizeof(node)); node *cursor = malloc(sizeof(node)); if (temp == NULL && cursor == NULL) { return false; } for (int i = 0; i < N; i++) { cursor = table[i]; temp = cursor; cursor = cursor->next; free(temp); } free(cursor); return true; } 

Valgrind states "All heap blocks were freed -- no leaks are possible" so that worked okay but when I run check50 I get the following errors:

:) dictionary.c exists

:) speller compiles

:( handles most basic words properly expected "MISSPELLED WOR...", not "MISSPELLED WOR..."

:( handles min length (1-char) words expected "MISSPELLED WOR...", not "MISSPELLED WOR..."

:( handles max length (45-char) words expected "MISSPELLED WOR...", not "MISSPELLED WOR..."

:( handles words with apostrophes properly expected "MISSPELLED WOR...", not "MISSPELLED WOR..."

:( spell-checking is case-insensitive expected "MISSPELLED WOR...", not "MISSPELLED WOR..."

:( handles substrings properly expected "MISSPELLED WOR...", not "MISSPELLED WOR..."

:| program is free of memory errors can't check until a frown turns upside down

Thanks in advance for any advice!!

2
  • quick question: did you change speller.c at all? Commented Aug 31, 2024 at 23:19
  • No speller.c was not altered in any way. Commented Aug 31, 2024 at 23:46

1 Answer 1

3

Time for a little tough love here. From time to time, new programmers in this class are under the incorrect impression that getting a program to compile means success. It doesn't. Just because a program compiles (and even if it has no memory leaks) doesn't mean it runs correctly. It can be full of bugs! Programs have to be thoroughly tested to validate that all the code works as expected, using input data designed to test specific parts of the code as well as the program as a whole.

I tested your program and found that it doesn't work. If you run it with a small dictionary as both dictionary and input, it rejects all the words as misspelled. Then, it produces a segmentation fault.

Let's deal with the seg fault first. The unload function is broken. In each loop, it resets to the first element in the linked list instead of stepping through it. That means that on the second pass, the code is trying to free memory that's already freed.

Take note of this, it's very important. When free(my_pointer) is executed, the memory at the address stored in my_pointer is freed, but my_pointer is NOT reset to NULL. It retains the same address as before. It's simply no longer valid. You could set it to NULL at that point, or to something valid at that point, unless you know it won't be used again, or you know it will be set to something else later and there's no chance of it being inadvertently accessed.

Hint: you only need one temp var, and table[i] can be used instead of the second temp var.

Also, think about this. What happens if either temp or cursor is null but not both?

If you want to leave fixing unload() for later, you can insert return true; as the first line in the unload function temporarily while you work on other stuff. It will bypass the rest of the function. You can't really work on it until load() is fixed anyways.

Speaking of return, look at the return true statement in check(). Knowing that a return statement immediately terminates a function, will the free() statement that follows ever be executed??? ;-)

Now, the main problem is in load. Look at the following code:

 else { n = table[temp_answer]->next; table[temp_answer] = n; 

Think carefully about what it does. Let's assume that table[temp_answer] is null because there are no entries yet. table[]->next should also be null. The code sets n to null and then sets table[temp_answer] to null. So, in the end, everything is set to null. The correct code is this:

 else { n->next = table[temp_answer]; table[temp_answer] = n; 

BTW, did the code initialize all the entries in table[] and table[]->next to NULL? Best practice is to always do so, just in case.

There may be more issues, but this covers most of the problems.

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

1
  • Thanks so much for the tough love, I really appreciate your feedback!! :-) Commented Sep 1, 2024 at 13:23

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.