How to free a linked list with pointers - c

I was trying to free memory for a linked list iteratively. The list has a struct which looks like this, and in this linked list, I don't add a url if it's in this list.
struct Node {
char *url;
struct Node *next;
};
Once done working with this linked list, I tried to free it, but got segmentation fault, I'm still in the way of learning c, I haven't got much clue of how to debugging such error other than directly searching for related topics. Referenced a few SOs this one, this one and this one, still cannot figure out where it got crashed.
Here's my code. Free feel to add comments if you think anything I missed in this implementation.
void url_push(struct Node *head, const char *url, size_t url_size) {
struct Node *new_node = (struct Node *) malloc(sizeof(struct Node));
new_node->url = malloc(url_size);
new_node->next = NULL;
for (int i = 0; i < url_size; i++)
*(new_node->url + i) = *(url + i);
struct Node *current = head;
while(1) {
if (strcmp(current->url, new_node->url) == 0) {
printf("Seen page %s!!!!!\n", new_node->url);
free(new_node);
break;
} else if (current->next == NULL) {
current->next = new_node;
break;
} else {
current = current->next;
}
}
}
int main() {
struct Node *head = (struct Node*)malloc(sizeof(struct Node));
head->url = "/";
head->next = NULL;
char *url = "www.google.com";
url_push(head, url, strlen(url));
url = "www.yahoo.com";
url_push(head, url, strlen(url));
url = "www.google.com";
url_push(head, url, strlen(url));
url = "www.wsj.com";
url_push(head, url, strlen(url));
struct Node *current = NULL;
while ((current = head) != NULL) {
printf("url: %s\n", head->url);
head = head->next;
free(current->url);
free(current);
}
}
Edited:
To reduce the confusions, I revised the struct. The purpose of using strcmp is to avoid adding a url that already seen.

