Speller misspelled all words - c

All my words are misspelled when I run the program. It compiles but doesn't work as intended. I believe it has something to do with either the hash/check/or load function. I've checked it many times but can't figure out the problem. I've tried outputting the newWord variable to see if it returns a copy in all lower case but for some reason it doesn't print out. Maybe that means that all the values are NULL? So it might be a problem in my load function. I'll double check that again. Thanks in advance.
EDIT: Ran the debugger and I believe that the load function is returning correct values. I think it just has to be either my hash or check function.
#include <stdbool.h>
#include <strings.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
const unsigned int N = 17577;
// Hash table
node *table[N];
//words global variable
int words = 0;
// Returns true if word is in dictionary else false
bool check(const char *word)
{
int hashValue = hash(word);
if(hashValue == 17576){
return false;
}
node *cursor = table[hashValue];
printf("/%s", cursor->word);
//review my notes for this while loop
//basically tmp->next is pointing to the NEXT ITERATION
//and tmp is our CURRENT ITERATION
//so we want to check a value, if !true, continue
while(cursor->next != NULL){
if (strcasecmp(word, cursor->word) == 0){
return true;
}
else{
cursor = cursor->next;
}
}
return false;
}
unsigned int hash(const char *word)
{
const int ASCII_APOSTROPHE = 39;
int alphaIndex;
char *newWord = NULL;
//make it lowercase for easier read
for(int i = 0, n = strlen(word); i < n; i++){
if(isalpha(word[i]) == 1){
newWord[i] = tolower(word[i]);
}
else if(word[i] == ASCII_APOSTROPHE || isalpha(word[i]) == 2){
newWord[i] = word[i];
}
else{
//last index of array
return 17576;
}
}
if(strlen(newWord) >= 3){
alphaIndex = (word[0] - 97) + (word[1] - 97) + (word[2] - 97);
}
else if(strlen(newWord) == 2){
alphaIndex = (word[0] - 97) + (word[1] - 97);
}
else if(strlen(newWord) == 1){
alphaIndex = (word[0] - 97);
}
else{
alphaIndex = 0;
}
return alphaIndex;
}
// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
FILE *file = fopen(dictionary, "r");
if(file == NULL){
printf("Could not open file!\n");
return false;
}
char *word = malloc(LENGTH + 1);
while(fscanf(file, "%s", word) != EOF){
node *n = malloc(sizeof(node));
if(n == NULL){
printf("Not enough memory!");
return 1;
}
strcpy(n->word, word);
n->next = table[hash(word)];
table[hash(word)] = n;
size();
}
free(word);
fclose(file);
return true;
}
// Returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void)
{
words++;
return words;
}
// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
for(int i = 0; i < N; i++){
node *head = table[i];
if(head != NULL){
node *cursor = head->next;
node *deleteCursor = cursor;
while(cursor->next != NULL){
free(deleteCursor);
cursor = cursor->next;
deleteCursor = cursor;
}
}
}
return true;
}

