I'm making a regex parser. The instruction "t->left = tmp;" the instruction "t->left = tmp;" creates a segmentation fault, but not always ! Try executing the code several times, you'll see that it doesn't always happen. The segmentation fault occurs when printing the tree, because one of the nodes has a child with address "0x62" or "0x54" or something similar. It's really weird because when "tmp" is created I check that both children are NULL but somehow one of them gets modified to "0x.." while executing.
Thanks to anyone that could help me solve this !
I spent quite a while trying to figure out why just adding a "left children" while parsing the tree will create a segmentation fault. I really don't understand because it's a simple pointer creation and assignment ! Comment the instruction "t->left = tmp;" and the segmentation fault is gone ! The weirdest issue so far..
Best regards !
/*
* Includes
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* Typedefs
*/
struct node {
char val;
struct node* left;
struct node* right;
};
typedef struct node NODE;
typedef struct node * TREE;
/*
* Tree handling
* - create
* - free
* - print
*/
TREE createNode(char val) {
TREE t = (TREE) malloc(sizeof(TREE));
t->val = val;
t->left = NULL;
t->right = NULL;
return t;
}
void freeTree(TREE t) {
if (t != NULL) {
if (t->left != NULL)
freeTree(t->left);
if (t->right != NULL)
freeTree(t->right);
free(t);
}
}
void printNode(TREE t) {
printf("------ NODE ------\n");
printf("t == %p\n", t);
if (t != NULL) {
printf("val = %c\n", t->val);
printf("left : %p\n", t->left);
printf("right : %p\n", t->right);
}
}
void printTree(TREE t) {
if (t != NULL) {
printf("%c\t[%p]\n", t->val, t);
printf("%p\n", t->left);
if (t->left != NULL) {
printf("----------------begin left----------------\n");
printTree(t->left);
printf("----------------end left----------------\n");
}
printf("%p\n", t->right);
if (t->right != NULL) {
printTree(t->right);
}
}
}
/*
* Misc functions
*/
char* concat(char *s1, char *s2)
{
char *result = malloc(strlen(s1)+strlen(s2)+1);//+1 for the zero-terminator
//in real code you would check for errors in malloc here
strcpy(result, s1);
strcat(result, s2);
return result;
}
char* substr(char* s, int start) {
int i = 0;
char* sub = malloc(4*(strlen(s) - start) + 1); // +1 for the zero-terminator
while (s[i+start] != '\0') {
sub[i] = s[i+start];
i++;
}
return sub;
}
char* substr_(char* s, int start, int end) {
int i = 0;
char* sub = malloc(4*(strlen(s) - start) + 1); // +1 for the zero-terminator
while (s[i+start] != '\0' && i < (end-start+1)) {
sub[i] = s[i+start];
i++;
}
return sub;
}
/*
* Regex handling
*/
TREE parseParenthesis(char* regex) {
if (regex[0] == '\0') return NULL;
printf("%s\n",regex);
TREE tree = createNode(regex[0]);
int i = 0;
int start = 1;
int lastParenthesisPos = 0;;
switch (regex[0]) {
case '(' :
while (regex[i] != '\0') {
if (regex[i] == ')')
lastParenthesisPos = i;
i++;
}
tree->left = parseParenthesis(substr_(regex, 1, lastParenthesisPos-1));
start = lastParenthesisPos + 1;
break;
case '|' :
case ')' : // Handled by case ')'
case '*' :
case '+' :
case '?' :
default : break;
}
tree->right = parseParenthesis(substr(regex, start));
return tree;
}
void parseExtras(TREE t, TREE parent) {
if (t == NULL) return;
TREE tmp = NULL;
switch (t->val) {
case '*' :
case '+' :
case '?' :
parseExtras(t->right, t);
tmp = createNode(parent->val);
t->left = tmp;
break;
case '(' :
case ')' :
case '|' :
default :
parseExtras(t->left, t);
parseExtras(t->right, t);
break;
}
}
/*
* Main
*/
int main() {
//char* regex = "a|(b|c*)?d|ef";
char* regex = "ab*dd*";
// Parse ()
TREE t = parseParenthesis(regex);
printf("************************************ OK - Parse parenthesis\n");
// Parse * + ?
parseExtras(t, NULL);
printf("************************************ OK - Parse extras\n");
printTree(t);
printf("************************************ OK - Print tree\n");
freeTree(t);
printf("************************************ OK - Free tree\n");
return 0;
}
You are allocating space only for a pointer, not the actual struct:
TREE t = (TREE) malloc(sizeof(TREE));
After this, you are modifying memory that is beyond the size of TREE (which is a pointer).
As a comment above said, don't use typedef unnecessarily.
Related
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?
I am trying to create a binary search tree that deletes the 2 leftmost nodes in a bst. For some reason, my code deletes the first value twice instead of moving onto the next.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct treeNode {
char *word; // the string word that is stored
int origin; // position of the word in the original text input’s line 1
struct treeNode *left; // pointer for the left children of the node
struct treeNode *right; // pointer for the right children of the node
struct treeNode *parent; // pointer for the parent of the node
};
typedef struct treeNode NODE;
NODE *
addNode(NODE * r, char *x)
{
// r = root pointer of the tree
// x = value to add into this tree
// return the root of the updated tree
NODE *p = malloc(sizeof(NODE));
p->word = malloc(strlen(x) + 1);
strcpy(p->word, x); // strcpy input: (destination, data to be copied)
// printf("%s", x);
p->parent = NULL;
p->left = NULL;
p->right = NULL;
// if tree is empty, tree consists of p only
if (r == NULL)
return p;
if (strcmp(x, r->word) > 0) {
r->right = addNode((r->right), x);
return r;
}
else {
// add new node the left subtree
r->left = addNode((r->left), x);
return r;
}
return r;
}
NODE *
getLeftMostNode(NODE * root)
{
// return the pointer to the right most node
if (root == NULL)
return NULL;
NODE *p = root;
while (p->left != NULL)
p = p->left;
return p;
}
NODE *
addTree2Tree(NODE * X, NODE * Y)
{
if (X == NULL)
return Y;
if (Y == NULL)
return X;
X = addNode(X, Y->word);
X = addTree2Tree(X, Y->left);
X = addTree2Tree(X, Y->right);
return X;
}
NODE *
removeNode(NODE * r)
{
// remove any node that store value x from tree
// r: root pointer of this tree
// return root pointer of the updated tree after removal
NODE *p = getLeftMostNode(r);
NODE *C = p->parent;
NODE *A = p->left;
NODE *B = p->right;
if (C == NULL) {
// p is root of the tree
free(p);
return addTree2Tree(A, B); // add tree A and tree B and return the new combination tree
}
if (A != NULL) {
// make A a child of C assuming position of P
if (p == C->left)
C->left = A;
else
C->right = A;
A->parent = C;
free(p);
return addTree2Tree(r, B);
}
if (B != NULL) {
if (p == C->left)
C->left = B;
else
C->right = B;
B->parent = C;
free(p);
return r;
}
if (p == C->left)
C->left = NULL;
else
C->right = NULL;
free(p); // free allocation for p
return r;
}
void
printArray(NODE * r)
{
// print all the values on the tree rooted at node "r" // print in alphabetical order
// if the tree is empty, return // print all the values on the tree rooted at node "r" // print in the in-order order: print left first, followed by root, followed by right values
if (r == NULL) {
return;
}
else {
printArray(r->left); // print all values in left subtree
printf("%s ", r->word);
printArray(r->right); // print all values in right subtree
}
}
int
main()
{
// input must be implemented by linked list, not array
NODE *root = NULL;
int ch;
char in[1000]; // input array
int len = 0;
char del[100]; // word to be deleted
char word[1000];
while ((ch = getchar()) != '\n')
in[len++] = ch;
in[len] = '\0';
// printf("%s\n", in);
int i = 0,
j = 0;
while (i <= len) {
// space to store a word
if ((in[i] == ' ') || (in[i] == '\0') || (in[i] == '\t')) {
word[j] = '\0'; // end of word
j = 0;
root = addNode(root, word);
// printf("%s\n", word);
}
else
word[j++] = in[I];
i++;
}
int k = 0;
removeNode(root);
removeNode(root);
printArray(root);
printf("\n");
return 0;
}
this is the error that I got
The function removeNode is looking for parent, but parent is never assigned in addNode. You want to assign r->right->parent = r; and r->left->parent = r;.
BST doesn't keep duplicate keys. If strcmp(x, r->word) == 0, then don't add a new node.
addNode should also be corrected so that if r is NULL, the function returns the new node immediately.
NODE* addNode(NODE* r, char* x)
{
if(!x)
return NULL;
if (!r)
{
NODE* p = malloc(sizeof(NODE)); if (!p) return NULL;
p->word = strdup(x);
p->parent = NULL;
p->left = NULL;
p->right = NULL;
return p;
}
if (strcmp(x, r->word) > 0)
{
r->right = addNode((r->right), x);
r->right->parent = r;
return r;
}
else if (strcmp(x, r->word) < 0)
{
r->left = addNode((r->left), x);
r->left->parent = r;
return r;
}
return r;
}
Modify the insert functions such that root is assigned only once:
while (i <= len)
{
if ((in[i] == ' ') || (in[i] == '\0') || (in[i] == '\t'))
{
word[j] = '\0';
j = 0;
if(!root)
root = addNode(root, word);
else
addNode(root, word);
}
else
word[j++] = in[i];
i++;
}
Double check the pointers to make sure NULL pointers are avoided. For example:
NODE* removeNode(NODE* r)
{
if(!r)
return NULL;
NODE* p = getLeftMostNode(r);
if(!p)
return NULL;
...
}
I have not checked the rest of the code but the example will work with these changes made.
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.
For a component of an assignment for college we have to implement a stack, which I think I've done well enough for it to be functional. When I'm testing the stack by itself it seems to work fine, however when I'm using it as part of my solution it behaves differently, and I can't figure out why. Can someone please point out my mistake? Thanks.
Edit: I can feel a lot of "how does it behave differently?" comments are on the way, so here's what I've noticed. When running the Testing stack section of main, all the operations execute and print perfectly fine, but when I'm running the second part of main and comment out the testing part instead, the program crashes when I'm trying to push onto the stack - something that didn't fail previously.
main.c
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
struct stackNode {
char data;
struct stackNode *nextPtr;
};
typedef struct stackNode StackNode;
typedef StackNode *StackNodePtr;
typedef enum {
false, true
} t_bool;
void* emalloc(size_t s) {
void* p = malloc(s);
if (NULL == p) {
fprintf(stderr, "Memory allocation failed.\n");
exit(EXIT_FAILURE);
}
return p;
}
void print_array(char* array, size_t n){
int i;
printf("[");
for(i = 0; i < n - 1; i++){
printf("%c, ", array[i]);
}
printf("%c]\n", array[i]);
}
// Determine if c is an operator.
int isOperator(char c) {
char ops [6] = {'+', '-', '*', '/', '%', '^'};
int i;
for (i = 0; i < 6; i++)
if (ops[i] == c) return true;
return false;
}
int op_priority(char c) {
if (c == '+' || c == '-') return 0;
else if (c == '*' || c == '/') return 1;
else if (c == '^' || c == '%') return 2;
return -1;
}
// Determine if the precedence of operator1 is less than, equal to, or greater than
// the precedence of operator2. The function returns -1, 0 and 1, respectively.
int precedence(char op1, char op2) {
int op1_p = op_priority(op1);
int op2_p = op_priority(op2);
if (op1_p < op2_p) return -1;
else if (op1_p > op2_p) return 1;
else return 0;
}
// Push a value on the stack.
void push(StackNodePtr *topPtr, char value) {
StackNodePtr temp = (StackNodePtr) emalloc(sizeof (StackNode));
temp->data = value;
temp->nextPtr = *topPtr;
*topPtr = temp;
}
// Pop a value off the stack.
char pop(StackNodePtr *topPtr) {
StackNodePtr t = *topPtr;
if (NULL != *topPtr) {
char c = t->data;
*topPtr = t->nextPtr;
free(t);
return c;
} else {
printf("Stack is empty.\n");
return '\0';
}
}
// Return the top value of the stack without popping the stack.
char peek(StackNodePtr topPtr) {
if (NULL != topPtr) {
return topPtr->data;
} else {
printf("Stack is empty.\n");
}
}
// Determine if the stack is empty.
int isEmpty(StackNodePtr topPtr) {
if (NULL == topPtr) return true;
return false;
}
// Prints the stack
void printStack(StackNodePtr topPtr) {
if (!isEmpty(topPtr)){
StackNodePtr t = topPtr;
while (NULL != t) {
printf("%c\t", t->data);
t = t->nextPtr;
}
printf("NULL\n");
} else {
printf("Stack is empty.\n");
}
}
// Convert the infix expression to postfix notation.
void convertToPostfix(char infix [], char postfix [], int expression_length) {
printf("At top of cnvToPostfix\n");
int infix_count = 0;
int postfix_count = 0;
////////////////////////////////////////////
StackNodePtr *stack;
push(stack, '(');
printStack(*stack);
////////////////////////////////////////////
infix[expression_length] = ')';
while (isEmpty(*stack)) {
char current = infix[infix_count++];
if (isdigit(current)) {
postfix[postfix_count++] = current;
} else if (current == '(') {
push(stack, current);
} else if (isOperator(current)) {
while (true) {
char top = peek(*stack);
if (isOperator(top) && precedence(current, top) >= 0) {
postfix[postfix_count++] = pop(stack);
} else {
break;
}
}
push(stack, current);
}
else if (current == ')') {
while (true) {
char top = peek(*stack);
if (top == '(') {
pop(stack);
break;
} else {
postfix[postfix_count++] = pop(stack);
}
}
}
}
}
int main() {
printf("Testing stack\n");
printf("Pushing 1, 2, and 3 onto stack, peeking and popping.\n");
StackNodePtr *stack;
push(stack, '1');
push(stack, '2');
push(stack, '3');
printf("Printing stack\n\n");
printStack(*stack);
printf("Peek: %c\n", peek(*stack));
printf("Pop: %c\n", pop(stack));
printf("Printing stack\n");
printStack(*stack);
/*
printf("Enter the infix expression.\n");
char c;
char infix [1024];
int count = 0;
while ((scanf("%c", &c)) == 1) {
if ((int) c == 10) break;
infix[count++] = c;
}
printf("The original infix expression is:\n");
print_array(infix, count);
char postfix [count];
convertToPostfix(infix, postfix, count);
printf("The expression in postfix notation is:\n");
print_array(postfix, count);
*/
return 0;
}
I see at least one immediate problem:
StackNodePtr *stack;
push(stack, '1');
Where is the initialisation for your stack? Use of uninitialised pointers is instant "undefined behaviour" territory.
If you look closely at your push code, you'll see it inserts the new item before the current one but set the new item's nextPtr pointer to the previous (uninitialised) value.
That means, the last item in the stack won't actually point to NULL.
You're not really initialising your stacks:
StackNodePtr *stack;
push(stack, '(');
It's also potentially confusing having StackNodePtr being a pointer type, and stack being a pointer to that type. You need to be clear in every possible usage how many levels of indirection should be applied.
To start with, imagine passing the new stack firstly to isEmpty:
StackNodePtr *stack;
printf("%d\n", isEmptypush(*stack));
What's isEmpty going to do on the value it is passed?
I think what you want instead is:
StackNodePtr stack = NULL;
push(&stack, '(');
Other uses of stack in that function should similarly be changed from *stack to stack, or stack to &stack.
I am implementing a knowledge tree in c that can read from a file. I am getting a seg fault in my newStr function. I'm not able to test the rest of my code with this problem. I don't have much experience with c. Any help would be greatly appreciated.
my .c file
#include
#include
#include"animal.h"
#include
#include
/*returns a new node for the given value*/
struct Node * newNode (char *newValue)
{
struct Node * tree;
tree = (struct Node*)malloc(sizeof(struct Node));
tree -> value = newStr(newValue);
return tree;
}
/* returns a new string with value passed as an argument*/
char * newStr (char * charBuffer)
{
int i;
int length = strlen(charBuffer);
char newStr;
if(charBuffer[0] == 'A' || charBuffer[0] == 'Q'){
for(i=1; i<length; i++)
newStr += charBuffer[i];
}
return (newStr + "\0");
}
/*Read from a File and create a tree*/
struct Node * readATree(FILE * f)
{
char c;
char buffer[100];
struct Node * newTree;
c = fgetc(f);
if (c == 'A'){
fgets(buffer, 100, f);
newTree = newNode(buffer);
newTree -> left = NULL;
newTree -> right = NULL;
}
else{
fgets(buffer, 100, f);
newTree = newNode(newStr(buffer));
newTree->left = readATree(f);
newTree->right = (struct Node *) readAtree(f);
}
return newTree;
}
/*Write Tree to a File*/
void writeAFile(struct Node* tree, FILE * f)
{
char buffer[100];
strcpy(buffer, tree->value);
if(tree != 0){
if(tree->left == NULL && tree->right == NULL){
fputc((char)"A", f);
fputs(buffer,f);
} else{
fputc((char)"Q",f);
fputs(buffer,f);
writeAFile(tree->left, f);
writeAFile(tree->right,f);
}
}
}
/*The play should start from here*/
int main (){
struct Node* node;
struct Node* root;
char ans[100];
char q[100];
FILE * f;
f = fopen("animal.txt", "r+");
if(f != NULL)
readATree(f);
else{
node = newNode("Does it meow?");
node->right = NULL;
node->right->right=NULL;
node->left->left=NULL;
node->left=newNode("Cat");
root = node;
}
while(node->left != NULL && node->right != NULL){
printf(node->value);
scanf(ans);
if(ans[0] == (char)"Y" || ans[0] == (char)"y")
node = node->left;
else if(ans[0] == (char)"N" || ans[0] == (char)"n")
node = node->right;
else
printf("That is not a valid input.\n");
}
if(ans[0] == (char)"Y" || ans[0] == (char)"y")
printf("I win!");
else if(ans[0] == (char)"N" || ans[0] == (char)"n"){
printf("What is your animal");
scanf(ans);
printf("Please enter a yes or no question that is true about %s?\n", ans);
scanf(q);
node->right = newNode(q);
node->right->left = newNode(ans);
node->right->right = NULL;
}
writeAFile(root,f);
fclose(f);
return 0;
}
.h file
#include
struct Node {
char *value;
struct Node * left;
struct Node * right;
};
struct Node * newNode (char *newValue) ;
char * newStr (char * charBuffer);
struct Node * readATree(FILE * f);
void writeAFile(struct Node* tree, FILE * f);
There might be several more, but here's some points on what's wrong:
Your newStr function is just very,
very wrong. At a guess you'd want
something like:
char * newStr (char * charBuffer)
{
char *newStr;
if(charBuffer[0] == 'A' || charBuffer[0] == 'Q') {
newStr = strdup(&charBuffer[1]);
} else {
newStr = strdup("");
}
if(newStr == NULL) {
//handle error
}
return newStr;
}
You can't cast a string to a char
like you do here:
if(ans[0] == (char)"Y" || ans[0] == (char)"y")
Do instead(same for similar code
elsewhere too)
if(ans[0] =='Y' || ans[0] == 'y')
Same as above when you call putc,
don't do
fputc((char)"A", f);
Do
fputc('A', f);
scanf needs a format string, don't
do:
scanf(ans);
Do e.g. (or just use fgets again)
if(scanf("%99s",ans) != 1) {
//handle error
}
char * newStr (char * charBuffer)
{
int i;
int length = strlen(charBuffer);
char newStr;
if(charBuffer[0] == 'A' || charBuffer[0] == 'Q'){
for(i=1; i<length; i++)
newStr += charBuffer[i];
}
return (newStr + "\0");
}
Well, there's a few interesting things here... To get down to brass tacks, you're trying to copy the contents of a character pointer into another and this function isn't going to do that. All you're really doing is summing the value of each char in charBuffer into newStr because a char is really just an 8-bit integer and then you return that integer as a pointer through an implicit cast so it is now being treated as a memory address.
You should look to use strdup(), as has been noted, since this is exactly what the function is supposed to do. No need to reinvent the wheel. :)
"+" operator as string concatenation does not work in c.
If you actually want to copy the a string use strdup(). This function allocates memory and copies the string into it.
Don't forget to free the allocated memory when done using it.