trie data structure insert function is not working. Why? - c

I have implemented a trie data structure (reference). When I insert into the data structure, I get a segmentation fault. It could be a semantic error. Please help to correct it.
#include <stdio.h>
#include <stdlib.h>
#define maxlength 10
typedef struct node {
int isend;
struct node *branch[27];
} trinode;
int count, len;
trinode *createnode() {
trinode *new = (trinode *)malloc(sizeof(trinode));
int ch;
for (ch = 0; ch < 26; ch++) {
new->branch[ch] = NULL;
}
new->isend = 0;
}
trinode *insert_trie(trinode *root, char *newenty) {
int ind;
trinode *proot;
if (root == NULL)
root = createnode();
proot = root;
for (int i = 0; i < maxlength; i++) {
ind = newenty[i] - 'a';
if (newenty[i] == '\0')
break;
else {
if (root->branch[ind] == NULL)
root->branch[ind] = createnode();
root = root->branch[ind];
}
if (root->isend != 0)
printf("trying to insert duplicate");
else
root->isend = 1;
return proot;
}
}
void print_trie(trinode *cur) {
char word[40];
for (int i = 0; i < 26; i++) {
if (cur->branch[i] != NULL) {
word[count++] = (i + 'a');
if ((cur->branch[i]->isend) == 1) {
printf("\n");
for (int j = 0; j < count; j++) {
printf("%c", word[j]);
}
}
print_trie(cur->branch[i]);
}
}
count--;
}
int search_trie(trinode *root, char *target) {
int ind;
for (int i = 0; i < maxlength && root; i++) {
ind = target[i] - 'a';
if (target[i] == '\0')
break;
else
root = root->branch[ind];
}
if (root && root->isend == 1)
return root;
else
return 0;
}
int main() {
int ch;
trinode *root = NULL;
char *newenty;
char *target;
int check;
while (1) {
printf("\n enter option 1.insert_trie 2.display 3.search 4.exit");
scanf("%d", &ch);
switch (ch)
{
case 1:
printf("enter word");
scanf("%s", newenty);
root = insert_trie(root, newenty);
break;
case 2:
count = 0;
print_trie(root);
break;
case 3:
printf("enter elem you want to search");
scanf("%s", target);
check = search_trie(root, target);
if (check == 0)
printf("word not found");
else
printf("found");
break;
case 4:
exit(0);
break;
}
}
}

For starters the function createnode returns nothing
trinode *createnode()
{
trinode *new=(trinode *)malloc(sizeof(trinode));
int ch;
for(ch=0;ch<26;ch++)
{
new->branch[ch]=NULL;
}
new->isend=0;
}
Also it is unclear why the condition in the for loop is ch<26 instead of ch < 27 while the data member branch has 27 elements
struct node *branch[27];
This for in the function insert_trie
for(int i=0;i<maxlength;i++)
does not make a sense because within the loop there is the return statement
return proot;
So the loop has no more than one iteration.
The function print_trie depends on the global variable count that is a very bad design and it is unclear what the function does.
The function search_trie is declared like
int search_trie(trinode *root,char *target)
That is it has the return type int. However the function returns a pointer of the type trinode*:
if(root && root->isend==1)
return root;
In main the pointers
char *newenty;
char *target;
are not initialized and have indeterminate values. Thus these statements
scanf("%s",newenty)
and
scanf("%s",target);
invoke undefined behavior.
And you need to format the text of the program. A bad formatting is usually a reason of bugs.

char *newenty;
….
scanf("%s",newenty);
root=insert_trie(root,newenty);
newenty isn't pointing to valid memory, allocate memory to it like below.
char *newenty = malloc(maxLength);

Related

What is wrong with my replace string with another string or character using linked list