There are two problems.
First one is that hash function is somehow running wrong. I did not debug it, I just replaced it with a very simple hash function (copied from https://stackoverflow.com/a/1469939/11000382).
unsigned int hash(const char *word)
{
char c = word[0];
int n = -1;
static const char *const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *p = strchr(alphabet, toupper((unsigned char)c));
if (p)
{
n = p - alphabet;
}
return n;
}
After this, I checked with $ ./speller texts/lalaland.txt but I was getting still more mispelled words (1738). However, it should be 955. Then I reviewed the check function, and I spotted a small bug.
This,
while(cursor->next != NULL){
Should be this,
while(cursor != NULL){
Then, it finds 955 mispelled words for lalaland.txt.

Related

C -> Valgrind -> Conditional jump or move depends on uninitialised value(s)

When i use valgrind i get: Conditional jump or move depends on uninitialised value(s) on line 37.
Line 37 is where the while loop starts, in the function "check".
I dont know what causes this problem, what it means or how to fix it.
Besides this there are no other problems.
This program is designed to take a dictionary and put it into a hash-table. then a text can be reviewed with the "check" function.
// Implements a dictionary's functionality
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <cs50.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;
int counter = 0;
// TODO: Choose number of buckets in hash table
const unsigned int N = 676;
// Hash table
node *table[N];
// Returns true if word is in dictionary, else false
bool check(const char *word)
{
int hash_value = hash(word);
node *cursor = table[hash_value];
while(cursor != NULL)
{
if(strcasecmp(cursor->word,word) == 0)
{
return true;
}
cursor = cursor->next;
}
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
int hash_0 = 0;
int hash_1 = 0;
for (int i = 65; i < 91; i++)
{
if (word[0] == i || word[0] == (i + 32))
{
hash_0 = (i - 65);
}
if (word[1] == i || word[1] == (i + 32))
{
hash_1 = (i - 65);
}
}
return ((hash_0 * 26) + hash_1);
}
// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
// opens the dictionary file
bool outcome = true;
FILE *dict = fopen(dictionary, "r");
if (dict == NULL)
{
outcome = false;
fclose(dict);
}
// read strings from file
char woord[LENGTH];
while (fscanf(dict, "%s", woord) != EOF)
// put string in node
{
node *pointer = malloc(sizeof(node));
counter++;
if (pointer == NULL)
{
outcome = false;
fclose(dict);
break;
}
strcpy(pointer -> word, woord);
// use the hash function
int hash_value = hash(pointer -> word);
// insert node into Hash Table
if (table[hash_value] == NULL)
{
table[hash_value] = pointer;
}
else
{
pointer -> next = table[hash_value];
table[hash_value] = pointer;
}
}
fclose(dict);
return outcome;
}
// 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)
{
bool outcome = true;
for (int i = 0; i < N; i++)
{
node *cursor = table[i];
node *destroyer = table[i];
while(cursor != NULL)
{
cursor = cursor -> next;
free(destroyer);
destroyer = cursor;
}
}
return outcome;
}

Cs50 pset5 - program crashing

I finished writing my code for speller. It compiles fine but the only output being printed is "Misspelled words". The words misspelled , words in text, words in dictionary does not get printed. I'm assuming its because the program crashes before then? Here is my code. If only I knew in which function or area my problem lies I might be able to fix it. Also, my hash function is to base hash indexes base on the first two letters of the word.
// Implements a dictionary's functionality
#include <ctype.h>
#include <stdbool.h>
#include <strings.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "dictionary.h"
int dsize = 0;
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// TODO: Choose number of buckets in hash table
const unsigned int N = 676;
// Hash table
node *table[N];
// Returns true if word is in dictionary, else false
bool check(const char *word)
{
// TODO
// hash word
int hashnumber = hash(word);
node *cursor = table[hashnumber];
// traversing linked list at that hash number
while(cursor != NULL)
{
if((strcasecmp(cursor->word, word) == 0))
{
return true;
}
}
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
int hash;
// TODO: Improve this hash function
for( int i = 97; i < 123; i ++)
{
hash = (i - 97) * 26;
// check asciivalue both uppercase and lowercase for first letter
if(word[0] == (char)i || word[0] == (char)(i - 32) )
{
for ( int j = 97; j < 122; j++)
{
// check asciivalue both uppercase and lowercase for second letter
if(word[1] == (char)j || word[1] == (char)(j - 32))
{
hash = hash + (j - 97);
}
}
}
}
return hash;
}
// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
for( int i = 0; i < N; i++)
{
table[i] = NULL;
}
FILE *input = fopen(dictionary, "r");
if (dictionary== NULL)
{
return false;
}
node *temp;
char word[LENGTH + 1];
while((fscanf(input, "%s", word)) != EOF)
{
temp = malloc(sizeof(node));
if(temp == NULL)
{
return false;
}
strcpy(temp->word, word);
int hashnumber = hash(word);
if (table[hashnumber] == NULL)
{
table[hashnumber] = temp;
}
else
{
temp->next = table[hashnumber];
table[hashnumber] = temp;
}
dsize++;
}
fclose(input);
return true;
}
// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
return dsize;
}
// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
// TODO
node *temp;
node *cursor;
for ( int i = 0; i < N; i++ )
{
cursor = table[i];
while(table[i] != NULL)
{
temp = cursor;
cursor = cursor->next;
free(temp);
}
if(cursor == NULL && i == (N - 1))
{
return true;
}
}
return false;
}

Check50 Errros: Not passing "handles substrings properly" tests. Check50 also can't check for a memory errors

