Iterating over linked list in C - c

I have a linked list that contains two "strings", one for searching and one for replacing. I also have a text file that I'm supposed to open and read line by line then see if the words exist in the "dictionary" (the linked list) if it does, I have to replace it with the word's definition. Then write the changed text into a new text file, so I thought I should use a buffer when reading.
The problem is, I don't know how to iterate over the linked list. So far I have two words in it but it only searches for the first one in the loop:
char *textLine = NULL;
size_t textlen = 0;
ssize_t readText;
struct node *n = malloc(sizeof(*n));
n = head;
char buffer[MAX_L];
while ((readText = getline(&textLine, &textlen, t)) != -1) {
char *t = strtok(textLine, " ");
while (t != NULL) {
if (strcmp(t,n->word) == 0) {
// do something
} else {
// do something
}
n = head;
t = strtok(NULL, " ");
}
}
head is NULL, I guess that's why it only searches for the first word I just don't really know how should I iterate over both the lines and the linked list.

How, specifically, to iterate over a linked list depends, to some extent, on its interface.
Not having the interface to the particular implementation you are using available, the question is difficult to answer; but typically; a linked list looks something like this:
typedef struct list_node ListNode;
struct list_node {
void *payload;
ListNode *next;
}
Iterating is usually (always?) done by following the next pointer, so long as it is not NULL; like so:
void iterate (ListNode *head) {
while (head) {
if (interested_in_payload(head->payload)) {
// do stuff
}
head = head->next;
}
}

This:
struct node *n = malloc(sizeof(*n));
n = head;
looks very scary. It's almost never correct to first allocate some memory, then immediately overwrite the pointer.
Perhaps you meant
head = n;
?

Related

C: From char array to linked list

I'm still learning how to program in C and I've stumbled across a problem.
Using a char array, I need to create a linked list, but I don't know how to do it. I've searched online, but it seems very confusing. The char array is something like this char arr[3][2]={"1A","2B","3C"};
Have a look at this code below. It uses a Node struct and you can see how we iterate through the list, creating nodes, allocating memory, and adding them to the linked list. It is based of this GeeksForGeeks article, with a few modifications. I reccommend you compare the two to help understand what is going on.
#include <stdio.h>
#include <stdlib.h>
struct Node {
char value[2];
struct Node * next;
};
int main() {
char arr[3][2] = {"1A","2B","3C"};
struct Node * linked_list = NULL;
// Iterate over array
// We calculate the size of the array by using sizeof the whole array and dividing it by the sizeof the first element of the array
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
// We create a new node
struct Node * new_node = (struct Node *)malloc(sizeof(struct Node));
// Assign the value, you can't assign arrays so we do each char individually or use strcpy
new_node->value[0] = arr[i][0];
new_node->value[1] = arr[i][1];
// Set next node to NULL
new_node->next = NULL;
if (linked_list == NULL) {
// If the linked_list is empty, this is the first node, add it to the front
linked_list = new_node;
continue;
}
// Find the last node (where next is NULL) and set the next value to the newly created node
struct Node * last = linked_list;
while (last->next != NULL) {
last = last->next;
}
last->next = new_node;
}
// Iterate through our linked list printing each value
struct Node * pointer = linked_list;
while (pointer != NULL) {
printf("%s\n", pointer->value);
pointer = pointer->next;
}
return 0;
}
There are a few things the above code is missing, like checking if each malloc is successful, and freeing the allocated memory afterwards. This is only meant to give you something to build off of!

Delete a string out of a linked list of strings

