Single linked list in C - 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

Related

Deleting a linked list node in a C function doesn't transfer to the calling function

I have this C function which is supposed to find an element in the linked list which has a specific "pos" value, delete it, and return the deleted value to the calling function. It does delete the item, but the change isn't saved in the calling function, the list just doesn't get updated with the new changes.
My list is structured like this:
struct list{
int value;
int pos;
struct list * next_ptr;
};
And my C function is this:
bool findDeleteElement(struct list **ptr, int position, int *value){
struct list** temp = ptr;
if(*ptr!=NULL){
while((*ptr)->pos!=position) ptr=&(*ptr)->next_ptr; //Gets to desired node
temp=ptr;
value=&(*ptr)->value; //saves the value
temp=&(*temp)->next_ptr; //Goes to next node
ptr=temp; //Makes ptr point to next node
return 1;
}
else return 0;
}
I just can't see what I'm missing.
I'm a beginner so I probably made a simple mistake.
Change to:
*value = (*ptr)->value; //saves the value
You only set value, the local copy of your external variable's address. This does not change your external variable in the calling function.
Some question:
What happens when position has the wrong value, such that no node is found?
What's the purpose of temp = ptr;, because temp is overwritten by temp = &(*temp)->next_ptr; without having been used.
Disclaimer: I've not further checked this function.
I kindly advise you to take on other code formatting rules that add more air and make things more readable. Here's an example:
bool findDeleteElement(struct list **ptr, int position, int *value)
{
struct list** temp = ptr;
if (*ptr != NULL)
{
// Gets to desired node
while((*ptr)->pos != position)
{
ptr = &(*ptr)->next_ptr;
}
temp = ptr;
*value = (*ptr)->value; // Saves the value
temp = &(*temp)->next_ptr; // Goes to next node
ptr = temp; // Makes ptr point to next node
return 1;
}
else
{
return 0;
}
}
You are confused about pointers and dereferencing and what & and * actually do. This is a normal state of affairs for a beginner.
To start with, ptr and value when used without * preceding them are function arguments and like automatic (local) variables they disappear when the function scope exits. So this statement:
value=&(*ptr)->value;
Merely changes the value of value i.e. what it points to and has no visible effect to the caller. What you need to change is the thing that value points to. i.e. the statement should look like this:
*value = (*ptr)->value;
The difference is that instead of setting value to the address of (*ptr)->value it sets what valuepoints to to (*ptr)->value.
You have a similar problem with ptr. But your problems are more subtle there because you are also trying to use it as a loop variable. It's better to separate the two uses. I'd write the function something like this:
bool findDeleteElement(struct list **head, int position, int *value)
{
struct list* temp = *head;
struct list* prev = NULL;
while(temp != NULL && temp->pos != position)
{
prev = temp;
temp = temp->next;
}
if (temp == NULL) // position not found
{
return false;
}
else
{
*value = temp->value;
// Now need to delete the node.
if (prev != NULL)
{
// If prev has been set, we are not at the head
prev->next = temp->next; // Unlink the node from the list
}
else // We found the node at the head of the list
{
*head = temp->next;
}
free(temp); // Assumes the node was malloced.
return true;
}
}
The above is not tested or even compiled. I leave that as an exercise for you.
int delete(struct llist **pp, int pos, int *result)
{
struct llist *tmp;
while ( (tmp = *pp)) {
if (tmp->pos != pos) { pp = &tmp->next; continue; }
*result = val;
*pp = tmp->next;
free(tmp);
return 1;
}
return 0;
}

Issues with linked list and pointers (C)