head->url = "/";
That is not malloced data so you can't free it!
Your other problem is in url_push() with new_node->url = malloc(url_size); which does not allocate enough space for the terminating 0 in the string (nor does it copy the terminating 0 so you end up not "stomping on memory" but do have unterminated strings...). Try new_node->url = strdup(url); instead.
Style wise: calculate url_size in url_push() instead of making each caller call strlen() do it once inside the function being called (note if you use strdup() then you don't need the url_size at all.
Final note: A tool like valgrind would find both of these problems easily.

There are multiple problems in your code:
you do not allocate space for the null terminator for the new_node->url strings in url_push, causing strcmp() too have undefined behavior.
the first node is not properly constructed: its url pointer is not allocated.
you so not check for memory allocation failure
You should make url_push() more generic: it should handle empty lists by returning the new head pointer. You do not need to pass the length of the url string, just use strdup(), and you should avoid allocating a new node before checking for duplicates.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Node {
char *url;
struct Node *next;
};
struct Node *url_push(struct Node *head, const char *url) {
struct Node *current = head;
if (current != NULL) {
for (;;) {
if (strcmp(current->url, url) == 0) {
printf("Seen page %s before!!!!!\n", url);
return head;
} else if (current->next == NULL) {
break;
} else {
current = current->next;
}
}
}
struct Node *new_node = malloc(sizeof(struct Node));
if (new_node == NULL || (new_node->url = strdup(url)) == NULL) {
fprintf(stderr, "memory allocation failure\n");
exit(1);
}
new_node->next = NULL;
if (current == NULL) {
head = new_node;
} else {
current->next = new_node;
}
return head;
}
int main() {
struct Node *head = NULL;
head = url_push(head, "/");
head = url_push(head, "www.google.com");
head = url_push(head, "www.yahoo.com");
head = url_push(head, "www.google.com");
head = url_push(head, "www.wsj.com");
while (head != NULL) {
printf("url: %s\n", head->url);
struct Node *current = head;
head = head->next;
free(current->url);
free(current);
}
return 0;
}

Related

Removing unique elements in a doubly linked list in C

I need a little help removing unique characters in a doubly linked list in C. So here's the logic I tried implementing: I counted the occurrence of each character in the doubly linked list. If it's occurrence is 1 time, then it is unique element and needs to be deleted. I'll be repeating the process for all elements. But my code in remove_unique_dll() function isn't working properly, please help me fix it. Here's my code-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
char data;
struct node *next;
struct node *prev;
};
struct node *head, *tail = NULL; //Represent the head and tail of the doubly linked list
int len;
void addNode(char data)
{
struct node *newNode = (struct node*) malloc(sizeof(struct node)); //Create new node
newNode->data = data;
if (head == NULL)
{ //If dll is empty
head = tail = newNode; //Both head and tail will point to newNode
head->prev = NULL; //head's previous will point to NULL
tail->next = NULL; //tail's next will point to NULL, as it is the last node of the list
}
else
{
tail->next = newNode; //newNode will be added after tail such that tail's next points to newNode
newNode->prev = tail; //newNode's previous will point to tail
tail = newNode; //newNode will become new tail
tail->next = NULL; //As it is last node, tail's next will point to NULL
}
}
void remove_unique_dll()
{
struct node *current = head;
struct node *next;
struct node *prev;
int cnt;
while (current != NULL)
{
next = current->next;
cnt = 1;
//printf("!%c ",next->data);
while (next != NULL)
{
if (next->data == current->data)
{
cnt += 1;
next = next->next;
}
else
next = next->next;
//printf("#%c %d %c\n",next->data,cnt,current->data);
}
if (cnt == 1)
{
prev = current->prev;
//printf("#%c %d",prev->data,cnt);
if (prev == NULL)
{
head = next;
}
else
{
prev->next = next;
}
if (next == NULL)
{
tail = prev;
}
else
{
next->prev = prev;
}
}
current = current->next;
//printf("#%c ",current->data);
}
head = current;
}
void display()
{
struct node *current = head; //head the global one
while (current != NULL)
{
printf("%c<->", current->data); //Prints each node by incrementing pointer.
current = current->next;
}
printf("NULL\n");
}
int main()
{
char s[100];
int i;
printf("Enter string: ");
scanf("%s", s);
len = strlen(s);
for (i = 0; i < len; i++)
{
addNode(s[i]);
}
printf("Doubly linked list: \n");
display();
remove_unique_dll();
printf("Doubly linked list after removing unique elements: \n");
display();
return 0;
}
The output is like this-
If you uncomment the printf() statements inside remove_unique_dll() you'll notice that no code below inner while loop is being executed after inner while loop ends. What's the issue here and what's the solution?
Sample input- aacb
Expected output- a<->a<->NULL
Some issues:
You shouldn't assign head = current at the end, because by then current is NULL
The next you use in the deletion part is not the successor of current, so this will make wrong links
As you progress through the list, every value is going to be regarded as unique at some point: when it is the last occurrence, you'll not find a duplicate anymore, as your logic only looks ahead, not backwards.
When you remove a node, you should free its memory.
Not a big issue, but there is no reason to really count the number of duplicates. Once you find the first duplicate, there is no reason to look for another.
You should really isolate the different steps of the algorithm in separate functions, so you can debug and test each of those features separately and also better understand your code.
Also, to check for duplicates, you might want to use the following fact: if the first occurrence of a value in a list is the same node as the last occurrence of that value, then you know it is unique. As your list is doubly linked, you can use a backwards traversal to find the last occurrence (and a forward traversal to find the first occurrence).
Here is some suggested code:
struct node* findFirstNode(char data) {
struct node *current = head;
while (current != NULL && current->data != data) {
current = current->next;
}
return current;
}
struct node* findLastNode(char data) {
struct node *current = tail;
while (current != NULL && current->data != data) {
current = current->prev;
}
return current;
}
void removeNode(struct node *current) {
if (current->prev == NULL) {
head = current->next;
} else {
current->prev->next = current->next;
}
if (current->next == NULL) {
tail = current->prev;
} else {
current->next->prev = current->prev;
}
free(current);
}
void remove_unique_dll() {
struct node *current = head;
struct node *next;
while (current != NULL)
{
next = current->next;
if (findFirstNode(current->data) == findLastNode(current->data)) {
removeNode(current);
}
current = next;
}
}
You have at least three errors.
After counting the number of occurrences of an item, you use next in several places. However, next has been used to iterate through the list. It was moved to the end and is now a null pointer. You can either reset it with next = current->next; or you can change the places that use next to current->next.
At the end of remove_unique_dll, you have head=current;. There is no reason to update head at this point. Whenever the first node was removed from the list, earlier code in remove_unique_dll updated head. So it is already updated. Delete the line head=current;.
That will leave code that deletes all but one occurrence of each item. However, based on your sample output, you want to leave multiple occurrences of items for which there are multiple occurrences. For that, you need to rethink your logic in remove_unique_dll about deciding which nodes to delete. When it sees the first a, it scans the remainder of the list and sees the second, so it does not delete the first a. When it sees the second a, it scans the remainder of the list and does not see a duplicate, so it deletes the second a. You need to change that.
Let's consider your code step by step.
It seems you think that in this declaration
struct node *head, *tail = NULL; //Represent the head and tail of the doubly linked list
the both pointers head and tail are explicitly initialized by NULL. Actually only the pointer tail is explicitly initialized by NULL. The pointer head is initialized implicitly as a null pointer only due to placing the declaration in file scope. It to place such a declaration in a block scope then the pointer head will be uninitialized.
Instead you should write
struct node *head = NULL, *tail = NULL; //Represent the head and tail of the doubly linked list
Also it is a very bad approach when the functions depend on these global variables. In this case you will be unable to have more than one list in a program.
Also the declaration of the variable len that is used only in main as a global variable
int len;
also a bad idea. And moreover this declaration is redundant.
You need to define one more structure that will contain pointers head and tail as data members as for example
struct list
{
struct node *head;
struct node *tail;
};
The function addNode can invoke undefined behavior when a new node can not be allocated
void addNode(char data)
{
struct node *newNode = (struct node*) malloc(sizeof(struct node)); //Create new node
//...
You should check whether a node is allocated successfully and only in this case change its data members. And you should report the caller whether a node is created or not.
So the function should return an integer that will report an success or failure.
In the function remove_unique_dll after this while loop
while (next != NULL)
{
if (next->data == current->data)
{
cnt += 1;
next = next->next;
}
else
next = next->next;
//printf("#%c %d %c\n",next->data,cnt,current->data);
}
if cnt is equal to 1
if (cnt == 1)
//..
then the pointer next is equal to NULL. And using the pointer next after that like
if (prev == NULL)
{
head = next;
}
else
{
prev->next = next;
}
is wrong.
Also you need to check whether there is a preceding node with the same value as the value of the current node. Otherwise you can remove a node that is not a unique because after it there are no nodes with the same value.
And this statement
head = current;
does not make sense because after the outer while loop
while (current != NULL)
the pointer current is equal to NULL.
Pay attention that the function will be more useful for users if it will return the number of removed unique elements.
Here is a demonstration program that shows how the list and the function remove_unique_dll can be defined.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
char data;
struct node *next;
struct node *prev;
};
struct list
{
struct node *head;
struct node *tail;
};
int addNode( struct list *list, char data )
{
struct node *node = malloc( sizeof( *node ) );
int success = node != NULL;
if (success)
{
node->data = data;
node->next = NULL;
node->prev = list->tail;
if (list->head == NULL)
{
list->head = node;
}
else
{
list->tail->next = node;
}
list->tail = node;
}
return success;
}
size_t remove_unique_dll( struct list *list )
{
size_t removed = 0;
for ( struct node *current = list->head; current != NULL; )
{
struct node *prev = current->prev;
while (prev != NULL && prev->data != current->data)
{
prev = prev->prev;
}
if (prev == NULL)
{
// there is no preceding node with the same value
// so the current node is possibly unique
struct node *next = current->next;
while (next != NULL && next->data != current->data)
{
next = next->next;
}
if (next == NULL)
{
// the current node is indeed unique
struct node *to_delete = current;
if (current->prev != NULL)
{
current->prev->next = current->next;
}
else
{
list->head = current->next;
}
if (current->next != NULL)
{
current->next->prev = current->prev;
}
else
{
list->tail = current->prev;
}
current = current->next;
free( to_delete );
++removed;
}
else
{
current = current->next;
}
}
else
{
current = current->next;
}
}
return removed;
}
void display( const struct list *list )
{
for (const node *current = list->head; current != NULL; current = current->next)
{
printf( "%c<->", current->data );
}
puts( "null" );
}
int main()
{
struct list list = { .head = NULL, .tail = NULL };
const char *s = "aabc";
for (const char *p = s; *p != '\0'; ++p)
{
addNode( &list, *p );
}
printf( "Doubly linked list:\n" );
display( &list );
size_t removed = remove_unique_dll( &list );
printf( "There are removed %zu unique value(s) in the list.\n", removed );
printf( "Doubly linked list after removing unique elements:\n" );
display( &list );
}
The program output is
Doubly linked list:
a<->a<->b<->c<->null
There are removed 2 unique value(s) in the list.
Doubly linked list after removing unique elements:
a<->a<->null
You will need at least to write one more function that will free all the allocated memory when the list will not be required any more.

