Getting a segfault with linked list - c

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).

Related

Linked list in C causing a memory leak upon creation and insertion

I have a linked list. It works fine but I was checking for memory leaks and realised that creating the list and creating a node for the list is causing memory leaks even though I go and free them later. It's saying there is memory lost due the malloc I create in both create list and insert. I can't go and free the mallocs because I need them, is this just a necessary evil or is there a way to fix it?
Is there anyway to stop these memory leaks?
#include <stdio.h>
#include <stdlib.h>
#include "linkedList.h"
#include "macros.h"
LinkedList* createLinkedList()
{
LinkedList* list;
list = malloc(sizeof(*list) * 1);
list->head = NULL;
list->tail = NULL;
list->length = 0;
return list;
}
void insertLast(LinkedList* list, int entry)
{
Node* newNode = malloc(sizeof(*newNode) * 1);
newNode->data = entry;
newNode->next = NULL;
if (list->tail == NULL)
{
list->head = newNode;
}
else
{
list->tail->next = newNode;
}
list -> tail = newNode;
list->tail-> next = NULL;
list->length++;
}
How I'm freeing the nodes:
void freeLinkedList(LinkedList* list)
{
int i = 0;
Node* current, *temp;
current = list->head;
while(i < list->length -1)
{
temp = current->next;
free(current);
current = temp;
i++;
}
}
In freeLinkedList your loop is not making sufficient iterations. For instance, when list->length is 1, there should be one call to free, but this does not happen as the loop makes no iterations in that case.
Don't make it more difficult than necessary: skip the use of i and just use the more natural condition. Also free list itself:
void freeLinkedList(LinkedList* list)
{
Node* temp;
Node* current = list->head;
while(current != NULL)
{
temp = current->next;
free(current);
current = temp;
}
free(list);
}
If the list contains length nodes then the loop in freeLinkedList should look at least like
while(i < list->length)
Also you need to free the pointer to the allocated LinkedList itself after calling the function.
Pay attention to that this statement in the function insertLast
list->tail-> next = NULL;
is redundant and may be removed.
You need to free list as well:
void freeLinkedList(LinkedList* list)
{
int i = 0;
Node* current, *temp;
current = list->head;
while(i < list->length -1)
{
temp = current->next;
free(current);
current = temp;
i++;
}
free(list);
}

How to free a linked list with pointers

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;
}

Checking if a Linked list is Empty in C