I am writing a C program to sort a linked list according to the largest values. I met an issue whereby the program just hangs when the program reached "prevPtr->next = headPtr".
I want the prevPtr->next to equate to headPtr, if the sum of prevPtr is larger than the sum of headPtr, however the program just hangs there.
compareNodes() function is used to compare the nodes to see if newNode has the same name as any other structs in the linked list, then it will add in the sum.
sortSimilarNodes() function is used to sort the nodes according to the sum of each struct.
The struct is here below:
struct purchase {
char name[30];
double sum;
struct purchase * next;
} ;
LOG * compareNodes(LOG * headPtr, char * name, char * price){
.
.
.
while (curPtr != NULL) {
if (strcmp(newNode->name, curPtr->name)==0) {
curPtr->sum += newNode->sum;
free(newNode);
similar = 1;
break;
}
//advance to next target
prevPtr = curPtr;
curPtr = curPtr->next;
}
/*if (curPtr == NULL){
if(strcmp(newNode->name, prevPtr->name)==0){
prevPtr->sum += newNode->sum;
free(newNode);
similar = 1;
}
}*/
if (similar == 1){
headPtr = sortSimilarNodes(curPtr, headPtr);
}
else{
headPtr = sortNodes(newNode, headPtr);
}
return headPtr;
}
LOG * sortSimilarNodes(LOG * newPtr, LOG * headPtr){
LOG * curPtr;
LOG * prevPtr;
if(headPtr->sum < newPtr->sum){
newPtr->next = headPtr;
return newPtr;
}
prevPtr = headPtr;
curPtr = headPtr->next;
while (curPtr == NULL){
}
while (curPtr != NULL){
if(strcmp(curPtr->name, newPtr->name)==0){
break;
}
prevPtr = curPtr;
curPtr = curPtr->next;
}
return headPtr;
}
This is the output of the program.
Thank you!
It's hard to tell from your code, because you haven't posted all of it, but you seem to have some misconceptions about linked lists. In particular:
There is no need for new nodes unless you really add new nodes to the list. That also means that you don't call malloc except when adding nodes. (There's no malloc in your code, but a suspicious free in your comparison function. Comparing does not involve creating or destroying anything; it just means to look what is already there.)
A corollary to the first point is that there should be no nodes in an empty list, not even dummy nodes. An empty list is a list whose head is NULL. Make sure that you initialise all head pointers before creating a new list:
LOG *head = NULL; // empty list
When you sort the list, the order of the list has changed and the old head is invalid. You cater for that by returning the new head:
head = sort(head);
But that seems redundant and it also seems to imply that the two pointers can be different. That's not the case, because the old pointer will point somehwre in the sorted list, not necessarily at its head. It's probably better to pass the head pointer's address in order to avoid confusion:
sort(&head);
Sorting linked lists can be tricky. One straightforward way is selection sort: Find the node with the highest value, remove it from the original list and add it at the front of a new list. Repeat until there are no more nodes in the original list.
Adding a new node n at the front of a list given by head is easy:
n->next = head;
head= n;
Adding a new node at the end of a list that is given by head is a bit more involved:
LOG **p = &head;
while (*p) p = &(*p)->next;
*p = n;
n->next = NULL;
Here, p is the address of the pointer that points to the current node, *p. After walking the list, that address is either the address of the head node (when the list is empty) or the address of the next pointer of the precedig node.
You could achieve something similar by keeping a prev pointer, but the pointer-to-pointer solution means that you don't have to treat the cases where there is no previous node specially at the cost of some extra & and * operators.
With that, your sorting routine becomes:
void sortByName(LOG **head)
{
LOG *sorted = NULL;
while (*head) {
LOG **p = head; // auxiliary pointer to walk the list
LOG **max = head; // pointer to current maximum
LOG *n; // maximum node
while (*p) {
if (strcmp((*p)->name, (*max)->name) > 0) max = p;
p = &(*p)->next;
}
n = *max;
*max = (*max)->next;
n->next = sorted;
sorted = n;
}
*head = sorted;
}
If you want to sort by sum, change the comparison to:
if ((*p)->sum > (*max)->sum) max = p;
Call the function like this:
LOG *head = NULL;
insert(&head, "apple", 2.3);
insert(&head, "pear", 1.7);
insert(&head, "strawberry", 2.2);
insert(&head, "orange", 3.2);
insert(&head, "plum", 2.1);
sortByName(&head);
print(head);
destroy(&head);
with the insert, destroy and print functions for completeness:
void insert(LOG **head, const char *name, double sum)
{
LOG *n = malloc(sizeof(*n));
if (n) {
snprintf(n->name, sizeof(n->name), "%s", name);
n->sum = sum;
n->next = *head;
*head = n;
}
}
void destroy(LOG **head)
{
LOG *n = *head;
while (n) {
LOG *p = n;
n = n->next;
free(p);
}
*head = NULL;
}
void print(LOG *l)
{
while (l) {
printf("%s: %g\n", l->name, l->sum);
l = l->next;
}
puts("");
}

Pointers to pointers - linked list mess

