linked list remains empty even after adding nodes? [closed] - c

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
thanx k-ballo, u solved my prevoius problem but then i landed into another one!!
i created nodes and then tried to display them, but every time i called append_node(), the double pointer **head_ptr(used to hold the address of the very first pointer *head, which in turn, holds the address of the very first node of the linked list), was holding a NULL value as if previous calls to append_node(&head, value) didnt add any node to *head.
so whenever i display the list, it reamins empty!! :
#include <stdio.h>
struct __node
{ int data;
struct __node *next;
};
typedef struct __node node;
int append_node(node **head_ptr, int value) //double pointer head_ptr to simulate call-by-reference
{ node *temp, *q;
temp = (node *) malloc(sizeof(node));
if(!temp)
{ printf("\ninsufficient memory!!");
return -1;
}
q = *head_ptr; //as *head_ptr is address of a pointer (which is *head), so any changes made after this line in q should also be reflected in main().. (i guess so!)
temp->data = value;
temp->next = NULL;
if(q == NULL)
{ q = temp;
printf("\nq is empty");
return 0;
}
while( q->next != NULL)
{ q = q->next;
}
printf("\nq is not empty");
q->next = temp;
return 0;
}
int disp_list(node **head_ptr)
{ node *q;
int i=1;
q = *head_ptr;
if(q != NULL)
{ while( q != NULL )
{ printf("|%d-%d|--->", i++, q->data);
q = q->next;
}
}
else
{ printf("\nlist is empty!!");
}
return 0;
}
int main()
{ node *head=NULL;
int value, res, i=0;
while(i<3)
{ printf("\nenter the data to be inserted into the node: ");
scanf("%d", &value);
res = append_node( &head, value);
i++;
}
printf("\nprinting all the nodes...\n") ;
res = disp_list(&head);
printf("\n---------------\nexiting...\n\n\n");
return 0;
}
i know i could have returned *q from append_node() and reassigned it to *head or declared *head as global.. but i want to *head to be manipulated by so-called-pass-by-reference method only. (theres no pass-by-reference actually in c!) my compiler is: gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4)
plz help..i m not an expert so please use easier terminology!! :p

