Cannot delete vowels from singly linked list - c

I am having an issue while deleting the vowel from a linked List. The program accept command line arguments, combines them in a single string and add each character to a linked list as node.
When i try to run the program with command line argument "lemon", the successfully deletes the vowels. i.e the program deletes the vowels successfully if the argument doesn't contain consequetive vowels.
On the other hand, if i try to do the same with command line argument "aeiou", the program crashes with message Segmentation fault(core dumped).. I am not getting any idea how to handle this..
The program must not create any global variables so i've used double pointer.
All the functions are working properly this problem may have occured due to some mistakes in locate() and removeVowels() function but i cannot figure out what the mistake is.
can this problem be solved using double pointer??
I cannot figure out what is wrong in this program.. I am new to c programming, please help me with this.. Please rectify me..
Thanks in advance.
The complete code is given below:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct linkedList {
char ch;
struct linkedList *node;
};
void printMenu(void);
char* combineWithNoSpaces(int, char *[]);
void addTolinkedList(char *, struct linkedList **, int *);
void printLinkedList(struct linkedList **);
struct linkedList *locate(struct linkedList**);
int delHead(struct linkedList **);
void removeVowels(struct linkedList**);
int isEmpty(struct linkedList **);
int main(int argc, char *argv[]) {
int choice, indexer = 0;
struct linkedList *s;
char *string;
if (argc == 1) {
printf("Parse a sentence");
} else {
s = (struct linkedList *) malloc(sizeof(struct linkedList));
string = combineWithNoSpaces(argc, argv);
addTolinkedList(string, &s, &indexer);
while (1) {
printMenu();
scanf("%d", &choice);
if (choice == 1) {
printLinkedList(&s);
} else if (choice == 2) {
if (!delHead(&s))
printf("Failed.Empty linked list");
} else if (choice == 3) {
removeVowels(&s);
} else if (choice == 4) {
if(isEmpty(&s)){
printf("Empty LinkedList");
}
else
printf("Not Empty");
} else if (choice == 5) {
break;
} else
printf("Invalic choice");
printf("\n");
}
}
return 0;
}
int isEmpty(struct linkedList **s){
if(*s == NULL)
return 1;
else
return 0;
}
struct linkedList *locate(struct linkedList **s) {
if ((*s)->node->ch == 'a' || (*s)->node->ch == 'e' || (*s)->node->ch == 'i'
|| (*s)->node->ch == 'o' || (*s)->node->ch == 'u'
|| (*s)->node->ch == 'A' || (*s)->node->ch == 'E'
|| (*s)->node->ch == 'I' || (*s)->node->ch == 'O'
|| (*s)->node->ch == 'U') {
return *s;
} else if ((*s)->node->node == NULL) {
return NULL;
} else
return locate(&((*s)->node));
}
void removeVowels(struct linkedList **s) {
struct linkedList *temp, *tag;
/* Checking whether the first node is null or not */
if ((*s)->ch == 'a' || (*s)->ch == 'e' || (*s)->ch == 'i'
|| (*s)->ch == 'o' || (*s)->ch == 'u'
|| (*s)->ch == 'A' || (*s)->ch == 'E'
|| (*s)->ch == 'I' || (*s)->ch == 'O'
|| (*s)->ch == 'U')
delHead(s);
do {
tag = locate(s);
if (tag != NULL) {
temp = tag->node->node;
free(tag->node);
tag->node = temp;
}
} while (tag != NULL);
}
int delHead(struct linkedList **s) {
struct linkedList *temp;
if ((*s) == NULL) {
return 0;
} else {
temp = (*s)->node;
free(*s);
*s = temp;
return 1;
}
}
void printLinkedList(struct linkedList **s) {
if ((*s) != NULL) {
printf("%c", (*s)->ch);
printLinkedList(&(*s)->node);
}
return;
}
void addTolinkedList(char *str, struct linkedList **s, int *indexer) {
if (*indexer == strlen(str)) {
*s = NULL;
return;
} else {
(*s)->ch = *(str + *indexer);
(*s)->node = (struct linkedList *) malloc(sizeof(struct linkedList));
++*indexer;
addTolinkedList(str, &(*s)->node, indexer);
}
}
char * combineWithNoSpaces(int argc, char *argv[]) {
int i, j;
int count = 0;
int memory = 0;
char *str;
for (i = 1; i < argc; i++) {
for (j = 0; j < strlen(argv[i]); j++) {
++memory;
}
}
str = (char *) malloc(memory * sizeof(char) + 1);
for (i = 1; i < argc; i++) {
for (j = 0; j < strlen(argv[i]); j++) {
*(str + count) = argv[i][j];
++count;
}
}
return str;
}
void printMenu(void) {
printf("\n\n"
"1. print input arguments (no spaces)\n"
"2. remove first character\n"
"3. remove vowels\n"
"4. is the linked list empty?\n"
"5. exit program\n"
"Enter your choice>");
}
The screen shot for output is :
For argument lemon
For argument aeiou

