Having trouble removing all nodes from a linked-list - c

This code deletes all nodes except the last one. But I want it to delete all nodes. Can anyone tell me what am I doing wrong?
deleteall(struct node **start)
{
struct node*temp,*curr;
while ((*start)->next!=NULL)
{
temp=*start;
*start=(*start)->next;
free(temp);
curr=(*start);
}
if ((*start)->next==NULL)
{
free(curr);
}
}

I created a basic implementation of a linked list and tested your code. It's not particularly pretty, but it works:
#include <stdlib.h>
#include <stdio.h>
struct node { struct node *next; };
struct node* create_node(struct node *next) {
struct node* node = malloc(sizeof(struct node));
node->next = next;
printf("created %p\n", node);
return node;
}
void deleteall(struct node **start)
{
struct node*temp,*curr;
while ((*start)->next!=NULL)
{
temp=*start;
*start=(*start)->next;
free(temp);
printf("free'd %p\n", temp);
curr=(*start);
}
if ((*start)->next==NULL)
{
free(curr);
printf("free'd %p\n", curr);
}
}
int main(int argc, char** argv) {
// create root node
struct node * ll = create_node(0);
// insert three nodes
ll->next = create_node(ll->next);
ll->next = create_node(ll->next);
ll->next = create_node(ll->next);
// delete all nodes (including root)
deleteall(&ll);
return 0;
}
The output is:
$ gcc test.c && ./a.out
created 0xc3c010
created 0xc3c030
created 0xc3c050
created 0xc3c070
free'd 0xc3c010
free'd 0xc3c070
free'd 0xc3c050
free'd 0xc3c030
As you can see, all nodes that are allocated are actually free'd.
Maybe you are confused by the fact, that the root node is not set to 0, but apparantly still contains the remains of the object previously located at that place. You could fix that if you assign 0 to the start pointer after you freed the nodes: *start = 0; (or by eliminating the additional curr pointer, as suggested in the other answer).
Consider that you could alternatively delete the nodes of your list recursively:
void delete_node_recursively(struct node *node) {
if (node) {
delete_node_recursively(node->next);
free(node)
}
}
If you want to have the root node set to 0 in the end, you can add a wrapper:
void delete_list(struct node **root) {
delete_node_recursively(*root);
*root = 0;
}

try this:
This was to simplify your code.
And Finally *start become NULL. (your code not become NULL)
deleteall(struct node **start){
struct node *temp;
while(*start){
temp = *start;
*start=(*start)->next;
free(temp);
}
}

Related

Printing doubly linked list in C goes into infinite loop

