Insert a string in a single linked list - c

I am trying to insert a string into a linked list of other strings.
The goal is to have the user enter whatever string they want (str_insert). Then, the user has to enter after which word they want to insert the string (new_node).
Unfortunately, the code manages to insert the word but it only ever inserts it in second position. The function used to insert the word is called insertion.
typedef struct dll {
char data;
int count;
struct dll* next;
} dll;
typedef struct dictionary {
dll * data;
struct dictionary* next;``
struct dictionary* prev;
} dictionary;
dll* entry(){
char data = getc(stdin);
if (data != '\n'){
dll* curr = create_dico(data);
curr->next=entry();
return curr;
}
return NULL;
}
dictionary* insertion(dictionary *dico) {
printf("Please enter the string you want to insert in your already
existing list: \n");
dictionary * str_insert = malloc(sizeof(dictionary));
str_insert->data = entry();
str_insert->next = NULL;
printf("Please enter after which word you would like to insert the
previous entry: \n");
dictionary* new_node =(dictionary*)malloc(sizeof(dictionary));
new_node->data = entry();
new_node->next = dico->next;
new_node->prev = dico;
if (dico->next != NULL) {
str_insert->next = dico->next;
dico->next = str_insert;
}
}

I managed to make it work by implementing another function that compared the input with the already existing list.
Here is the final result:
dictionary* research(dictionary* dico, dll *search){
dll *save = search;
while (dico != NULL) {
dll *tmp = dico->data;
search = save;
while(tmp->data == search->data && tmp->next != NULL && search->next != NULL){
tmp = tmp->next;
search = search->next;
}
if(tmp->data == search->data){
return dico;
}
dico = dico->next;
}
return NULL;
}
void insertion(dictionary *dico) {
printf("Please enter the string you want to insert in your already existing list: \n");
dictionary * str_insert = malloc(sizeof(dictionary));
str_insert->data = entry();
str_insert->next = NULL;
printf("Please enter after which word you would like to insert the previous entry: \n");
dictionary* search =(dictionary*)malloc(sizeof(dictionary));
search->data = entry();
search = research(dico, search->data);
if (search == NULL){
printf("Sorry, this word isn't in the list.\n");
}
else{
if(search->next != NULL){
search->next->prev = str_insert;
}
str_insert->next = search->next;
search->next = str_insert;
str_insert->prev = search;
}
}

Related

Wrong value when inserting into a linked list in c

I am trying to insert words into a hash table and it looks like it works but when I try to print the word inside the node (just to check if its still correct) I get a bogus value. When my code prompts for the word I said 'Hey' and when it prompts for place I said '5'. The string that is printed out(which is supposed to be the word inside the node) is HH9[]A\A]A^A_f. What is happening to the word inside the node and am I inserting the node correctly?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct node
{
char word[20];
struct node *next;
}
node;
int main (void)
{
node* table[10];
char wrd[10];
printf("Word to insert: ");
fgets(wrd, 10, stdin);
int place;
printf("Place to insert word: ");
scanf("%d", &place);
node *n = malloc(sizeof(node));
if(n == NULL)
{
return 1;
}
strcpy(n->word, wrd);
if(table[place] == NULL)
{
n = table[place];
n->next = NULL;
}
else
{
n->next = table[place];
n = table[place];
}
printf("Word inside node: %s \n" , n->word);
}
EDIT
I changed the code and tried to implement it on a larger scale but my while loop gives me a segfault. This is the function I put it in:
FILE* dct = fopen ("/dictionaries/large", "r");
char *wrd = NULL;
while(fscanf(dct, "%s", wrd) != EOF)
{
int place = hash(wrd);
node *n = malloc(sizeof(node));
node *anchor = NULL;
node *end = NULL;
if(n == NULL)
{
return 1;
}
strcpy(n->word, wrd);
n->next = NULL;
if (!end) //Initial state
anchor = end = n;
else //Every following node.
end = end->next = n;
strcpy(n->word, wrd);
n->next = table[place];
table[place] = n;
counter++;
}
return false;
It has to read from the dictionary file and load the word into memory(or a hash table).
A linked list is a linked list because it does not have a fixed size.
The table array is therefor superfluous.
What you need for your linked list to work is to remember the anchor and nothing more.
A small example:
Node *anchor = NULL;
Node *end = NULL;
Node *node = malloc(sizeof(Node));
node->next = NULL;
if (!end) //Initial state
anchor = end = node;
else //Every following node.
end = end->next = node;
At this point, you can still access the node you've just filled. Don't forget to iterate over your list later and free those allocations though.
This code doesn't make any sense:
if(table[place] == NULL)
{
n = table[place]; // since we know table[place] is null, that sets n to null!
n->next = NULL; // We just set n to NULL, we can't access n->next!
}
else
{
n->next = table[place]; // This sets n to a garbage value since table[place] was never assigned a value
n = table[place]; // This leaks the value we malloc'ed. We were supposed to link it to the list!
}

strcmp in Linked List insertion crashing program

As part of an assignment, I'm supposed to implement a singly linked list in c.
I've done this plenty of times before in a few different languages, but after a few hours of pain I've gotten stuck on a problem using strcmp.
This is the structure I'm using:
typedef struct node {
char *name;
float score;
struct node *next;
} node;
The problem is specific to the insertion function, which is supposed to be similar to an insertion sort, since I need to have the nodes in the list sorted in alphabetical order.(my professor specified that the insertion function does the sorting, despite not calling it an insertion sort).
void insert(node **start, char *name, float score) { // to insert a record into the linked list sorted by name in dictionary order.
//create new node
node *n_node = new_node(name, score);
node *current;
current = *start;
if (current != NULL) { //-----------if list is not empty
node *prev = NULL;
if (current->next != NULL) { //--if list has more than 1 element
while (current != NULL && strcmp(name, current->name) > 0) { //cycle through list to sorted insertion point
// ^^^^^^^Problem Here^^^^^^^^
//while name is greater than current name, means lower on alphabet (z>a)
prev = current;
current = current->next;
}
if (current != NULL) { //-----not at end of list
//once current is not < new node, connect between prev and current
prev->next = n_node;
n_node->next = current;
} else { // ------------------at end of list
prev->next = n_node;
}
} else { //-----------------------list has only one element
current->next = n_node;
}
} else { //--------------------------List is empty - assign new node as first element
*start = n_node;
}
}
The problem is that my program crashes and burns without any errors or warnings (I'm using eclipse with CDT).
The program works fine when
while (current != NULL && strcmp(name, current->name) > 0)
is modified to
while (current != NULL /*&& strcmp(name, current->name) > 0*/).
It seems obvious to me that name or current->name are causing a problem with the operation of strcmp, but I can't seem to get around that.
Edit:
I'll add that this function is called from another function, which retrieves and tokenises strings from a file containing pairs of names and marks, but my testing hasn't suggested that it passes a bad string or characters via the call.
For some extra detail, here's my new_node function:
node *new_node(char *name, float score) {
node *new = (struct node*) malloc(sizeof(struct node));
new->name = malloc(strlen(name) + 1);
strcpy(new->name, name);
new->score = score;
new->next = NULL;
return new;
}
(I realise using new as the name of the node isn't smart, and I will change that)
and the function that calls insert:
int data_import(node **startp, char *infilename) { // to import data from the file and insert .
int max_line = 100;
char line[max_line];
char delimiters[] = ",";
char name[500] = "";
char *namep;
namep = &name[0];
float score = 0.0f;
int i = 0;
FILE *fi;
char *token;
// open file to read
fi = fopen(infilename, "r");
if (fi == NULL) { // Cannot open the file.
perror("error");
return 0;
}
// read each line, increase counter, retrieve data
while (fgets(line, max_line, fi) != NULL) {
//fputs(line, stdout); //console output confirmation
token = strtok(line, delimiters);
strcpy(namep, token);
token = strtok(NULL, delimiters); //increment token to mark variable
score = atof(token);
insert(startp, namep, score);
i++;
}
//close file
fclose(fi);
return i;
}
what happens if you have element called apple as your first element and you try to add element called about ?
you will be thrown out of below while loop straight away and your prev will be unassigned :
while (current != NULL && strcmp(name, current->name) > 0) { //cycle through list to sorted insertion point
// ^^^^^^^Problem Here^^^^^^^^
//while name is greater than current name, means lower on alphabet (z>a)
prev = current;
current = current->next;
}
this particular part looks suspicious to me :
after that you will enter in below routine :
if (current != NULL) { //-----not at end of list
//once current is not < new node, connect between prev and current
prev->next = n_node;
n_node->next = current;
}
as your *prev is unassigned and you try to access it (prev->next = n_node;).you will get crash here.

Linked list insertion doesn't work as expected

I'm writing a function that places new nodes alphabetically into a linked list structure by sorting them by the name field. Here is my program, intended to test that it can successfully insert a new node into an existing structure:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_NAME_LENGTH 100
#define MAX_JOB_LENGTH 100
struct Employee
{
/* Employee details */
char name[MAX_NAME_LENGTH+1]; /* name string */
char sex; /* sex identifier, either ’M’ or ’F’ */
int age; /* age */
char job[MAX_JOB_LENGTH+1]; /* job string */
/* pointers to previous and next employee structures in the linked list
(for if you use a linked list instead of an array) */
struct Employee *prev, *next;
};
void place_alpha(struct Employee *new, struct Employee **root);
int main(){
struct Employee *a;
struct Employee *c;
struct Employee *b;
a = malloc(sizeof(struct Employee));
c = malloc(sizeof(struct Employee));
b = malloc(sizeof(struct Employee));
strcpy(a->name, "A");
a->sex = 'F';
a->age = 42;
strcpy(a->job, "Optician");
a->prev = NULL;
a->next = c;
strcpy(c->name, "C");
c->sex = 'F';
c->age = 22;
strcpy(c->job, "Nurse");
c->prev = a;
c->next = NULL;
strcpy(b->name, "B");
b->sex = 'M';
b->age = 34;
strcpy(b->job, "Rockstar");
b->prev = NULL;
b->next = NULL;
place_alpha(b, &a);
if(a->prev == NULL)
{
printf("a->prev is correct\n");
}else{
printf("a->prev is INCORRECT\n");
}
if(a->next == b)
{
printf("a->next is correct\n");
}else{
printf("a->next is INCORRECT");
}
if(b->prev == a)
{
printf("b->prev is correct\n");
}else{
printf("b->prev is INCORRECT\n");
}
if(b->next == c)
{
printf("b->next is correct\n");
}else{
printf("b->next is INCORRECT\n");
}
if(c->prev == b)
{
printf("c->prev is correct\n");
}else{
printf("c->prev is INCORRECT\n");
}
if(c->next == NULL)
{
printf("c->next is correct\n");
}else{
printf("c->next is INCORRECT\n");
}
}
void place_alpha(struct Employee *new, struct Employee **root) //Places a new node new into the database structure whose root is root.
{
if(*root==NULL) //If there is no database yet.
{
*root = new;
(*root)->prev = NULL;
(*root)->next = NULL;
}
else
{
if(strcmp(new->name, (*root)->name)<=0) // if the new node comes before root alphabetically
{
new->next = *root;
new->prev = (*root)->prev;
if((*root)->prev != NULL)
{
(*root)->prev->next = new;
}
(*root)->prev = new;
*root = new;
return;
}
else if((*root)->next == NULL) // If the next node is NULL (we've reached the end of the database so new has to go here.
{
new->prev = *root;
new->next = NULL;
(*root)->next = new;
return;
}
else if(strcmp(new->name, (*root)->name)>0) // If the new node comes after root alphabetically
{
place_alpha(new, &(*root)->next);
return;
}
}
}
Sadly, the program is unsuccessful, as showcased by the output:
a->prev is correct
a->next is correct
b->prev is INCORRECT
b->next is correct
c->prev is INCORRECT
c->next is correct
Program ended with exit code: 0
I can't figure out why, as I've clearly set b->next to c and c->prev to b.
This was tricky: there is a subtile bug in your place_alpha() function: you update *root even if it is not the root node of the list. This causes the pointer b to be updated erroneously. place_alpha() should only be called with a pointer to the actual root node.
I modified your code to make it more readable and reliable:
I wrote a function to create a new node
I protected the string copies from overflow using calloc() and strncat(). Read about these functions in the manual.
I use place_alpha() to insert all 3 nodes into the list in the same order you do.
I use newp instead of new to avoid C++ keywords in C code.
Note that place_alpha() must be called with a pointer to the head pointer of the list, if you pass a pointer to an intermediary node, chaining back along the prev links would locate the first node, but if the new employee should be inserted at the head of the list, you would not have the address of the root node to update in the caller's scope. This is the reason many programmers prefer to use a specific structure for the list head.
Here is the updated code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_NAME_LENGTH 100
#define MAX_JOB_LENGTH 100
struct Employee {
/* Employee details */
char name[MAX_NAME_LENGTH + 1]; /* name string */
char sex; /* sex identifier, either 'M' or 'F' */
int age; /* age */
char job[MAX_JOB_LENGTH + 1]; /* job string */
/* pointers to previous and next employee structures in the linked list
(for if you use a linked list instead of an array) */
struct Employee *prev, *next;
};
void place_alpha(struct Employee *new, struct Employee **root);
struct Employee *new_employee(const char *name, char sex, int age, const char *job) {
struct Employee *newp = calloc(1, sizeof(*newp));
if (!newp) {
fprintf(stderr, "cannot allocate employee\n");
exit(1);
}
strncat(newp->name, name, MAX_NAME_LENGTH);
newp->sex = sex;
newp->age = age;
strncat(newp->job, job, MAX_JOB_LENGTH);
newp->next = newp->prev = NULL;
return newp;
}
int main(void) {
struct Employee *list = NULL;
struct Employee *a = new_employee("A", 'F', 42, "Optician");
struct Employee *b = new_employee("B", 'M', 34, "Rockstar");
struct Employee *c = new_employee("C", 'F', 22, "Nurse");
place_alpha(a, &list);
place_alpha(c, &list);
place_alpha(b, &list);
if (a->prev == NULL) {
printf("a->prev is correct\n");
} else {
printf("a->prev is INCORRECT\n");
}
if (a->next == b) {
printf("a->next is correct\n");
} else {
printf("a->next is INCORRECT");
}
if (b->prev == a) {
printf("b->prev is correct\n");
} else {
printf("b->prev is INCORRECT\n");
}
if (b->next == c) {
printf("b->next is correct\n");
} else {
printf("b->next is INCORRECT\n");
}
if (c->prev == b) {
printf("c->prev is correct\n");
} else {
printf("c->prev is INCORRECT\n");
}
if (c->next == NULL) {
printf("c->next is correct\n");
} else {
printf("c->next is INCORRECT\n");
}
return 0;
}
void place_alpha(struct Employee *newp, struct Employee **root) {
// Insert a new node newp into the database structure whose root is root.
struct Employee *ep;
if (*root == NULL) { // if there is no database yet.
newp->next = newp->prev = NULL;
*root = newp;
return;
}
if ((*root)->prev) {
// invalid call, should only pass the root node address
fprintf(stderr, "invalid call: place_alpha must take a pointer to the root node\n");
return;
}
if (strcmp(newp->name, (*root)->name) <= 0) {
// if the new node comes before root alphabetically
newp->next = *root;
newp->prev = NULL;
newp->next->prev = newp;
*root = newp;
return;
}
for (ep = *root;; ep = ep->next) {
if (ep->next == NULL) {
// If the next node is NULL, we've reached the end of the list
// so newp has to go here.
newp->prev = ep;
newp->next = NULL;
newp->prev->next = newp;
return;
}
if (strcmp(newp->name, ep->next->name) <= 0) {
// The new node comes between ep and ep->next alphabetically
newp->prev = ep;
newp->next = ep->next;
newp->prev->next = newp->next->prev = newp;
return;
}
}
}
EDIT: place_alpha was a bit redundant, so I cleaned it and got a much simpler version:
void place_alpha(struct Employee *newp, struct Employee **root) {
//Places a new node newp into the database structure whose root is root.
struct Employee **link = root;
struct Employee *last = NULL;
while (*link && strcmp(newp->name, (*link)->name) > 0) {
last = *link;
link = &last->next;
}
newp->prev = last;
newp->next = *link;
if (newp->next) {
newp->next->prev = newp;
}
*link = newp;
}

C - Doubly Linked List always null

I am writting a program on doubly linked list with the following data structure:
typedef struct telephoneBookNode {
int id;
char name[NAME_LENGTH];
char telephone[TELEPHONE_LENGTH];
struct telephoneBookNode * previousNode;
struct telephoneBookNode * nextNode;
} TelephoneBookNode;
typedef struct telephoneBookList {
TelephoneBookNode * head;
TelephoneBookNode * tail;
TelephoneBookNode * current;
} TelephoneBookList;
In the following function, I read data from a text file to the linked list, the file content look like this:
/*100, Alice, 0411112222
101, Bob, 0411112222
102, Ali, 0411112223*/
TelephoneBookList * commandLoad(char* fileName) {
TelephoneBookList *(*createList)(TelephoneBookNode*, char[]) = createTelephoneBookList;
char entry[100], *temp1, *temp2;
TelephoneBookList* aList = NULL;
TelephoneBookNode* aNode = NULL;
FILE* telephoneListFile = NULL;
int countEntry = 0;
Boolean check;
telephoneListFile = fopen(fileName, "r");
if (!telephoneListFile)
return NULL;
else {
while (fgets(entry, 100, telephoneListFile)) {
temp2 = strcpy(temp2, entry);
temp1 = strtok(entry, "\n");
check = addressBookEntryCheck(temp1);
if (!check)
return NULL;
else
//here I pass aNode pointer to the below function
aList = (*createList)(aNode, temp2);
}
fclose(telephoneListFile);
printf("printed"); //This line is reached when program complied
return aList;
}
}
This is the function to create the list, problem may be here: it doesnot add new node to the list, it just replaces the first node with the new one. Finally, the linked list only has 1 record which was the last one in text file. How can I fix the code? Thank you!
TelephoneBookList * createTelephoneBookList(TelephoneBookNode* node, char entry[]) {
TelephoneBookList* aList = malloc(sizeof *aList);
TelephoneBookNode* aNode = (TelephoneBookNode*) malloc(sizeof *aNode);
char *tokens;
tokens = strtok(entry, ", ");
aNode->id = atoi(tokens);
tokens = strtok(NULL, ", ");
strcpy(aNode->name, tokens);
tokens = strtok(NULL, ", ");
strcpy(aNode->telephone, tokens); //Just assigning values to a node
//program always go to this block, means `node` is always null
if (node == NULL) {
aNode->nextNode = NULL;
aNode->previousNode = NULL;
node = aNode;
aList->current = node;
aList->head = node;
aList->tail = node;
}
else { //This block is not reached
while (node->nextNode)
node = node->nextNode;
node->nextNode = aNode;
aNode->previousNode = node;
aList->tail = node->nextNode;
}
return aList;
}
This is the function to check entry:
Boolean addressBookEntryCheck(char entry[]) {
char *tokens;
tokens = strtok(entry, ", ");
if(!tokens || strlen(tokens) < 1 || strlen(tokens) > 3)
return FALSE;
else {
if (!isNumber(tokens))
return FALSE;
else {
tokens = strtok(NULL, ", ");
if (!tokens)
return FALSE;
else
{
tokens = strtok(NULL, ", ");
if (!tokens)
return FALSE;
else if (!isNumber(tokens) || strlen(tokens) != 10)
return FALSE;
else
return TRUE;
}
}
}
}
Every time you call
createTelephoneBookList
you create a new list
TelephoneBookList* aList = malloc(sizeof *aList);
You also copy to an uninitialized pointer
temp2 = strcpy(temp2, entry);
I would suggest you create one function to create the list header, one function to add new items e.g.
aList = createList()
while (fgets(entry,sizeof(entry),fp)!=NULL)
{
if (!addEntry(aList,entry))
{
fprintf(stderr, "failed additem item %s\n", entry);
}
}
...
In addEntry parse the string
int id = 0;
char name[NAME_LENGTH];
char telephone[TELEPHONE_LENGTH];
p = strtok(entry, ","); // id
if (p != NULL)
{
id = atoi(p);
p = strtok(NULL, ","); // name, store to temporary string
if (p != NULL )
{
strcpy(name,p);
p = strtok(NULL, ","); // telephone number, store to temporary string
if ( p != NULL )
{
strcpy(telephone,p);
// here you can allocate the new node
}
}
}
// disclaimer omitted checks for length etc which any good program should have. also make sure you have room for \0
if any of the strtok above fail return 0 otherwise allocate a new entry
TelephoneBookNode* aNode = malloc(sizeof(TelephoneBookNode));
aNode->id = id;
strcpy(aNode->name, name);
strcpy(aNode->telephone, telephone);
Then add to your aList
//program always go to this block, means `node` is always null
if (node == NULL) {
....
This is because the caller of the function passed aNode and it never changes within that loop. So it will always pass same value of aNode which is NULL.
I haven't looked at the logic of your code in details, but I think you may want to pass aList->head or rather you already pass aList so just use that.

elements storing

code print elements after store them :
void print(struct node* root)
{
while ( c != NULL )
{
printf( "\n%d ", c->line1);
printf( "%s", c->curr );
c = c->next;
}
}
print method
Just looking at the code, this line seems like a potential issue:
temp->curr=current_input;
It looks like all the nodes .curr will get set = current_input. I'm guessing you need to do something like:
temp->curr = malloc(1 + strlen(current_input));
strcpy(tmp->curr, current_input);
Use strcpy_s if strcpy causes a warning.
First you should realize a list consists of nodes, which contain pieces of your data — so you need to allocate a new node for each piece of data you want to store in a list.
Then you insert each newly created node into the list and finally print the list when done.
Additionaly remember that data need to be either copied into the node (like line1) or copied somewhere else, for example onto the heap, and then linked to the node with a pointer, like curr (see the answer by #rcgldr).
struct node *root = NULL;
struct node *createnode(int line, const char *input)
{
struct node *n = malloc(sizeof(struct node));
if(n != NULL)
{
n->line1 = line;
n->curr = input;
n->next = NULL;
}
return n;
}
void insertnode(struct node* n)
{
n->next = root;
root = n;
}
void printlist(struct node* n)
{
for( ; n != NULL; n = n->next)
{
printf( "%d: %s\n", n->line1, n->curr);
}
}
int main(int argc, const char * argv[])
{
char *input;
struct node *temp;
type t;
do
{
t=getword(); //call to get the type of t
switch (t)
{
case number:
case keyword:
input = strdup(current_input); // make a copy of user input
if(input != NULL)
{
temp = createnode(line, input);
if(temp != NULL) // created?
insertnode(temp); // insert into the list
else
{
free(input); // free unused input copy
t = EOF; // make the loop terminate
}
}
else // user input copy failed
t = EOF; // make the loop terminate
break;
default:
break;
}
}
while (t != EOF);
print(root);
return 0;
}

Resources