When I try to use speller.c with the large dictionary and the text 'hi', it says it could not load/open. When I use a large dictionary, it occasionally gives me a segmentation fault. Valgrind says:
==2378==
==2378== HEAP SUMMARY:
==2378== in use at exit: 1,240 bytes in 4 blocks
==2378== total heap usage: 5 allocs, 1 frees, 1,808 bytes allocated
==2378==
==2378== 224 bytes in 1 blocks are definitely lost in loss record 1 of 4
==2378== at 0x4C2AB80: malloc (in
/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2378== by 0x401250: load (dictionary.c:105)
==2378== by 0x40095D: main (speller.c:45)
==2378==
==2378== 224 bytes in 1 blocks are definitely lost in loss record 2 of 4
==2378== at 0x4C2AB80: malloc (in
/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2378== by 0x401295: load (dictionary.c:114)
==2378== by 0x40095D: main (speller.c:45)
==2378==
==2378== 224 bytes in 1 blocks are definitely lost in loss record 3 of 4
==2378== at 0x4C2CC70: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2378== by 0x40134A: load (dictionary.c:135)
==2378== by 0x40095D: main (speller.c:45)
==2378==
==2378== LEAK SUMMARY:
==2378== definitely lost: 672 bytes in 3 blocks
==2378== indirectly lost: 0 bytes in 0 blocks
==2378== possibly lost: 0 bytes in 0 blocks
==2378== still reachable: 568 bytes in 1 blocks
==2378== suppressed: 0 bytes in 0 blocks
==2378== Reachable blocks (those to which a pointer was found) are not shown.
==2378== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==2378==
==2378== For counts of detected and suppressed errors, rerun with: -v
==2378== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
My code lists every word as misspelled. When I try to free the memory, none of the loss bytes are retrieved. Here is my code:
// define trie
typedef struct node
{
bool is_word;
struct node *children[27];
}
node;
/**
* Returns true if word is in dictionary else false.
*/
bool check(const char* word)
{
// declare trav and root nodes and assign all pointers in root/trav to NULL
node* root = calloc(1, sizeof(node));
node* trav = root;
// declare string length
int wordLength = strlen(word);
for (int letter = 0; letter < wordLength; letter++)
{
int ind;
// set into ASCI if apostrophe
if (word[letter] == '\'')
{
// set index for easy math
ind = 26;
}
else
{
// set into ASCI into index variable for easy math/keeping
ind = tolower(word[letter]);
ind = ind - 'a';
}
// check if letter is NULL i.e. word is mispelled
if (trav->children[ind] == NULL)
{
// if so, return false
return false;
}
// if not at last letter, move to next node
else if (letter != wordLength - 1)
{
trav = trav->children[ind];
}
// if at end of word, return is_word
else if (letter == wordLength - 1)
{
return trav->is_word;
}
}
return false;
}
/**
* Loads dictionary into memory. Returns true if successful else false.
*/
bool load(const char* dictionary)
{
//set wordCount
int wordCount = 0;
// open dictionary
FILE* dic = fopen(dictionary, "r");
// check to make sure all is good
if (dic == NULL)
{
printf("Could not open dictionary.\n");
return false;
}
// alert user that all is good
// printf("Successfully opened dictionary!!!\n");
// declare root node
node* root = malloc(sizeof(node));
// assign NULL to all root -> children pointers
for (int num = 0; num < 27; num++)
{
root->children[num] = NULL;
}
// declare trav node
node* trav = malloc(sizeof(node));
trav = root;
// assign NULL to all trav -> children pointers
for (int ind = 0; ind < 27; ind++)
{
trav->children[ind] = NULL;
}
// iterate over every letter in trie
for (char c = fgetc(dic); c != EOF; c = fgetc(dic))
{
int l = tolower(c);
// check for all letters
if (l != '\'' && l != '\n')
{
// check if letter is NULL, like Z.C. recommended in walkthrough
if (trav->children[l - 'a'] == NULL)
{
// malloc new node and make it into ASCI
trav->children[l - 'a'] = calloc(1, sizeof(node));
trav->children[l - 'a'] = NULL;
}
// move to next node
trav = trav->children[l - 'a'];
}
// check for end of word
if (l == '\n')
{
// increase wordCount size for size function
wordCount++;
// return true for true (pretty straight-forward)
return true;
}
}
// close dictionary
fclose(dic);
return false;
}
Thank you in advance!
UPDATE Here is my updated code:
// define trie
typedef struct node
{
bool is_word;
struct node *children[27];
}
node;
// declare root & trav
node* root;
node* trav;
// initialize wordCount
int wordCount;
/**
* Returns true if word is in dictionary else false.
*/
bool check(const char* word)
{
// declare trav and root nodes and assign all pointers in root/trav to NULL
// root = calloc(1, sizeof(node));
trav = root;
// declare string length
int wordLength = strlen(word);
for (int letter = 0; letter < wordLength; letter++)
{
int ind;
// set into ASCI if apostrophe
if (word[letter] == '\'')
{
// set index for easy math
ind = 26;
}
else
{
// set into ASCI into index variable for easy math/keeping
ind = tolower(word[letter]);
ind = ind - 'a';
}
// check if letter is NULL i.e. word is mispelled
if (trav->children[ind] == NULL)
{
// if so, return false
return false;
}
// if not at last letter, move to next node
else if (letter != wordLength - 1)
{
trav = trav->children[ind];
}
// if at end of word, return is_word
else if (letter == wordLength - 1)
{
return trav->is_word;
}
}
return false;
}
/**
* Loads dictionary into memory. Returns true if successful else false.
*/
bool load(const char* dictionary)
{
//set wordCount
wordCount = 0;
// open dictionary
FILE* dic = fopen(dictionary, "r");
// check to make sure all is good
if (dic == NULL)
{
printf("Could not open dictionary.\n");
return false;
}
// alert user that all is good
// printf("Successfully opened dictionary!!!\n");
// declare root node
root = calloc(1, sizeof(node));
// assign NULL to all root -> children pointers
for (int num = 0; num < 27; num++)
{
root->children[num] = NULL;
}
// declare trav node
trav = calloc(1, sizeof(node));
trav = root;
// assign NULL to all trav -> children pointers
for (int ind = 0; ind < 27; ind++)
{
trav->children[ind] = NULL;
}
// iterate over every letter in trie
for (char c = fgetc(dic); c != EOF; c = fgetc(dic))
{
int l = tolower(c);
// check for all letters
if (l != '\'' && l != '\n')
{
// check if letter is NULL, like Z.C. recommended in walkthrough
if (trav->children[l - 'a'] == NULL)
{
// calloc new node and make it into ASCI
trav->children[l - 'a'] = calloc(1, sizeof(node));
trav->children[l - 'a'] = NULL;
}
// move to next node
trav = trav->children[l - 'a'];
}
// check for end of word
if (l == '\n')
{
// increase wordCount size for size function
wordCount++;
// return true for true (pretty straight-forward)
return true;
}
}
// close dictionary
fclose(dic);
return false;
}
=2378== ==2378== For counts of detected and suppressed errors, rerun with: -v
in the valgrind output. You can get more detailed info from valgrind by using this command line:valgrind -v --leak-check=full --show-leak-kinds=all --track-origins=yes