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

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.

Related

Storing strings from pointers in Linked lists

Recently started to practice linked lists. I am aware of the basic algorithm and concept and thought of implementing LL to store a bunch of strings which are input by the user.
But apparently I keep getting Segmentation fault.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct _node{
char *s;
struct _node *next;
}
node;
int main()
{
node *head = NULL;
int a = 0;
char ch;
char *str = malloc(10);
do
{
printf("\nDude %i:", a);
fgets(str, 10, stdin);
node *n = malloc(sizeof(node));
if(n == NULL)
{
printf("\ninsufficient memory");
return 1;
}
if(a == 0)
{
strcpy(n->s, str);
n->next = NULL;
head = n;
}
else
{
strcpy(n->s, str);
n->next = head;
head = n;
}
a++;
printf("\n continue?(y/n): ");
scanf("\n%c", &ch);
}while(ch == 'y');
for(node *temp = head; temp != NULL; temp = temp -> next)
{
printf("\n%s", temp->s);
}
return 0;
}
I do understand that my logic/code is flawed somewhere since I am touching memory I should not touch but cannot seem to point out where since it is my first time dealing with linked lists.
When you are malloc'ing space for the struct, you are only allocating space for the pointer to the string in your _node struct. You need to allocate some memory where you store the string and point the pointer s to it, before you do the strcpy.
i.e.
n->s = malloc(sizeof(char)*100);
Remember that you also need to have a strategy to de-allocate this memory.
As the others hinted, these sort of errors are usually easily caught by looking/debugging with gdb. Remember that it's useful to compile with the -g flag to get useful debugging info.
The reason you catch a ''Segmentation fault' is because you don't allocate memory for s variable of struct node before copying actual string: strcpy(n->s, str).
So, allocate memory for s:
n->s = (char *) malloc(10 * sizeof(char));
Note that you cannot write anything into an unallocated space, so you need to call malloc for the string in each node.
If the string lengths are fixed, then you can specify the length in the definition of struct node to avoid the malloc problem.
Also, it is suggested to always free the objects that will no longer be referenced.
With a few revisions, the codes below may be helpful:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 10
typedef struct node {
char str[LEN];
struct node *next;
} Node;
int main() {
Node *head = NULL;
int n = 0;
char c = 'y';
while (c == 'y') {
Node *node = malloc(sizeof(Node));
printf("Node #%d: ", n);
scanf(" ");
/* Store the string directly into the node. */
fgets(node->str, 10, stdin);
/* Remove the newline character. */
node->str[strcspn(node->str, "\n")] = 0;
node->next = head;
head = node;
++n;
printf("Continue? (y/N): ");
scanf("%c", &c);
};
Node *curr = head;
while (curr != NULL) {
printf("%s\n", curr->str);
Node *temp = curr;
curr = curr->next;
/* Remember to free the memory. */
free(temp);
}
return 0;
}

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.

Segmentation Fault occurring when accessing the same memory in one function instead of another