I have a linked list with many chars which I input from my input (what is the weather today?), to be replaced with another string (for example what replaced with how, so I get how is the weather today?).
But if the given words are right next to each other for example whatwhat, it will change to howwhat, disregarding the second part.
I think the problem is in the compare function, but I have no clue how to fix it, but the logic of replace should go like this:
If the words from my list and the needed word are the same, then proceed to iterate to the position where the next node of the word that should be changed (unwanted word) should be (pretty much the end of the word), then I create a new linked list with character with the wanted word, and connect temp to the start of the list and the next of the list to the position where the next character of the word that needs to be changed (unwanted word), which I found in the first loop.
Also don't roast my input() function, I know it is unsafe I just want to see what unsafe means with my own eyes, while I still have nothing to lose.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
int value_c;
struct node *next_c;
struct node *prev_c;
};
typedef struct node string;
int compare(string *head, char *word) {
int counter = 0;
string *temp = head;
for (int i = 0; i < strlen(word); i++) {
if (temp->value_c == word[i]) {
temp = temp->next_c;
counter++;
}
}
if (counter == strlen(word))
return 1;
else
return 0;
}
void print_c(string *head) {
while (head != NULL) {
printf("%c", head->value_c);
head = head->next_c;
}
}
void append_c(string **head, char thing) {
string *newNode = (string *)malloc(sizeof(string));
newNode->value_c = thing;
newNode->next_c = NULL;
if (*head == NULL) {
*head = newNode;
newNode->prev_c = NULL;
return;
}
string *temp = *head;
while (temp->next_c != NULL)
temp = temp->next_c;
temp->next_c = newNode;
newNode->prev_c = temp;
}
string *replace_all1(string *head, char *what, char *with_what) {
string *temp = head;
while (temp != NULL) {
printf("%c ", temp->value_c);
if (compare(temp, what) == 1) {
printf("%i ", 1);
printf("%c ", temp->value_c);
string *new = temp;
for (int i = 0; i < strlen(what) - 1; i++) {
new = new->next_c;
}
string *word = NULL;
for (int i = 0; i < strlen(with_what); i++) {
append_c(&word, with_what[i]);
}
string *word_temp = word;
while (word_temp->next_c != NULL) {
word_temp = word_temp->next_c;
}
word_temp->next_c = new->next_c;
if (temp->prev_c != NULL) {
temp->prev_c->next_c = word;
} else {
head = word;
print_c(head);
temp = word;
print_c(temp);
word->prev_c = NULL;
}
}
temp = temp->next_c;
}
printf("\n");
return head;
}
string *String(char *str) {
string *st = NULL;
int i = 0;
while (str[i] != '\0') {
append_c(&st, str[i]);
i++;
}
return st;
}
string *input() {
char *a = (char *)malloc(sizeof(char));
scanf("%[^\n]", a); //maximum of 1408
string *stri = String(a);
return stri;
free(a);
}
int main() {
string *list = NULL;
string *big_boy_string = input();
//printf("%c", big_boy_string->value_c);
//print_c(big_boy_string);
//printf("\n");
//printf("%i", compare(big_boy_string, "what"));
//printf("%i ", len(big_boy_string));
//printf("\n");
//print_c(slice(big_boy_string, 1, 10));
//print_c(replace(big_boy_string, 'h', 'a'));
//printf("\n");
//print_c(reverse(big_boy_string));
print_c(replace_all1(big_boy_string, "a", "b"));
//getline();
}
char *a = (char*) malloc(sizeof(char));
scanf("%[^\n]",a); //maximum of 1408
The first statement allocates memory for just 1 byte. So the maximum is not 1408, but 1. It can store a single char, or the null-terminator if it's a string, but no more.
Next, scanf() will write to out of bounds memory, and invoke undefined behaviour. The subsequent functions all depend on this undefined behaviour, so I'm not going to look at them.
But then, you've a memory leak in the same function.
return stri;
free(a);
You return before freeing the allocated memory. The call to free() is never executed.
The return value of malloc() is also ignored. Code risks undefined behaviour if the subsequent dereferences are on a NULL pointer.
Aside: The cast is meaningless and may hide a bug. malloc() and family returns a void * that is implicitly converted to the right type.
Re: Also don't roast my input() function, I know its unsafe I just
want to see what unsafe means with my own eyes.
If you are already aware of this, then you shouldn't be asking why your code doesn't work. You are relying on undefined behaviour (playing with fire).
There is no need to look further than the input function: it has undefined behavior or the worst kind because you attempt to read the input string into a very small array, allocated for a single byte. You must fix this first. Since you know the maximum length of your input string, you can use this:
string *input(void) {
char a[1409];
if (scanf("%1408[^\n]", a) != 1) { //maximum of 1408
// invalid or missing input
return NULL;
}
scanf(%*[^\n]"); // consume any remaining characters on the input line
scanf(%*1[\n]"); // consume the newline if present
return String(a);
}
Here is an alternative using getchar() instead of scanf() which is quite tricky and error prone:
string *input(void) {
char a[1409];
int c;
size_t i = 0;
while ((c = getchar()) != EOF && c != '\n') {
if (i + 1 < sizeof(a))
a[i++] = (char)c;
}
if (c == EOF && i == 0) {
/* end of file without any input */
return NULL;
}
a[i] = '\0';
return String(a);
}
The compare function is incorrect: it should return false as soon as the comparison fails and it must test for the end of string (temp == NULL):
int compare(const string *head, const char *word) {
string *temp = head;
for (size_t i = 0; word[i] != '\0'; i++) {
if (temp == NULL || temp->value_c != word[i])
return 0;
temp = temp->next_c;
}
return 1;
}
The replace_all1() function has problems too:
for (int i = 0; i < strlen(what) - 1; i++) will cause undefined behavior if what is an empty string because strlen(what) - 1 is unsigned with the value SIZE_MAX in this case, causing the loop to proceed for a very long time, well beyond the end of the list pointed to by new.
while (word_temp->next_c != NULL) will cause a undefined behavior if the replaced word is empty as word_temp will be NULL.
once you replace the sublist, you do not update temp correctly to point to the node after the replaced one, which you could achieve by setting temp to word_temp.
the function does not free the replaced sublist.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
int value_c;
struct node *next_c;
struct node *prev_c;
};
typedef struct node string;
void string_append_char(string **head, int c) {
string *node = malloc(sizeof(*node));
if (node == NULL) {
fprintf(stderr, "out of memory\n");
exit(1);
}
node->value_c = c;
node->next_c = NULL;
if (*head == NULL) {
node->prev_c = NULL;
*head = node;
} else {
string *temp = *head;
while (temp->next_c != NULL)
temp = temp->next_c;
node->prev_c = temp;
temp->next_c = node;
}
}
string *string_new(const char *str) {
string *st = NULL;
for (int i = 0; str[i] != '\0'; i++) {
string_append_char(&st, str[i]);
}
return st;
}
string *string_input(const char *prompt) {
string *st = NULL;
int c;
if (prompt) {
printf("%s", prompt);
}
while ((c = getchar()) != EOF && c != '\n') {
string_append_char(&st, c);
}
return st;
}
void string_print(const char *before, const string *head, const char *after) {
printf("%s", before);
while (head != NULL) {
putchar(head->value_c);
head = head->next_c;
}
printf("%s", after);
}
void string_free(string *head) {
while (head != NULL) {
string *next = head->next_c;
free(head);
head = next;
}
}
int string_compare(const string *head, const char *word) {
const string *temp = head;
for (size_t i = 0; word[i] != '\0'; i++) {
if (temp == NULL || temp->value_c != word[i])
return 0;
temp = temp->next_c;
}
return 1;
}
int string_replace(string **head, const char *what, const char *with_what) {
int count = 0;
if (*what == '\0')
return 0;
string *temp = *head;
while (temp != NULL) {
if (string_compare(temp, what)) {
count++;
// locate the last node of the substring
string *temp_end = temp;
for (size_t i = 0; what[i + 1] != '\0'; i++) {
temp_end = temp_end->next_c;
}
string *next = temp_end->next_c;
if (*with_what == '\0') {
// just delete the substring
if (temp->prev_c != NULL) {
temp->prev_c->next_c = next;
} else {
*head = next;
}
if (next) {
next->prev_c = temp->prev_c;
}
} else {
// create a string from the replacement
string *word = string_new(with_what);
// locate the last node of the new substring
string *word_end = word;
while (word_end->next_c != NULL) {
word_end = word_end->next_c;
}
word->prev_c = temp->prev_c;
if (temp->prev_c != NULL) {
temp->prev_c->next_c = word;
} else {
*head = word;
}
word_end->next_c = next;
if (next) {
next->prev_c = word_end;
}
}
temp_end->next_c = NULL;
string_free(temp);
temp = next;
} else {
temp = temp->next_c;
}
}
return count;
}
int main() {
string *list = string_input("enter string: ");
string_print("input: ", list, "\n");
printf("replacing 'what' to 'how': %d matches\n", string_replace(&list, "what", "how"));
string_print("rep1: ", list, "\n");
printf("replacing 'a' to 'b': %d matches\n", string_replace(&list, "a", "b"));
string_print("rep2: ", list, "\n");
printf("deleting 'h': %d matches\n", string_replace(&list, "h", ""));
string_print("rep3: ", list, "\n");
string_free(list);
return 0;
}
Sample session:
enter string: what is the weather today?
input: what is the weather today?
replacing 'what' to 'how': 1 matches
rep1: how is the weather today?
replacing 'a' to 'b': 2 matches
rep2: how is the webther todby?
deleting 'h': 3 matches
rep3: ow is te webter todby?

Adding struct pointer to a pointer array

I have a problem and I really dont know what to do.
I'am trying to insert "new students" to an student-array. The array contains pointers to the created structs. Can somebody find the error? It adds the student-structs to the array but especially the printing doesnt work.
It would be really helpful, if somebody could help me. :) PS: You can just copy the code.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_HASH 10
typedef struct student
{
unsigned int matnr;
char *name;
struct student *next_student;
} Student;
Student **hash_tabelle[MAX_HASH];
void insert_student (unsigned int matnr, char *name)
{
Student *neuer_student = malloc(sizeof(Student));
neuer_student->name = malloc(sizeof(*name)+1);
neuer_student->matnr = matnr;
strcpy(neuer_student->name, name);
neuer_student->next_student = NULL;
// Index im Hash-Array ermitteln
int hash_index = matnr % 10;
if(hash_tabelle[hash_index] == NULL)
{
neuer_student->next_student = hash_tabelle[hash_index];
hash_tabelle[hash_index] = neuer_student;
}
else
{
while(*hash_tabelle[hash_index] != NULL && (((*hash_tabelle[hash_index])->matnr - neuer_student->matnr) <= 0))
hash_tabelle[hash_index] = &(*hash_tabelle[hash_index])->next_student;
neuer_student->next_student = *hash_tabelle[hash_index];
*hash_tabelle[hash_index] = neuer_student;
}
}
void print_hash_tabelle()
{
for(int i = 0; i != MAX_HASH - 1; i++){
printf("%d)\t", i);
hash_tabelle[i] = &(*hash_tabelle[i])->next_student;
for(; hash_tabelle[i] != NULL; hash_tabelle[i] = &(*hash_tabelle[i])->next_student){
printf("%s (%d)", (&(*hash_tabelle[i])->name), (&(*hash_tabelle[i])->matnr));
}
printf("\t");
}
}
int main()
{
unsigned int matnr;
char name[100];
do
{
printf("Matrikelnummer:\t");
scanf("%d", &matnr);
fflush(stdin);
getchar(); // um das \n aus dem Puffer zu kriegen und rauszuschmeißen
printf("Name:\t\t");
fgets(name, 30, stdin);
insert_student(matnr, name);
}
while (matnr != 0);
print_hash_tabelle();
return 0;
}
Using a hash table is so simple... No need to use dereferencing for a fixed-size array of linked-list pointers.
Step 1 - a hash table is a array of linked-list pointers.
As #BLUEPIXY suggests:
Student *hash_tabelle[MAX_HASH];
Step 2 - to allocate and free each linked-list, initialize each item to NULL.
Otherwise, if(hash_tabelle[hash_index] == NULL) is Undefined
behavior in the function insert_student().
void hash_init()
{
for(int i=0;i<MAX_HASH;i++) {
hash_tabelle[MAX_HASH]=NULL;
}
}
Step 3 - allocate enough char to store the char *name to insert_student().
As # WhozCraig suggests, use strlen().
void insert_student (unsigned int matnr, char *name)
{
Student *neuer_student = malloc(sizeof(Student));
neuer_student->name = malloc(strlen(name)+1);
neuer_student->matnr = matnr;
strcpy(neuer_student->name, name);
neuer_student->next_student = NULL;
Step 4 - add the neuer_student in the hash_tabelle[] (function insert_student())
Warning: the index shall be included in the size of the array
[0..MAX_HASH[. (using 10 instead of MAX_HASH could become a bug).
int hash_index = matnr % MAX_HASH;
When the hash_tabelle[hash_index] is NULL, simple store the
neuer_student. No need to modify neuer_student->next_student.
if(hash_tabelle[hash_index] == NULL)
{
hash_tabelle[hash_index] = neuer_student;
}
Else explore the linked-list of hash_tabelle[hash_index] to store
the neuer_student at the end.
else
{
Student *tmp;
tmp = hash_tabelle[hash_index];
while (tmp->next_student!=NULL) {
tmp = tmp->next_student;
}
tmp->next_student = neuer_student;
}
Step 5 - to print the all items of the hash table (function print_hash_tabelle())
Reuse the same method to explore each linked-list pointer.
Warning: explore all item from 0 to MAX_HASH-1
void print_hash_tabelle()
{
for(int i = 0; i < MAX_HASH; i++){ // ERR != MAX_HASH - 1; i++){
printf("%d)\t", i);
Student *tmp = hash_tabelle[i];
while (tmp!=NULL) {
printf("%s (%d)", tmp->name, tmp->matnr);
tmp = tmp->next_student;
}
printf("\n");
}
}
Step 6 - free the memory of each item of the hash_tabelle[].
Free the allocated string free(tmp->name);.
Remove the current student hash_tabelle[i] = tmp->next_student;
Free the allocated student free(tmp);
Repeat until the end of the linked-list
That's all (no change in the main() except adding a call to hash_free() at the end).
void hash_free()
{
for(int i=0;i<MAX_HASH;i++) {
Student *tmp = hash_tabelle[i];
while (tmp!=NULL) {
free(tmp->name);
hash_tabelle[i] = tmp->next_student;
free(tmp);
tmp = hash_tabelle[i];
}
}
}
like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_HASH 10
typedef struct student {
unsigned int matnr;
char *name;
struct student *next_student;
} Student;
Student *hash_tabelle[MAX_HASH];
void insert_student (unsigned int matnr, char *name){
Student *neuer_student = malloc(sizeof(Student));
neuer_student->name = malloc(strlen(name)+1);
strcpy(neuer_student->name, name);
neuer_student->matnr = matnr;
//neuer_student->next_student = NULL;
int hash_index = matnr % MAX_HASH;
Student head = { .next_student = hash_tabelle[hash_index] };
Student *prev = &head, *curr = head.next_student;
while(curr != NULL && curr->matnr <= neuer_student->matnr){
prev = curr;
curr = curr->next_student;
}
neuer_student->next_student = curr;
prev->next_student = neuer_student;
hash_tabelle[hash_index] = head.next_student;
}
void print_hash_tabelle(void){
for(int i = 0; i < MAX_HASH; i++){
printf("%d)\t", i);
for(Student *p = hash_tabelle[i]; p; p = p->next_student){
printf("%s (%d)\t", p->name, p->matnr);
}
printf("\n");
}
}
void free_hash_tabelle(void){
for(int i = 0; i < MAX_HASH; i++){
Student *p = hash_tabelle[i];
while(p){
Student *temp = p->next_student;
free(p->name);
free(p);
p = temp;
}
}
}
int main(void){
int matnr = -1;//for %d of scanf
char name[100];
while(1){
printf("Matrikelnummer(-1 for end input): ");fflush(stdout);
scanf("%d", &matnr);
if(matnr < 0)
break;
while(getchar() != '\n');
printf("Name: ");fflush(stdout);
fgets(name, sizeof name, stdin);
name[strcspn(name, "\n")] = 0;
insert_student(matnr, name);
}
print_hash_tabelle();
free_hash_tabelle();
return 0;
}

finding a dangling pointer

I have a problem with my code. I am getting a segmentation fault error, which I understand is a dangling pointer problem(generally) or a faulty allocation of memory. The compiler dose not show at what line the problem might be, so my question is how do I detect these problems for further concern? and where would my problem be in the code?
here is my code:
`#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ARRAY_SIZE(a) sizeof(a)/sizeof(a[0])
#define ALPHABET_SIZE (256)
#define CHAR_TO_INDEX(c) ((int)c - (int)'a')
#define LEVELS 255
// trie node
struct n
{
char value,level,isLeaf;
struct n* children[ALPHABET_SIZE];
struct n* failLink;
};
typedef struct n node;
//trie
struct t
{
node *root;
int count;
};
typedef struct t trie;
void bytesCpy(char *to, char *from, int len)
{
int i;
for(i=0;i<len;i++)
{
to[i]=from[i];
}
}
// Returns new trie node (initialized to NULLs)
node *getNode(trie *t, char value,char level)
{
node *pNode = NULL;
pNode = (node *)malloc(sizeof(node));
if (pNode)
{
printf("ok\n");
int i;
for (i = 0; i < ALPHABET_SIZE; i++)
{
pNode->children[i] = NULL;
}
pNode->failLink = t->root;
pNode->value=value;
pNode->level=level;
pNode->isLeaf=0;
}
else
printf("error\n");
return pNode;
}
// Initializes trie (root is dummy node)
void initialize(trie *t)
{
t->root = getNode(t, '[', 0);
//t->count = 0;
}
// If not present, inserts key into trie
// If the key is prefix of trie node, just marks leaf node
void insert(trie *t, char key[], int len)
{
int level;
char value;
node *node = t->root;
for (level = 0; level<len; level++)
{
value = key[level];
printf("value: %c\n",value);
if (node->children[value] == NULL)
{
node->children[value] = getNode(t, value, level+1);
}
node = node->children[value];
}
node->isLeaf=1;
}
// Returns non zero, if key presents in trie
int search(trie *t, char key[])
{
int level;
int length = strlen(key);
int value;
node *node;
node = t->root;
for (level = 0; level < length; level++)
{
value = key[level];//CHAR_TO_INDEX(key[level]);
if (!node->children[value])
{
node = node->failLink;
return 0;
}
node = node->children[value];
}
return (0 != node);// && node->value);
}
void search1(trie *t, char *c, int len)
{
node *curNode = t->root;
int i;
for(i=0; i<=len; i++)
{
printf("i=%d curnode=%p\n",i,curNode);
if(curNode->isLeaf) //leaf: cuvant gasit
{
printf("if1 curGasit \n");
do{
curNode=curNode->failLink;
if(curNode->isLeaf)
printf("if1 curGasit \n");
else break;
}while(1);
continue;
}
else //nu e gasit inca
{
if(curNode->children[c[i]]==NULL) //fail
{
printf("if2\n");
curNode = curNode->failLink;
continue;
}
else //litera gasita: go on
{
printf("el2\n");
curNode=curNode->children[c[i]];
}
}
}
printf("end of search\n");
}
node* searchAux(trie *t, node *curRoot, char cuv[], char len, int level ,int failLevel)
{
char cuvAux[1024];
bytesCpy(cuvAux,cuv,len);
printf("searchAux level:%d cuvAux:%s curRootLevel:%d\n",level,cuvAux,curRoot->level);
if(cuvAux[level+1] == '\0') //got to the end of cuvAux
{
printf("1st if\n");
return curRoot;
}
if(curRoot->children[cuvAux[level+1]] == NULL) //fail: letter not found
{
printf("3rd if\n");
return searchAux(t, t->root, &cuvAux[failLevel+1], len, 0, failLevel+1);
}
else //letter found: go on
{
printf("3rd else\n");
if(cuvAux[level+2] == '\0') //the found letter was the last of the string
{
printf("4th if\n");
return curRoot->children[cuvAux[level+1]]; //return final pointer
}
else //the found letter was not the last of the string: continue with the next one
{
printf("4th else\n");
return searchAux(t, curRoot->children[cuvAux[level+1]], cuvAux, len, level+1, failLevel);
}
}
}
void createFailLinks(trie *t, node* curRoot, char cuv[], int level)
{
int i;
char cuvAux[1024];
bytesCpy(cuvAux,cuv,1024);
if(curRoot == NULL)
return;
for(i=0;i<ALPHABET_SIZE/*curRoot->children[i] != NULL*/;i++)
{
if(curRoot->children[i] == NULL)
continue;
else
{
cuvAux[level] = curRoot->children[i]->value;
printf("createFailLinks %c%d\n",cuvAux[level],curRoot->children[i]->level);
curRoot->children[i]->failLink = searchAux(t, t->root, cuvAux, level+1, 0, 0);
createFailLinks(t,curRoot->children[i],cuvAux,level+1);
}
}
printf("got\n");
}
void printTrie(node *curRoot)
{
int i;
if(curRoot == NULL)
return;
printf("%c: ", curRoot->value);
for(i=0;i<ALPHABET_SIZE;i++)
if(curRoot->children[i] != NULL)
{
printf("%c ", i);
}
printf("\n");
for(i=0;i<ALPHABET_SIZE;i++)
if(curRoot->children[i] != NULL)
{
printTrie(curRoot->children[i]);
}
}
void checkLinks(node* curRoot)
{
int i;
if(curRoot == NULL)
return;
printf("node %c%d: ",curRoot->value,curRoot->level);
for(i=0;i<256;i++)
if(curRoot->children[i] != NULL)
printf("\n\t%c%d:%c%d",curRoot->children[i]->value, curRoot->children[i]->level, curRoot->children[i]->failLink->value,curRoot->children[i]->failLink->level);
printf("\n");
for(i=0;i<256;i++)
if(curRoot->children[i] != NULL)
checkLinks(curRoot->children[i]);
}
int mai()
{
FILE *fd = fopen("VirusDatabase.txt","r");//O_RDONLY);
int i;
char c;
for(i=0;i<1000;i++)
{
fscanf(fd, "%c", &c);
printf("%c",c);
}
}
int main()
{
// Input keys (use only 'a' through 'z' and lower case)
char keys[][1024] = { "he", "she", "her", "his", "heres"};
char cuv[] = {'\0','\0','\0','\0','\0','\0'};
trie t;
char output[][32] = { "Not present in trie", "Present in trie" };
int i;
char text[]={"andreiherutshevlastashecristihiskatjaheres"};
initialize(&t);
// Construct trie
for (i = 0; i < ARRAY_SIZE(keys); i++)
{
insert(&t, keys[i], strlen(keys[i]));
}
createFailLinks(&t, t.root, cuv, 0);
printTrie(t.root);
printf("\n\n");
checkLinks(t.root);
search1(&t, text, strlen(text));
return 0;
// Search for different keys
printf("%s --- %s\n", "abcd", output[search(&t, "abcd")]);
printf("%s --- %s\n", "ab", output[search(&t, "ab")]);
printf("%s --- %s\n", "ccdd", output[search(&t, "ccdd")]);
printf("%s --- %s\n", "thaw", output[search(&t, "thaw")]);
return 0;
char a = getchar();
}`
Do you have access to a debugger? I ran your code in a debugger and get a memory access violation at line 157 here:
return searchAux(t, t->root, &cuvAux[failLevel+1], len, 0, failLevel+1);
You seem to be recursively calling searchAux. ie you have:
node* searchAux(trie *t, node *curRoot, char cuv[], char len, int level ,int failLevel)
{
char cuvAux[1024];
...
return searchAux(t, t->root, &cuvAux[failLevel+1], len, 0, failLevel+1);
...
Anyway, eventually the buffer size variable failLevel exceeds the size of your buffer so you are attempting to access memory outside the bounds of your array which is why you get an access violation.
The easiest way to debug is use an interactive debugger. On Windows there is a free version of Visual Studio with a very good debugger. On linux you can use GDB.
Failing that you can embed print statements to print out variables before the crash.
You can add print statements at lines of code.
#include <iostream>
std::cout << "At Line: " << __LINE__ << endl;
putting that at various lines of code, you can see what lines got executed, and find where it crashes.
This is for C++. My bad. Same idea, but put printf() statements and see where it stopped executing to narrow down the crash location.

HashTable top 20 count ideas

I'm having a bit of trouble thinking of an idea to solve my problem.
I have a word counting program, which uses a hashtable to count
all of the words in any number of files, and print only the words
that are in all files, and their counts. I also store all of my used
hash indexs in a linked list.
Solved my own problem, I knew the answer would be simple. I just figured out the one with the lowest count and if my new value was greater than than that, but it at the index of the one of the lowest count in the array of the twenty word structs.
Thanks for all of your help everyone!
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>
/*Structures*///////////////////////////////////////////
//A struct to hold the words in the hash tables and their
//counts
struct counter{
int count;
int printed;
char word[51];
int allfiles[101];
struct counter * next;
};
//A struct to hold the hash indexes of the already visited
//index, for easy printing
struct index{
int used;
struct index * next;
};
//A simple struct to pass arguments to the work function for
//threading
struct arguments{
void * id;
int fileid;
};
////////////////////////////////////////////////////////
/*Functions*////////////////////////////////////////////
static int hash(char * word);
static void inHash(struct counter * newWord, int hash, int FILEID);
static void indexchain(int hash);
//static void hashprint(int NUMFILES);
static void * work(struct arguments *);
static void toptwenty(int NUMFILES);
static void print();
////////////////////////////////////////////////////////
/*Global Variables*/////////////////////////////////////
struct counter * top[20] = {0};
struct counter * hashtable[6222] = {0};
struct index * head;
////////////////////////////////////////////////////////
int main(int argc, char * argv[])
{
//check for valid number of arguments
if(argc < 2)
{
fprintf(stderr, "invalid number of arguments");
return 1;
}
//set up index chain starts with a null node
head = malloc(sizeof(struct index));
head->next = NULL;
head->used = -1;
//loop through any number of files
int arg;
for(arg = 1; arg < argc; arg++)
{
struct arguments * argum = malloc(sizeof(struct arguments));
argum->fileid = arg;
argum->id = ((void*)argv[arg]);
work(argum);
}
//hashprint(argc);
toptwenty(argc);
print();
return 0;
}
/*Function Definitions*/
//this function takes a file name and counts
//the words in the file
static void * work(struct arguments * argum)
{
int FILEID = argum->fileid;
void * in = argum->id;
int fd = open((char*)in, O_RDONLY);
if (fd == -1)
{
fprintf(stderr, "can't open %s for reading!\n", (char*)in);
exit(-1);
}
int BUFLEN = (int) lseek(fd, 0, SEEK_END);
lseek(fd, 0, 0);
//A few variable
char buf[BUFLEN + 1];
int lastRead;
lastRead = read(fd, buf, BUFLEN);
if (lastRead == -1)
{
fprintf(stderr, "error reading file %s!\n", (char*)in);
exit(-1);
}
//Parse the filebuffer for words.
char newword[51];
int c;
int curindex = 0;
buf[BUFLEN + 1] = ' ';
//not doing the last space because it is eof
for(c = 0; c < BUFLEN + 1; c++)
{
if((buf[c] >= 'A' && buf[c] <= 'Z'))
{
buf[c] += 32;
}
if(buf[c] >= 'a' && buf[c] <= 'z')
{
//add the next char to the string.
newword[curindex] = buf[c];
curindex++;
}
else
{
//make a new struct for the entry, and add it to the hashtable
//add its hash to the
if(strlen(newword) >= 6)
{
struct counter * temp = malloc(sizeof(struct counter));
strcpy(temp->word,newword);
int thishash = hash(temp->word);
//Only save hash indexes if they are in the first files
if(FILEID == 1)
{
indexchain(thishash);
}
inHash(temp, thishash, FILEID);
}
int wordlength = strlen(newword);
int i;
for(i = 0;i < wordlength; i++)
{
newword[i] = 0;
}
curindex = 0;
}
}
close(fd);
return in;
}
//Bad hash function by just adding ascii values of the
//characters
static int hash(char * word)
{
int loop = strlen(word);
int i;
int hashval = 0;
for(i = 0; i < loop; i++)
hashval += word[i];
return hashval;
}
//add a new word to the hash table
static void inHash(struct counter * newWord, int hash, int FILEID)
{
int eflag = 0;
if(hashtable[hash] == NULL)
{
//if the entry isnt in the table
if(FILEID == 1)
{
newWord->allfiles[FILEID] = 1; /*FILEID ARRAY TEST*/
newWord->count = 1;
newWord->next = NULL;
hashtable[hash] = newWord;
}
}
else
{
//if its not, but what if it is?
struct counter * cur = hashtable[hash];
if(strcmp(cur->word, newWord->word) == 0)
{
//is the word in the first slot?
cur->count += 1;
cur->allfiles[FILEID] = 1; /*FILEID ARRAY TEST*/
eflag = 1;
}
else
{
while(cur->next != NULL)
{
cur = cur->next;
if(strcmp(cur->word, newWord->word) == 0)
{
//if the word already exsists, update the count
cur->allfiles[FILEID] = 1; /*FILEID ARRAY TEST*/
cur->count += 1;
eflag = 1;
break;
}
}
}
//if its not in any bucket, make a new bucket
if(eflag == 0)
{
//Else add the new entry to the end of that list
if(FILEID == 1)
{
newWord->allfiles[FILEID] = 1; /*FILEID ARRAY TEST*/
newWord->count = 1;
newWord->next = NULL;
cur->next = newWord;
}
}
}
}
//adding a value to the linked list for printing
static void indexchain(int hash)
{
struct index * p = head;
int eflag = 0;
while(p->next != NULL)
{
if(p->used != hash)
p = p->next;
else
{
eflag = 1;
break;
}
}
if(eflag == 0)
{
struct index * newValue = malloc(sizeof(struct index));
newValue->used = hash;
newValue->next = NULL;
p->next = newValue;
}
}
/*
//This function will print the values in the hash tables and their counts
//Prints based on number of files to check if words are in all files
static void hashprint(int NUMFILES)
{
struct index * p;
p = head->next;
int hash;
int i;
int printbool = 1;
while(p != NULL)
{
hash = p->used;
struct counter * ptr = hashtable[hash];
while(ptr != NULL)
{
if(ptr->printed == 0)
{
for(i = 1; i < NUMFILES; i++)
{
if(ptr->allfiles[i] == 0)
{
printbool = 0;
break;
}
else
printbool = 1;
}
if(printbool == 1)
{
ptr->printed = 1;
printf("%s %d\n", ptr->word, ptr->count);
}
}
ptr = ptr->next;
}
p = p->next;
}
}
*/
//A function to see which numbers have the top twenty highest count
static void toptwenty(int NUMFILES)
{
struct index * p;
p = head->next;
int hash;
int i;
int printbool = 1;
while(p != NULL)
{
hash = p->used;
struct counter * ptr = hashtable[hash];
while(ptr != NULL)
{
if(ptr->printed == 0)
{
for(i = 1; i < NUMFILES; i++)
{
if(ptr->allfiles[i] == 0)
{
printbool = 0;
break;
}
else
printbool = 1;
}
if(printbool == 1)
{
for(i = 0; i < 20; i++)
{
if(top[i] == NULL)
{
top[i] = ptr;
break;
}
else if(ptr->count > top[i]->count)
{
top[i] = ptr;
break;
}
}
}
}
ptr = ptr->next;
}
p = p->next;
}
}
//print the top 20 count
static void print()
{
int i;
for(i = 0; i < 20; i++)
{
if(top[i] != NULL)
{
if(top[i]->printed == 0)
{
//printf("%s\n", top[i]->word);
printf("%s %d\n", top[i]->word, top[i]->count);
top[i]->printed = 1;
}
}
else
break;
}
}
Create an priority Queue that holds the 20 hash indexes that have the top counts and their corresponding counts.
When you are counting the lowest value is at the top of the queue if your new word beats it remove it from the queue O(1) and add your new one to the queue O(log(n)) which is only O(log(20)).

".exe file has stopped working" when run

The program below compiles fine, but gives the error ".exe file ahs stopped working" when I run it. Please help. Any suggestions?
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXSIZE 500
struct key
{
int item;
struct key *left;
struct key *right;
};
typedef struct key star;
void make_tree(star *link, int j, char a[]);
int find_num_of_leaves(star *node);
star *tree;
char input[MAXSIZE];
int main()
{
int i=0;
int num;
printf("Enter the number:\n");
scanf("%[^\n]", input);
tree = (star *) malloc(sizeof(star));
tree->item = -1;
make_tree(tree, i, input);
printf("#######");
num = find_num_of_leaves(tree);
printf("#######");
printf("\n\n%d", num);
return(0);
}
void make_tree(star *link, int j, char a[])
{
if(a[j] == '\0')
{
link->left = NULL;
link->right = NULL;
return;
}
if(a[j+1] == '\0')
{
link->right = NULL;
return;
}
if(int(a[j]) > 0)
{
link->left = (star *) malloc(sizeof(star));
(link->left)->item = a[j];
return make_tree(link->left, j+1, a);
}
if(((10*int(a[j])) + int(a[j+1])) <= 26)
{
link->right = (star *) malloc(sizeof(star));
(link->right)->item = (10*int(a[j])) + int(a[j+1]);
return make_tree(link->right, j+1, a);
}
}
int find_num_of_leaves(star *node)
{
if(node == NULL)
return 0;
if(node->left == NULL && node->right == NULL)
return 1;
else
return find_num_of_leaves(node->left) + find_num_of_leaves(node->right);
/*if(node->left == NULL)
find_num_of_leaves(node->right);
if(node->right == NULL)
find_num_of_leaves(node->left);
if(node->right != NULL && node->left != NULL)
{
find_num_of_leaves(node->left);
find_num_of_leaves(node->right);
}*/
}
When doing make tree your link->left does not get initialised if the code passes through this bit:
(for instance, if you enter a single digit into the console)
if(a[j+1] == '\0')
{
link->right = NULL;
return;
}
Hence, when your code calls find_num_of_leaves which, in turn calls find_num_of_leaves, it crashes when it tries to dereference the left part of the node.

Resources