Your initial call to append_node is passing a pointer to a pointer to node which is uninitialized (let's pressume its null, though it will probably be just garbage). Then you do
q = *head_ptr;
//above statement causes a segment fault error..
// that statement should be fine, we will get the value of main's head, which we pressume to be null
// now we will try to dereference null by accesing its next element
while( q->next != NULL)
{ q = q->next;
}

There are two major problems with this program:
head is not initialized and contains garbage.
You don't handle the case of an empty list in append_node().
Both problems will lead to segmentation fault errors.

Related

Linked List remove node function not working properly [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 months ago.
Improve this question
When I run the program below - the output I get is
head node created
node addded with value of 22
node addded with value of 22343
node addded with value of 7
22
22343
7
last node has been removed
current last nodes value is 22343
22
22343
7
This issue is that , if the last node in the list is stated to have a data value of 22343 when the removenode function is called , how is it possble that the last value printed is 7 and not 22343 - when the traverse function is called? despite the fact that the *next pointer of the last node is set to NULL in the removenode funtion.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node_n
{
int value;
struct node *next;
};
typedef struct node_n node;
node* makeheadnode()
{
node *temp = (node*)malloc(sizeof(node));
temp->next = NULL;
temp->value = NULL;
printf("\n head node created");
return temp;
}
void addnode(node *target, int data)
{
while (target->next != NULL)
{
target = target->next;
}
target->next = (node*)malloc(sizeof(node));
target = target->next;
target->value = data;
target->next = NULL;
printf("\n node addded with value of %d ",target->value);
}
int removenode(node *target)
{
node *temp;
if(target->next == NULL)
{
printf("\n only one node is present");
return 1;
}
while(target -> next != NULL)
{
temp = target -> next;
if(temp -> next == NULL)
{
target->next == NULL;
printf("\n last node has been removed \n current last nodes value is %d",target->value);
return 1;
}
else
{
target = target-> next;
}
}
}
int traverse(node *target)
{
if(target->next == NULL)
{
printf("\n this list is empty");
return 1;
}
while (target->next != NULL)
{
target = target -> next;
printf("\n %d", target -> value);
}
return 1;
}
int main()
{
node *head = makeheadnode();
addnode(head,22);
addnode(head,22343);
addnode(head,007);
traverse(head);
removenode(head);
traverse(head);
}
The problem is a typo. In your removenode function, you have:
target->next == NULL;
Where it should be:
target->next = NULL;
If you compile with warnings on, i.e. -Wall or even -Werror, the compiler should have warned you with a message like equality comparison result unused.
Furthermore, since you're removing the node, you should free it so you don't have any memory leaks. Setting a pointer to NULL does not free the pointer. Many, including myself, also see it as good practice to set the pointer to NULL after freeing.
free(target->next)
target->next = NULL
For more info on that, see this post

Why is the program crashing after assigning a pointer [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed 3 years ago.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Improve this question
Managing my linked-list is not working. My program just crashes after I set the value "next" to point on previous "head" of the list and after I search and find an element. What can I do?
The program compiles and starts, but it just crashes returning a random address from the memory.
I've tried to change the function to return the pointer of the new "head" instead of being void, but the result is the same.
By verifying where the program stops i found out that it stops doing "new node->next = (*head)" and on previous attempts with the instruction "return last".
I've tried changing almost completely the function just to understand the problem, but even if i pass a pointer to and already allocated list in the main the address does not work and it crashes.
Just to understand whats going on assume that the the program enters for sure in the if with the condition "type_temp=='A'"
This is the main:
#include"devices.h"
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
#define LINE_LENGTH 80
#define COMMAND_LENGTH 30
int main(int argc, char** argvs)
{
FILE *fp;
struct Type_A** devices_A = NULL;
struct Type_B** devices_B = NULL;
struct Type_C** devices_C = NULL;
struct Request_Type_C** requests_devices_C = NULL;
int system_power, usable_power,
solar_system_power,solar_system_power_temp;
int id_temp,power_level_temp;
int power_level_normal_temp, power_level_low_temp;
char type_temp;
char file_line[LINE_LENGTH], command[COMMAND_LENGTH];
char *sub_line;
fp = fopen("input1.txt","r");
if(fp == NULL)
{
printf("Error opening the file\n");
return 1;
}
if(fgets(file_line,sizeof(file_line),fp) == NULL)
{
printf("Error reading the first line\n");
return 1;
}
sub_line = strtok(file_line, " ");
strcpy(command,sub_line);
sub_line = strtok(NULL, " ");
system_power = atoi(sub_line);
usable_power = system_power;
while(fgets(file_line,sizeof(file_line),fp) != NULL)
{
sub_line = strtok(file_line, " ");
strcpy(command,sub_line);
if(strcmp(command,"DEVICE_CONNECTED") == 0)
{
sub_line = strtok(NULL, " ");
id_temp = atoi(sub_line);
sub_line = strtok(NULL, " ");
type_temp = *sub_line;
if(type_temp == 'A')
{
sub_line = strtok(NULL, " ");
power_level_normal_temp = atoi(sub_line);
sub_line = strtok(NULL, " ");
power_level_low_temp = atoi(sub_line);
//function with the problem 1
add_device_a(devices_A,id_temp,type_temp,
power_level_normal_temp,power_level_low_temp,0,0);
//function with the problem 2
add_device_a_to_system(devices_A,id_temp,&usable_power);
}
.
.
.
This is the first function with the problem:
void add_device_a(struct Type_A** head, int id, char type,
int power_level_normal, int power_level_low,
int connected, int consume)
{
//allocate the new node
struct Type_A *new_node = (struct Type_A*) malloc(sizeof(struct Type_A));
//put in the data
new_node->id = id;
new_node->type = type;
new_node->power_level_normal = power_level_normal;
new_node->power_level_low = power_level_low;
new_node->connected = connected;
new_node->consume = consume;
//setting the next of the new node
new_node->next = (*head); <-instruction that generates the problem
crashing the program
//move the head to point to the new node
(*head) = new_node;
return;
} //end add_device_a
This is the second function that generates the problem:
int add_device_a_to_system(struct Type_A** head, int id, int* usable_power)
{
struct Type_A *node = find_device_a_by_id(head, id);` <-instruction
that generates the problem
.
.
.
The true function that generates the problem
struct Type_A *find_device_a_by_id(struct Type_A** head, int id)
{
//used for traverse the list
struct Type_A *last = *head;
//check if last is truly the last node
while(last != NULL)
{
//if the id is equal return the pointer to that node
if(last->id == id) {
return last; **<-instruction that makes the program crash**
}
//else keep going with the next
last = last->next;
}
//didn't find an id equal to the one passed ad parameter
return NULL;
}//end of *find_device_a_by_id
Adding an element to the list should add the element on the linked list as first and modify the pointer to that entry.
Finding an element should return a pointer to that specific entry on the linked-list.
You are defining a pointer to a pointer to your struct:
struct Type_A** devices_A = NULL;
Right now it does not point to a valid struct Type_A* as you haven't created one to point it to. So when you pass this into your function add_device_a and it dereferences that variable, you invoke undefined behavior, in this case probably a segfault.
What you probably actually want is to define struct Type_A* devices_A = NULL; And then when you pass it into your function, pass in the address of that pointer:
add_device_a(&devices_A,id_temp,type_temp,
power_level_normal_temp,power_level_low_temp,0,0);
You probably want to declare devices_A as struct Type_A* devices_A = NULL (not as a double pointer), and then call add_device_a() using add_device_a(&devices_A, ....
The way you're doing it is confusing and requires that you allocate space for devices_A, also in this context dereferencing *head when devices_A is NULL is making the program read from address NULL which is undefined behavior and may cause crashes.
You can also see this question about how to manage linked lists properly.

Creating a push() method for a singly linked list with two parameters

I need to create the push method for a program that push an element into a stack. I have created this typedef:
typedef struct node{
int value;
struct node *next;
} Node;
With this snippet of code in my main:
Node *stackptr;
stackptr = NULL;
This is where I have a problem and am not sure exactly what is going on - In my push method im not sure if I am returning the updated pointer to the top of the stack. Im suppose to check if it is empty as well but I am going to get to that last. Here is the push() function:
void push(Node *stkptr, int i){
Node *temp;
temp = malloc(sizeof(Node));
temp->value = i;
temp->next = *stkptr;
return *stkptr = temp;
}
Hope this makes some sort of sense what I am trying to get across. Thanks for any advice you are able to give me. Hope all is well.
Last I am in need of fixing my int pop() function! I have to return the value of the node that was popped. I believe I am almost there - my compiler is still throwing errors. This is what I have so far:
int pop(Node** stkptr){
Node *temp;
temp = malloc(sizeof(Node));
if((*stkptr) == NULL){
fprintf(stderr, "The stack is empty. Pop is not allowed\n");
return 0;
}
else{
temp = *stkptr;
stkptr = *temp;
}
return stkptr;
free(temp);
}
However, the compiler is throwing the error:
incompatible types when assigning to type ‘struct Node **’ from type ‘Node’
warning: return makes integer from pointer without a cast
Can someone please help me fix my problem! Thanks!
There must be a lot of duplicates for this (for example, Implementing stack with linked list in C from the related questions section), but basically, you need to pass a pointer to a pointer into the function:
void push(Node **stkptr, int i)
{
Node *temp;
temp = malloc(sizeof(Node));
temp->value = i;
temp->next = *stkptr;
*stkptr = temp;
}
You also can't return a value from a function that returns void. You should also check that the memory allocation worked.
You'd call this from, for example, your main program:
Node *stack = NULL;
int i;
while (get_an_integer(&i) != EOF)
push(&stack, i);
where get_an_integer() is a hypothetical function that reads an integer from somewhere and assigns it to i, while returning a status (0 — got an integer; EOF — didn't get an integer).
An alternative design returns the new head of the stack from the function:
Node *push(Node *stkptr, int i)
{
Node *node;
node = malloc(sizeof(Node));
node->value = i;
node->next = stkptr;
return node;
}
with calling sequence:
Node *stack = NULL;
int i;
while (get_an_integer(&i) != EOF)
stack = push(stack, i);
A question about pop()
The pop() function appears to remove and destroy the first item on the stack, rather than returning it. However, there are a number of flaws in it, such as it allocates space, then overwrites the pointer with information from the stack, then returns before freeing the data. So, assuming that the demolition job is required, the code should be:
int pop(Node **stkptr)
{
assert(stkptr != 0);
Node *temp = *stkptr;
if (temp == NULL)
{
fprintf(stderr, "The stack is empty. Pop is not allowed\n");
return 0;
}
else
{
*stkptr = temp->next;
free(temp); // Or call the function to deallocate a Node
return 1;
}
}
This now returns 1 when successful and 0 when the stack was empty. Alternatively, if you wanted the value from the top of the stack returned rather than freed, then:
Node *pop(Node **stkptr)
{
assert(stkptr != 0);
Node *temp = *stkptr;
if (temp == NULL)
{
fprintf(stderr, "The stack is empty. Pop is not allowed\n");
return 0;
}
else
{
*stkptr = temp->next;
return temp;
}
}
Or, since you are told by the return value whether there was anything to pop, and printing in a library function can be objectionable, maybe even:
Node *pop(Node **stkptr)
{
assert(stkptr != 0);
Node *temp = *stkptr;
if (temp != NULL)
*stkptr = temp->next;
return temp;
}
Warning: none of the code has been submitted to a compiler for verification.

Single linked list in C

I am trying to write a singly-linked list in C. So far, I just get segmentation faults.
I am probably setting the pointers wrong, but I just couldn't figure how to do it correctly.
The list should be used for "processors" sorted from highest priority (at the beginning of the list) to lowest priority (at the end of the list). Head should point to the first element, but somehow I am doing it wrong.
First of all here is the code:
struct process {
int id;
int priority;
struct process *next;
}
struct process *head = NULL;
void insert(int id, int priority) {
struct process * element = (struct process *) malloc(sizeof(struct process));
element->id = id;
element->priority = priority;
while(head->next->priority >= priority)
head = head->next;
element->next = head->next;
head->next = element;
// I put here a printf to result, which leads to segmenatition fault
// printf("%d %d\n", element->id, element->priority);
}
/* This function should return and remove element with the highest priority */
int pop() {
struct process * element = head->next;
if(element == NULL)
return -1;
head->next = element->next;
free(element);
return element->id;
}
/* This function should remove a element with a given id */
void popId(int id) {
struct process *ptr = head;
struct process *tmp = NULL;
while(prt != NULL) {
if(ptr->id == id) {
ptr->next = ptr->next->next;
tmp = ptr->next;
} else {
prt = ptr->next;
}
}
free(tmp);
}
Unfortunately, I could not try out pop() and popId() due to the segmentation fault.
May anyone tell me what I am doing wrong?
EDIT: Now, I edited the insert function. It looks like this:
void insert(int id, int priority) {
struct process * element = (struct process *) malloc(sizeof(struct process));
struct process * temp = head;
element->id = id;
element->priority = priority;
if(head == NULL) {
head = element; // edited due to Dukeling
element->next = NULL;
} else {
while(temp->next != NULL && temp->next->priority >= priority)
temp = temp->next;
element->next = head->next;
head->next = element;
}
// I put here a printf to result, which leads to segmenatition fault
// printf("%d %d\n", element->id, element->priority);
}
But I still get segmentation fault for pop() and popId(). What did I miss here?
You don't check if head is NULL in insert.
You actually don't check if head is NULL in any function. You should, unless you want to put some dummy element on head, to simplify the code.
For insert:
About these lines:
while(head->next->priority >= priority)
head = head->next;
If head is NULL, that's not going to work. This may not actually be a problem if head can never be NULL for whichever reason (e.g. it has a dummy element as gruszczy mentioned).
You're changing head, thus you're getting rid of the first few elements every time you insert. You probably need a temp variable.
You need to also have a NULL check in case you reach the end of the list.
So, we get:
struct process *temp = head;
while (temp->next != NULL && temp->next->priority >= priority)
temp = temp->next;
For pop:
If the first element isn't a dummy element, then you should be returning the ID of head, not head->next (and you were trying to return a value of an already freed variable - this is undefined behaviour).
if (head == NULL)
return -1;
int id = head->id;
struct process *temp = head;
head = head->next;
free(temp);
return id;
For popId:
You're checking ptr's ID, but, if it's the one we're looking for, you're removing the next element rather than ptr. You should be checking the next one's ID.
head == NULL would again need to be a special case.
The free should be in the if-statement. If it isn't, you need to cater for it not being found or finding multiple elements with the same ID.
You should break out of the loop in the if-statement if there can only be one element with that ID, or you want to only remove the first such element.
I'll leave it to you to fix, but here's a version using double-pointers.
void popId(int id)
{
struct process **ptr = &head;
while (*ptr != NULL)
{
if ((*ptr)->id == id)
{
struct process *temp = *ptr;
*ptr = (*ptr)->next;
free(temp);
}
else
{
prt = &(*ptr)->next;
}
}
}
Note that the above code doesn't break out of the loop in the if-statement. This can be added if you're guaranteed to only have one element with some given ID in the list, or you want to just delete the first such element.
Your not checking your pointers before accessing their values for dereference. This will automatically lead to undefined behavior if the pointer is invalid (NULL or indeterminate). With each implementation below, note we don't access data via dereference unless the pointer is first-known as valid:
Implementation: insert()
void insert(int id, int priority)
{
struct process **pp = &head;
struct process *element = malloc(sizeof(*element);
element->id = id;
element->priority = priority;
while (*pp && (*pp)->priority >= priority)
pp = &(*pp)->next;
element->next = *pp;
*pp = element;
}
Implementation: pop()
Your pop() function appears to be designed to return the popped value. While this isn't entirely uncommon it has the undesirable side-effect of having no mechanism for communicating to the caller that the queue is empty without a sentinel-value of some sort (such as (-1) in your case. This is the primary reason most queues have a top(), pop(), and isempty() functional interface. Regardless, assuming (-1) is acceptable as an error condition:
int pop()
{
struct process *tmp = head;
int res = -1;
if (head)
{
head = head->next;
res = tmp->id;
free(tmp);
}
return res;
}
Implementation: popId()
Once again, looking for a specific node can be accomplished with a pointer-to-pointer in a fairly succinct algorithm, with automatic updating done for you due to using the actual physical pointers rather than just their values:
void popId(int id)
{
struct process ** pp = &head, *tmp = NULL;
while (*pp && (*pp)->id != id)
pp = &(*pp)->next;
if (*pp)
{
tmp = *pp;
*pp = tmp->next;
free(tmp);
}
}
I strongly advise stepping through each of these with a debugger to see how they work, particularly the insert() method, which has quite a lot going on under the covers for what is seemingly a small amount of code.
Best of luck

how to implement linked list deletion?

#include<stdio.h>
struct node {
int info;
struct node *next;
};
typedef struct node *nodeptr;
nodeptr i;
nodeptr q;
nodeptr p;
nodeptr *plist;
nodeptr getnode(void)
{
nodeptr p;
p = (nodeptr) malloc(sizeof(struct node));
return p;
}
void freenode(nodeptr p)
{
free(p);
}
int main()
{
int i;
nodeptr *k;
int a;
int *px;
int r;
nodeptr end;
nodeptr s;
nodeptr start;
p = getnode();
q = getnode();
q = start;
p = end;
for (i = 0; i < 6; i++) {
printf("enter value");
scanf("%d", &r);
p = getnode();
p->info = r;
q->next = p;
q = q->next;
}
q = start;
while ((q->next) != NULL) {
printf("n%d", (q->next)->info);
q = q->next;
}
scanf("%d", &a);
end = getnode();
end->info = a;
end->next = NULL;
for (q = start; q->next != NULL; q = q->next)
;
q->next = end;
q = start;
while ((q->next) != NULL) {
printf("n%d", (q->next)->info);
q = q->next;
}
for (q = start; q->next->next != NULL; q = q->next)
;
freenode(q->next);
q->next = NULL;
q = start;
while (q->next != NULL) {
printf("n%d", (q->next)->info);
q = q->next;
}
return 0;
}
in this program alist is made and an element is inserted at the end
in this the element is getting deleted but the list is not shown properly
only last two elements are getting displayed
please help so as to show the whole list with element deleted
There is a lot wrong, undortunately. As WhozCraig said, there's a lot of other posts on this topic, so you should have probably searched a little more before posting. But since you have, let's walk through some of the issues together.
nodeptr i;
nodeptr q;
nodeptr p;
nodeptr *plist;
Here you are declaring a ton of global variables, most with bad names. What's i? What's p? What's q? Further down, you redeclare variables with the same names. Some with the same type, others with different type. This make it confusing to know which variable you're referencing.
Generally speaking, avoid global variables and choose descriptive names. In this case, you can just get rid of i, p and q.
Also, you never initialize plist to anything; you should get into the habit of initializing variables to some sane default value. In this case, NULL could be appropriate, but since you do not use the variable at all it can be deleted.
nodeptr getnode(void)
{
nodeptr p;
p = (nodeptr) malloc(sizeof(struct node));
return p;
}
This is good, however in C you should not cast the result of malloc to a particular type as this is considered bad form and can cause subtle and hard to detect bugs. Just assign the return from malloc directly.
Secondly, you never check to make sure that malloc succeeded. Granted, it's unlikely that it would fail in your simple program, but you should get in the habit of checking the return value of functions that can fail.
And you should probably initialize the allocated memory to some default value, because the memory returned to you by malloc is full of junk. In this case, something like this seems appropriate:
if(p) /* only if we allocated memory. */
memset(p, 0, sizeof(struct node));
There are times when you could skip this, but clearing the memory is a sane default practice.
void freenode(nodeptr p)
{
free(p);
}
This is also fine, but you should consider verifying that p is not NULL before you call free. Again, this comes down to robustness, and it's a good habit to get into.
int main()
{
int i;
nodeptr *k;
int a;
int *px;
int r;
nodeptr end;
nodeptr s;
nodeptr start;
Again, here we have a lot of unitialized variables, but at least some of the names are a bit better. But notice what happens:
You declare a variable called i of type int. But you've already declared a global variable called i that is of type nodeptr. So now, the variable in the local scope (the int) shadows (that is, it hides it) the global variable. So inside main the name i refers to the int. This just adds to the confusion when someone is reading your program.
p = getnode();
q = getnode();
OK... so, over here you allocate two new nodes and make p and q point to those nodes. So far so good.
q = start;
p = end;
Oops... now this is a problem. We now make p and q point to wherever start and end respectively point to.
And where do those point to? Who knows. Both start and end are unitialized, so they can point to anything. From this point on, your program exhibits undefined behavior: this means that anything can happen. Most likely, in this case, it will just crash.
Unfortunately from here on down, things become a lot more confusing. Instead of trying to explain everything, I'll just give some general commentary.
for (i = 0; i < 6; i++) {
printf("enter value");
scanf("%d", &r);
p = getnode();
p->info = r;
q->next = p;
q = q->next;
}
This loop is supposed to read 6 integers and put them in our linked list. This seems like a simple thing to do but there are issues.
First of all, you never check the return of scanf to know if the input operation succeeded. As I said before, you should always check the return value of functions that can fail and handle the failure accordingly. But in this case, let's ignore that rule.
A big problem is that q points to a random location in memory. So we're in undefined behavior land.
Another big problem is that there are two cases to consider: when the list is empty (i.e. the first time we're adding a number to the list when i == 0) and when the list is not empty (i.e. every other time). The behavior in those two cases differs. When i == 0 we can't just blindly set q->next, because even if q didn't point to a random location, there would, conceptually, be no q the way it's used here.
What we need here is some extra logic: if this is the first node that we are creating, set q to point to that node. Otherwise, set q->next to that node and then do q = q->next.
Please note, also, that you never set p->next anywhere, which would cause your list to not be NULL-terminated (something that you rely on here and in other loops). The memset fix in getnode corrects this problem, but generally you should make sure that if your code expects a particular behavior ("an unlinked node's next pointer points to NULL; lists are NULL-terminated") you should have code to ensure that behavior.
q = start;
Again, here, we reset q to point to start which is still uninitialized and points to garbage.
while ((q->next) != NULL) {
printf("n%d", (q->next)->info);
q = q->next;
}
This is a classic printing loop. Nothing wrong here, per se, although I think that stylistically, those parentheses around q->next are overkill and make reading the code a little more difficult than it has to be. My guideline would be to only add parentheses when they're necessary to override the default evaluation order of C or when the parentheses helps to visually explain to the reader how to group the expression in his head when mentally parsing the code.
scanf("%d", &a);
end = getnode();
end->info = a;
end->next = NULL;
This is fine, except for the error-checking issue with scanf, although you don't prompt the user to enter a number. But you correctly and explicitly make end->next point to NULL which is great.
for (q = start; q->next != NULL; q = q->next)
;
Again, the problem here is that q is set to start which, unfortunately, still points to garbage.
q->next = end;
q = start;
while ((q->next) != NULL) {
printf("n%d", (q->next)->info);
q = q->next;
}
This is the second time you've had to type this code to print the list. Generally, you should avoid code duplication. If you find that you need a particular code block in more than one place, it makes sense to split it out into a function and use the function. This makes understanding and maintaining the code easier.
for (q = start; q->next->next != NULL; q = q->next)
;
This loop is tricky to understand because of the q->next->next bit. Ask yourself "if I'm reading this, am I immediately sure that q->next can't ever be NULL?" If you aren't, then you really ought to rewrite this loop.
freenode(q->next);
q->next = NULL;
q = start;
Again, q is made to point to start which is unitialized. But hey, if we haven't crashed yet... ;)
while (q->next != NULL) {
printf("n%d", (q->next)->info);
q = q->next;
}
And again... this should really be a function.
return 0;
}
For a better implementation I refer you to one of the many other questions asked here (just search for "linked list delete". The implementation in this question by Khalid Waseem could also be of help, but it's not very documented, so you will have to carefully study and analyze the code to make sure that you understand it.
See below implementation for a better understanding.
struct node {
int info;
struct node *next;
};
typedef struct node node;
//Function to print a given single linked list.
void print_list(node *start)
{
//Check if the given list is empty.
if(start == NULL)
printf("List Empty!!!");
else
{
printf("Current List:");
//Visit each node one by one
while(start != NULL)
{
printf(" %d", start->info);
start = start->next;
}
}
}
//Function to insert a node at end of single linked list with given data
node* insert_at_end(node *start, int data)
{
node *ptr;
//Create a new node and assign memory using malloc
node* new_node = (node*)malloc(sizeof(node));
if(new_node != NULL)
{
//Initialize new node with data.
new_node->info = data;
new_node->next = NULL;
}
else
{ //Panic
printf("\nMemory not allocated. Insertion failed!!!");
return start;
}
//If input list is empty. then new_node becomes the first node of link list.
if(start == NULL)
return new_node;
else
{
//travel to the last node of list
ptr = start;
while(ptr->next != NULL)
ptr = ptr->next;
//Attach the newly created node at end of list.
ptr->next = new_node;
return start;
}
}
//Delete a node from the end of a Single linked list
node* delete_at_end(node *start)
{
node *ptr;
//If input list is empty. nothing to delete just return.
if(start == NULL)
return NULL;
//Just one node in the given linked list.
else if(start->next == NULL)
{
//Free the memory assigned to the node.
free(start);
return NULL;
}
else
{ //Travel to the second last node of the linked list.
ptr = start;
while(ptr->next->next != NULL)
ptr = ptr->next;
//free the last node.
free(ptr->next);
ptr->next = NULL;
return start;
}
}
int main()
{
int i, data;
node *Head_node = NULL;
for(i = 1; i<=5 ; i++)
{
printf("\nEnter node %d :", i);
scanf("%d", &data);
// Insert at End
Head_node = insert_at_end(Head_node, data);
// Print current List
print_list(Head_node);
}
for(i = 5; i>=1 ; i--)
{
printf("\nDeleting node %d :\n", i);
// Delete at End
Head_node = delete_at_end(Head_node);
// Print current List
print_list(Head_node);
}
return 0;
}

Resources