Getting a segfault with linked list

Apologies for the very basic question, but I can't figure this out. I am trying to build a simple linked list and append some values to it in C.
Below is the list.c file
#include <stdio.h>
#include <stdlib.h>
#include "./list.h"
int main(int argc, char *argv[]) {
int arr[] = {1,2,3,4};
List *list = createList();
int i = 0;
for(i = 0; i < 4; i++) {
appendList(list, arr[i]);
}
return 0;
}
List *createList() {
List *list = malloc(sizeof(List));
if(list == NULL) {
return NULL;
}
list->head = malloc(sizeof(Node));
list->tail = malloc(sizeof(Node));
if(list->head == NULL || list->tail == NULL) {
free(list);
return NULL;
}
list->size = 0;
return list;
}
void appendList(List *list, int num) {
if(list->head->value == 0) {
list->head->value = num;
list->tail->value = num;
return;
}
Node *current = calloc(1, sizeof(Node));
current = list->head;
while(current->next != NULL) {
current = current->next;
}
current->next = calloc(1, sizeof(Node));
if(current->next == NULL) {
free(current->next);
printf("Failed to allocate memory");
exit(1);
}
current->next->value = num;
list->size += 1;
list->tail = current->next;
}
And below is the header file
#ifndef List_h
#define List_h
#include <stdlib.h>
typedef struct node {
int value;
struct node *next;
} Node;
typedef struct {
Node *head;
Node *tail;
int size;
} List;
List *createList();
void appendList(List *, int num);
Node *removeList(List *);
void printList(List *);
#endif
While running through a debugger, my code seems to be working fine, which makes even less sense.
I assume my issue is in the while loop inside of appendList, where I am trying to access some unallocated piece of memory. Is the issue then with the check I am making, current->next != NULL? Does accessing an unallocated piece of memory necessary return NULL?
Hmm, well my thoughts are that you've created the initial head and tail Nodes and you didn't set its value. Later you use value to determine whether or not you need to add another node or set head and tail to the value passed:
void appendList(List *list, int num) {
if(list->head->value == 0) {
list->head->value = num;
list->tail->value = num;
return;
}
...
The memory returned from malloc will not be necessarily zero, so your algorithm should ensure that all values are set before proceeding.
You then proceed to reach the end of your list:
Node *current = calloc(1, sizeof(Node));
current = list->head;
while(current->next != NULL) {
current = current->next;
}
However, again, while list->head exists, you never set the value of list->head->next! Following an unassigned pointer is not going to end nicely for you in the best of cases.
Consider creating a method to create a new node:
Node* createNode() {
Node* node = malloc(sizeof(Node));
if(node == NULL) {
return NULL;
}
node->value = 0;
node->next = NULL;
return node;
}
Also please note that there's a minor correction to the code here (unrelated to your segmentation fault, but could still create memory leak):
list->head = malloc(sizeof(Node));
list->tail = malloc(sizeof(Node));
if(list->head == NULL || list->tail == NULL) {
free(list);
return NULL;
}
Note that it is possible for list->head to correctly be assigned memory and list->tail to not be correctly assigned memory. In that case, you risk having a memory leak for list->head. Please take the necessary precautions.
Especially in embedded systems, the code compiled for debug mode and the one for release mode can differ. So, for me, there is no surprise that your code works in debug and won't in release.
When creating linked lists using malloc, it is possible that the compiler sets the address of your "struct node * next" element, a non-accessible location in memory. So if you try to access it, you'll get a segfault. (or BAD_EXC in MacOS)
If you suspect that malloc is your problem, try creating a small list with no malloc and see if you have segfault, i.e. use:
struct node myNode;
struct node* pmyNode = &myNode;
In your while loop, I suppose, you are trying to go to the last element of your list. So, instead of:
while(current->next != NULL) {
current = current->next;
}
Try to do this:
last_linked_list_element->next = last_linked_list_element;
current = first_linked_list_element;
while(current != current->next) {
current = current->next;
}
You will break out of the loop when you are at the last element of your list.
Another solution would be to try:
last_linked_list_element->next = NULL;
or
last_linked_list_element->next = &random_identifier;
This will make sure that the pointer locates to an accesible location in memory. Does this solve your problem?
In addition to the previous post, in the following code:
Node *current = calloc(1, sizeof(Node));
current = list->head;
while(current->next != NULL) {
current = current->next;
}
you should to delete the line Node *current = calloc(1, sizeof(Node)); because in this way you allocate memory and than don't use it (subsequently you assign currect pointer to another value).

Free memory from linked list in C

I have been trying to free the allocated memory of a file loaded into a linked list, I have managed to free the nodes, but I can't figure out how to free the allocated memory of the file's values copies.
I have tried something like that:
void FreeString(struct node * newNode)
{
for (int i = 0; i < 5; i++)
{
free(newNode->string);
}
}
but the compiler would crash with a segmentation fault, and valgrind would still point out to memory leaks.
it would be appreciated if anyone can tell me what am I doing wrong, and point me to the right direction.
Full code:
The struct:
typedef struct node
{
char *string;
struct node *next;
}node;
// main function here...
void Push(struct node **RefHead, char *word)
{
struct node *newNode = NULL;
newNode = (struct node *)malloc(sizeof(node));
newNode->string = (char*)malloc(strlen(word) + 1); // can't free this part here
strcpy(newNode->string, word);
newNode->next = *RefHead;
*RefHead = newNode;
}
Loading the file into memory:
void FileToNode()
{
struct node *head = NULL, *current = NULL;
infile = fopen("file.txt", "r");
if (infile == NULL)
{
printf("Could not open file\n");
exit(1);
}
while (fgets(word, sizeof(word), infile))
{
Push(&head, word);
}
fclose(infile);
current = head;
while(current)
{
printf("%s", current->string);
current = current->next;
}
freeAll(head);
}
The Free function:
void freeAll(struct node *head)
{
struct node *current = NULL;
while ((current = head) != NULL)
{
head = head->next;
free(current);
}
}
Am I missing something? What's wrong with:
void freeAll(struct node *head)
{
struct node *current = NULL;
while ((current = head) != NULL)
{
head = head->next;
free(current->string);
free(current);
}
}
It's not the problem, but you should probably replace:
newNode->string = (char*)malloc(strlen(word) + 1); // can't free this part here
strcpy(newNode->string, word);
with:
newNode->string = strdup (word);
The problem is this:
void FreeString(struct node * newNode)
{
for (int i = 0; i < 5; i++)
{
free(newNode->string);
}
}
Once you call free, newNode->string no longer points to an allocated object (because you just freed it). So you can't pass it to free again.

linked list insertion at end when header node is not null

I'm having a problem with inserting a node at the end of a linked list. It's not being executed when the start node is not null and I don't understand the problem. Please help me out here. The function is called second time but is not going to the else block.
typedef struct token_Info
{
int linenumber;
char* token;
char value[200];
struct token_Info* next;
} token_Info;
token_Info *tokenlist;
token_Info* insert_at_end( token_Info *list,char *name)
{
printf("token identified \t");
token_Info *new_node;
token_Info *temp,*start;
start = list ;
char *tempname ;
tempname = name;
new_node= malloc(sizeof(token_Info));
new_node->token = malloc(sizeof(strlen(tempname)+1));
strcpy(new_node->token,tempname);
new_node->next= NULL;
// printf("%d",strlen(tempname));
if(new_node == NULL){
printf("nFailed to Allocate Memory");
}
if(start==NULL)
{
start=new_node;
return start;
}
else
{
printf("anvesh");
temp = start;
while(temp->next != NULL)
{
temp = temp ->next;
}
temp->next = new_node;
return temp;
}
}
tokenlist = insert_at_end(tokenlist,"TK_BEGIN");
tokenlist = insert_at_end(tokenlist,"TK_BEGIN1");
UPDATE
I found two bugs, the first was the head of the list was not being returned when appending the list. The other in the memory allocation for the token string which incorrectly used sizeof.
I repositioned the test of the malloc() return value, and added a second one. I removed several unnecessary temporary variables that were cluttering the code. I added two functions, show_list() and free_list(). Finally, remember that the value string field is still uninitialised.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct token_Info
{
int linenumber;
char* token;
char value[200];
struct token_Info* next;
} token_Info;
token_Info* insert_at_end( token_Info *list, char *name)
{
token_Info *new_node, *temp;
new_node= malloc(sizeof(token_Info));
if(new_node == NULL){ // repositioned
printf("\nFailed to allocate node memory\n");
exit(1); // added
}
new_node->token = malloc(strlen(name)+1); // removed sizeof
if(new_node->token == NULL){ // added
printf("\nFailed to allocate token memory\n");
exit(1);
}
strcpy(new_node->token, name);
new_node->next= NULL;
if(list==NULL)
return new_node;
// append
temp = list;
while(temp->next != NULL)
temp = temp->next;
temp->next = new_node;
return list; // original head
}
void free_list( token_Info *list)
{
token_Info *temp;
while (list) {
temp = list->next;
free(list->token);
free(list);
list = temp;
}
}
void show_list( token_Info *list)
{
printf ("\nCurrent list:\n");
while (list) {
printf ("%s\n", list->token);
list = list->next;
}
}
int main(int argc, char **argv)
{
token_Info *tokenlist = NULL;
tokenlist = insert_at_end(tokenlist, "TK_BEGIN");
show_list(tokenlist);
tokenlist = insert_at_end(tokenlist, "TK_SECOND");
show_list(tokenlist);
tokenlist = insert_at_end(tokenlist, "TK_FINAL");
show_list(tokenlist);
free_list(tokenlist);
return 0;
}
Program output:
Current list:
TK_BEGIN
Current list:
TK_BEGIN
TK_SECOND
Current list:
TK_BEGIN
TK_SECOND
TK_FINAL
The question could also be whether you want tokenlist to be a running end of the list, or remain at the start.
As of right now, your first call:
tokenlist = insert_at_end(tokenlist,"TK_BEGIN");
has tokenlist being the only node in the list.
The second call tokenlist = insert_at_end(tokenlist,"TK_BEGIN1"); returns 'temp' which happens to also be the 'TK_BEGIN' node, ( ie, the first node )
If you want the return value to be the last element, you would return new_node instead of temp. If you want to retain the start, you would return start;
All that said:
The calls to it are not part of any function,
I just ran it with the calls in main and got this output:
int main(void){
tokenlist = insert_at_end(tokenlist,"TK_BEGIN");
tokenlist = insert_at_end(tokenlist,"TK_BEGIN1");
return 0;
}
$> ./a.out
token identified token identified anvesh

Malloc with scope and global variables

#include<stdio.h>
#include<stdlib.h>
struct node {
int num;
struct node *next;
}*head=NULL, *curr=NULL;
void print(){
curr = head;
while(curr != NULL){
printf("%d\n", curr->num);
curr = curr->next;
}
}
struct node* memAlo(){
return (struct node *)malloc(sizeof(struct node));
}
void addNode(int no){
curr = head;
while(curr != NULL){
curr = curr->next;
}
curr = memAlo();
if(curr == NULL){
printf("\nmemory up\n");
return;
}
else{
curr->num = no;
curr->next = NULL;
printf("%d\n",curr->num);
}
}
void hellop(){
printf("%d", head->num);
}
int main(){
int i;
curr = head;
for(i=1;i<10;i++){
addNode(i);
}
print();
/*head = memAlo();
head->num = 1;
head->next = NULL;
hellop();*/
}
I am sure I have messed up somewhere. The thing is that the head pointer doesn't get the memory allocated by the memAlo() fn() but how to get there? Please help
What I am trying is to create a singly linked list holding numbers from 1 to 9 and to print them using print(). Actually AddNode() is to create single node at the end of the linked list each time the for loop in main() executes.
You set head = NULL at the point where you first defined head. Except in that one place, we never see head on the left-hand side of = anywhere in your program. So of course head is always equal to NULL and never anything else.
You will probably want to insert some code at the start of your addNode function to test whether head == NULL at that point; and if that is true, you will want to assign the result of memAlo() to head instead of curr. You will have to adjust some of the other logic as well.
Your code for allocating a node is wrong. It should create a node, make some space for it, then return it.
struct node *memAlo() {
struct node *nd = malloc(sizeof(*nd));
return nd;
}
This creates a pointer to a node, properly allocates it, then returns it.
Problems I see:
Not dealing with empty list, i.e. when head == NULL.
Creating nodes that are not linked to each other.
curr = memAlo();
allocated memory for a node and returns it to you, but it does not connect the node with anything else.
Try this:
void addNode(int no){
struct node* temp = NULL;
// Deal with an empty list.
if ( head == NULL )
{
head = memAlo();
head->num = no;
head->next = NULL;
}
// Move curr until we reach the last node of the list.
curr = head;
while(curr->next != NULL){
curr = curr->next;
}
temp = memAlo();
if(temp == NULL){
printf("\nmemory up\n");
return;
}
else{
// Link the new node to the previous last node.
temp->num = no;
temp->next = NULL;
printf("%d\n",temp->num);
curr->next = temp;
}
}
It seems that since head is initially NULL, and then you start allocating nodes without saving the address of the first one, you lose the address of the first one, and then can't walk the list from the beginning.
The part you commented out illustrate the problem.
As a side note, there is no free in your program. Remember to always free the memory you alloc
#include<stdio.h>
#include<stdlib.h>
struct node
{
int num;
struct node *next;
};
struct node *head, *curr;
struct node *pos;
void addNode(int n)
{
if(head==NULL)
{
head = (struct node*)malloc(sizeof(struct node));
head->num = n;
head->next = NULL;
curr = head;
}
else
{
while(curr != NULL)
{
pos = curr;
curr = curr->next;
}
curr = (struct node*)malloc(sizeof(struct node));
curr->num = n;
curr->next = NULL;
pos->next = curr;
}
}
void printList()
{
curr = head;
while(curr != NULL)
{
printf("%d",curr->num);
curr = curr->next;
}
}
int main()
{
head = NULL;
curr = head;
int i, a[] = {4,5,1,2,3,9,0};
for(i=0;i<7;i++)
{
addNode(a[i]);
}
curr = head;
printList();
}
This seems to have solved my problem. I figured it out though. Thanks for all your help.

Resources