I'm writing a simple C program to manage a linked list defined as follow:
typedef struct node {
int value;
struct node *next;
} *List;
I reviewed the code and it seems okay but when printing results something is not working well.
My main, with problems on comments:
int main(void) {
List n = list_create(1);
insert(n, 2);
insert(n, 3);
insert(n, 5);
insert(n, 4);
//something here does not work properly. It produces the following output:
//Value: 1
//Value: 2
//Value: 3
//Value: 4
//where is value 5?
print_list(n);
delete(n, 3);
print_list(n);
return 0;
}
I don't know where am I destroying list structure. These are my functions, to debug, if you are too kind.
List list_create(int value) {
List new = malloc(sizeof(struct node));
new->value = value;
new->next = NULL;
return new;
}
List new_node(int value, List next_node) {
List new = malloc(sizeof(struct node));
new->value = value;
new->next = next_node;
return new;
}
void print_list(List l) {
List *aux;
for (aux = &l; (*aux) != NULL; aux = &((*aux)->next))
printf("Valor: %d\n", (*aux)->value);
}
void insert(List l, int value) {
List *p;
for (p = &l; (*p) != NULL; p = &((*p)->next))
if ((*p)->value > value) {
List tmp = *p;
List new = new_node(value, tmp);
*p = new;
break;
}
*p = new_node(value, NULL);
}
void delete(List l, int value) {
List *p;
for (p = &l; (*p) != NULL; p = &((*p)->next))
if ((*p)->value == value) {
List del = (*p);
(*p) = ((*p)->next);
free(del);
break;
}
}
This code has (at least) two bugs:
The line
if ((*p)->value > value){
means that if you start the list with 1 as the first value and then try to insert 2,3,4..., the body of the 'if' statement never runs, so nothing ever gets inserted.
If you insert a value below the starting value, you have to modify the list pointer itself. However, as #EOF alluded, you are trying to modify a value passed to a function by taking its address. This won't work. &l does not give you the address of the List you passed, it gives you the address of the local copy on insert()'s stack. You are better off modifying the values of first element of the list 'in place'. If you really want to make the List parameter mutable, you'll need to pass it as a List *, and call the function with the address of the list (e.g. insert(&n,2); ) Your delete() function suffers from the same problem - try deleting the first element of the list.
Try this for your insert function:
void insert(List l, int value)
{
List p;
// Find end of list or highest item less than value
for(p = l; p->next != NULL && p->next->value < value; p = p->next);
if (p->value >= value) {
// Over-write p with new value, and insert p as a new one after.
// This saves having to modify l itself.
int tmpval = p->value;
p->value = value;
p->next = new_node(tmpval, p->next);
} else {
// Insert new item after p
p->next = new_node(value, p->next);
}
}
A comment: it is possible the way you are using pointers is not helping the debugging process.
For example, your print_list() could be re-written like this:
void print_list(List l){
List aux;
for(aux = l; aux != NULL; aux = aux->next)
printf("Valor: %d\n", aux->value);
}
and still behave the same. It is generally good practice not to 'hide' the pointer-like nature of a pointer by including a '*' in the typedef.
For example, if you define your list like this:
typedef struct node{
int value;
struct node *next;
} List
And pass it to functions like this:
my_func(List *l, ...)
then it'll make some of these issues more apparent. Hope this helps.
There are many problems in your code:
Hiding pointers behind typedefs is a bad idea, it leads to confusion for both the programmer and the reader.
You must decide whether the initial node is a dummy node or if the empty list is simply a NULL pointer. The latter is much simpler to handle but you must pass the address of the head node to insert and delete so they can change the head node.
printlist does not need an indirect pointer, especially starting from the address of the pointer passed as an argument. Simplify by using the Node pointer directly.
in insert you correctly insert the new node before the next higher node but you should then return from the function. Instead, you break out of the switch and the code for appending is executed, replacing the inserted node with a new node with the same value and a NULL next pointer. This is the reason 5 gets removed and lost when you insert 4. Furthermore, you should pass the address of the head node so a node can be inserted before the first.
delete starts from the address of the argument. It cannot delete the head node because the pointer in the caller space does not get updated. You should pass the address of the head node.
You should avoid using C++ keywords such as new and delete in C code: while not illegal, it confuses readers used to C++, confuses the syntax highlighter and prevents compilation by C++ compilers.
Here is a simplified and corrected version:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int value;
struct Node *next;
} Node;
Node *new_node(int value, Node *next_node) {
Node *node = malloc(sizeof(*node));
if (node != NULL) {
node->value = value;
node->next = next_node;
}
return node;
}
void print_list(Node *list) {
for (; list != NULL; list = list->next)
printf("Valor: %d\n", list->value);
}
void insert_node(Node **p, int value) {
while ((*p) != NULL && (*p)->value < value)
p = &(*p)->next;
*p = new_node(value, *p);
}
void delete_node(Node **p, int value) {
while (*p != NULL) {
if ((*p)->value == value) {
Node *found = *p;
*p = (*p)->next;
free(found);
// return unless delete() is supposed to remove all occurrences
return;
} else {
p = &(*p)->next;
}
}
}
int main(void) {
Node *n = NULL;
insert_node(&n, 2);
insert_node(&n, 3);
insert_node(&n, 5);
insert_node(&n, 4);
insert_node(&n, 1);
print_list(n);
delete_node(&n, 3);
print_list(n);
delete_node(&n, 1);
print_list(n);
return 0;
}

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.

