Array of linked lists added to from directory - c

I've been trying to create an array of linked lists. The array being size 26 each part corresponding to a letter of the alphabet. The user inputs a directory of the PC and the name of any folders or files in that directory are then added to the a linked list in the array based on what letter they start with.
How i've been trying to do it->
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
My node and its declaration:
struct node{
char data[50];
struct node *next;
};
struct node* nodeArray[26];
My alphabet:
const char* basis[26] = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"};
A string comparing function to check which linkedlist in the array my word goes(compares to alphabet)
int StartsWith(const char *a, const char *b)
{
if(strncasecmp(a, b, strlen(b)) == 0) return 1;
return 0;
}
Where I add the node and also where the problem is(the printf("1") is there to stop my computer from basically crashing):
void addNode(struct node **q,const char *d){
if(((*q)->data)==NULL){
*q = malloc(sizeof(struct node));
strncpy((*q)->data,d,50);
(*q)->next = NULL;
} else {
(*q)->next = malloc(sizeof(struct node));
*q = (*q)->next;
printf("1");
addNode(q,d);
}
}
The function that calls addNode, directory is a computer directory that's already been checked to exist:
void returner(char* directory){
int i;
DIR *dp;
struct dirent *ep;
char* tempD;
dp = opendir (directory);
struct node **z;
while ((ep = readdir(dp))){
tempD = (char*)malloc(50);
if ( !strcmp(ep->d_name, ".") || !strcmp(ep->d_name, "..") ){
} else {
strncpy(tempD, ep->d_name, 50);
for(i=0; i<26 ; i++){
if(StartsWith(tempD, basis[i])){
z = &nodeArray[i];
addNode(z,tempD);
print();
}
}
}
free(tempD);
}
closedir (dp);
}
Print function:
void print(){
int i;
struct node *temp;
for(i=0 ; i < 26; i++){
temp = malloc(sizeof(struct node));
temp = nodeArray[i];
while(temp != NULL){
printf("%s\n",temp->data);
temp = temp->next;
}
}
}
The program seems fine when adding the first node to a spot on the array such as "aaa.txt" "bbb.txt" "ccc.txt" "ddd.txt", but once a second is attempted to be added like a "ccd.txt" after a "ccc.txt" exists when it keeps going forever or until the pc crashes

You're not checking the right value in your addNode for finding the list insertion point.
Pointer-to-pointer enumeration through a linked list is frequently used to walk from the head pointer to the last next pointer in the list, each time holding the address of the said-pointer. When you reach one that is NULL (which will be head in the case of an empty list), you stop, and you can use your pointer-to-pointer via dereference to assign your new node address.
If you want to insert on the tail, the way to do it would be something like this:
#define DATA_MAX_LEN 50
void addNode(struct node **q,const char *d)
{
// assumes a null-terminated linked list
while (*q)
q = &(*q)->next;
*q = malloc( sizeof **q );
// ensures truncation and termination
strncpy((*q)->data,d,DATA_MAX_LEN-1);
(*q)->data[ DATA_MAX_LEN-1] = 0;
// make sure we terminate the list at our new node
(*q)->next = NULL;
}
Invoked from your updated returner function like this:
void returner(char* directory)
{
DIR *dp = opendir (directory);
if (dp)
{
struct dirent *ep;
while ((ep = readdir(dp)))
{
// skip parent and self symbolic links
if (ep->d_name[0] == '.' && (ep->d_name[1] == 0 || (ep->d_name[1] == '.' && ep->d_name[2] == 0)))
continue;
for(int i=0; i<26 ; i++)
{
if(StartsWith(ep->d_name, basis[i]))
addNode(nodeArray+i, ep->d_name);
}
}
closedir (dp);
}
}

Related

Linked list same value

