C - Segfaulting when trying to access atribute of initialized struct - c

I'm making my own version of malloc using a free list. For some reason my program is seg faulting when I try to access and change newnode->size. I'm not sure why this is happening as it is not a problem when I attempt to change returnnode. All I need to do is change newnode->size and
newnode->next.
For context this is my struct:
typedef struct freenode
{
size_t size;
struct freenode *next;
} freenode;
This is the area within my code that is causing the issue:
curr = freelist;
freenode *prev = NULL;
freenode *returnnode = NULL;
freenode *newnode = NULL;
while (curr != NULL)
{
// Ignore this part
if (curr->size - size <= 32 && curr->size - size >= 0)
{
returnnode = curr;
if (prev)
{
prev->next = curr->next;
}
else
{
freelist = curr->next;
}
}
// Error is being caused in this area
if (curr->size - size > 32)
{
returnnode = curr;
returnnode->size = size;
newnode = curr + size;
// Specific point of error
newnode->size = curr->size - size;
char str[18] = "\nmade it here\n";
write(STDOUT_FILENO, str, 18);
newnode->next = curr->next;
if (prev)
{
prev->next = newnode;
}
else
{
freelist = newnode;
}
}
prev = curr;
curr = curr->next;
}
I've tried making a temp freenode and realized it wouldn't work as I need the pointer to the new node to be at a specific point in the heap. Doing that would place it on the stack.
I've tried a bunch of other trivial things and nothing has worked.

Related

Removing an element in a linked list whose value is less than the next adjacent element

Is there any error in this code? I am getting segmentation fault in this.
Question is about deleting elements whose value are less than the next element.
void Remove()
{
struct Node* prev = NULL;
struct Node* curr = head;
struct Node* Next = NULL;
while(curr!=NULL)
{
Next = curr->next;
if(curr->data < Next->data)
{
if(curr == head)
{
struct Node* temp2 = head;
head = head->next;
free(temp2);
curr = head;
//Next = curr->next;
}
else
{
struct Node* temp1 = curr;
prev->next = curr->next;
free(temp1);
curr = Next;
//Next = curr->next;
}
}
else
{
prev = curr;
curr = Next;
//Next = curr->next;
}
}
}
Here is one problem:
while(curr!=NULL)
{
Next = curr->next;
if(curr->data < Next->data)
When you reach the end of the list curr->next is NULL. So Next is NULL. Still you dereference it (i.e. Next->data), so your program will (likely) crash with a seg fault.
You must check for Next being NULL before you access Next->data

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

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.

linked list and an Invalid read of size 4

I've been implementing a linked list to scrape the rust out of my development skills, but noticed valgrind reports an Invalid read of size 4 during my test of removing middle elements.
==1197== Invalid read of size 4
==1197== at 0x804885C: main (list.c:135)
==1197== Address 0x426e76c is 4 bytes inside a block of size 12 free'd
==1197== at 0x40257ED: free (vg_replace_malloc.c:366)
==1197== by 0x804875E: list_remove (list.c:112)
==1197== by 0x8048857: main (list.c:137)
The code in the main that triggers this is:
for (iter = l2->head; iter; iter = iter->next) {
if (iter->n >= 10 && iter->n <= 14)
list_remove(l2, iter);
The remove function is:
void list_remove(struct list *list, struct node *node)
{
if (node == list->head && node == list->tail) {
list->head = list->tail = NULL;
}
else if (node == list->head) {
list->head = node->next;
list->head->prev = NULL;
}
else if (node == list->tail) {
list->tail = node->prev;
list->tail = NULL;
}
else {
struct node *prev, *next;
prev = node->prev;
next = node->next;
prev->next = next;
next->prev = prev;
}
free(node);
}
Any idea of what I could be doing wrong?
You are freeing the value in the loop, then dereferencing it to get at its "next" pointer. You need a temp value to do this right:
for (iter = l2->head; iter; iter = next) {
next = iter->next;
if (iter->n >= 10 && iter->n <= 14)
list_remove(l2, iter);
}
You are releasing the iter pointer when you free(node). Then you try to read from iter->next which doesn't exist any more.
Hhm... All you have to do, is read the valgrind message.
invalid read here: main (list.c:135) - that's iter->next,
from a freed location, memory freed here: list_remove (list.c:112), that's free(node);.
Just cache the next pointer before removing.

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