I am working on Pset5 Speller. I made hashing function using the concept of binary numbers of base 26. So single alphabet words are stored in index 1-26, words containing apostrophes are stored in index 0 and the remaining are hashed using the first two alphabets. I tried to debug the code and run Valgrind on it still was unable to find the reason for failing of Substring tests any suggestions
// Implements a dictionary's functionality
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include <cs50.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 * 26) + 26 + 1 ;
// Hash table
node *table[N];
int numberofwords = 0;
// Returns true if word is in dictionary, else false
bool check(const char *word)
{
int index = hash(word);
node *checker;
checker = table[index];
while (checker != NULL)
{
int comp = strcasecmp(word, checker->word);
if (comp == 0)
{
return true;
}
else
{
checker = checker->next;
}
}
// TODO
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
int value = 0;
int length = strlen(word);
for (int i = 0; i < length; i++)
{
char c = word[i];
if (c == '\'')
{
value = 0;
return value;
}
}
if (length == 1)
{
value = tolower(word[0]) - 'a' + 1;
return value;
}
else
{
value = (26 * (tolower(word[1]) - 'a' + 1)) + (tolower(word[0]) - 'a' + 1);
return value;
}
}
// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
//open dictionary and loop till EOF
char buffer[LENGTH + 1];
FILE *temp = fopen(dictionary, "r");
if (temp == NULL)
{
return false;
}
for (int i = 0; i < N; i++)
{
table[i] = NULL;
}
while (fscanf(temp, "%s", buffer) != EOF)
{
node *temp_node = malloc(sizeof(node));
if (temp_node == NULL)
{
return false;
}
strcpy(temp_node->word, buffer);
temp_node->next = NULL;
//hash the word
int locate = hash(buffer);
if (table[locate] == NULL)
{
table[locate] = temp_node;
}
else
{
temp_node->next = table[locate];
table[locate] = temp_node -> next;
}
numberofwords++;
}
fclose(temp);
// TODO
return true;
}
// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
// TODO
return numberofwords;
}
// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
for (int i = 0; i < N; i++)
{
node *start = table[i];
node *freeer = start;
node *remember = start;
while (remember != NULL)
{
remember = remember->next;
free(freeer);
freeer = remember;
}
}
// TODO
return true;
}
here is the link to errors
https://submit.cs50.io/check50/ef7901d85e821af117b76bf7a2f43f44f38e3301
This looks like a problem in load:
temp_node->next = table[locate];
table[locate] = temp_node -> next;
It looks circular, they are pointing to each other.
Try debugging with the small dictionary and a text file that contains the 5 words in ACTUAL OUTPUT pane plus the word cat.
check50 did not check for memory errors because of the failed test ("can't check until a frown turns upside down")

Cs50 pset5 speller segmentation, memory errors