I am trying to understand the linked list in C. So i am trying to write a program which will read from a file and create a linked list. But I hit a roadblock which I couldn't find a reason why.
Although I set the head value node *h to n only one time it looks like the value is automatically changing to the next value of n. To check I used printf at the end. All of them are returning the same result. Can anyone help please?
P.S - This is my first time using stackoverflow.
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
char *name;
struct node *next;
} node;
int main (void)
{
//load the file.
FILE *fp = fopen("dictionary.txt", "r");
if (fp == NULL)
{
printf("Unable to open the file\n");
}
char characters[45];
//initialize the linked list.
node *n , *t, *h;
int flag = 0;
while(fgets(characters, 45, fp) != NULL)
{
//define node for n
n = malloc(sizeof(node));
if (n == NULL)
{
printf("Out of memory!!!");
}
//set the value of n
n -> name = characters;
//set the temp & head value to n first time
if (flag == 0)
{
t = n;
h = n;
}
//set the temp -> next value to n after first time
else
{
t -> next = n;
}
flag = 1;
}
printf("%s\n", h -> name);
printf("%s\n", t -> name);
printf("%s\n", n -> name);
}
name member in your node struct is only a pointer to a string (character array).
each node you assign name to point to the very same character array:
char characters[45];
you should allocate the character array for any node:
#define MAX_LEN 45
typedef struct node
{
char name[MAX_LEN];
struct node *next;
} node;
and copy the string:
//set the value of n
strncpy(n -> name,characters, MAX_LEN);
// ensure null terminated
n->name[MAX_LEN-1] = '\0';

Add a list on a trie node in C