Im trying to learn doubly linked lists. I used the following to print:
typedef struct Node{
int data;
struct Node* prev;
struct Node* next;
}node;
typedef struct List{
node *head;
}list;
node * createNode(int data) {
node * newNode = (node*)malloc(sizeof(node));
newNode->data = data;
newNode->prev = NULL;
newNode->next = NULL;
return newNode;
}
_Bool isEmpty(const list *L)
{
if (L->head == NULL)
return 1;
return 0;
}
_Bool insert(list *L, node *N) {
if(isEmpty(L)) {
L->head = N;
}
else{
L->head->prev = N;
N->next = L->head;
L->head = N;
}
if (L->head==N)
return 1;
return 0;
}
void _print(list *L){
node *temp=L->head;
while(temp!=NULL){
printf("%d ", temp->data);
temp = temp->next;
}
printf("\n");
}
int main(int argc, char *argv[]){
list *L1=(list *)malloc(sizeof(list));
node *N1=createNode(3);
node *N2=createNode(1);
node *N3=createNode(5);
insert(L1, N3);
insert(L1, N2);
insert(L1, N1);
_print(L1);
}
for reference my list struct only contains a pointer "head" and my node struct contains next, prev and data.
It prints the correct data but goes into infinite loop.
What is the reason ?
The problem is that this line in main:
list *L1=(list *)malloc(sizeof(list));
Allocates memory for the list, but does not initialize it.
Without initialization the value of L1->head can be anything.
And if it happens to be different than 0 (i.e. NULL), insert will interpret it as pointing to a valid node (which it isn't).
The result is undefined behavior (UB), which means anything can happen. It might seem to work, it can crash, or get into an infinite loop etc.
In order to fix it, you need to initialize the list pointed by L1.
You can do it at least in 2 ways:
Replace the call to malloc with calloc, which also zeroes the allocated memory:
list* L1 = (list*)calloc(sizeof(list), 1);
Add an explicit initialization after the malloc:
list* L1 = (list*)malloc(sizeof(list));
L1->head = NULL; /* <--- initialization */
You can also add a function for encapsulating the initialization.

creating a list of nodes with C

I want to createe a list of nodes that links to each other, I use head to remember the address of the first node, prev to link, and newdata to get the input, but it turns out that my head prev and newdata are all in the same address, can someone help me with this plz
typedef struct node
{
void* stdPtr;
struct node* link;
}NODE;
NODE* createNode(void* std)
{
NODE* nodePtr;
nodePtr=(NODE*)malloc(sizeof(NODE));
nodePtr->stdPtr=std;
nodePtr->link=NULL;
return nodePtr;
}
typedef NODE* nodePtr;
int main(void)
{
FILE* fin;
fin=fopen("input.txt","r");
//define
int i=0;
intPtr ID,grade;
STD* stdinfo;
nodePtr head=NULL;
nodePtr prev=(nodePtr)malloc(sizeof(NODE));
//nodePtr newdata=(nodePtr)malloc(sizeof(NODE));
prev=head;
//malloc space to ptr
ID=(intPtr)malloc(sizeof(int));
grade=(intPtr)malloc(sizeof(int));
stdinfo=(STD*)malloc(sizeof(STD));
//read student data and compare
while(fscanf(fin,"%d%d",&(stdinfo->ID),&(stdinfo->grade))!=EOF)
{
nodePtr newdata=(nodePtr)malloc(sizeof(NODE));
newdata=createNode(stdinfo);
if (prev==NULL)
{
prev=newdata;
head=prev;//為什麼只有在這裡=prev後面會跑掉?
}
printf("%d %d\n",*(int*)head,*(int*)prev);
if(prev->link!=NULL)
{
prev=prev->link;
}
prev->link=newdata;
}
fclose(fin);
return 0;
}
Important parts are missing (types, input.txt) to run your program which makes it harder to help you.
You create an instance of STD prior to the loop, then overwrite whatever data you store in it on each iteration and store the address of that one instance in each node. You need to create an instance of both NODE and STD per loop iteration (or change the definition of NODE so it can hold the STD data instead of a pointer to STD).
You use this pattern a couple of times which allocate data, then immediately leak the data by overwriting the pointer:
nodePtr prev=(nodePtr)malloc(sizeof(NODE));
prev=head;
...
nodePtr newdata=(nodePtr)malloc(sizeof(NODE));
newdata=createNode(stdinfo);
Here is more straight forward version to get you going:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
void *stdPtr;
struct node* link;
} NODE;
NODE* createNode(void *std, NODE *prev) {
NODE *nodePtr = malloc(sizeof(NODE));
nodePtr->stdPtr=std;
nodePtr->link=prev;
return nodePtr;
}
void printNodes(NODE *tail) {
for(; tail; tail = tail->link) {
printf("%s\n", (const char *) tail->stdPtr);
}
}
int main(void) {
NODE *tail = NULL;
tail = createNode("hello", tail);
tail = createNode("world", tail);
printNodes(tail);
}

linked list of strings in C