This code works to my satisfaction. It is more nearly an MCVE (Minimal, Complete, Verifiable Example.
I called the program rv19. When run like this, it gives the output shown:
$ rv19 apple
[apple]
[ppl]
$ rv19 nutmeg
[nutmeg]
[ntmg]
$ rv19 ply
[ply]
[ply]
$ rv19 aeiou
[aeiou]
[]
$ rv19 aardvark abstemiously facetiously aeiou minions lampoon shampoo
[aardvarkabstemiouslyfacetiouslyaeiouminionslampoonshampoo]
[rdvrkbstmslyfctslymnnslmpnshmp]
$
The code (rv19.c):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct linkedList
{
char ch;
struct linkedList *node;
};
char *combineWithNoSpaces(int, char *[]);
void addTolinkedList(char *, struct linkedList **, int *);
void printLinkedList(struct linkedList **);
struct linkedList *locate(struct linkedList **);
int delHead(struct linkedList **);
void removeVowels(struct linkedList **);
void freeLinkedList(struct linkedList *);
int main(int argc, char *argv[])
{
int indexer = 0;
struct linkedList *s;
char *string;
if (argc == 1)
{
printf("Parse a sentence. Usage: %s word [word ...]\n", argv[0]);
}
else
{
s = (struct linkedList *) malloc(sizeof(struct linkedList));
printf("s = %p\n", (void *)s);
string = combineWithNoSpaces(argc, argv);
addTolinkedList(string, &s, &indexer);
printLinkedList(&s);
removeVowels(&s);
printLinkedList(&s);
printf("s = %p\n", (void *)s);
freeLinkedList(s);
free(string);
}
return 0;
}
static inline int isvowel(char c)
{
return(c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' ||
c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U');
}
struct linkedList *locate(struct linkedList **s)
{
if ((*s)->node == NULL)
return NULL;
if (isvowel((*s)->node->ch))
{
return *s;
}
else if ((*s)->node == NULL)
{
return NULL;
}
else
return locate(&((*s)->node));
}
void removeVowels(struct linkedList **s)
{
struct linkedList *temp, *tag;
/* Remove leading vowels */
while ((*s) != NULL && isvowel((*s)->ch))
{
//printf("Remove leading '%c'\n", (*s)->ch);
struct linkedList *ts = *s;
delHead(&ts);
*s = ts;
}
struct linkedList *n = *s;
while (n != NULL && (tag = locate(&n)) != NULL)
{
/* Remove multiple embedded or trailing vowels */
while (tag->node != NULL && isvowel(tag->node->ch))
{
temp = tag->node;
tag->node = tag->node->node;
free(temp);
}
n = tag->node;
}
}
int delHead(struct linkedList **s)
{
struct linkedList *temp;
if ((*s) == NULL)
return 0;
else
{
temp = (*s)->node;
free(*s);
*s = temp;
return 1;
}
}
void printLinkedList(struct linkedList **s)
{
struct linkedList *n = *s;
putchar('[');
while (n != NULL)
{
putchar(n->ch);
n = n->node;
}
putchar(']');
putchar('\n');
}
void addTolinkedList(char *str, struct linkedList **s, int *indexer)
{
if (*indexer == (int)strlen(str))
{
free(*s);
*s = NULL;
}
else
{
(*s)->ch = *(str + *indexer);
(*s)->node = (struct linkedList *) malloc(sizeof(struct linkedList));
++*indexer;
addTolinkedList(str, &(*s)->node, indexer);
}
}
char *combineWithNoSpaces(int argc, char *argv[])
{
int argl[argc+1];
int memory = 0;
for (int i = 1; i < argc; i++)
{
argl[i] = strlen(argv[i]);
memory += argl[i];
}
char *str = (char *) malloc(memory + 1);
char *base = str;
for (int i = 1; i < argc; i++)
{
strcpy(base, argv[i]);
base += argl[i];
}
return str;
}
void freeLinkedList(struct linkedList *node)
{
while (node != NULL)
{
struct linkedList *next = node->node;
free(node);
node = next;
}
}
This is still not as polished as it could be. I changed the printing so as to get a marker before the start and after the end of the output; it is easier to see unwanted blanks and other characters like that. It's now iterative. I'd change the interface to the function, too, so it takes a struct linkedList * instead of a struct linkedList **. The code in removeVowels() is tricky; it iterates to remove repeated initial vowels; it iterates to remove repeated vowels after a non-vowel. The locate() function now returns a pointer to a non-vowel node that has a vowel in the next node. This code frees both the string and the list (using a new function, freeLinkedList() to free the list).
I've checked it with a couple of debugging versions of malloc(), and it seems to be leak free and corruption free.
I still haven't run it with valgrind because I can't get it to run properly after building it on macOS Sierra 10.12:
valgrind: mmap-FIXED(0x0, 253952) failed in UME (load_segment1) with error 12 (Cannot allocate memory).
This was with the latest code downloaded from SVN (revision 16097).

I tried to simplify all the functions -- some were taking (pointers to) pointers as arguments when they needn't do so.
A few highlights of the many changes:
main: changed the main control structure to a switch statement. Initialized the linkedList pointer to NULL instead of a malloc'd one as entering an empty string would cause addTolinkedList() to leak this memory. Added a call to new function freeLinkedList() when the exit option is selected.
locate: renamed this locateVowel() and restructured with removeVowel() to have only one place that actually looks for vowels. Removed potential memory leak.
combineWithNoSpaces: rewrote this to be string oriented instead of character oriented.
addTolinkedList: made the index(er) argument a simple int that gets incremented on recursion which simplified a number of issues.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
struct linkedList {
char ch;
struct linkedList *node;
};
void printMenu(void);
char* combineWithNoSpaces(int, char *[]);
void addTolinkedList(char *, struct linkedList **, int);
void printLinkedList(struct linkedList *);
struct linkedList **locateVowel(struct linkedList **);
bool delHead(struct linkedList **);
void removeVowels(struct linkedList **);
bool isEmpty(struct linkedList *);
void freeLinkedList(struct linkedList *);
int main(int argc, char *argv[]) {
int choice;
char *string;
if (argc == 1) {
fprintf(stderr, "Enter a sentence\n");
return EXIT_FAILURE;
}
struct linkedList *s = NULL;
string = combineWithNoSpaces(argc, argv);
addTolinkedList(string, &s, 0);
free(string);
while (true) {
printMenu();
(void) scanf("%d", &choice);
printf("\n");
switch (choice) {
case 1:
printLinkedList(s);
break;
case 2:
if (!delHead(&s)) {
printf("Failed. Empty linked list\n");
}
break;
case 3:
removeVowels(&s);
break;
case 4:
if (isEmpty(s)) {
printf("Empty LinkedList\n");
} else {
printf("Not Empty\n");
}
break;
case 5:
freeLinkedList(s);
return EXIT_SUCCESS;
default:
printf("Invalid choice\n");
}
}
return EXIT_SUCCESS;
}
bool isEmpty(struct linkedList *s) {
return (s == NULL);
}
struct linkedList **locateVowel(struct linkedList **s) {
if (*s == NULL) {
return NULL;
}
char ch = tolower((*s)->ch);
if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') {
return s;
}
return locateVowel(&((*s)->node));
}
void removeVowels(struct linkedList **s) {
struct linkedList **vowel;
while ((vowel = locateVowel(s)) != NULL) {
struct linkedList *temporary = (*vowel)->node;
if (temporary == NULL) {
free(*vowel); // a vowel with nothing following it
*vowel = NULL;
break;
}
(*vowel)->ch = temporary->ch;
(*vowel)->node = temporary->node;
free(temporary);
s = vowel;
}
}
bool delHead(struct linkedList **s) {
if (*s == NULL) {
return false;
}
struct linkedList *temporary = (*s)->node;
free(*s);
*s = temporary;
return true;
}
void printLinkedList(struct linkedList *s) {
printf("\"");
while (s != NULL) {
printf("%c", s->ch);
s = s->node;
}
printf("\"\n");
}
void addTolinkedList(char *string, struct linkedList **s, int index) {
if (index == strlen(string)) {
*s = NULL;
} else {
*s = malloc(sizeof(struct linkedList));
(*s)->ch = string[index];
(*s)->node = NULL;
addTolinkedList(string, &(*s)->node, index + 1);
}
}
char *combineWithNoSpaces(int argc, char *argv[]) {
int characters = 0;
for (int i = 1; i < argc; i++) {
characters += strlen(argv[i]);
}
char *string = calloc(characters + 1, 1);
for (int i = 1; i < argc; i++) {
(void) strcat(string, argv[i]);
}
return string;
}
void freeLinkedList(struct linkedList *s) {
while (s != NULL) {
struct linkedList *temporary = s;
s = s->node;
free(temporary);
}
}
void printMenu(void) {
printf("\n"
"1. print string (no spaces)\n"
"2. remove first character\n"
"3. remove vowels\n"
"4. is the linked list empty?\n"
"5. exit program\n"
"Enter your choice: ");
}

Related

Double pointer in the function

I am trying to insert strings in the binary search tree.
So what I am to trying is,
parsing strings from a file(contains instruction set) and then inserting in the function
insertOpcodeFromFile().
So this function will execute
(*node) = Node_insert(&node,instruction).
the node will be the root of binary tree which is located in main function.
So in simple way to explain, I want to manipulate(insert) the root pointer in the main function by using double pointer in the other function contain insert function.
I have a simple understanding about the pointer, but in this situation, I need to use more than double pointer I think.
please explain me about the double pointer clearly using this example.
Here is my code(I commenting out insert_node)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef BINARYTREE_H_
#define BINARYTREE_H_
typedef struct node *NodePtr;
typedef struct node {
char *word;
int count;
NodePtr left;
NodePtr right;
} Node;
NodePtr Node_alloc();
NodePtr Node_insert(NodePtr node_ptr, char *word);
void clearArray(char a[]);
void insertOpcodeFromFile(FILE *opcodeFile, NodePtr *node);
void Node_display(NodePtr);
char *char_copy(char *word);
#endif
int main(int argc, const char * argv[]) {
FILE * opFile;
FILE * progFile;
struct node *root = NULL;
if ( argc != 4) { // # of flag check
fprintf(stderr, " # of arguments must be 4.\n" );
exit(1);
}
opFile = fopen ( argv[1], "r");
if(opFile == NULL)
{
fprintf(stderr,"There is no name of the opcode file\n");
exit(1);
}
progFile = fopen ( argv[2], "r");
if(progFile == NULL)
{
fprintf(stderr,"There is no name of the program file \n");
exit(1);
}
insertOpcodeFromFile(opFile, &root);
//Node_display(root);
}/* main is over */
void insertOpcodeFromFile(FILE *opcodeFile, NodePtr *node)
{
int fsize = 0;
int lengthOfInst = 0;
int c;
int i;
char buffer[100];
fsize = getFileSize(opcodeFile);
enum flag {ins,opc,form};
int flag = ins;
char instruction[6];
unsigned int opcode = 0;
unsigned char format;
while (c != EOF)
{
c = fgetc(opcodeFile);
buffer[i++] = c;
if (c == 32){
switch (flag) {
case ins:
flag = opc;
memcpy(instruction,buffer,i);
instruction[i] = '\0';
clearArray(buffer);
i = 0;
// printf("인스트럭션 : %s\n",instruction );
break;
case opc:
flag = form;
opcode = atoi(buffer);
clearArray(buffer);
i = 0;
// printf("옵코드 : %d\n",opcode );
break;
default:
break;
}/* end of switch */
}/* end of if(space) */
if((c == 10) || (c == EOF))
{
if (flag == form)
{
format = buffer[0];
clearArray(buffer);
i = 0;
// printf("포멧: %c\n", format);
}
flag = ins;
//node = Node_insert(node,instruction);
}
}
//Node_display(node);
}
int getFileSize(FILE *opcodeFile)
{ int fsize = 0;
fseek(opcodeFile,0, SEEK_SET);
fseek(opcodeFile,0, SEEK_END);
fsize = (int)ftell(opcodeFile);
fseek(opcodeFile,0, SEEK_SET);
return fsize;
}
int countUntilSpace(FILE *opcodeFile, int currentPosition)
{ char readword[1];
char *space = " ";
char *nextLine = "/n";
int i = 0;
//printf("현재: %d\n",currentPosition );
while(1)
{
fread(readword, sizeof(char),1,opcodeFile);
i++;
if(strcmp(readword,space) == 0 || strcmp(readword,nextLine) == 0)
{
//printf("break\n");
break;
}
}
fseek(opcodeFile,currentPosition ,SEEK_SET);
//printf("끝난 현재 :%d\n",ftell(opcodeFile) );
//printf("%I : %d\n",i );
return i - 1;
}
void clearArray(char a[])
{
memset(&a[0], 0, 100);
}
NodePtr Node_alloc()
{
return (NodePtr) malloc(sizeof(NodePtr));
}
NodePtr Node_insert(NodePtr node_ptr, char *word)
{
int cond;
if (node_ptr == NULL) {
node_ptr = Node_alloc();
node_ptr->word = char_copy(word);
node_ptr->count = 1;
node_ptr->left = node_ptr->right = NULL;
} else if ((cond = strcmp(word, node_ptr->word)) == 0) {
node_ptr->count++;
} else if (cond < 0) {
node_ptr->left = Node_insert(node_ptr->left, word);
} else {
node_ptr->right = Node_insert(node_ptr->right, word);
}
return node_ptr;
}
void Node_display(NodePtr node_ptr)
{
if (node_ptr != NULL) {
Node_display(node_ptr->left);
printf("%04d: %s\n", node_ptr->count, node_ptr->word);
Node_display(node_ptr->right);
}
}
char *char_copy(char *word)
{
char *char_ptr;
char_ptr = (char *) malloc(strlen(word) + 1);
if (char_ptr != NULL) {
char_ptr = strdup(word);
}
return char_ptr;
}
In this case, in main(),
Node *root;
Why do you need to use a "double" pointer ( Node ** ) in functions that alter root is because root value as to be set in these functions.
For instance, say you want to allocate a Node and set it into root.
If you do the following
void alloc_root(Node *root) {
root = malloc(sizeof (Node));
// root is a function parameter and has nothing to do
// with the 'main' root
}
...
// then in main
alloc_root( root );
// here main's root is not set
Using a pointer to pointer (that you call "double pointer")
void alloc_root(Node **root) {
*root = malloc(sizeof (Node)); // note the *
}
...
// then in main
allow_root( &root );
// here main's root is set
The confusion comes probably from the Node *root in main, root being a pointer to a Node. How would you set an integer int i; in a function f? You would use f(&i) to call the function f(int *p) { *p = 31415; } to set i to the value 31415.
Consider root to be a variable that contains an address to a Node, and to set its value in a function you have to pass &root. root being a Node *, that makes another *, like func(Node **p).

Why am I getting a segmentation fault on a limit less than 169? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
The program below is supposed to count the words in a C file. If I define MAXWORD to be less than 169 I get a segmentation fault. I find this to be confusing as I never use more than 8 characters from that 'word' string I declare inside of main. Not sure where or what to look at next so any pointers (no pun intended) would be appreciated.
After I compile it with gcc wc.c getword.c -o wc I run ./wc < wc.c I get a segmentation fault but only when I set MAXWORD less than 169.
This is the wc.c file
#include "getword.h"
#include <stdlib.h>
#define MAXWORD 169
struct tnode {
char *word;
int count;
struct tnode *left;
struct tnode *right;
};
struct tnode *addtree(struct tnode *, char *);
void printtree(struct tnode *);
int main(void) {
char word[MAXWORD];
struct tnode *root;
while (getword(word, MAXWORD) != EOF) {
printf("word: %s\n", word);
if (isalpha(word[0]))
root = addtree(root, word);
}
printtree(root);
return 0;
}
struct tnode *talloc(void);
struct tnode *addtree(struct tnode *p, char *word) {
int cond;
if (p == NULL) {
p = talloc();
p->word = strdup(word);
p->count = 1;
p->left = p->right = NULL;
} else if ((cond = strcmp(word, p->word)) == 0)
p->count++;
else if (cond < 0)
p->left = addtree(p->left, word);
else
p->right = addtree(p->right, word);
return p;
}
struct tnode *talloc(void) {
return (struct tnode *) malloc(sizeof(struct tnode));
}
void printtree(struct tnode *p) {
if (p != NULL) {
printtree(p->left);
printf("%4d %s\n", p->count, p->word);
printtree(p->right);
}
}
And here's the getword.c file:
#include "getword.h"
#define STACKMAX 100
void skip_quote(char c);
void skip_comment(char c);
void skip_line(void);
int getch(void);
void ungetch(int);
int getword(char *word, int lim) {
int c;
char *w = word;
while (isspace(c = getch()))
;
if (c != EOF)
*w++ = c;
if (c == '#') {
skip_line();
return c;
}
if (c == '"' || c == '\'') {
skip_quote(c);
return c;
}
if (c == '/' && ((c = getch()) == '*' || c == '/')) {
skip_comment(c);
return c;
}
if (!isalpha(c)) {
*w = '\0';
return c;
}
for ( ; --lim > 0; w++)
if (!isalnum(*w = getch()) && *w != '_') {
ungetch(*w);
break;
}
*w = '\0';
return word[0];
}
void skip_quote(char type) {
int prev, current;
prev = type;
current = '\0';
while ((prev == '\\' || current != type) && prev != current) {
prev = current;
current = getch();
}
}
void skip_comment(char c) {
int prev;
prev = '\0';
if (c == '/')
skip_line();
else if (c == '*')
while (prev != '*' && (c = getch()) != '/')
prev = c;
}
void skip_line(void) {
while (getch() != '\n')
;
}
int cstack[STACKMAX];
int sp = 0;
int getch(void) {
return (sp > 0) ? cstack[--sp] : getchar();
}
void ungetch(int c) {
if (sp < STACKMAX)
cstack[sp++] = c;
else
printf("error: stack is full\n");
}
This is the header getword.h header file
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int getword(char *, int);
Why am I getting a segmentation fault here?
You invoked undefined behavior by using a value of an uninitialized variable having automatic storage duration root, which is indeterminate, in the main() function. Try initializing it before use, like:
struct tnode *root = NULL;
In your function
struct tnode *addtree(struct tnode *p, char *word) {
int cond;
if (p == NULL) {
you are using value of pointer p, but you pass unitialized pointer to it in main function:
root = addtree(root, word);
SOLUTION:
Initialize pointer:
struct tnode *root = NULL;
You said
I get a segmentation fault but only when I set MAXWORD less than 169.
and you ask
Do you know why it wasn't causing a segmentation fault when the
MAXWORD limit was 169 or higher?
The undefined behaviour happened independently of value of MAXWORD as you have used uninitialized pointer in all paths of execution of your code. It was undefined behaviour, so undefined behaviour is the answer to your question.

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.

Segmentation fault while inserting into a hash table

I want to be able to use my getNextWord function to return a pointer to the next word in the file. I think I'm getting the seg fault while inserting but I just can't figure it out. Any help on this would be excellent. Also, I should probably find a better way of getting my hash_table_size than increasing a count for the total number of words in the file then rewinding. How can I make the size grow automatically?
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
int hash_table_size;
char* getNextWord(FILE* fd) {
char c;
char buffer[256];
int putChar = 0;
while((c = fgetc(fd)) != EOF) {
if(isalnum(c)) break;
}
if(c == EOF) return NULL;
buffer[putChar++] = c;
while((c = fgetc(fd)) != EOF) {
if(isspace(c) || putChar >= 256 -1) break;
if(isalnum(c))
buffer[putChar++] = c;
}
buffer[putChar] = '\0';
return strdup(buffer);
}
struct node {
struct node *next;
int count;
char* key;
};
struct list {
struct node *head;
int count;
};
struct list *hashTable = NULL;
/*
* djb2 hash function
*/
unsigned int hash(unsigned char *str) {
unsigned int hash = 5381;
int c;
while(c == *str++)
hash = ((hash << 5) + hash) + c;
return (hash % hash_table_size);
}
struct node* createNode(char *key) {
struct node *new_node;
new_node = (struct node *)malloc(sizeof(struct node));
strcpy(new_node->key, key);
new_node->next = NULL;
return new_node;
}
void hashInsert(char *str) {
int hash_dex = hash(str);
struct node *new_node = createNode(str);
if(!hashTable[hash_dex].head) {
hashTable[hash_dex].head = new_node;
hashTable[hash_dex].count = 1;
return;
}
new_node->next = (hashTable[hash_dex].head);
hashTable[hash_dex].head = new_node;
hashTable[hash_dex].count++;
return;
}
void display() {
struct node *current;
int i;
while(i < hash_table_size) {
if(hashTable[i].count == 0)
continue;
current = hashTable[i].head;
if(!current)
continue;
while(current != NULL) {
char tmp[256];
strcpy(tmp, current->key);
printf("%s", tmp);
current = current->next;
}
}
return;
}
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: ./hashFile textfile\n");
}
else {
FILE *file = fopen(argv[1], "r");
if(file == 0) {
printf("Could not open file\n");
}
else {
char *new_word;
while((new_word = getNextWord(file)) != NULL) {
hash_table_size++;
}
rewind(file);
hashTable = (struct list *)calloc(hash_table_size, sizeof(struct list));
while((new_word = getNextWord(file)) != NULL) {
hashInsert(new_word);
}
display();
fclose(file);
}
}
return 0;
}
int c;
while(c == *str++)
hash = ((hash << 5) + hash) + c;
c is not initialized here. As is i in display function. Please enable all the compiler warnings and fix them.
Also:
char c;
char buffer[256];
int putChar = 0;
while((c = fgetc(fd)) != EOF) {
if(isalnum(c)) break;
}
c has to be of type int not char.
change
while(c == *str++)
to
while(c = *str++)

".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