I'm adding words (character per node) on a trie data structure - that happens correctly based on a implementantion I found on the web -
http://www.techiedelight.com/trie-implementation-insert-search-delete/
Although I want to extend this and add a list containing some data based on the words, such term frequency etc.
Right now I'm facing an issue with the pointer of the list when adding the first element on a trie node - in the method append_posting_list - and getting a segmetation fault.
Here is the code so far.
main.h
#ifndef TRIE_H
#define TRIE_H
#define CHAR_SIZE 26
typedef struct posting_list {
int doc_id;
int tf;
int df;
struct posting_list *next;
} posting_list_node ;
struct Trie
{
posting_list_node *p_node; // this will be the head of the posting list for every word;
int isLeaf; // 1 when node is a leaf node
struct Trie* character[CHAR_SIZE];
};
struct Trie* getNewTrieNode();
void insert(struct Trie* *head, char* str, int doc_id);
int search(struct Trie* head, char* str);
#endif //TRIE_H
main.c
#include <stdio.h>
#include <stdlib.h>
#include "main.h"
int main(){
struct Trie* head = getNewTrieNode();
insert(&head, "hello", 1);
return 0;
}
// Function that returns a new Trie node
struct Trie* getNewTrieNode()
{
struct Trie* node = (struct Trie*)malloc(sizeof(struct Trie));
node->isLeaf = 0;
for (int i = 0; i < CHAR_SIZE; i++)
node->character[i] = NULL;
return node;
}
posting_list_node* get_mem(){
posting_list_node* p;
p = (posting_list_node *)malloc(sizeof(posting_list_node));
if (p == NULL){
printf("Memory allocation failed\n");
exit(EXIT_FAILURE);
}
return p;
}
void append_posting_list(int doc_id, posting_list_node **n){
posting_list_node *new, *q;
new = get_mem();
new->doc_id = doc_id;
new->tf = 1;
new->next = NULL;
// if new is the first element of the list
if(n == NULL) {
*n = new;
} else {
q = *n;
while( q->next!=NULL) {
q = q->next;
}
q->next = new;
}
}
// Iterative function to insert a string in Trie.
void insert(struct Trie* *head, char* str, int doc_id)
{
// start from root node
struct Trie* curr = *head;
while (*str)
{
// create a new node if path doesn't exists
if (curr->character[*str - 'a'] == NULL)
curr->character[*str - 'a'] = getNewTrieNode();
// go to next node
curr = curr->character[*str - 'a'];
// move to next character
str++;
}
// already found this word, increase frequency
if(curr->isLeaf) {
curr->p_node->tf += 1;
} else {
append_posting_list(doc_id, curr->p_node);
// mark current node as leaf
curr->isLeaf = 1;
}
}
// Iterative function to search a string in Trie. It returns 1
// if the string is found in the Trie, else it returns 0
int search(struct Trie* head, char* str)
{
// return 0 if Trie is empty
if (head == NULL)
return 0;
struct Trie* curr = head;
while (*str)
{
// go to next node
curr = curr->character[*str - 'a'];
// if string is invalid (reached end of path in Trie)
if (curr == NULL)
return 0;
// move to next character
str++;
}
// if current node is a leaf and we have reached the
// end of the string, return 1
return curr->isLeaf;
}
I'm really stuck here.
Any suggestions would be really appreciated.
I found a couple things that when fixed, got rid of your segmentation fault.
In getNewTrieNode() I think you need to set p_node to NULL
struct Trie* getNewTrieNode() {
struct Trie* node = (struct Trie*)malloc(sizeof(struct Trie));
node->isLeaf = 0;
for (int i = 0; i < CHAR_SIZE; i++)
node->character[i] = NULL;
node->p_node = NULL;
return node;
}
append_posting_list() takes post_list_node **, but in insert(), you are passing just post_list_node *
void append_posting_list(int doc_id, posting_list_node **n)
append_posting_list(doc_id, curr->p_node);
looks like it should be
append_posting_list(doc_id, &(curr->p_node));
In append_posting_list()
if (n == NULL) {
should be
if (*n == NULL) {
in order to see if a pointer to an empty list is being passed in.
You should really have some functions to print out your data structure while you are working on it, so you can test each piece as you develop it. Simply compiling and running code and not getting any errors is no gurantee the code is working correctly with complex data structures like this. Making sure that each piece works perfectly before going on to the next piece will save you hours in trying to track down segmentation faults and other errors like this.

segmentation fault when adding array to a node n-ary tree

I'm trying to create an N-ary tree where I have a char array ex: {A,B,C,D} to insert to a tree.
I set the root to be "/"
if the command is mkdir /A/B/C => create node A at root, then B at A and C at B. if the command is mkdir B/C/D =>create node D inside C, etc... I simplified the code below so hopefully, there won't be any typo here. Anyway, upon debugging with gdb, it looks like the upon reaching search function will give me a segmentation fault, I made the code below, I'm really sure the insert function will have the same error as well but I haven't been able to test it out yet.
head.c
#pragma once
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define len 128
#define num 128
typedef struct tree{
char name;
char type;
struct node *child, *sibbling, *parentNode;
}node;
char *baseName[64];
node *root, *cwd;
tree.c
node *createNode(node * newNode, char ch, char ty){
node *curNode = (node*)malloc(sizeof(node));
curNode->name = ch;
curNode->type = ty;
curNode->parentNode = newNode;
curNode->sibbling = curNode->child=NULL;
return curNode;
}
node * insertNode(node *parent, char name, char type){
if(parent->child == NULL){
parent->child=parent;
createNode(parent->child,name,type);
}
else{
parent->sibbling = parent;
createNode(parent->sibbling,name,type);
}
}
node *searchNode(node *curNode, char name){
if(curNode->name ==name){ <------------error here
return curNode;
}
if(name != curNode->name && curNode->sibbling != '\0'){
searchNode(curNode->sibbling, name);
}
if(name != curNode->name && curNode->child != '\0'){
searchNode(curNode->sibbling, name);
}
return 0;
}
void mkDir(){
int index = 0;
int flag =0;
int baseFlag=0;
node *pwd = root;
///// insert
while(dirName[index] !='\0'){
if(searchNode(root,dirName[index]) != NULL){ <-- error in this searchNode function //no node exist
// insertNode(pwd,"A","D"); <---this probably error too
printf("found A");
}
else{
//node exist
cwd = searchNode(root,dirName[index]);
insertNode(cwd,dirName[index],"D");
}
index++;
}
}
memset(dirName,'\0',sizeof(dirName));
}
I suspect you are passing in a null node reference to the searchNode function, hence when you try to access the property name you are getting a segfault.
I would recommend testing for and handling for null references in your code.
function createNode return type is node*.In function insertNode you must store the address of new node in some other variable of type node*.
node *r
r=createNode(parent->child,name,type);
....
...
In the function searchNode you must check
if(curnode!=NULL) {
if(curNode->name ==name){
return curNode;
}
}
In the last line you are returning 0 but return type is node*
return either NULL or (node*)0.

C - LinkedList Sorting Infinite Loop

I am creating a program that will read a word from a text file in main.c, and send it over to list.c file to create a new node to store that word. The node will also store three ints: first (number of times this word appears in txt file 1), second(number of times this word appears in txt file 2), and dif (abs(first-second)). After adding all the new words to the file and counting the number of times each word exists in each txt file, the main.c will call a method that will calculate the difference between first and second for each node. This is difference (stored in dif for each node) will be used to sort the linked nodes in decreasing order.
EX. word: the, first: 2888, second: 2466, dif: 422.
red, 39 12 27
.....
However, when main calls the sort method, a infinite loop occurs. This infinite loop comes from the inner loop of the sorting algorithm, where the current node is assigned the node from the curr->next pointer. Somewhere during the sort method, the current node's next pointer points to the current node, not the actual next node in the linkedlist. If the sort method is dactivated, then all other functions work fine, including printAll which goes through the entire list and prints the data in each node (see my example above).
My issue is that I cannot find where in my sort method how current->next started to point to the current node. Any help is appreciated!
/*
* list.h
*/
#ifndef LIST_H_
#define LIST_H_
typedef struct node Node;
void findWord(char *word, int book);
void addWord(char *word, int book);
void editWord(Node **endPtr, int book);
void sort();
void swap(Node **a, Node **b);
void calculateDiff();
void printAll();
#endif /* LIST_H_ */
/*
* list.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"
typedef struct node{
int first;
int second;
int dif;
char name[20];
struct node *next;
}Node;
Node *front = NULL;
/*
* Sees if the current word exists in the
* linkedlist.
*/
void findWord(char *word, int book) {
Node *curr = front;
int boolean = 0;
while (curr != NULL) {
if(strcmp(curr->name, word) == 0) {
boolean = 1;
editWord(&curr, book);
break;
}
curr = curr->next;
}
if(!boolean) { //Add word if it does not exist.
addWord(word, book);
}
}
/*
* Creates a new node for the added word. Adds to front.
*/
void addWord(char *word, int book) {
Node *newNode = malloc (sizeof(Node));
/*
* Since this word is being added
* to the linkedlist with a newly
* created node, either the
* first or second int must be to 1
* while the other is set to 0. Based
* off of book int.
*/
if(book == 1) {
newNode->first = 1;
newNode->second = 0;
} else {
newNode->first = 0;
newNode->second = 1;
}
newNode->dif = 0;
strcpy(newNode->name, word);
newNode->next = front;
front = newNode;
}
/*
* Edits the data for an existing word.
* Only called if current word exists in
* the linkedlist.
*/
void editWord(Node **endPtr, int book) {
if (book == 1) {
(*endPtr)->first++;
} else {
(*endPtr)->second++;
}
}
/*
* Sorts the list in descending order based on
* difference value.
*/
void sort() {
Node *curr, *last = NULL;
curr = front;
while (curr != last) {
while (curr->next != last) {
if(curr->dif < curr->next->dif ) {
swap(&curr, &curr->next);
}
curr = curr->next;
}
last = curr;
curr = front;
}
}
/*
* Swaps the data in the current and next node in the list.
*/
void swap(Node **a, Node **b) {
int temp;
char nameTemp[20];
//Swap first
temp = (*a)->first;
(*a)->first = (*b)->first;
(*b)->first = temp;
//Swap second
temp = (*a)->second;
(*a)->second = (*b)->second;
(*b)->second = temp;
//Swap dif
temp = (*a)->dif;
(*a)->dif = (*b)->dif;
(*b)->dif = temp;
//Swap name
strcpy(nameTemp, (*a)->name);
strcpy((*a)->name, (*b)->name);
strcpy((*b)->name, nameTemp);
}
/*
* Calculates the difference between first and second
*/
void calculateDiff() {
Node *curr = front;
while(curr != NULL) {
curr->dif = abs((curr->first - curr->second));
curr = curr->next;
}
}
/*
* Prints all the data from the nodes.
*/
void printAll() {
printf("|| Word || RedBadge || LittleRegiment || Diff\n");
Node *curr = front;
while ( curr != NULL ) {
printf("%s, %d, %d, %d\n", curr->name, curr->first, curr->second, curr->dif);
curr = curr->next;
}
}
/*
* main.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "list.h"
void readBook(int book, FILE *infile);
void readLine(char *line, int book);
int main (void) {
setvbuf(stdout, NULL, _IONBF,0);
FILE *infile = fopen("RedBadge.txt", "r");
FILE *infile2 = fopen("LittleRegiment.txt", "r");
readBook(1, infile);
readBook(2, infile2);
fclose(infile);
fclose(infile2);
calculateDiff();
sort();
printAll();
return 0;
}
void readBook(int book, FILE *infile) {
char line[70];
//Read in each line
while (!feof(infile)) {
fgets(line, 70, infile);
readLine(line, book);
}
}
void readLine(char *line, int book) {
int i = 0, j = 0;
char word[20];
while (line[i]) {
line[i] = tolower(line[i]); //Convert line to lowercase
if((line[i] <= 'z' && line[i] >= 'a') || line[i] == 39 || line[i] == '-') {
word[j] = line[i];
j++;
} else if (j != 0) {
word[j] = '\0';
findWord(word, book);
j = 0;
}
i++;
}
}
I believe your error is actually a buffer overflow. There are words in those books that are longer than 19 characters (the max that will fit in your word variable). When your readline function tries to read those words it will write outside the boundaries of the word array, which is undefined behavior. It will then also use strcpy to copy the word into the node, which will also overflow the node's word array.
A quick fix is to just throw away the extra characters past 19 that won't fit in your word array. In readline add a test for how big j is:
if (j < sizeof word - 1) {
word[j] = line[i];
j++;
}
One of the words in question is "ain't--plundering----" (at least in the copy of the text i downloaded), which leads me to think maybe you also should split words on punctuation.

Pointer trouble creating binary trees

I am creating a binary tree from a bitstring in c. ie 1100100 creates a tree:
1
/ \
1 1
I decided to use a recursive function to build this tree however i keep getting the error
Debug assertion failed...
Expression : CrtIsValidHeapPointer(pUserData)
here is a fragment of my code
typedef
struct Node {
char key;
struct Node *left;
struct Node *right;
} Node;
char string[1000];
int i = 0;
void insertRecursivePreorder(Node **node)
{
Node* parent = *node;
if(string[i] == '0')
{
parent = NULL;
i++;
}
else
{
Node *newn = (Node*)malloc(sizeof(Node));
newn->key = string[i];
parent = newn;
i++;
insertRecursivePreorder(&newn->left); //errors occur here
insertRecursivePreorder(&newn->right); //errors occur here
free(newn);
free(parent);
}
}
int main(void)
{
void printTree(Node* node);
Node* root = NULL;
scanf("%s", string);
insertRecursivePreorder(&root);
//... do other junk
}
i was wondering why this error comes about and what i can do to fix it.
The immediate problem is likely to be calling free on a pointer twice. In insertRecursivePreorder, you set parent to newn, and then call free on both. As an example of this, the following program fails (but works if you comment out one of the free(..)s):
#include <stdlib.h>
int main() {
int *a = malloc(sizeof(int)),
*b = a;
free(a);
free(b);
return 0;
}
However, there are several problems with your logic here. You should only call free when you have completely finished with the pointer, so if you are using your tree later you can't free it as you construct it. You should create a second function, recursiveDestroyTree, that goes through and calls free on the tree (from the bottom up!).
And, you probably want *node = newn rather than parent = newn, since the latter is the only one that actually modifies node.
(You could also change your function to return a Node * pointer, and then just go:
root = insertRecursivePreorder();
and
newn->left = insertRecursivePreorder();
newn->right = insertRecursivePreorder();
instead of trying to keep track of pointers to pointers etc.)
(Furthermore, on a stylistic point, using global variables is often bad practice, so you could have your insertRecursivePreorder take int i and char * string parameters and use them instead of global variables.)
The problem was: you were never assigning to the double pointer in 'insertRecursivePreorder', so root always stayed NULL.
#include <stdio.h>
#include <stdlib.h>
typedef
struct Node {
char key;
struct Node *left;
struct Node *right;
} Node;
/* slightly changed the syntax for the str
** ; now '.' indicates a NULL pointer, values represent themselves.
*/
char *string = "12..3.." ;
/* Removed the global index 'i' */
void printTree(Node* node, int level);
unsigned insertRecursivePreorder(Node **pp, char *str);
unsigned insertRecursivePreorder(Node **pp, char *str)
{
unsigned pos =1;
if (!*str) { *pp = NULL; return 0; } /* safeguard for end of string */
if (*str == '.') { *pp = NULL; return pos; }
*pp = malloc(sizeof **pp);
(*pp)->key = *str;
pos += insertRecursivePreorder(&(*pp)->left, str+pos);
pos += insertRecursivePreorder(&(*pp)->right, str+pos);
return pos;
}
void printTree(Node* node, int level)
{
unsigned pos,len;
len = level> 0 ? level : -level;
for (pos =0; pos < len; pos++) putchar (' ');
if (!level) printf ("Root=");
else if (level<0) printf ("Left=");
else printf ("Right=");
if (!node) { printf( "Null\n" ); return; }
printf("Key=%c\n", node->key );
printTree(node->left, -(len+1) ) ;
printTree(node->right, len+1) ;
}
int main(void)
{
Node *root = NULL;
unsigned result = 0;
result = insertRecursivePreorder(&root, string);
printf( "Result=%u\n", result);
printTree(root, 0);
return 0; printTree(root, 0);
}
Output:
Result=7
Root=Key=1
Left=Key=2
Left=Null
Right=Null
Right=Key=3
Left=Null
Right=Null

Resources