I have a simple linked list (Which I'm given for a assignment), and I'm trying to check if it's empty (It has no header node), but my implementation doesn't seem to work.
I have the .c file:
#include <stdio.h>
#include <stdlib.h>
#include "test.h"
int main(void) {
List * node;
node = NULL;
node = malloc(sizeof(List));
addToList(node);
return 0;
}
void addToList(List * node) {
if(node == NULL) {
node->value = 3;
node->next = NULL;
}
else {
//add to end of the list:
List * temp = malloc(sizeof(List));
temp->value = 4;
while(node->next != NULL)
node = node->next;
node->next = temp;
temp->next = NULL;
}
}
And the Linked list in the struct (In the .h file)
typedef struct List {
int value;
List * next;
}List;
However, the if statement never executes, even though the list is empty. The struct I'm given doesn't have a header node(I can't change it), so how would I go about fixing this?
Any help would be much appreciated.
The problem is in addToList
node == NULL
should be
node->next == NULL
then you'll also need to insure that function isn't given a null pointer.
Currently you are providing a valid pointer the function and so it is never == NULL
See:
node = malloc(sizeof(List));
addToList(node);
here node is assigned a pointer to a List and provided to addToList.
I suspect what you are really looking for doesn't include that if/else at all and should look something like this (NOTE: You must initialize your list node by hand before calling this function. malloc just gives you a pointer to garbage).
//add to end of the list:
void addToList(List *node) {
if (node == NULL)
return;
List * temp = malloc(sizeof(List));
temp->value = 4;
while(node->next != NULL)
node = node->next;
node->next = temp;
temp->next = NULL;
}
As it was already said the problem is that at first you allocated a node
node = malloc(sizeof(List));
and it got the address of the allocated memory and only after that you called the function
addToList(node);
with this node as an argument.
As result this condition within the function
if(node == NULL) {
equal to false. node is not equal to NULL. It is equal to the address of the allocated memory.
It is much better when the function allocates itself each new node. However in this case you have to declare the function differently.
It and its call can look the following way
#include <stdio.h>
#include <stdlib.h>
#include "test.h"
void addToList( List ** node, int value );
// ^^^^^^^ ^^^^^^^^^
int main(void)
{
List * node NULL;
addToList( &node, 4 );
return 0;
}
void addToList( List ** node, int value )
{
while ( *node ) node = &( *node )->next;
List * temp = malloc( sizeof( List ) );
if ( temp != NULL )
{
temp->value = value;
temp->next = NULL;
*node = temp;
}
}
The condition node == NULL is always false because, before accessing the addToList function, you write node = malloc(sizeof(List)).
Try remove this declaration and change the if statement in
if(node == NULL) {
node = malloc(sizeof(List));
node->value = 3;
node->next = NULL;
}

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.

Pointer to struct incrementation

was implementing a singular linked list in C.
struct node
{
int data;
struct node *next;
};
struct list_el {
int val;
struct list_el * next;
};
typedef struct list_el item;
void main() {
item * curr, * head,*track;
int i;
head = NULL;
for(i=1;i<=10;i++) {
curr = (item *)malloc(sizeof(item));
curr->val = i;
curr->next=0;
if(head!=NULL)
head->next = curr;
head = curr;
}
curr = curr-10;
while(curr) {
printf("%d\n", curr->val);
curr = curr->next ;
}
}
As there are 10 elements in the list, so to make the pointer point to the first element, I tried decreasing curr (pointer to struct) by 10, but this got me half way through the list, the values printed were 5,6,7,8,9,10.
The size of the struct is 4, whereas the size of the pointer is 2, it seems the pointer is decreased by 2*10=20 bytes instead of 40, is this normal? (as I read that pointer increments/decrements according to the size of its type)
You cannot use pointer arithmetic on a linked list: the items are allocated separately (with malloc) and so they will not be necessarily adjacent in memory. That approach would only work with an array.
There are several problems.
First of all, the following insertion code isn't correct:
if(head!=NULL) head->next = curr;
head = curr;
Basically, the element pointed to by head is irrevocably lost.
Secondly, the behaviour of the following code is undefined:
curr = curr-10;
You cannot move across several malloc()ed blocks using pointer arithmetic.
Once you fix the insertion logic, it will become possible to traverse the list like so:
for (curr = head; curr != NULL; curr = curr->next) {
....
}
Your code curr = curr-10 will not bring you back to the head of the linklist.
As Viruzzo pointed out in a comment, you cannot use pointer arithmetic on elements of a linked list. As the word "linked" implies, there are only pointers linking the items together, they're not required to be located at adjacent addresses.
The pointer arithmetic will simply decrease the pointer by a fixed number of bytes, it will not follow pointers. Your list, being singly-linked, doesn't even have previous-element pointers to follow.
curr = curr-10; is wrong. It does not perform the operation that you think it does!
To print the contents of your linked list, you need to start from the head and go through each and every node until you hit NULL (assuming its not a circular list).
void display()
{
NODE * current = head;
if (current == NULL) {
printf("Empty list \n");
return;
}
while(current != NULL) {
printf("%d ", current->data);
current = current->next;
}
printf("\n");
return;
}
And to add new node in the front, you can use the following code snippet.
void addfront(int data)
{
NODE *newnode = NULL;
if ((newnode = malloc(sizeof(NODE))) != NULL) {
newnode->data = data;
newnode->next = NULL;
} else {
printf("Couldn't allocate space for new element \n");
return;
}
if (head == NULL) {
// empty list
head = newnode;
tail = newnode;
} else {
newnode->next = head;
head = newnode;
}
return;
}
To add new node at the rear, you can use the following code snippet.
void addrear(int data)
{
NODE * newnode = NULL;
if ((newnode = (NODE *) malloc(sizeof(NODE))) != NULL) {
newnode->data = data;
newnode->next = NULL;
} else {
printf("unalbe to allocate memory to the new element - %d \n", data);
return;
}
if (tail == NULL) {
assert(head == NULL && tail == NULL);
head = tail = newnode;
} else {
tail->next = newnode;
tail = newnode;
}
return;
}
All the above mentioned code snippet assumes, you have head and tail as global variables.
Hope this helps!

Resources