I am working on a word processor where it is requested to be able to delete a word out of a list of words.
Basically, the user enters words (thus, strings of characters) which are then stored in a linked list (here dico, thanks to the structure dictionary which represents all the words that the user has entered).
I am unfortunately stuck : it seems like the code I wrote only ever deletes the second character, whereas I would like it to be able to delete the word requested by the user (here : str).
For instance, if the user had previously entered : "hello world" and they would now like to delete the world "world", the dico should now be "hello".
typedef struct dll {
char data;
int count; //not needed here
struct dll* next;
} dll; //linked list of each character : dll represents one word
typedef struct dictionary {
dll * data;
struct dictionary* next;
struct dictionary* prev;
} dictionary; //linked list of all the words
dll* entry(){
char data = getc(stdin);
if (data != '\n'){
dll* curr = create_dico(data);
curr->next=entry();
return curr;
}
return NULL;
}
void suppression(dictionary** dico) {
printf("Please enter what you wish to remove out of the list: \n");
dictionary *str = malloc(sizeof(dictionary));
str->data = entry();
str->next = NULL;
dictionary* temp = *dico;
if (str->data == NULL){
*dico = temp->next;
free(temp);
return;
}
while (temp != NULL && temp->data->data == str->data->data) {
temp = temp->next;
}
dictionary *next = temp->next->next;
free(temp->next);
temp->next = next;
}
Your deletion function doesn't reflect the data structures you are using: linked lists of linked lists!
The very first thing you need to do is detect where the word is located, you need to compare the two linked lists for that purpose:
// notice: pointer to dll, not dictionary!
dll* str = entry();
dictionary* temp = *dico;
while(temp)
{
dll* s = str; // you yet need original str for deletion!
dll* word = temp->data;
while(word && s && word->data == s->data)
{
word = word->next;
s = s->next;
}
// OK, now we need to know if we reached the ends of BOTH word and s
// -> in that case, both are equal!
if(!word && !s)
break;
}
So we iterated over the words list now. If we found the string inside, we stopped prematurely, otherwise we reached the null-element at the very end. So:
if(temp)
{
// we didn't reach end of the words' list -> we found an equal element
// at first, we'd remove the current word from the linked simply by
// re-linking predecessor and successor nodes
// the nice thing about is that you created a doubly linked list
// so we have both of them available from current node, so:
if(temp->prev)
temp->prev->next = temp->next;
else
// special case: we are deleting the head node!
*dico = temp->next;
if(temp->next)
temp->next->prev = temp->prev;
// no else needed, as we haven't a dedicated tail node
// now we need to delete the word's characters!
dll* word = temp->data;
while(word)
{
dll* next = word->next;
free(word);
word = next;
}
// now we yet need to delete the word node itself!
free(temp);
}
Fine so far, the list is adjusted. We created a temporary reference string, though, which itself needs to be freed again as well:
while(str)
// well, just the same as when deleting the word...
As you do the same thing twice, you might create a common function for...
Be aware that above is untested code, no guarantee that it is bug-free. But it should suffice to show where you have to keep an eye on... Be aware, too, that this answer is based on quite a few assumptions, mainly the lists having been created correctly before, as you didn't provide a minimal reproducible example.

Search linked list by substring and create a new linkedlist with all structs that contain the substring

Suppose I have the following struct:
struct _node {
int id;
char *name;
struct node *next;
};
I want to write a function that goes through the linkedlist and looks for structs whose name member contains a certain substring and adds those structs to a new linkedlist and returns the new linkedlist.
I attempted doing this using strstr but at some point I am getting an infinite loop and I can't figure out exactly why the infinite loop is happening.
Here is my function:
struct _node *containSubstr(struct _node *head, char needle[]) {
if (head == NULL) {
printf("BLOOP BLEEP BOOP BEEP.\n");
exit(EXIT_FAILURE);
}
struct _node *curr = head;
struct _node *returnHead = createEmptyNode();
while (curr != NULL) {
char haystack[strlen(curr->name)];
strcpy(haystack, curr->name);
strToLower(needle);
strToLower(haystack);
if (strstr(haystack, needle) != NULL) {
// this is where I get the infinite loop
append(returnHead, curr);
}
curr = curr->next;
}
return returnHead;
}
The functions append and createEmptyNode are tested and work fine.
I went over the logic multiple times and I think this must work. I filled my code with print statements and it seems like after it finds all the nodes that contain the substring it keeps repeating the last node and goes into an infinite loop.
Here is my append function:
void append(struct _node *head, struct _node *newNode) {
if (head == NULL) {
printf("BLOOP BLEEP BOOP BEEP.\n");
exit(EXIT_FAILURE);
}
struct _node *curr = head;
if(curr == NULL) {
head = newNode;
}
else {
while(curr->next != NULL) {
curr = curr->next;
}
curr->next = newNode;
}
}
Imagine this case: you have a list L that contains just 2 nodes (A and B) in your linked list. Imagine that both nodes A and B contain a substring you are looking for:
Original list L:
A->B->NULL
So after first iteration your new list L2 should look like this:
A->NULL
But in your append function you don't create a deep copy of a new node. Therefore, your new list L2 looks like this:
Empty_node->A->B->NULL
In the next step you move to node B. So you take your L2 and append there B. Your L2 after second iteration looks like this:
Empty_node->A->B->B (B points to itself).
Since you don't create deep copies you are actually always working with list L and when you append node B to what you think is the list L2 you actually append B to L and then B points to itself (curr->next = newNode; in your append function). So in the next iteration you are again asking if B contains the string you are looking for.
Conclusion
You need to create deep copies when creating new list.
In the current setup your append function modifies original list.