I'm doing the speller program and for the past few days I feel like I'm going in circles, receiving the same problems over and over again. Now, the error is free(): "invalid pointer
Aborted", most likely refering to the hash function, in which I use calloc,yet I can't understand what am I doing wrong there. Most likely there are multiple mistakes in my other functions, so tips regarding them would be very appreciated. I'll post the entire program, so I don't have to send snippets of it later. Completely lost here.
Ok, thanks to Tim Randal's answer the free() error looks fixed, however a segmentation error mentioned previously took his place.
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dictionary.h"
#include <strings.h>
#include <ctype.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 = 1000;
// Number of words loaded into the dictionary
int counter = 0;
// Hash table
node *table[N] = {0};
// Returns true if word is in dictionary, else false
bool check(const char *word)
{
size_t len = strlen(word);
char *lower = calloc(len+1, sizeof(char));
for (size_t i = 0; i < len; ++i) {
lower[i] = tolower((unsigned char)word[i]);
}
node *cursor = NULL;
cursor = table[hash(lower)];
while (cursor != NULL)
{
if (strcasecmp(cursor->word,lower) == 0)
{
free(lower);
return true;
}
else
{
cursor = cursor->next;
}
}
free(lower);
return false;
}
// Hashes word to a number
//hash function djb2 by Dan Bernstein
unsigned int hash(const char *word)
{
size_t len = strlen(word);
char *lower = calloc(len+1, sizeof(char));
for (size_t i = 0; i < len; ++i)
{
lower[i] = tolower((unsigned char)word[i]);
}
unsigned long hash = 5381;
int c;
while ((c = *lower++))
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
free(lower);
if (hash > N)
{
hash = hash % N;
return hash;
}
else
{
return hash;
}
}
// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
char word[LENGTH + 1];
node *new_node = NULL;
node *tmp = NULL;
FILE *file = fopen(dictionary,"r");
if (file == NULL)
{
printf("Could not open file\n");
return false;
}
while(fscanf(file, "%s",word) != EOF)
{
new_node = malloc(sizeof(node));
if (new_node == NULL)
{
printf("Not enough memory!\n");
return false;
}
strcpy(new_node->word,word);
unsigned int index = hash(word);
if(table[index] == NULL)
{
table[index] = new_node;
new_node->next = NULL;
}
else
{
tmp = table[index];
table[index] = new_node;
new_node->next = tmp;
}
counter++;
}
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)
{
const char *word = NULL;
int index = hash(word);
for(node *cursor = table[index]; cursor != NULL;cursor = cursor->next)
{
for(node *tmp = table[index]; tmp != NULL; tmp = tmp->next)
{
free(tmp);
}
free(cursor);
}
return true;
}
Here's one problem. I'm not saying it's the only one.
while ((c = *lower++))
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
free(lower);
You're freeing a pointer after changing it. You will need to copy lower to another pointer, which gets incremented and tested. The original lower needs to remember the address of the first byte allocated.
char* test = lower;
while ((c = *test++))
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
free(lower);

Have a problem when trying to check for my solution on pset5 CS50

I've been having some trouble coming up with the solution for an error. Basically my code builds a hash table using linked lists and arrays (in order to build a dictionary) and then spell checks .txt files in order to ensure that a word is in the dictionary. When I try to check it with CS50 check50 I get the following output :
:) speller compiles
:( handles most basic words properly
expected "MISSPELLED WOR...", not "MISSPELLED WOR..."
:) handles min length (1-char) words
:) handles max length (45-char) words
:) handles words with apostrophes properly
:) spell-checking is case-insensitive
:) handles substrings properly
:) program is free of memory errors
So as you can see I have a problem with the most basic words. I couldn't find a solution or a fix for my code.
Listing my code below :
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.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 = 27;
//Number of words on dictionary
int COUNTER = -1;
//Check if dictionary is loaded
bool LOAD = false;
// Hash table
node *table[N] = {NULL};
// Returns true if word is in dictionary else false
bool check(const char *word)
{
unsigned int k = hash(word);
node *trav = table[k];
while (trav->next != NULL)
{
if ((strcasecmp(word, trav->word)) == 0)
{
return true;
}
else
{
trav = trav->next;
}
}
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
// assign a number to the first char of buffer from 0-25
if ((isalpha(word[0]) > 0))
{
return tolower(word[0]) - 'a';
}
else
{
return 26;
}
}
// Loads dictionary into memory, returning true if successful else false
char c;
bool load(const char *dictionary)
{
FILE *file = fopen(dictionary, "r");
if (file == NULL)
{
LOAD = false;
return false;
}
char wordy[LENGTH + 1];
do
{
c = fscanf(file, "%s", wordy);
node *n = malloc(sizeof(node));
if (n == NULL)
{
LOAD = false;
return false;
}
strcpy(n->word, wordy);
n->next = NULL;
unsigned int i = hash(wordy);
if (table[i] == NULL)
{
table[i] = n;
}
else
{
node *p = table[i];
while (true)
{
if (p->next == NULL)
{
p->next = n;
break;
}
p = p->next;
}
}
COUNTER++;
}
while (c != EOF);
fclose(file);
LOAD = true;
return true;
}
// Returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void)
{
if (LOAD)
{
return COUNTER;
}
else
{
return 0;
}
}
// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
for (int i = 0; i < N; i++)
{
node *cursor = table[i];
while (cursor != NULL)
{
node *temp = cursor;
cursor = cursor->next;
free(temp);
}
}
LOAD = false;
return true;
}
Run ./speller dictionaries/small texts/cat.txt and you will get a seg fault. That is because check is trying to access trav->next when table[k] is NULL here while (trav->next != NULL). I'll let you work out (the very simple) correction.

Resources