I am implementing a LinkedList with a bunch of ListNodes that are structs which contain some basic information about people. I have two files, one that is main.c, and another that is main.h. Whenever I attempt to print the list by passing the root to a function, I get an error.
Here is main.c:
#include "main.h"
/* Edward Nusinovich
This C file is going to have a LinkedList containing information about people.
The user can interact with it and manipulate the list.
*/
int main(int argc, char **argv){
if(!checkIfValidArguments(argc).value){return -1;}
ListNode *root = askForDetails(1,argv);
ListNode *current = root;
current->next = NULL;
ListNode *temp;
int index = 2;
while(index<argc){
temp = askForDetails(index,argv);
current->next = temp;
current = current->next;
index++;
}
userLoop(root);
return 0;
}
In my main.h file, I have no problem printing attributes of the root parameter in the function "userLoop", but as soon as I pass ListNode *root to "print" or "stuff" I get a seg fault when trying to print its values.
Here is main.h:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define true 1
#define false 0
typedef struct bool{
int value:1;
} boolean;
//this is going to store info about a person
typedef struct people{
char *name;
char *hairColor;
char *eyeColor;
char *age;
struct people *next;
} ListNode;
//using a 1 bit bitfield we have constructed, stores whether or not the user has entered a proper number of inputs
boolean checkIfValidArguments(int numArgs){
boolean validArguments;
if(numArgs>1){validArguments.value=true;}
else{validArguments.value=false; printf("We need some names of people.\n");}
return validArguments;
}
//this will construct a new Person and return him to
ListNode *askForDetails(int personIndex, char **argv){
ListNode toReturn;
char *name = argv[personIndex];
printf("Please enter the hair color, eye color, and age of %s.\n",name);
char *inBuf=malloc(100);
char nextchar=getchar();
int index = 0;
if(nextchar!='\n'){inBuf[index]=nextchar; index++;}
while((nextchar=getchar())!='\n'){
inBuf[index] = nextchar;
index ++;
}
toReturn.name = name;
toReturn.hairColor = strtok(inBuf," ");
toReturn.eyeColor = strtok(NULL," ");
toReturn.age = strtok(NULL,"\n");
ListNode *newNode = malloc(sizeof(ListNode));
newNode = &toReturn;
return newNode;
}
char *getInput(char *message){
printf("%s",message);
char *inBuf = malloc(40);
char nextchar=getchar();
int index = 0;
if(nextchar!='\n'){inBuf[index]=nextchar; index++;}
while((nextchar=getchar())!='\n'){
inBuf[index] = nextchar;
index ++;
}
return inBuf;
}
void addToEnd(ListNode *root){
ListNode *current = root;
char *inBuf = getInput("\nEnter the name of a person who you want to add: \n");
ListNode *toAdd = malloc(sizeof(ListNode));
toAdd = askForDetails(0,&inBuf);
toAdd->name = inBuf;
toAdd->next = NULL;
while((current->next) != NULL){
current = current->next;
}
current->next = toAdd;
}
void print(ListNode *root){
printf("The name is %s.\n",root->name);
/*
ListNode *current = root;
do{
printf("\n%s's hair is %s, their eyes are %s and they are %s years old.\n",current->name,current->hairColor,current->eyeColor,current->age);
current = current->next;
}while(current!=NULL);
*/
}
void remEnd(ListNode *root){
ListNode *current = root;
if(current == NULL){ return; }
}
void addAfter(ListNode *root){
ListNode *current = root;
char *name = getInput("\nWho do you want to add after?\n");
int comparison = 0;
while(current!=NULL&&(comparison = strcmp(name,current->name))!=0){
current = current -> next;
}
if(current==NULL){printf("\nIndividual not found.\n"); return;}
else{
char *newPerson = getInput("What's the name of the person you wish to add? ");
ListNode *toAdd = askForDetails(0,&newPerson);
ListNode *next = current->next;
current -> next = toAdd;
toAdd->next = next;
return;
}
}
void stuff(ListNode *root){
printf("name is %s.\n",root->name);
printf("Root lives at %u.\n",root);
}
void userLoop(ListNode *root){
char input = ' ';
printf("Root lives at %u.\n",root);
while(true){
printf("name is %s.\n",root->name);
if(input!='\n'){
printf("\nWhat would you like to do with your list:\n");
printf("A) Add an element at the end of the list\n");
printf("B) Remove an element from the end of the list\n");
printf("C) Add an element after an element on your list\n");
printf("D) Print your list\n");
printf("E) Quit this program\n\n");
}
input = getchar();
switch(input){
case 'A': addToEnd(root); break;
case 'B': remEnd(root); break;
case 'C': addAfter(root); break;
case 'D': stuff(root); break;
case 'E': return;
}
}
}
When printing the address in memory of root in both functions, I get the same value, so I'm not sure why I am unable to access the values in root in one function instead of the other.
Thank you so much for any help.
You don't seem to quite grasp how the memory model works in C. Your offending piece of code is probably:
ListNode *newNode = malloc(sizeof(ListNode));
newNode = &toReturn;
return newNode;
This returns a pointer to the local variable toReturn, not the malloc'd memory address. You need to copy the data from toReturn into your malloc'd memory space. However, even worse you don't malloc space for each of your strings, so each of your nodes point to the same input buffer. This should work, since you malloc with for every node, however if
you are going to start deleting nodes managing your memory is going to be a little awkward. You also don't make sure there is enough room in your buffer.
I suggest looking at some online resources (or ideally a book) to refresh on how C memory works.
Edit: I did not learn C online, but a quick google search turned up this, which at a quick glance seems to be a decent resource.
I would recommend looking into book list. I used C Programming A Modern Approach.
I'm going to assume you're on a 64 bit system so that pointers are 8 bytes & integers are 4 bytes. Use %p for pointers, not %u

Why is my linked list only printing last entry?

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

Resources