Create and print a tree in C - c

I am trying to create a program that creates a tree from all the words in a file and the same words sorted.
Here is the code I have:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 30
typedef struct node *tree;
typedef struct node {
tree left;
tree right;
struct dictionary {
char *word;
char *sortedWord;
} value;
} node;
void swap(char *a,char *b){
char tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
char * bubble_sort(char *word){
char *ptr = word;
int n = strlen(word);
int i,j;
for(i=0;i<n-1;i++)
for(j=0;j<n-i-1;j++)
if(*(ptr+j)>*(ptr+j+1))
swap((ptr+j),(ptr+j+1));
return word;
}
char *RemoveNewLines(char *word){
char *newString = malloc(SIZE * sizeof(char));
char ch;
int currentLetter = 0;
int len = strlen(word);
while (currentLetter < len){
ch = word[currentLetter];
if (ch != '\n'){
newString[currentLetter] = ch;
}
else {
newString[currentLetter] = '\0';
}
currentLetter++;
}
return newString;
}
void createTree(tree memory){
// FILE *fp = fopen("words.txt","r");
// FILE *fp = fopen("words_no_duplicates1.txt","r");
FILE *fp = fopen("words_no_duplicates2.txt","r");
char *word = (char *)malloc(SIZE * sizeof(char));
if(fp == NULL)
{
perror("Error opening file");
exit(1);
}
// create the top node of the tree
node seedNode;
memory = &seedNode;
// initially just store the seed in the tree
memory->left = NULL;
memory->right = NULL;
fgets (word,SIZE,fp);
memory->value.word = (char *)malloc(SIZE * sizeof(char));
memory->value.word = strcpy(memory->value.word,RemoveNewLines(word));
// printf("%s\n",memory->value.word);
memory->value.sortedWord = (char *)malloc(SIZE * sizeof(char));
memory->value.sortedWord = strcpy(memory->value.sortedWord,bubble_sort(RemoveNewLines(word)));
// printf("%s\n",memory->value.sortedWord);
// printf("\n");
while ( fgets (word,SIZE,fp) != NULL){
memory->left = NULL;
memory->right = NULL;
memory->value.word = (char *)malloc(SIZE * sizeof(char));
memory->value.word = strcpy(memory->value.word,RemoveNewLines(word));
memory->value.sortedWord = (char *)malloc(SIZE * sizeof(char));
memory->value.sortedWord = strcpy(memory->value.sortedWord,bubble_sort(RemoveNewLines(word)));
// printf("%s\t %s\n",memory->value.word,memory->value.sortedWord);
// printf("%s\n",memory->value.word);
// printf("%s\n",memory->value.sortedWord);
// printf("\n");
}
fclose(fp);
}
void printTree(tree memory){
if (memory != NULL){
printTree(memory->left);
printf("%s",memory->value.word);
printf("%s",memory->value.sortedWord);
printf("\n");
printTree(memory->right);
}
}
int main(){
node seedNode;
tree memory = &seedNode;
createTree(memory);
printTree(memory);
return 0;
}
If I uncomment the print statements in createTree function, it all looks ok and prints what I want. But if I try to use printTree function then it ends with "Segmentation fault".
Where do I go wrong?
You can test with random file which contains one word per line.
#
After Joachim Pileborg reply, I changed my code as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 30
typedef struct node *tree;
typedef struct node {
tree left;
tree right;
struct dictionary {
char *word;
char *sortedWord;
} value;
} node;
node seedNode;
tree memory = &seedNode;
void swap(char *a,char *b){
char tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
char * bubble_sort(char *word){
char *ptr = word;
int n = strlen(word);
int i,j;
for(i=0;i<n-1;i++)
for(j=0;j<n-i-1;j++)
if(*(ptr+j)>*(ptr+j+1))
swap((ptr+j),(ptr+j+1));
return word;
}
char *RemoveNewLines(char *word){
char *newString = malloc(SIZE * sizeof(char));
char ch;
int currentLetter = 0;
int len = strlen(word);
while (currentLetter < len){
ch = word[currentLetter];
if (ch != '\n'){
newString[currentLetter] = ch;
}
else {
newString[currentLetter] = '\0';
}
currentLetter++;
}
return newString;
}
tree * createTree(tree *memory){
// FILE *fp = fopen("words.txt","r");
FILE *fp = fopen("words_no_duplicates1.txt","r");
char *word = (char *)malloc(SIZE * sizeof(char));
if(fp == NULL)
{
perror("Error opening file");
exit(1);
}
// create the top node of the tree
//node seedNode;
// initially just store the seed in the tree
(*memory)->left = NULL;
(*memory)->right = NULL;
fgets (word,SIZE,fp);
(*memory)->value.word = (char *)malloc(SIZE * sizeof(char));
(*memory)->value.word = strcpy((*memory)->value.word,RemoveNewLines(word));
// printf("%s\n",memory->value.word);
(*memory)->value.sortedWord = (char *)malloc(SIZE * sizeof(char));
(*memory)->value.sortedWord = strcpy((*memory)->value.sortedWord,bubble_sort(RemoveNewLines(word)));
// printf("%s\n",memory->value.sortedWord);
// printf("\n");
while ( fgets (word,SIZE,fp) != NULL){
(*memory)->left = NULL;
(*memory)->right = NULL;
(*memory)->value.word = (char *)malloc(SIZE * sizeof(char));
(*memory)->value.word = strcpy((*memory)->value.word,RemoveNewLines(word));
(*memory)->value.sortedWord = (char *)malloc(SIZE * sizeof(char));
(*memory)->value.sortedWord = strcpy((*memory)->value.sortedWord,bubble_sort(RemoveNewLines(word)));
// printf("%s\t %s\n",memory->value.word,memory->value.sortedWord);
// printf("%s\n",memory->value.word);
// printf("%s\n",memory->value.sortedWord);
// printf("\n");
}
fclose(fp);
return memory;
}
void printTree(tree memory){
if (memory != NULL){
printTree(memory->left);
printf("%s\n",memory->value.word);
printf("%s\n",memory->value.sortedWord);
printf("\n");
printTree(memory->right);
}
}
int main(){
createTree(&memory);
printTree(memory);
return 0;
}
Although now createTree function looks strange to me, after executing the code I have printed the last word, and it sorted, from file words_no_duplicates1.txt (these are the values memory->value.word, and memory->value.sortedWord) The trees memory->left and memory->right remains empty.
Can you please help?

There are many problems with your code, I will point out a couple that stood out to me.
In the createTree function you have these two lines
node seedNode;
memory = &seedNode;
Those are troublesome because first the argument memory is passed by value meaning the value passed when calling the function is copied and all you have inside the function is your local variable with its copy of the value. Changing the variable will not change the original variable you used when calling the function. You can solve this by either returning the pointer or by emulating passing by reference.
The second problem with this assignment is that you make it point to a local variable. Local variables go out of scope once the function returns, and will not exist any more. Keeping and then dereferencing a pointer to this (non-existent) variable will lead to undefined behavior, and most likely crashes. This can be solved either by not doing the assignment at all, and just rely on the pointer you pass a argument, or by dynamically allocating memory for the node.

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

Trouble with Malloc and Linked List

I have a function that reads a text file filled with a word on every line. Here is an example of a text file I'm using
and
but
five
follows
four
has
is
like
line
lines
littlest
not
once
one
only
other
six
the
three
twice
two
word
words
Code:
typedef struct node node_t;
struct node {
char data[MAX_WORD];
int term;
node_t *next;
};
node_t *head;
int
int_struct(int lines){
FILE *fp;
char ch;
int n = 0, i, switch_num=1, test_first=0, test_first_2=0;
node_t *node, *curr_add;
fp = fopen("text.txt", "r");
node = (node_t*)malloc(sizeof(node_t));
for (i=1; i<=lines; i++){
switch_num = 1;
n=0;
if (test_first != 0){
if (test_first_2){
node = (node_t*)malloc(1000000);
}
test_first_2=1;
while ((ch = getc(fp)) != '\n'){
node -> term = i;
node -> data[n] = ch;
n++;
}
curr_add -> next = node;
curr_add = node;
}
else{
test_first = 1;
head = curr_add = node;
}
}
curr_add -> next = NULL;
fclose(fp);
return num;
}
What I want to do is to read each word and add it to a linked list.
However I am having trouble with malloc (at the moment I just add in a lot of bytes) and need advice on how to properly use it inside the function I have. I've done a general search and tried my best to try and do what most examples do. But I still can't seem to get my function working. For example, every time I execute the program it will read and add all the words into the linked list. However, the program crashes on the last word, and returns NULL. If anyone is able to point me in the right direction, I'd be very grateful.
Issues
There are no checks for return values. Particularly, fopen and malloc
may return NULL. If they do, you'll catch a segmentation fault error on the
first attempt to access the returned value.
Overcomplicated logic. You don't need these switch_num, test_first and test_first_2
variables (see sample code below).
No need in getc when you're reading a text file line-by-line - use
fgets instead.
Too many memory allocations. You don't need more than sizeof(node_t) + length of the line bytes per line.
The allocated memory is not freed. The dynamic memory should be freed as
soon as it is not needed.
Example using linked list
The following reads a text file into a linked list. Memory is allocated for
each list item, and for each line in the file resulting in n * 2 memory
allocations, where n is the number of lines in the file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* strerror, strdup */
#include <errno.h>
typedef struct _node {
unsigned line;
char *data;
struct _node *next;
} node_t;
static void
destroy_list(node_t *list)
{
node_t *node;
for (node = list; node; node = node->next) {
if (node->data != NULL)
free(node->data);
free(node);
}
}
static node_t *
create_list_item(const char *data, unsigned line)
{
node_t *node = calloc(1, sizeof(node_t));
if (node == NULL) {
fprintf(stderr, "calloc: %s\n", strerror(errno));
} else {
node->line = line;
node->data = strdup(data);
if (node->data == NULL) {
fprintf(stderr, "strdup: %s\n", strerror(errno));
free(node);
node = NULL;
}
}
return node;
}
/* Returns pointer to new linked list */
static node_t *
read_file(FILE *fp, char *buf, size_t buf_len)
{
node_t *list = NULL;
node_t *prev = NULL;
node_t *node;
unsigned i;
for (i = 0; fgets(buf, buf_len, fp); prev = node) {
if ((node = create_list_item(buf, ++i)) == NULL) {
fprintf(stderr, "calloc: %s\n", strerror(errno));
break;
}
if (list == NULL)
list = node;
if (prev != NULL)
prev->next = node;
}
return list;
}
static void
print_list(const node_t *list)
{
const node_t *node;
for (node = list; node; node = node->next)
printf("%d: %s", node->line, node->data);
}
int main(int argc, char const* argv[])
{
const char *filename = "text.txt";
char buf[1024] = {0};
FILE *fp = NULL;
node_t *list = NULL;
if (NULL == (fp = fopen(filename, "r"))) {
fprintf(stderr, "failed to open file %s: %s\n",
filename, strerror(errno));
return 1;
}
list = read_file(fp, buf, sizeof(buf));
fclose(fp);
if (list) {
print_list(list);
destroy_list(list);
}
return 0;
}
Example using dynamic array
It is inefficient to allocate memory for each line (twice) in the file,
not only because the system calls (malloc, realloc, etc.) are costly,
but also because the items are placed non-contiguously. Accessing contiguous
region of memory is usually faster.
In the following code, the linked list is replaced with dynamic array. We
initialize memory for 10 lines at once. The size is increased as necessary.
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* strerror, strdup */
#include <errno.h>
typedef struct _node {
size_t line;
char *data;
} node_t;
static void
destroy_array(node_t *array, size_t size)
{
size_t i;
node_t *item;
for (i = 0; i < size; i++) {
item = &array[i];
if (item->data)
free(item->data);
}
free(array);
}
static void
print_array(node_t *array, size_t size)
{
size_t i;
node_t *item;
for (i = 0; i < size; i++) {
item = &array[i];
if (item->data) {
printf("%ld: %s", item->line, item->data);
}
}
}
static node_t *
read_file(FILE *fp, char *buf, size_t buf_len,
const size_t array_step, size_t *array_size)
{
node_t *item;
node_t *array = calloc(array_step, sizeof(node_t));
size_t size = 0;
if (array == NULL) {
fprintf(stderr, "calloc:%s\n", strerror(errno));
return array;
}
while (fgets(buf, buf_len, fp)) {
if (size && size % array_step == 0) {
array = realloc(array, sizeof(node_t) * (array_step + size));
if (array == NULL) {
fprintf(stderr, "realloc:%s\n", strerror(errno));
break;
}
}
item = &array[size++];
item->line = size;
item->data = strdup(buf);
if (item->data == NULL) {
fprintf(stderr, "strdup: %s\n", strerror(errno));
break;
}
}
*array_size = size;
return array;
}
int main(int argc, char const* argv[])
{
node_t *array;
const size_t array_step = 10;
size_t array_size;
const char *filename = "text.txt";
char buf[1024] = {0};
FILE *fp = NULL;
if (NULL == (fp = fopen(filename, "r"))) {
fprintf(stderr, "failed to open file %s: %s\n",
filename, strerror(errno));
return 1;
}
array = read_file(fp, buf, sizeof(buf), array_step, &array_size);
fclose(fp);
if (array) {
print_array(array, array_size);
destroy_array(array, array_size);
}
return 0;
}
Note the changes in node_t structure.

Linked lists, operations with parameter

I'm trying to implement program in with i can create ~arbitrary number of singly linked lists dynamically and perform operations on particular one (defined by parameter). I create dynamic array of head pointers so that i can refer to the certain head node defined by paramater(index of an array + 1). Parameter is just (1,2,3..number of lists). So far I have managed to implement only initialise and push function but the program after complilation doesn't work as expected. Where is the problem?
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define CHUNK 10
typedef struct
{
char *str;
struct node *next;
} node;
node *initialise(node **array, int *amount_of_lists);
void push(node **array, int *amount_of_lists);
char *getString(void);
int main()
{
node **heads = NULL; //initially null, pointer to the dynamic array of head pointers
int amount_of_lists = 0;
int *no_of_heads = &amount_of_lists;
initialise(heads, no_of_heads);
initialise(heads, no_of_heads);
push(heads, no_of_heads);
push(heads, no_of_heads);
return 0;
}
node *initialise( node **array, int *amount_of_lists ) /*reallocate memory for another head pointer ans return the pointer to node*/
{
++(*amount_of_lists);
printf("\n%d", *amount_of_lists);
array = (node**)realloc(array, sizeof(node*)*(*amount_of_lists));
return array[(*amount_of_lists) - 1] = malloc(sizeof(node));
}
int readParameter(int *amount_of_lists)
{
int parameter = 0, control = 0;
bool repeat = 0;
do
{
if(repeat)
{
printf("\nWrong parameter, try again.");
}
printf("\n Enter list parameter: ");
control = scanf("%d", &parameter);
fflush(stdin);
repeat = 1;
}
while( control != 1 || parameter < 1 || parameter > (*amount_of_lists) );
return parameter;
}
void push(node **array, int *amount_of_lists)
{
int parameter = readParameter(amount_of_lists) - 1;
node *temp = array[parameter];
array[parameter] = malloc(sizeof(node));
array[parameter] -> next = temp;
array[parameter] -> str = getString();
}
char *getString(void)
{
char *line = NULL, *tmp = NULL;
size_t size = 0, index = 0;
int ch = EOF;
while (ch)
{
ch = getc(stdin);
/* Check if we need to stop. */
if (ch == EOF || ch == '\n')
ch = 0;
/* Check if we need to expand. */
if (size <= index)
{
size += CHUNK;
tmp = realloc(line, size);
if (!tmp)
{
free(line);
line = NULL;
break;
}
line = tmp;
}
/* Actually store the thing. */
line[index++] = ch;
}
return line;
}
As BLUEPIXY somewhat crypticly hinted at in his comment 1), in order to modify main()'s heads in initialise(), you have to pass heads by reference to initialise(), i. e. change
initialise(heads, no_of_heads);
initialise(heads, no_of_heads);
to
initialise(&heads, no_of_heads);
initialise(&heads, no_of_heads);
consequently
node *initialise( node **array, int *amount_of_lists )
changes to
node *initialise(node ***array, int *amount_of_lists)
and inside array changes to *array, i. e.
*array = realloc(*array, sizeof(node *) * *amount_of_lists);
return (*array)[*amount_of_lists - 1] = malloc(sizeof(node));

C — How would I make my stack completely dynamic? [duplicate]

This question already exists:
C- How can I push Strings to stack one element at a time?
Closed 7 years ago.
Currently my code uses a stack and pushes a user entered string into the stack one by one. However I would like to make it dynamic, what would I malloc/realloc, I know I'm missing something completely obvious but I guess I have tunnel vision... help?
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
char a [MAXSIZE];
char * p = a;
int top = -1;
void push ( char n )
{
if ( top == 99)
{
printf( "stack overflow");
return;
}
top+=1;
a[top] = n;
}
/* Function to delete an element from the stack */
void pop(){
if(top == -1)
printf("Stack is Empty");
else
top-=1;
}
char *inputString(FILE* fp, size_t size){
//The size is extended by the input with the value of the provisional
char *str;
int ch;
size_t len = 0;
str = realloc(NULL, sizeof(char)*size);//size is start size
if(!str)return str;
while(EOF!=(ch=fgetc(fp)) && ch != '\n'){
str[len++]=ch;
if(len==size){
str = realloc(str, sizeof(char)*(size+=16));
if(!str)return str;
}
}
str[len++]='\0';
return realloc(str, sizeof(char)*len);
}
int balanced (char * m){
int size = sizeof(m);
int i, j;
for (i=0; i<=size; ++i){
push(m[i]);
}
}
int main(void){
char *m;
printf("input string : ");
m = inputString(stdin, 10);
printf("%s\n", m);
balanced(m);
int i;
for (i=0;i<=sizeof(a);++i){
printf("\n%c", a[i]);
}
free(m);
return 0;
}
If I understand your question properly, this is what you are supposed to do.
struct Stack
{
char c;
struct Stack *next;
}*stack = NULL;
char pop()
{
if(stack == NULL)
{
printf("Stack Underflow\n");
return NULL;
}
c = stack -> c;
struct Stack * temp = stack;
stack = stack -> next;
free(temp);
return c;
}
void push(char c)
{
struct Stack * temp = malloc(sizeof(struct Stack));
temp -> next = NULL;
temp -> c = c;
if (stack == NULL)
stack = temp;
else
{
temp -> next = stack;
stack = temp;
}
}

C array being overwritten/deleted? very confused

I am working on a project in C and it is working great except for one function which seems to be overwriting my array and writing weird numbers such as 1970802352 which keeps count of word occurrences in a file
this is my header file:
#ifndef LIST_H
#define LIST_H
struct Node_{
char* word;
//array holding names of files word occurs in
char **filesIn;
int numFilesIn;
//array holding count of how many times word occured in file
int* occursIn;
struct Node_ *next;
int isHead;
};
typedef struct Node_ Node;
int insert(char *wordToAdd, char *File);
int addOccur(Node *addedTo, char *File);
Node *createNode(char *wordToAdd, char *File);
void destroyNodes();
#endif
and this is the function that keeps overwriting the array:
Node *head;
int insert(char *wordToAdd, char *File){
if(head == NULL){
Node *new;
new = createNode(wordToAdd, File);
new->isHead = 1;
head = new;
return 0;
}
else{
Node *trace;
trace = head;
char *traceWord;
int wordSize;
wordSize = strlen(trace->word);
traceWord = (char*) malloc(wordSize + 1);
strcpy(traceWord, trace->word);
int a =strcmp(wordToAdd, traceWord);
free(traceWord);
if(a == 0){
int b = addOccur(trace, File);
//printf("addOccur returned %d\n", b);
return 0;
}
if(a < 0){
Node *Insert = createNode(wordToAdd, File);
trace->isHead = 0;
Insert->isHead = 1;
Insert->next = trace;
head = Insert;
return 0;
}
else{
Node *backTrace;
backTrace = head;
while(trace->next != NULL){
trace = trace->next;
traceWord = trace->word;
a = strcmp(wordToAdd, traceWord);
if(a < 0){
Node* Insert = createNode(wordToAdd, File);
Insert->next = trace;
backTrace->next = Insert;
return 0;
}
if(a == 0){
addOccur(trace, File);
//free(wordToAdd);
return 0;
}
if(a > 0){
backTrace = trace;
continue;
}
}
Node *Insert = createNode(wordToAdd, File);
trace->next = Insert;
return 0;
}
}
return 1;
}
and the other functions are:
Node* createNode(char *wordToAdd, char *File){
Node *new;
new = (Node*)malloc(sizeof(Node));
memset(new, 0, sizeof(Node));
new->word = wordToAdd;
char **newArray;
newArray = (char**)malloc(sizeof(char*));
newArray[0] = File;
new->filesIn = newArray;
int a[1];
a[0] = 1;
new->occursIn = a;
//new->occursIn[0] = 1;
new->numFilesIn = 1;
return new;
}
int addOccur(Node *addedTo, char *File){
char **fileList = addedTo->filesIn;
char *fileCheck;
int i = 0;
int fileNums = addedTo->numFilesIn;
for(i = 0; i < fileNums; i++){
fileCheck = fileList[i];
if(strcmp(fileCheck, File) == 0){
int *add1;
add1 = addedTo->occursIn;
int j = add1[i];
j++;
add1[i] = j;
return 0;
}
}
int numberOfFilesIn;
numberOfFilesIn = addedTo->numFilesIn;
char **newList = (char**)malloc(sizeof(char*) * numberOfFilesIn + sizeof(char*));
i = 0;
char *dest;
char *src;
for(i = 0; i < numberOfFilesIn; i++){
src = fileList[i];
int len;
len = strlen(src);
dest = (char*)malloc(sizeof(char) * (len + 1));
strcpy(dest, src);
newList[i] = dest;
}
int len2;
len2 = strlen(File);
newList[i] = File;
free(fileList);
int r = addedTo->numFilesIn;
r++;
addedTo->numFilesIn = r;
addedTo->filesIn = newList;
i = 0;
int *g;
g = addedTo->occursIn;
int count2;
count2 = addedTo->numFilesIn;
count2++;
int a[count2];
for(i = 0; i < count2 -1; i++){
a[i] = g[i];
}
a[count2 - 1] = 1;
return 0;
}
When going to gdb i notice that the value of
head->occursIn[0]
changes after the line
wordSize = strlen(trace->word);
and I have no clue why.
In your CreateNode() function, you are not allocating storage for the occursIn array. You are simply declaring a local array within the function and then assigning the occursIn pointer:
int a[1];
a[0] = 1;
new->occursIn = a;
The array a[1] goes away when the createNode function returns, so at that point your occursIn pointer is pointing to a value that is subject to being overwritten.
And even if the storage was allocated correctly in createNode, you've set a fixed size for the array but your whole strategy depends on that array having an element for each file; and in addOccurs you don't do anything to allocate a new larger array for a new file.
You may want to re-evaluate your strategy and switch to using lists instead of arrays.

Resources