Unable to insert second element to a linked list | Pointer to function gets corrupted

Bellow is the relevant code:
typedef struct Node_t {
ListElement data;
struct Node_t* next;
} Node;
struct List_t {
Node* head;
Node* tail;
Node* current;
int size;
CopyListElement copyF;
FreeListElement freeF;
};
static ListResult initializeNode(List list, ListElement element, Node* newNode){
printf("\nEntered initializeNode\n");
if ((list == NULL) || (element == NULL)) return LIST_NULL_ARGUMENT;
newNode = malloc(sizeof(Node));
if (newNode == NULL) return LIST_OUT_OF_MEMORY;
printf("\nWithin initializeNode, before copyF\n");
ListElement newElement = list->copyF(element);
printf("\nWithin initializeNode, after copyF\n");
if (newElement == NULL) return LIST_OUT_OF_MEMORY;
newNode->data = newElement;
printf("\nLast line within initializeNode\n");
return LIST_SUCCESS;
}
List listCreate(CopyListElement copyElement, FreeListElement freeElement){
//Check if there is a NULL argument.
if ((copyElement == NULL) || (freeElement == NULL)) return NULL;
//Check wether there is enough memory.
List newList = malloc(sizeof(List));
if (newList == NULL) return NULL;
//Initialize an empty List.
newList->head = NULL;
newList->tail = NULL;
newList->size = 0;
newList->current = NULL;
newList->copyF = copyElement;
newList->freeF = freeElement;
return newList;
}
ListResult listInsertFirst(List list, ListElement element){
printf("\nEntered listInsertFirst\n");
Node* newNode;
ListResult result = initializeNode(list, element, newNode);
printf("\n Node was initialized\n");
if (result != LIST_SUCCESS) {
return result;
}
printf("\nEntering logistic works within listInsertFirst\n");
//Finish logistic work within the Node.
newNode->next = list->head;
list->head = newNode;
list->size++;
printf("\nElement was inserted successfully\n");
printf("\nCheck list->CopyF within listInsertFirst\n");
list->copyF(element);
printf("\nCheck list->CopyF within listInsertFirst: PASSED\n");
return LIST_SUCCESS;
}
Within main function I'm trying:
List list = listCreate(&copyInt, &freeInt);
ListResult result;
int el=2;
//ListElement e1;
//ListElement e2;
result = listInsertFirst(list,&el);
printf("\nresult = %d\n", result);
result = listInsertFirst(list,&el);
printf("\nresult = %d\n", result);
After compiling and running I get:
Entered listInsertFirst
Entered initializeNode
Within initializeNode, before copyF
Within initializeNode, after copyF
Last line within initializeNode
Node was initialized
Entering logistic works within listInsertFirst
Element was inserted successfully
Check list->CopyF within listInsertFirst Segmentation fault: 11
For some reason the pointer [to function] list->copyF gets corrupted [I think].
I'm assuming this is C code, not C++, based on the tags. Given that you have a mix of data definitions and actual code statements, which I wouldn't expect to work in C, I'm not 100% sure it is real C, in which case I may be wrong about the error below.
First of all, the interface to initializeNode() doesn't do what you probably intend. You probably want:
static ListResult initializeNode(List list, ListElement element, Node** newNodep)
{
Node *newNode = malloc(sizeof(Node));
if (newNode == NULL) return LIST_OUT_OF_MEMORY;
ListElement newElement = list->copyF(element);
if (newElement == NULL) return LIST_OUT_OF_MEMORY;
newNode->data = newElement;
*newNodep = newNode;
return LIST_SUCCESS;
}
That way the Node you create gets passed back.
I don't know what CopyInt() does, but if it's really the function hitting the Bus Error the bug with initializeNode() can't be your problem. However, it's possible that you aren't seeing the output of all your printfs before the crash gets reported.
If CopyInt() does what I'd expect, it does something like:
ListElement CopyInt(int *val)
{
ListElement *e = malloc(sizeof(ListElement));
if (e)
e->val = *val;
return e;
}
The only way you are going to get a second-time bus error here is if you've messed up the data structures maintained by the library function malloc(). Unfortunately for that theory, I don't see anything worse than a memory leak here.
My guess that the bug that actually causes the crash is this line:
newNode->next = list->head;
Like #Arlie Stephens said - code for initializeNode doesn't do anything as the pointer is passed by value and the actual pointer still points to junk. So when you do newNode->next = list->head; you're basically writing to an unknown address and it's very likely to get a segmentation fault.
Why does it only happens on the second call? No idea, it's undefined behavior.
Crazy idea - it's possible that newNode->next is initialized to the address of copyF and trying to write into it cause you to corrupt copyF...Try printing the address of newNode->next and the address of copyF.

Resources