C: Adding data from text file into a singly linked list

I'm recently started learning C programming. I have some java experience so I know my way around codes, I like to think..
This little thing I'm working on is killing me.
I'm trying to make a program that read lines from a text file -> store it in a singly linked list -> print out the singly linked list
This is my code so far:
typedef struct node {
char *data;
struct node *next;
} node;
node *start = NULL;
node *current;
void add(char *line) {
node *temp = malloc(sizeof(node));
// This line under I believe where my problem is...
temp->data = line;
temp->next = NULL;
current = start;
if(start == NULL) {
start = temp;
} else {
while(current->next != NULL) {
current = current->next;
}
current->next = temp;
}
}
This is my function for reading the file and sending characters to the add function
void readfile(char *filename) {
FILE *file = fopen(filename, "r");
if(file == NULL) {
exit(1);
}
char buffer[512];
while(fgets(buffer, sizeof(buffer), file) != NULL) {
// I've tried to just send i.e: "abc" to the add function
// which makes the program work.
// like: add("abc");
// my display method prints out abc, but when I'm sending buffer
// it prints out nothing
// Thing is, I've spent way to much time trying to figure out what
// I'm doing wrong here...
add(buffer);
}
fclose(file);
}
I'm sure this is a fairly simple problem, but I've spent way too much time with this problem.
And if there is anything other that look off/could be better I appreciate feeback on that aswell :)
Try:
temp->data = strdup(line);
to duplicate (make a copy of) what line points at.
Otherwise every line points at the buffer which is getting overwritten with each new line.
You need to allocate memory for the string - each line is read into buf and so you need to copy it out or it will be overwritten with subsequent lines. I suggest one of two approaches, the first being the simplest with what you already have, but the second being better as you only need to do one free() for each object.
The first one is just a single change to your add() function:
temp->data = malloc(strlen(line)+1);
strcpy(temp->data, line);
Now, when you want to free an object in your linked list you must first call free() on data and then free() on the object itself.
However you can change the structure slightly and then you can allocate the whole object in one go:
typedef struct node {
struct node *next;
char data[0];
} node;
Then your add() function would look like this:
void add(char *line) {
node *temp = malloc(sizeof(node)+strlen(line)+1);
strcpy(temp->data, line);
temp->next = NULL;
current = start;
if(start == NULL) {
start = temp;
} else {
while(current->next != NULL) {
current = current->next;
}
current->next = temp;
}
}
Note that of course you should do error checking after each malloc() in production code. When you are done with an object a single free() is enough to free the whole structure.
Edit: The "array length 0" feature is a GCC specific extension, as noted by #crashmstr in the comments. If you use an array length of 1, it should work in any compiler though:
typedef struct node {
struct node *next;
char data[1];
} node;
Since an extra byte is already allocated in this case, the malloc() call in the add() function would then become:
node *temp = malloc(sizeof(node)+strlen(line)+1-1);
(of course the +1-1 can be omitted, but it is just to show that we still need space for the null terminator but an extra byte is already included in the sizeof).

Creating a LinkedList using sscanf in C

I need to implement a LinkedList from a file .csv file. My node is defined like this:
struct NODE {
char username[50];
char password[50];
char usertype[50];
struct NODE *next;
} *head=NULL;
I have put my whole .csv file inside an 1D array called database. I then want to sscanf this array and put each corresponding word inside a particular field inside my node. I have the following code written down:
void createList() {
// I need a while-loop here //
struct NODE* toAdd = (struct NODE*)malloc(sizeof(struct NODE));
sscanf(database, "%[^','],%[^','],%[^'\n']", toAdd->username, toAdd->password, toAdd->usertype);
if (add(toAdd) == false) {
printf("Error: was unable to initialize password validation!");
exit(EXIT_FAILURE);
}
}
My add function looks like this:
BOOLEAN add(struct NODE *p) {
if (p == NULL) return false;
if (head == NULL) {
p->next = NULL;
head = p;
} else {
p->next = head;
head = p;
}
return true;
}
Is there something wrong with the functions above? To sum up, I want to read from an array. I "break" this array into three-word-block, then assign the first one to the username field of the node, the second one to the password field, etc. I want to do this on my whole array, therefore creating one big LinkedList of nodes.
Thank you for your help.

Resources