I'm making a program that reads a given dictionary into a trie tree, and then
performs auto complete on a string inputted by the user. When I use the dictionary file that I am required to use (~100,000 words) I get a segmentation fault. I can't seem to figure out what is causing the segmentation fault. Any help would be appreciated.
typedef struct trieTree {
int data;
struct trieTree *array[26];
}trieTree;
insert function:
trieTree* insert_tree(trieTree *t, char *s, int val)
{
int i;
trieTree *p;
if (strlen(s) == 0)
return t;
if (t == NULL)
t = new_tree(t);
p = t;
for (i = 0; i < strlen(s); ++i) {
if (p->array[s[i] - 'a'] == NULL)
p->array[s[i] - 'a'] = malloc(sizeof (trieTree));
p = p->array[s[i] - 'a'];
}
p->data = val;
return t;
}
Filling the tree:
trieTree* load_tree(trieTree *t, char *file)
{
char s[MAX];
FILE *f = fopen(file, "r");
if (f == NULL)
printf("Error! File not found.");
else
while (feof(f) == 0) {
fscanf(f, "%s", s);
t = insert_tree(t, s, 1);
}
return t;
}
Main function
int main()
{
trieTree t;
new_tree(&t);
load_tree(&t, "dict.txt");
char word[100];
printf("Enter word: ");
scanf("%s", word);
char dat[100] = "";
search_tree(&t, word, dat);
return 0;
}
trieTree* new_tree(trieTree *t)
{
int i;
t = malloc(sizeof (trieTree));
for (i = 0; i < 24; ++i)
t->array[i] = 0;
return t;
}
Your function new_tree() returns a pointer to allocated memory but the returned value is ignored. That's a memory leak, and your code continues to use an uninitialized variable. That's a problem!
int main()
{
trieTree t;
new_tree(&t);
load_tree(&t, "dict.txt");
…
trieTree* new_tree(trieTree *t)
{
int i;
t = malloc(sizeof(trieTree));
for (i = 0; i < 24; ++i)
t->array[i] = 0;
return t;
}
The 24 in the function should be 26, of course. But the function allocates memory and assigns it to the local pointer (original set to point to t in main(), but the malloc() zaps that value). That pointer is returned, but the return is ignored. The variable t in main() is still uninitialized, but it is passed to the load_tree() function.
Frankly, you need:
int main()
{
trieTree *tp = new_tree();
load_tree(&t, "dict.txt");
…
trieTree* new_tree(void)
{
int i;
trieTree *t = malloc(sizeof(trieTree));
if (t == 0)
{
fprintf(stderr, "memory allocation failure\n");
exit(EXIT_FAILURE);
}
for (i = 0; i < 26; ++i)
t->array[i] = 0;
return t;
}
Note that errors should be reported on the standard error channel; that is what it's for. And that every memory allocation should be checked, because if you don't check, it will fail and your program will crash.
There are probably a lot of other problems; I've not investigated them all. This should get you further before crashing.
This seems to work for me, though admittedly I only tested it on a 'dictionary' of 257 words.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { MAX = 1024 };
typedef struct trieTree
{
int data;
struct trieTree *array[26];
} trieTree;
static trieTree *new_tree(void)
{
int i;
trieTree *t = malloc(sizeof(trieTree));
if (t == 0)
{
fprintf(stderr, "malloc for %zu bytes failed\n", sizeof(trieTree));
exit(EXIT_FAILURE);
}
t->data = 0;
for (i = 0; i < 26; ++i)
t->array[i] = 0;
return t;
}
static trieTree *insert_tree(trieTree *t, char *s, int val)
{
int i;
trieTree *p;
if (strlen(s) == 0)
return t;
if (t == NULL)
t = new_tree();
p = t;
int len = strlen(s);
for (i = 0; i < len; ++i)
{
if (p->array[s[i] - 'a'] == NULL)
p->array[s[i] - 'a'] = new_tree();
p = p->array[s[i] - 'a'];
}
p->data = val;
return t;
}
static trieTree *load_tree(trieTree *t, char *file)
{
char s[MAX];
FILE *f = fopen(file, "r");
if (f == NULL)
{
fprintf(stderr, "Error! File not found.");
exit(EXIT_FAILURE);
}
else
{
while (fscanf(f, "%s", s) == 1)
t = insert_tree(t, s, 1);
fclose(f);
}
return t;
}
static void print_trie(trieTree *t, char *pad)
{
int len = strlen(pad);
char space[len + 3];
memset(space, ' ', len + 2);
space[len + 2] = '\0';
for (int i = 0; i < 26; i++)
{
if (t->array[i] != 0)
{
printf("%s%c\n", pad, i + 'a');
print_trie(t->array[i], space);
}
}
}
static void free_trie(trieTree *t)
{
if (t != 0)
{
for (int i = 0; i < 26; i++)
free_trie(t->array[i]);
free(t);
}
}
int main(void)
{
trieTree *tp = new_tree();
if (tp != 0)
{
tp = load_tree(tp, "dict.txt");
print_trie(tp, "");
free_trie(tp);
}
return 0;
}
I believe it is leak free, too.
Note that this code will crash and burn if any of the input words contains any upper-case letters, or digits, or punctuation. It only handles lower-case and white space; anything else is an unchecked disaster waiting to devastate your program. That's because I've not done any substantive work in the insert_tree() function. You need to worry about 'invalid' characters in that function, probably by case-converting upper-case letters to lower-case and ignoring anything that's not a letter.
Related
I'm having some trouble with understanding the problem in my code that caused the segmentation fault. The error message below points to the line: containing table[tableIndex] = n;. I have checked that the maximum value of tableIndex is lower than the size of table[], therefore eliminating the possibility of accessing an element of an array beyond the size of the array. Please take a look at my code for the load function and I would appreciate it if someone could provide an answer to this problem. Thanks in advance.
Process terminating with default action of signal 11 (SIGSEGV)
==960== Bad permissions for mapped region at address 0x403D90
==960== at 0x401BF7: load (dictionary.c:119)
==960== by 0x40129E: main (speller.c:40)
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// Number of buckets in hash table
const unsigned int N = 702;
// Hash table
node *table[N];
int wordCount = 0;
bool load(const char *dictionary) {
for (int i = 0; i < N; i++) {
table[i] = NULL;
}
int wordIndex = 0;
int tableIndex = 0;
char tmpW[LENGTH + 1];
for (int i = 0; i <= LENGTH; i++) {
tmpW[i] = 1;
}
char c;
FILE *file = fopen(dictionary, "r");
while (fread(&c, sizeof(char), 1, file)) {
if (c != '\n') {
tmpW[wordIndex] = c;
wordIndex++;
}
else if (c == '\n') {
wordIndex = 0;
node *n = malloc(sizeof(node));
if (n == NULL) {
return 1;
}
tableIndex = hash(tmpW);
if (tableIndex > test) {
test = tableIndex;
}
for (int i = 0; i < LENGTH; i++) {
n->word[i] = tmpW[i];
}
n->word[LENGTH] = '\0';
n->next = table[tableIndex];
table[tableIndex] = n;
wordCount++;
}
else {
wordCount = 0;
fclose(file);
unload();
return false;
}
}
fclose(file);
return true;
}
I have a school assignment in which we have to read a text file, sort the words by alphabetical order and write the result into a new text file.
I've already got a program that can read the file and print it on the screen and a different program to sort words which you have to type in. Now I'm trying to merge these two programs, so that the data which been read out of the file will be put into the sorting program.
The program that we use to make the code is called CodeBlocks. Below are the two programs. I hope that you can give me advice and an example how to fix this because I tried everything I know but couldn't get it working.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#define MAX_NUMBER_WORDS 100
char* ReadFile(char *filename)
{
char *buffer = NULL;
int string_size, read_size;
FILE *handler = fopen(filename, "r");
if (handler)
{
//seek the last byte of the file
fseek(handler, 0, SEEK_END);
//offset from the first to the last byte, or in other words, filesize
string_size = ftell(handler);
//go back to the start of the file
rewind(handler);
//allocate a string that can hold it all
buffer = (char*)malloc(sizeof(char) * (string_size + 1));
//read it all in one operation
read_size = fread(buffer, sizeof(char), string_size, handler);
//fread doesnt set it so put a \0 in the last position
//and buffer is now officialy a string
buffer[string_size] = '\0';
if (string_size != read_size)
{
//something went wrong, throw away the memory and set
//the buffer to NULL
free(buffer);
buffer = NULL;
}
}
return buffer;
}
int numberOfWordsInDict(char **dict)
{
int i;
for (i = 0; i < MAX_NUMBER_WORDS; i++)
{
if (dict[i] == NULL)
return i;
}
return MAX_NUMBER_WORDS;
}
void printDict(char **dict)
{
int i;
printf("Dictionary:\n");
for (i = 0; i < numberOfWordsInDict(dict); i++)
printf("- %s\n", dict[i]);
if (numberOfWordsInDict(dict) == 0)
printf("The dictionary is empty.\n");
}
void swapWords(char **dict, char *word, char *word2)
{
int i, p1 = -1, p2 = -1;
char *tmp;
for (i = 0; i < numberOfWordsInDict(dict); i++)
{
if (strcmp(dict[i], word) == 0)
p1 = i;
if (strcmp(dict[i], word2) == 0)
p2 = i;
}
if (p1 != -1 && p2 != -1)
{
tmp = dict[p1];
dict[p1] = dict[p2];
dict[p2] = tmp;
}
}
void sortDict(char **dict)
{
int swap;
int i = 0;
do
{
swap = 0;
for (i = 0; i < numberOfWordsInDict(dict) - 1; i++)
{
if (strcmp(dict[i], dict[i + 1]) > 0)
{
swapWords(dict, dict[i], dict[i + 1]);
swap = 1;
}
}
} while (swap == 1);
}
void splitSentenceToWords(char **words, char *sentence)
{
int p1 = 0, p2 = 0;
int nrwords = 0;
char *word;
while (sentence[p2] != '\0')
{
if (isspace(sentence[p2]) && p1 != p2)
{
word = (char*)malloc(sizeof(char)*(p2 - p1 + 1));
words[nrwords] = word;
strncpy(words[nrwords], &sentence[p1], p2 - p1);
words[nrwords][p2 - p1] = '\0';
nrwords++;
p1 = p2 + 1;
p2 = p1;
}
else
{
p2++;
}
}
if (p1 != p2)
{
word = (char*)malloc(sizeof(char)*(p2 - p1 + 1));
words[nrwords] = word;
strncpy(words[nrwords], &sentence[p1], p2 - p1);
words[nrwords][p2 - p1] = '\0';
nrwords++;
p1 = p2 + 1;
p2 = p1;
}
}
int main(void)
{
char sentence[1024];
char *dict[MAX_NUMBER_WORDS] = {};
char *words[MAX_NUMBER_WORDS] = {};
char *string = ReadFile("test.txt");
if (string)
{
puts(string);
free(string);
}
//printf("Type een zin in: ");
scanf("%[^\n]s", &sentence);
splitSentenceToWords(words, &sentence);
printDict(words);
printf("Words has been sorted\n");
sortDict(words);
printDict(words);
return 0;
}
You are on the right track. The problem is that after your read in your file, you are not using the input to build your word list. Instead of;
splitSentenceToWords(words, &sentence);
try:
splitSentenceToWords(words, &string);
Delete
free(string)
This will get you started. You will have to clean this up when you understand it a bit better.
Incorrect code to check if a word can be made of smaller given words (word break).This is the code I wrote for the above mentioned problem, however an online judge declares it as incorrect, what could be the possible reasons? And how should I modify my code?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Node structure */
typedef struct node {
int letter[26];
struct node* next[26];
int is_word;
} node;
/* Create node */
node* getnode(void) {
node* p = malloc(sizeof(node));
int i;
for (i = 0; i < 1004; i++) {
p->letter[i] = 0;
p->next[i] = NULL;
}
p->is_word = 0;
return p;
}
/* make dictionary */
void fill_dictionary(char word[], node* start) {
int len = strlen(word), i;
node* temp = start;
for (i = 0; i < len; i++) {
if (temp->letter[word[i] % 'a'] == 0) {
temp->letter[word[i] % 'a'] = 1;
temp->next[word[i] % 'a'] = getnode();
temp = temp->next[word[i] % 'a'];
} else {
temp = temp->next[word[i] % 'a'];
}
}
temp->is_word = 1;
return;
}
int spell_check(char line[100003], node* start) {
int len = strlen(line), i, flag = 0;
node* temp = start;
for (i = 0; i < len; i++) {
if (temp->letter[line[i] % 'a'] == 0) {
return 1;
} else {
temp = temp->next[line[i] % 'a'];
flag = 0;
if (temp->is_word == 1) {
flag = 1;
temp = start;
}
}
}
if (flag == 1) {
return 0;
} else {
return 1;
}
}
int main(void) {
int n, i, ans, m;
scanf("%d %d", &n,&m); // no. of words in dictionary
node* start = getnode();
for (i = 0; i < n; i++) {
char word[11]; // max length of dictionary word
scanf("%s", word);
fill_dictionary(word, start);
}
scanf("%d", &n); // no. of lines to be checked
for (i = 0; i < n; i++) {
char line[100003]; // max length of a line
scanf("%s", line);
ans = spell_check(line, start);
if (ans == 0) {
printf("YES\n");
} else {
printf("NO\n");
}
}
return 0;
}
Here's one way to to it. This compiles and runs. It displays the parsed result. It tries to read the dictionary from a file called "dictionary.text" in the current directory. You can change it to put the dictionary wherever you want. I commented it heavily to help you understand it but it has some subtle C things you may need to really think about and figure out. One bit of advice: Name everything in a program as extremely accurately for what it is/does as possible (but reasonably succinct). That will help immensely when trying to debug or figure out what you did wrong. Careless names really make code confusing and hard to debug.
Good luck!
Example:
$ gcc -o wordsplitter wordsplitter.c
$ wordsplitter xyzhellogoodbyefoodogcatpigcarwhereareyouhorse
xyz "hello" "goodbye" foo "dog" "cat" pigcar "where" "are" "you" horse
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DICTIONARY_FILEPATH "dictionary.txt"
#define MAX_WORD_SIZE 100
/*
* Error codes (usually this is put in a header file and included)
*/
#define SUCCESS 0
#define FILE_NOT_FOUND -1
#define OUT_OF_MEMORY -2
typedef struct word {
struct word *next;
char *word;
} word_t;
word_t *dictionaryListhead = NULL;
typedef struct wordsubcomponent {
struct wordsubcomponent *next;
char *text;
int isDictionaryWord;
} wordsubcomponent_t;
int
loadDictionaryFromFile(char *filename, word_t **listhead)
{
char wordFromFile[MAX_WORD_SIZE];
word_t *lastWordStored = NULL;
FILE *dictionaryFile = fopen(filename, "r");
if (dictionaryFile == NULL) {
return FILE_NOT_FOUND;
}
while(fgets(wordFromFile, sizeof(wordFromFile), dictionaryFile)) {
word_t *newDictionaryWordNode;
if ((newDictionaryWordNode = calloc(sizeof(word_t), 1)) == NULL) { // calloc automatically zeroes memory
return OUT_OF_MEMORY;
}
char *cp = strchr(wordFromFile, '\n');
if (cp != NULL)
*cp = '\0'; // get rid of trailing \n
newDictionaryWordNode->word = strdup(wordFromFile);
if (*listhead == NULL) {
lastWordStored = *listhead = newDictionaryWordNode;
} else {
lastWordStored = lastWordStored->next = newDictionaryWordNode;
}
}
fclose(dictionaryFile);
return SUCCESS;
}
wordsubcomponent_t
*newsubcomponent() {
wordsubcomponent_t *subcomp = NULL;
if ((subcomp = calloc(sizeof(wordsubcomponent_t), 1)) != NULL) {
subcomp->text = strdup(""); // seed with empty string (instead of NULL) so we can append
} else {
fprintf(stderr, "out of memory (fatal). program exiting\n");
exit(-1);
}
return subcomp;
}
/*
* Returns an linked list of word subcomponents for the given word, split up around dictionary words
*/
wordsubcomponent_t *getWordSubcomponents(char *wordToParse, word_t *listhead) {
wordsubcomponent_t *subcomponents, *currSubcomp;
subcomponents = currSubcomp = newsubcomponent();
for (char *cp = wordToParse; cp < wordToParse + strlen(wordToParse);) { // exit when cp gets to end of word to parse.
int matchFlag = 0;
for (word_t *wordNode = listhead; wordNode != NULL; wordNode = wordNode->next) {
if (strncasecmp(cp, wordNode->word, strlen(wordNode->word)) == 0) { // prefix of cur. ptr is dict word.
if (strlen(currSubcomp->text) != 0) // Detected non-dict text in subcomp.
currSubcomp = currSubcomp->next = newsubcomponent(); // leave in list & add new subcomp for dict word.
currSubcomp->text = wordNode->word; // save dict-word in subcomp
currSubcomp->isDictionaryWord = 1;
currSubcomp = currSubcomp->next = newsubcomponent(); // dict-word in list, so get new subcomp
cp += strlen(wordNode->word); // advance cp past extracted dict-word
matchFlag = 1;
break; // break out of inner-loop
}
}
if (!matchFlag) { // No dict-word found at cp
char oneNullTerminatedLetter[2] = { *cp++, '\0' }; // put 1st ltr into NULL-terminated string & adv cp.
strcat(currSubcomp->text, oneNullTerminatedLetter); // append letter-as-string to curr subcomp
}
}
return subcomponents;
}
void
dumpDictionary(word_t *listhead) {
printf("\nList of dictionary words:\n");
printf("----------------\n");
for (word_t *wordNode = listhead; wordNode != NULL; wordNode = wordNode->next) {
printf(" %s\n", wordNode->word);
}
printf("----------------\n\n");
}
int
main(int argc, char **argv)
{
int status;
if ((status = loadDictionaryFromFile(DICTIONARY_FILEPATH, &dictionaryListhead)) < 0) {
switch(status) {
case FILE_NOT_FOUND:
fprintf(stderr, "Error accessing dictionary: %s\n", argv[0]);
break;
case OUT_OF_MEMORY:
fprintf(stderr, "Out of memory");
break;
}
return EXIT_FAILURE;
}
/*
* Load dictionary first so we can show them the list of words if they didn't
* pass in a command line argument with the word to parse.
*/
if (argc < 2) {
fprintf(stderr, "Usage: %s <word_to_parse>\n\n", argv[0]);
dumpDictionary(dictionaryListhead);
return EXIT_FAILURE;
}
wordsubcomponent_t *subcomp = getWordSubcomponents(argv[1], dictionaryListhead);
while(subcomp != NULL && strlen(subcomp->text) > 0) {
if (subcomp->isDictionaryWord)
printf("\"%s\" ", subcomp->text);
else
printf("%s ", subcomp->text);
subcomp = subcomp->next;
}
printf("\n");
return EXIT_SUCCESS;
}
#nerdist colony:
There is a resource leak in loadDictionaryFromFile. This means a file pointer was not closed when returning from this function in case of an error.
Here is a corrected copy of this function
int loadDictionaryFromFile(char *filename, word_t **listhead)
{
char wordFromFile[MAX_WORD_SIZE];
word_t *lastWordStored = NULL;
FILE *dictionaryFile = fopen(filename, "r");
if (dictionaryFile == NULL) {
return FILE_NOT_FOUND;
}
while(fgets(wordFromFile, sizeof(wordFromFile), dictionaryFile)) {
word_t *newDictionaryWordNode;
if ((newDictionaryWordNode = calloc(sizeof(word_t), 1)) == NULL) { // calloc automatically zeroes memory
fclose(dictionaryFile); // <-- Close the file pointer
return OUT_OF_MEMORY;
}
char *cp = strchr(wordFromFile, '\n');
if (cp != NULL)
*cp = '\0'; // get rid of trailing \n
newDictionaryWordNode->word = strdup(wordFromFile);
if (*listhead == NULL) {
lastWordStored = *listhead = newDictionaryWordNode;
} else {
lastWordStored = lastWordStored->next = newDictionaryWordNode;
}
}
fclose(dictionaryFile);
return SUCCESS;
}
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
Doing a homework and I'm having problems with, what I believe, pointers.
The assignment consists in the following:
I have a txt file where each line as a name and a password.
thisismyname:thisismypassword
I have to read this data, process it into struct linked list, run all the list and send the password to a brute-force algorithm. This algorithm, after finding the pass, should write the pass on the struct. In the end, I should run the list and write the data to a txt file
My problem is when I find the password. It is not storing its value in the struct. At the end I can read the data, I can see that the brute-force is working but at the end, I'm only managing to write the name and pass to file. The unencrypted pass is being written as NULL so I believe is a pointer problem.
This is the code (Removed all the things that I believe are irrelevant):
typedef struct p {
char *name;
char *pass;
char *pass_desenc;
struct p *next_person;
} person;
typedef struct n {
int a;
int b;
} numbers;
int readFile(person **people) {
FILE * fp;
char line[100];
if ((fp = fopen(STUDENTS_FILE, "r")) != NULL) {
while (fgets(line, sizeof (line), fp) != NULL) {
person *p;
char email[27] = "";
char password[14] = "";
char *change = strchr(line, '\n');
if (change != NULL)
*change = '\0';
/* Gets email*/
strncpy(email, line, 26);
email[27] = '\0';
/* Gets pass*/
strncpy(password, line + 27, 14);
password[14] = '\0';
p = (person*) malloc(sizeof (person));
if (p == NULL) {
return -1;
}
p->name = (char*) malloc(strlen(email));
if (p->name == NULL) {
return -1;
}
sprintf(p->name, "%s", email);
p->name[strlen(email)] = '\0';
p->pass = (char*) malloc(strlen(password));
if (p->pass == NULL) {
return -1;
}
sprintf(p->pass, "%s", password);
p->pass[strlen(password)] = '\0';
p->next_person = (*people);
(*people) = p;
countPeople++;
}
fclose(fp);
return 0;
}
return -1;
}
void fmaps(int id, numbers pass_range, person *people) {
/*This function will run all my list and try to uncrypt pass by pass.
On the brute-force pass in unencrypted and when it return to this function, I can print the data.
*/
while (people != NULL && j > 0) {
for (i = 1; i <= PASS_SIZE && notFound == 1; i++) {
notFound = bruteForce(i, people, &total_pass);
}
notFound = 1;
count = count + total_pass;
printf("#####Email: %s Pass: %s PassDesenq: %s \n", people->name, people->pass, people->pass_desenc);
people = people->next_person;
j--;
}
}
void fcontrol(int n, person *people) {
/*This function should write the data to a file
I can see that all data is written as expected but people->pass_desenc is writing/printing NULL
*/
if ((fp = fopen(STUDENTS_LOG_FILE, "a+")) != NULL) {
while (people != NULL) {
printf("#####1111Email: %s Pass: %s PassDesenq: %s \n", people->name, people->pass, people->pass_desenc);
fprintf(fp, "%d%d%d%d%d%d:grupo%d:%s:%s\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, 1, people->name, people->pass_desenc);
people = people->next_person;
}
}
fclose(fp);
}
int main() {
/*Struct*/
person *people = NULL;
if (readFile(&people)) {
printf("Error reading file!\n");
return 0;
}
/*Function to send data to brute-force*/
fmaps(i, pass_range, people);
/*After all data is processed, this function writes the data to a file*/
fcontrol(NR_PROC, people);
destroyList(&people);
return 0;
}
int bruteForce(int size, person *people, int *total_pass) {
int i;
char *pass_enc;
int *entry = (int*) malloc(sizeof (size));
char pass[50];
char temp;
pass[0] = '\0';
for (i = 0; i < size; i++) {
entry[i] = 0;
}
do {
for (i = 0; i < size; i++) {
temp = (char) (letters[entry[i]]);
append(pass, temp);
}
(*total_pass)++;
/*Compare pass with test*/
pass_enc = crypt(pass, salt);
if (strcmp(pass_enc, people->pass) == 0) {
people->pass_desenc = (char*) malloc(strlen(pass));
if (people->pass_desenc == NULL) {
return -1;
}
sprintf(people->pass_desenc, "%s", pass);
people->pass_desenc[strlen(pass)] = '\0';
return 0;
}
pass[0] = '\0';
for (i = 0; i < size && ++entry[i] == nbletters; i++) {
entry[i] = 0;
}
} while (i < size);
free(entry);
return 1;
}
void append(char *s, char c) {
int len = strlen(s);
s[len] = c;
s[len + 1] = '\0';
}
void destroyList(person **people) {
person *aux;
printf("\nList is being destroyed.");
while (*people != NULL) {
aux = *people;
*people = (*people)->next_person;
free(aux);
printf(".");
}
printf("\nList destroyed.\n");
}
I believe that the changes being made in fmaps are local and are not passing to main.
Any help is appreciated...
This is how you could code the file reader/parser. It avoids str[n]cpy(), and does all string operations using memcpy() + the offsets + sizes. (which need to be correct in both cases, obviously)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
typedef struct p {
char *name;
char *pass;
// char *pass_desenc;
struct p *next;
} person;
#define STUDENTS_FILE "students.dat"
unsigned countPeople = 0;
int readFile(person **people) {
FILE * fp;
char line[100];
size_t len, pos;
fp = fopen(STUDENTS_FILE, "r");
if (!fp) {
fprintf(stderr, "Could not open %s:%s\n"
, STUDENTS_FILE, strerror(errno));
return -1;
}
while ( fgets(line, sizeof line, fp) ) {
person *p;
len = strlen(line);
/* remove trailng '\n', adjusting the length */
while (len && line[len-1] == '\n') line[--len] = 0;
/* Ignore empty lines */
if ( !len ) continue;
/* Library function to count the number of characters in the first argument
** *not* present in the second argument.
** This is more or less equivalent to strtok(), but
** 1) it doen not modify the string,
** 2) it returns a size_t instead of a pointer.
*/
pos = strcspn(line, ":" );
/* Ignore lines that don't have a colon */
if (line[pos] != ':') continue;
p = malloc(sizeof *p);
if ( !p ) { fclose(fp); return -2; }
p->next = NULL;
p->name = malloc(1+pos);
if ( !p->name ) { fclose(fp); return -3; } /* this could leak p ... */
memcpy(p->name, line, pos-1);
p->name[pos] = 0;
p->pass = malloc(len-pos);
if ( !p->pass ) {fclose(fp); return -4; } /* this could leak p and p->name */
memcpy(p->pass, line+pos+1, len-pos);
/* Instead of pushing (which would reverse the order of the LL)
** , we append at the tail of the LL, keeping the original order.
*/
*people = p;
people = &p->next ;
countPeople++;
}
fclose(fp);
return 0;
}
I am trying to get words inserted into a hash table. When I run the code, it's supposed to give me a list of the frequency of each word, but it just gives me nothing.
I'm sure it's either to do with my print function, or my insert function, probably more my insert function. I know it's isn't mylib.h, but I'm just not sure where I'm going wrong.
It doesn't insert anything into my table or print it. I'm not really sure what's going on.
hashtable.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "htable.h"
struct htablerec {
char **key;
int *frequencies;
int num_keys;
int capacity;
};
void *emalloc(size_t s) {
void *result = malloc(s);
if (NULL == result) {
fprintf(stderr, "Memory allocation failed!\n");
exit(EXIT_FAILURE);
}
return result;
}
htable htable_new(int capacity) {
int i;
htable h = emalloc(sizeof * h);
h->capacity = capacity;
h->num_keys = 0;
h->frequencies = emalloc(h->capacity * sizeof h->frequencies[0]);
h->key = emalloc(h->capacity * sizeof h->key[0]);
for (i = 0; i < h->capacity; i++) {
h->frequencies[i] = 0;
h->key[i] = NULL;
}
return h;
}
void htable_free(htable h) {
free(h->frequencies);
free(h->key);
free(h);
}
static unsigned int htable_word_to_int(char *word) {
unsigned int result = 0;
while (*word != '\0') {
result = (*word++ + 31 * result);
}
return result;
}
int htable_insert(htable h, char *str) {
int i;
/*convert string to integer*/
unsigned int index = htable_word_to_int(str);
/*calculate index to insert into hash table*/
int remainder = index%h->capacity;
/*once calculated position in the hash table, 3 possibilities occur*/
/*no string in this positon, copy string to that position, increment number of keys, return 1*/
if (h->key[remainder] == NULL) {
h->frequencies[remainder] = 1;
h->num_keys++;
return 1;
}
/*the exact same string is at the position, increment frequency at that position, return frequency*/
if (strcmp(str, h->key[remainder]) == 0) {
h->frequencies[remainder]++;
return h->frequencies[remainder];
}/*a string is at that position, but it isnt the rightone, keep moving along the array
until you find either an open space or the string you are looking for*/
if (h->key[remainder] != NULL && strcmp(str, h->key[remainder]) != 0) {
/*you may need to wrap back around to the beginning of the table, so each time you add
to the position you should also mod by the table capacity.*/
for (i = 0; i <= h->capacity; i++) {
if (h->key[remainder] != NULL && h->capacity == i) {
i = 0;
}
/*no string in this positon, copy string to that position, increment number of keys*/
if (h->key[remainder] == NULL) {
h->frequencies[remainder] = 1;
h->num_keys++;
}
/*if you find the string you were looking for, increment the frequecny at the position
and return the frequency*/
if (strcmp(str, h->key[remainder]) == 0) {
h->frequencies[remainder]++;
return h->frequencies[remainder];
}
}
}
/*if you have kept looking for an open space but there isnt one, the hash table must be full so return 0*/
return 0;
}
void htable_print(htable h, FILE *stream) {
int i;
for(i = 0; i < h->capacity; i++) {
if(h->key[i] != NULL) {
fprintf(stream, "%d%s\n", h->frequencies[i], h->key[i]);
}
}
}
htable.h:
#ifndef HTABLE_H_
#define HTABLE_H_
#include <stdio.h>
typedef struct htablerec *htable;
extern void htable_free(htable h);
extern int htable_insert(htable h, char *str);
extern htable htable_new(int capacity);
extern void htable_print(htable h, FILE *stream);
extern int htable_search(htable h, char *str);
#endif
mylib.c:
#include <stdio.h>
#include <stdlib.h>
#include "mylib.h"
#include "htable.h"
int main(void) {
htable h = htable_new(18143);
char word[256];
while (getword(word, sizeof word, stdin) !=EOF) {
htable_insert(h, word);
}
htable_print(h, stdout);
htable_free(h);
return EXIT_SUCCESS;
}
mylib.h:
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
int getword(char *s, int limit, FILE *stream) {
int c;
char *w = s;
assert(limit > 0 && s != NULL && stream != NULL);
/*skip to the start fo the word */
while (!isalnum(c = getc(stream)) && EOF != c)
;
if(EOF == c) {
return EOF;
} else if (--limit > 0) { /*reduce limit by 1 to allow for the \0 */
*w++ = tolower(c);
}
while(--limit > 0) {
if(isalnum(c = getc(stream))) {
*w++ = tolower(c);
} else if ('\'' == c) {
limit++;
} else {
break;
}
}
*w = '\0';
return w - s;
}
You never set h->key[remainder] to anything in htable_insert, so h->key[i] is still NULL for all i when you call htable_print.
/*no string in this positon, copy string to that position, increment number of keys, return 1*/
if (h->key[remainder] == NULL) {
h->frequencies[remainder] = 1;
h->num_keys++;
return 1;
}
...
/*no string in this positon, copy string to that position, increment number of keys*/
if (h->key[remainder] == NULL) {
h->frequencies[remainder] = 1;
h->num_keys++;
}
You never copy the string. Try something like...
char *key = emalloc(strlen(str) + 1);
strcpy(str, key);
h->key[remainder] = key;