Why is my linked list only printing last entry? - c

I'm trying to read specific lines from a file and add it to a linked list and then print it out.
Code below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct list {
int uid;
char* uname;
struct list* next;
}node;
void push(node ** head, int uid ,char* uname) {
node * new_node;
new_node = malloc(sizeof(node));
new_node->uid = uid ;
new_node->uname=uname;;
new_node->next = *head;
*head = new_node;
}
void print_list(node *head) {
node * current = head;
while (current != NULL) {
printf("%u:%s\n", current->uid,current->uname);
current = current->next;
}
}
int main(int argc, char **argv){
node *current=NULL;
FILE *fp=fopen(argv[1],"r" );
if (fp==NULL){
perror("Failed to open file");
exit(EXIT_FAILURE);
}
char s[1024];
const char token[2]=":";
char *stoken;
while(!feof(fp)){
int count=0;
int tempint;
char* tempchar=malloc(sizeof(char));
fgets(s, 1024, fp);
stoken = strtok(s,token);
current=malloc(sizeof(node));
while(stoken != NULL){
if (count==0){
tempchar=stoken;
}
if (count==2){
sscanf(stoken,"%d",&tempint);
}
count++;
stoken=strtok(NULL,token);
}
push(&current,tempint,tempchar);
}
fclose(fp);
print_list(current);
}
My problem is when print_list is ran the only thing who gets printed is the last entry.
For this input :
hello:asd:123:foo:ar
hi:proto:124:oo:br
hey:qwe:321:fo:bar
the only thing which gets printed is
321:hey
is it my push which is wrong or my print_list?

The problem is the way you are treating the result of strtok: you are setting its value right into the node, instead of copying it.
Make a copy of name when adding a node:
void push(node ** head, int uid ,char* uname) {
node * new_node;
new_node = malloc(sizeof(node));
new_node->uid = uid;
new_node->uname=malloc(strlen(uname)+1);
strcpy(new_node->uname, uname);
new_node->next = *head;
*head = new_node;
}
You should also look at the way that you are using tempchar in the main function. You allocate a space for a single character to it, which gets written over with the result of strtok, leaking the malloc-ed memory.

It's because you always overwrite head in the push() function, you should make it NULL initially and then check if it's NULL the first time and assign to it the first node, and then don't reassing anything to it, your program has a memory leak because of this too.
Also you are malloc()ing the node outside the function and then inside the function again,which causes another memory leak.
You should also check if malloc() returns NULL which indicates an error like when the system runs out of memory, dereferencing a NULL pointer is undefined behavior.
And a final note, you must check the return value of scanf() before accessing the target variables, or that would again cause undefined behavior.