I am trying to create a linked list of strings in C and have had problems adding the first Node into the list. For whatever reason my program prints NULL even though I reference the head variable to newNode but it does not copy the string from struct pointer to struct pointer. Any help is appreciated. Thanks!
#include "stdafx.h"
#include <stdlib.h>
#include <string.h>
typedef struct stringData {
char *s;
struct stringData *next;
} Node;
Node *createNode(char *s) {
Node *newNode = (Node *)malloc(sizeof(Node));
newNode->s = s;
newNode->next = NULL;
return newNode;
}
void insert(Node *head, Node *newNode) {
if (head == NULL) {
head->s = newNode->s;
head = newNode;
}
}
void printList(Node *head) {
while (head != NULL) {
printf("%s\n", head->s);
head = head->next;
}
}
int main()
{
Node *head = createNode(NULL);
Node *a = createNode("A");
insert(head, a);
printList(head);
return 0;
}
Following code snippet is wrong:
void insert(Node *head, Node *newNode) {...}
...
insert(head, a);
You need to pass the pointer by reference. Currently you are changing local copy (argument).
Fix
Change your insert as:
void insert(Node **head, Node *newNode) {...}
And call as:
insert(&head, a);
What elseAtleast insert (and possibly) more functions are not fool-proof (guaranteed null pointer dereference, else case not handled etc). You need to debug and fix many such cases. Working your approach properly on paper before coding may help.
Here is a modified version of the code that gives an example of inserting new nodes at both the start of a list and the end of a list. In fact, the insert function could be used to insert a new node at any position in the list, since all it needs is a pointer to a link and a pointer to the node to be inserted.
#include <stdlib.h>
#include <stdio.h>
typedef struct stringData {
char *s;
struct stringData *next;
} Node;
Node *createNode(char *s) {
Node *newNode = (Node *)malloc(sizeof(Node));
newNode->s = s;
newNode->next = NULL;
return newNode;
}
void insert(Node **link, Node *newNode) {
newNode->next = *link;
*link = newNode;
}
void printList(Node *head) {
while (head != NULL) {
printf("%s\n", head->s);
head = head->next;
}
}
int main(void)
{
Node *head = NULL;
Node *tail = NULL;
Node *n;
n = createNode("B");
// First node at start of list - head is updated.
insert(&head, n);
// First node is also the tail.
tail = n;
n = createNode("A");
// Insert node at start of list - head is updated.
insert(&head, n);
n = createNode("C");
// Insert node at end of list.
insert(&tail->next, n);
// Update tail.
tail = n;
printList(head);
return 0;
}

Connect preorder predecessor with its successor in a binary search tree