change like as follows
char* tempchar;//=malloc(sizeof(char));
fgets(s, 1024, fp);
stoken = strtok(s,token);
//current=malloc(sizeof(node));//don't update like this
while(stoken != NULL){
if (count==0){
tempchar=strdup(stoken);//malloc and strcpy

Related

I cant find the error of my linked list( why is my head pointer moving?)

I have tried so many times to set my head pointer pointing to the first node. At first(in the empty list) it correctly points the first node. But after the first loop, the head pointer points to the newnode linked. Actually now Im quite unsure about my whole code as well.
int main(void){
struct library *head = NULL; //set the head pointer to NULL
int option;
printf("Enter the number:");
while((option = getchar())!= 9){
switch(option){
case '1':
{
char title[1000];
char author[1000];
char subject[1000];
printf("Enter title of the book you want to add:");
scanf("%s",title);
printf("Enter author of the book you want to add:");
scanf("%s",author);
printf("Enter subject of the book you want to add:");
scanf("%s",subject);
add_book(title,author,subject,&head);
printf("successful! and head pointer is pointing to %s\n",head->collection.title);
break;
}
}
}
void add_book(char title[],char author[],char subject[], struct library ** head){
struct library *current;
struct library *newnode = malloc(sizeof(struct library));
newnode->collection.title = title;
newnode->collection.author = author;
newnode->collection.subject = subject; // assigning value inside newnode
newnode->num_books = 0;
newnode->next = NULL; // assign NULL value to the end of newnod
//when the head is NULL which means when the list is empty
if(*head == NULL)
{
current = newnode;
*head = current;
return;
}
else
{
current = *head; //assign the first node to current pointer
//find the last node of the list
while(current->next != NULL)
{
current = current->next;
}
current->next = newnode; // link the last node to new node
return;
}
}
This is struct for this
struct book {
char* title;
char* author;
char* subject;
};
struct library {
struct book collection;
int num_books;
struct library* next;
};
The lifetime of char title[1000];, char author[1000];, and char subject[1000]; ends when execution reaches the end of the block inside case '1': { /* ... */ }. Once this happens, the pointers that were assigned in add_book become dangling pointers - pointing to invalid memory.
To remedy this, you must ensure the lifetime of your strings matches the lifetime of the structures that contain them. This can be done either by allocating enough space in the structure itself
struct book {
char title[1000];
/* etc. */
};
or by dynamically allocating enough space for a copy of each string. In any case you must copy the string to this memory (man 3 strcpy).
If it is available on your system, man 3 strdup does both steps of the second form at once. Otherwise, it is roughly the same as strcpy(malloc(strlen(source_string) + 1), source_string);.
Also note that the scanf specifier %s is as dangerous as gets when used without a field-width specifier (e.g., char buffer[1000]; scanf("%999s", buffer);), as it can potentially overflow your buffer.
An example program. Enter strings one-by-one, and terminate with EOF CTRL+D (Windows: CTRL+Z, RETURN).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct link {
char *string;
/* alternatively: char string[512]; */
struct link *next;
};
void add_link(struct link **root, const char *string) {
struct link *node = calloc(1, sizeof *node);
node->string = strdup(string);
/* alternatively: strcpy(node->string, string) */
if (*root) {
struct link *tail = *root;
while (tail->next)
tail = tail->next;
tail->next = node;
} else
*root = node;
}
int main(void) {
struct link *head = NULL;
while (1) {
char buffer[512];
if (!fgets(buffer, sizeof buffer, stdin))
break;
/* remove newline */
buffer[strcspn(buffer, "\n")] = '\0';
add_link(&head, buffer);
}
for (struct link *node = head, *next; node; node = next) {
next = node->next;
printf("STRING: %s\n", node->string);
free(node->string);
free(node);
}
}
Note: in a real program you should always check the return values of your memory allocating functions (malloc, calloc, strdup, etc.) as they can fail.

Fail to push head on Linked List

I tried to create a program to add elements to a linked list. The elements consist of name and age. But it fails to add without giving me any error. Could you please show me my mistake?
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define MAX 9999
struct data {
char name[MAX];
int age;
struct data *next;
};
void pushHead(struct data **head, struct data **tail, char name[], int age) {
struct data *node = (struct data *)malloc(sizeof(struct data));
strcpy(node->name, name);
node->age = age;
if (*head == NULL) {
node = *head;
node = *tail;
node->next = NULL;
} else {
node->next = *head;
*head = node;
}
}
void view(struct data *head) {
struct data *curr = head;
if (curr == NULL)
printf("No Data\n");
else {
while (curr != NULL) {
printf("%s(%d)\n", curr->name, curr->age);
curr = curr->next;
}
}
}
int main(int argc, char const *argv[]) {
struct data *head = NULL;
struct data *tail = NULL;
pushHead(&head, &tail, "Felix", 19);
view(head);
return 0;
}
Output : No Output
My code is working when I put the head on global scope (by changing all the functions to work globally), but when I try to put the head in main scope it doesn't work.
In pushHead(), you are doing:
node = *head;
node = *tail;
this end up assigning NULL to node pointer because *head and *tail both are NULL. Note that this is a memory leak as your program loose the memory reference which the node pointer is holding. Instead, you should do
*head = node;
*tail = node;
Some suggestions:
For storing name in the list node, you are taking buffer of size
9999 (MAX macro) which is (IMO) very large. I believe, a buffer
of size 256 is more than enough for this purpose. Or, you can also
have buffer of exact size required for storing name by allocating
the memory dynamically to it. For this , you have to take a char *
member instead of char array for name and allocate memory to it
dynamically based on size of name parameter of pushHead() and in
this case, you need to make sure to free it explicitly when deleting
the list nodes.
When using strcpy() to copy string, make sure that destination
buffer is large enough to contain the source string to avoid
overflows.
Follow good programming practice. Always check malloc return and
ensure to free the allocated memory once you are done with it.
Do not cast the malloc return.
To include standard library header files use <>, i.e. #include "stdio.h" -> #include <stdio.h>, check this.

Problem using free() in a loop creating a linked list from a file

So I have a file called file.txt and i want to create a linked list from the information it contains, where each line of the file is a new node. So far I have this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct sAirport{
char name;
int number;
struct sAirport *next;
}tAirport;
tAirport *createNode(tAirport *newNode, char str[1000]);
void createLinkedList(tAirport **head, tAiport *newNode);
int main()
{
FILE *fa = fopen("test.txt", r);
char str[1000] = {0};
tAirport *head = NULL;
tAirport *newNode = NULL;
while(fgets(str, sizeof(str), fa) != NULL)
{
newNode = createNode(newNode, str);
createLinkedList(&head, newNode);
free(newNode);
newNode = NULL;
}
return 0;
}
tAirport *createNode(tAirport *newNode, char str[1000])
{
char *aux = NULL;
newNode = malloc(sizeof(tAirport));
if(newNode == NULL)
exit(EXIT_FAILURE);
aux = strtok(str, " ");
strcpy(&newNode->name, aux);
aux = strtok(NULL, " ");
sscanf(aux, "%d", &newNode->number);
newNode->next = NULL;
return newNode;
}
void createLinkedList(tAirport **head, tAirport newNode)
{
tAirport *temp = NULL;
if(*head == NULL)
{
*head = newNode;
return;
}
temp = *head;
while(temp->next != NULL)
temp = temp->next;
temp->next = newNode;
}
I'm getting weird results and Valgrind says I have lost bytes but I don't know what to do.
Edited so that it can run.
For example the file I'm testing with is:
John 33
Mary 42
Peter 12
What should I do?
Aside from all those warning you will get from compiling this. I just want to tell you that you are misunderstanding how malloc(),free(), and pointer work.
First of all, pointer is just an unsigned long, a natural number just like any other number. The difference is that the pointer store the address of the real memory ( in this case is newNode).
In your program, you malloc() to get your memory, asisgn the memory address to newNode, then you tell your list to hold newNode, finally you free it. So you just free the memory you wish to keep, your list now only hold a bunch of address to freed memory.
Solution for this is, get rid of free() while populating your list, and free them later
The sAirport structure is define the name to be one character. However, from the code, looks like the createNode will allow long name (up to 999 characters). When the createNode create the new entry, the strcpy will overwrite data beyond the allocated space, and will likely cause segmentation fault, or "funny" data.
Consider extending name to the proper size, or using dynamic allocation (malloc) for name.

runtime error: null pointer passed as argument 1, which is declared to never be null

I wrote a program that creates Linkedlists with two values.
It worked when I just had int values in it but now that I added char* this error messages shows
runtime error: null pointer passed as argument 1, which is declared to never be null
As mentioned before this worked fine until I added char* to the constructor and the struct. Not sure where it goes wrong as the error seems to come from different lines in the code everytime I run it... So what do i need to change ?
#include <stdio.h>
#include <cs50.h>
#include <string.h>
typedef struct node {
int val;
char* name;
struct node *next;
} node_t;
void addFirst(int value, char* word, node_t** nd) {
//initialize new node, allocate space, set value
node_t * tmp;
tmp = malloc(sizeof(node_t));
tmp->val = value;
strcpy(tmp->name, word);
//let the new nodes next pointer point to the old head
tmp->next = *nd;
//Make tmp the head node
*nd = tmp;
}
int findItem(int value,char* word, node_t *nd) {
if(nd->val == value)
return 0;
while(nd->next != NULL) {
if(nd->val == value && strcmp(word, nd->name) == 0)
return 0;
if(nd->next != NULL)
nd = nd->next;
}
return -1;
}
int main (void) {
node_t *head = malloc(sizeof(node_t));
head->val = 0;
strcpy(head->name, "");
head->next = NULL;
addFirst(15, "word", &head);
addFirst(14,"word2", &head);
printf("%i \n", findItem(15, "word", head));
}
The problem is in strcpy(head->name, "");. Here, you;re trying to use the memory location pointer to by head->name, but you never assigned a valid memory to it.
You need to make sure that the pointer points to a valid memory location, before you write to / read from that memory location. Attempt to access invalid memory invokes undefined behavior.
This is applicable for other uninitialized instances of name, too.
If you can live with POSIX standard, instead of strcpy(), you can make use of strdup()

linked list not stored correctly, prints all nodes the same

i am having trouble with this problem i can not find the bug
i am storing strings form a file to a linked list.
lets say the file contains 5 strings
jack
juan
steven
mike
sam
the problem is that when i print the 5 node's linked list
it prints [sam] [sam] [sam] [sam] [sam] .
it prints the last string in all nodes
i am confused
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Node {
char * data;
struct Node *next;
};
struct Node *head;
void print() {
while (head != NULL) {
printf(" [%s] ", head->data);
head = head->next;
}
printf("\n");
}
void insertb(char *data) {
struct Node *temp;
temp = (struct Node*)malloc(sizeof(struct Node));
temp->next = NULL;
temp->data = data;
if (head == NULL) {
head = temp;
printf("%s\n", head->data);
} else {
temp->next = head;
head = temp;
printf("%s %s\n", temp->data, temp->next->data);
}
}
int main (int argc, char *argv[]) {
FILE *file = fopen(argv[1], "r");
head = NULL;
char data[10];
//int data;
while (fscanf(file, "%s",&data) != EOF) {
insertb(data);
// printf("%s\n", data);
}
print();
fclose(file);
return 0;
}
You have only a single buffer to store your strings, data. Its contents get overwritten with every call to fscanf.
Try insertb(strdup(data));.
you are setting the head to temp, which is the very last one every time you add some stuff into the list. In insertb function the else block is probably where you want to look for. Also it is considered to be a pretty bad idea to make global variables, hence it is very likely to change the content of the global variable, unintentionally and that can screw things over. I suggest you to look for pass by reference stuff in C also. I see that the other answer tells you to use strdup, maybe I am wrong too and I don't want to argue with that, but strdup duplicates the string. Instead of that I'd "re-initialize" the char array with
memset(buffer, 0, bufferLength);
and put manually a "\0" char at the end of the string to prevent saving rubbish in the buffer. Hope this helps.

Resources