Actually in an interview i was asked to write a code through which every node in a binary search tree is having a extra pointer namely "next" we have to connect this pointer of every node to its pre order successor ,can any one suggest me the code as i was not able to do so. the tree nodes has above structure :-
struct node {
int data ;
struct node *left,*right;
struct node *next; //this pointer should point to pre order successor
};
thank you .
Cracked the the solution thanks to you guys ,below is the whole code written in c :-
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *left,*right,*next;
};
struct node* getNode(int data)
{
struct node* temp=(struct node*)malloc(sizeof(struct node));
temp->left=temp->right=NULL;
temp->data=data;
return temp;
}
void insert(struct node**root,int data)
{
if(!*root)
{
*root=(struct node*)malloc(sizeof(struct node));
(*root)->left=(*root)->right=NULL;
(*root)->data=data;
}
else if(data<(*root)->data)
insert(&((*root)->left),data);
else if(data>(*root)->data)
insert(&((*root)->right),data);
}
struct node* preorderSuccessor(struct node* root,struct node* p)
{
int top,i;
struct node *arr[20];
if(!root || !p)
return NULL;
if(p->left)
return p->left;
if(p->right)
return p->right;
top=-1;
while(root->data!=p->data)
{
arr[++top]=root;
if(p->data<root->data)
root=root->left;
else
root=root->right;
}
for(i=top;i>=0;i--)
{
if(arr[i]->right)
{
if(p!=arr[i]->right)
return arr[i]->right;
}
p=arr[i];
}
return NULL;
}
void connect(struct node* parent,struct node *r)
{
if(r)
{ connect(parent ,r->left);
r->next = preorderSuccessor(parent,r);
connect(parent,r->right);
}
}
int main()
{
struct node* root=NULL,*temp=NULL;
int arr[]={10,11,2,3,9,8,4,5},size,i;
size=sizeof(arr)/sizeof(arr[0]);
for(i=0;i<size;i++)
insert(&root,arr[i]);
connect(root,root);
struct node *ptr = root;
while(ptr){
// -1 is printed if there is no successor
printf("Next of %d is %d \n", ptr->data, ptr->next? ptr->next->data: -1);
ptr = ptr->next;
}
return 0;
}
As Eugene said: So traverse the tree with preorder traversal and connect. To do that, you need to know which node, if any, you visited last.
You can do that with the usual recursive approach by passing a reference to the previous node. This must be the address of a variable that is valid throughout the recursion, because the previous node is not necessarily closer to the root. You could use a global variable, but a variable created in a wrapper function may be better:
void connect_r(struct node *node, struct node **whence)
{
if (node) {
if (*whence) (*whence)->next = node;
*whence = node;
connect_r(node->left, whence);
connect_r(node->right, whence);
}
}
void connect(struct node *head)
{
struct node *p = NULL;
connect_r(head, &p);
if (p) p->next = NULL;
}
The pointer p in connect, whose address is passed to the recursive function connect_r holds the node whose next pointer should be updated next. The update doesn't happen on the first visited node. and the next member of the last visited node must explicitly be set to NULL after the recursion.
Alternatively, you can connect the nodes iteratively by using a stack:
void connect(struct node *head)
{
struct node *p = NULL;
struct node **prev = &p;
struct node *stack[32]; // To do: Prevent overflow
size_t nstack = 0;
if (head) stack[nstack++] = head;
while (nstack) {
struct node *node = stack[--nstack];
*prev = node;
prev = &node->next;
if (node->right) stack[nstack++] = node->right;
if (node->left) stack[nstack++] = node->left;
}
*prev = NULL;
}
The connected next pointers are a snapshot of the current tree. Insertions, deletions and rearrangements of nodes will render the next chain invalid. (But it can be made valid again by calling connect provided that the tree's left and right links are consistent.)

Using Pass by reference with linked lists

So I've use pass by reference on my linked list code but the problem is it's not printing soo how do I actually fix this?
my code:
#include<stdio.h>
#include<stdlib.h>
struct node
{
int x;
struct node *next;
};
void add(struct node **root, int x)
{
struct node *conductor;
if(root==NULL)
{
(*root)=malloc(sizeof(struct node));
(*root)->x=x;
(*root)->next=NULL ;
}
else
{
conductor = *root;
while(conductor->next!=NULL)
{
conductor = conductor -> next;
}
conductor->next=malloc(sizeof(struct node));
conductor->next->x=x;
conductor->next->next=NULL;
}
}
void display(struct node *root)
{
struct node *conductor;
conductor=root;
while(conductor!=NULL)
{
printf("%d",conductor->x);
conductor = conductor ->next;
}
}
int main()
{
struct node *root;
root=NULL;
add(&root,5);
add(&root,4);
display(root);
free(root);
system("pause");
}
In better form
http://codepad.org/CPdUvK0x
Isn't it all nodes in my program are linked?
void add(struct node **root, int x)
{
struct node *conductor;
if(root==NULL)
That should be if (*root == NULL)
Since you're calling add(&root... root will never be NULL.
The check:
if(root==NULL)
should be
if(*root==NULL)
as root is being passed by address.
Also you do free(root) to free the entire list which is incorrect as it frees only the first node and makes the other nodes unreachable causing memory leak. To fix this you need to free the nodes one by one as:
struct node *tmp = root;
while(root) {
tmp = root->next;
free(root);
root = tmp;
}
the problem is in add():
if(root==NULL)
this test is wrong: root being passed by reference is never NULL (see in the main, it contains the address of the root node). you should correctly test if the rrot node is NULL:
if (*root == NULL)
i would also add that your way of freeing the memory allocated for the ist is wrong:
free(root)
will only free the root node, but will leak the child nodes...

Resources