Linked List- NULL pointer check? - c

In this code snippet for adding to a Linked List, what is if (List==NULL) doing? I tried to throw some inputs at it to see if I could engage that statement with no luck. What type of input would work?
main()
{
struct Node *List;
List = NULL;
append (&List, 5);
}
void append(struct Node **List, int num)
{
if (List == NULL)
{
return;
}
if (*List == NULL)
{
*List = malloc(sizeof(struct Node));
(*List)->data = num;
(*List)->next = NULL;
}
//some additional cases edited out for brevity
}

If for whatever reason you (or the user of your library) call append(NULL,42); then, thanks to the if(List == NULL) check, your program won't crash. Otherwise (if you remove the if(List == NULL) check) it is undefined behavior and practically segmentation fault would happen. That check is an instance of defensive programming.
In principle it looks like append is intended to be called as append(&somevar, someint) but this is not documented, so adding the extract check (which is extremely cheap at runtime!) is worthwhile.

If you pass NULL as the List pointer the program will crash when you dereference it in:
if (*List == NULL)
So you must check that that function wasn't called with NULL as the parameter

Related

Does a node's behaviour change when it is a member of a struct?

I'm trying to learn how to use linked lists, so I've written myself a function to recursively go through a linked list and print a word stored in each node, but it's only printing the penultimate item and then repeating indefinitely. I've debugged this and I can see it's because the last node will satisfy n.next != NULL, so I wanted to change the condition to n != NULL to avoid this, but I get the error message: error: invalid operands to binary expression ('node' (aka 'struct node') and 'void *'). I've tried to search the error message on Google and SO but I can't explain why n.next != NULL compiles nicely but n != NULL doesn't. To me, I'd say n and n.next are both type node, but presumably my intuition is deceiving me somehow. Is it because n.next is a struct member that it's behavior changes, or am I on the wrong track?
I include the code below (function in question is at the bottom):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node
{
char word[20];
struct node *next;
}
node;
void print (node n);
node *table[1];
int main(void)
{
// TODO
char word[20];
FILE *file = fopen("list", "r");
node *first = malloc(sizeof(node));
table[0] = first;
if (file != NULL)
{
while (fscanf(file, "%s", word) != EOF)
{
node *entry = malloc(sizeof(node));
if (entry != NULL)
{
strcpy (entry->word, word);
entry->next = first->next;
first->next = entry;
}
}
}
print(*first);
}
void print (node n)
{
while(n != NULL)
{
printf("%s\n", n.word);
print(*n.next);
}
}
To me, I'd say n and n.next are both type node
Not so; n is a node, but n.next is type node *, i.e. a pointer to a node. Pointers can be null but structs cannot.
Thus the object passed to print is guaranteed valid. (If first were a null pointer then print(*first) would already have crashed, or "caused undefined behavior", before you even entered print.)
It's also not necessary to have a loop in print, since the recursion handles the list traversal. Indeed, if you try to keep the loop as it is, it's an infinite loop, because nothing in the body modifies the value of n.
I would write:
void print (node n)
{
printf("%s\n", n.word);
if (n.next != NULL)
print(*n.next);
}
However this approach is not really idiomatic, and it's also not very efficient, since passing structs by value tends to involve unnecessary copying and stack usage. It'd be more common, as dbush suggests, to have a version that takes pointers:
void print(const node *np)
{
if (np)
{
printf("%s\n", np->word);
print(np->next);
}
}
which you then call as print(first);.
A next good exercise would be to try to write a version of print that doesn't use recursion, since that will allow you to handle very long lists that might exceed your stack size.
there are mainly to problems:
don't forget to initialize the value after malloc, or they can be anything, especially the next will not be NULL as you expected.
node *first = (node*)malloc(sizeof(node));
first->word[0] = '\0';
first->next = NULL;
node *entry = (node*) malloc(sizeof(node));
entry->word[0] = '\0';
entry->next = NULL;
I prefer to use calloc than malloc
node* first = (node*)calloc(1, sizeof(node));
assert(first);
node* entry = (node*)calloc(1, sizeof(node));
assert(entry);
in the function of print
void print (node* n)
{
if(n != NULL)
{
printf("%s\n", n->word);
print(n->next);
}
}
since you call print recursively, if should be used rather than while

Exception when deleting element from linked list

I try to delete a word (char* value) from a linked list but I am getting an exception when I compare my word to the links list node word.
EXC_BAD_ACCESS (code=1, address=0xa00000002)
I'm not sure why this is happening, I would appreciate to get any solution to the problem.
LinkedList* DeleteWordElement(LinkedList* head, char* value){
LinkedList *previous=head, *current=head->next;
if (head == NULL)
return head;
if (head->data == value)
{
LinkedList *temp = head;
head = head->next;
free(temp);
return head;
}
while (previous!=NULL)
{
if (previous->data == value) // Exception
break;
current = previous;
previous = previous->next;
}
if (previous != NULL)
current->next = previous->next;
free(previous);
return head;
}
Before doing:
LinkedList *previous=head, *current=head->next;
you need to check if the head is NULL. Then you should use strcmp, instead of ==, to compare the C-string value:
strcmp compares the actual C-string content, while using == between
two C-string is asking if these two char pointers point to the same
position. (source)
Finally, you do not need to keep the previous pointer, the current->next pointer is enough:
LinkedList* DeleteWordElement(LinkedList* head, char* value){
if (head == NULL)
return head;
if (strcmp(value, head->data) == 0){
LinkedList *next = head->next;
free(head);
return next;
}
LinkedList *current=head;
while (current->next != NULL){
if (strcmp(value, current->next->data) == 0){
LinkedList *next = current->next;
current->next = current->next->next;
free(next);
break;
}
current = current->next;
}
return head;
}
The code can be shorten if you use the recursive version, albeit at the cost of performance:
LinkedList* DeleteWordElement(LinkedList* current, char* value){
if(current != NULL){
if (strcmp(value, current->data) == 0){
LinkedList *result = current->next;
free(current);
return result;
}
current->next = DeleteWordElement(current->next, data);
}
return current;
}
As has already been pointed in the other answer and in the comments section, the expression
current=head->next
will cause undefined behavior when head == NULL.
Another problem is that the expression
head->data == value
does not compare the actual string contents, but instead it compares the pointers themselves (i.e. the memory addresses). This is not what you want, because the pointers will probably always be different, even when the string contents are identical. In order to compare the actual string contents, you must use the function strcmp instead.
The other answer already contains a solution to the problem. However, I would like to provide an alternate solution, which is shorter and more efficient for the computer, but is maybe harder to understand for a programmer, because it uses double pointers (i.e. pointers to pointers):
LinkedList* DeleteWordElement( LinkedList *head, char* value )
{
LinkedList **pp = &head, *p;
while ( (p=*pp) != NULL )
{
if ( strcmp( p->data, value ) == 0 )
{
//found node, so unlink and remove it
*pp = p->next;
free( p );
break;
}
pp = &p->next;
}
return head;
}
As you can see, this solution only requires a single if statement, in contrast to the code in your answer which requires 4 if statements and the other answer, which requires 3 if statements. These additional if statements are not necessary when using double pointers, because the same code can handle all cases. Therefore, you don't need to introduce additional code paths for every single case. As a consequence, this solution also has no need for code duplication.
It is also worth mentioning that the function signature
LinkedList* DeleteWordElement(LinkedList* head, char* value)
is a bit inefficient. The return value is the new head, so the code that calls the function must update the list head based on the return value. It would be simpler if the code that calls the function simply passes the address of the list head pointer, so the function can update the list head itself, when necessary. That way, the code which calls the function won't have to do any additional work.
In order to accomplish this, you can change the function signature to the following:
void DeleteWordElement( LinkedList** pp_head, char* value )
Because the address of a pointer is a pointer to a pointer (i.e. a double pointer), you must now use ** instead of only *.
Also, now that you are no longer using the return value of the function, you may want to use it for something else. For example, you may want the function to return whether the value was found or not. Therefore, you may want to change the signature to the following:
bool DeleteWordElement( LinkedList** pp_head, char* value )
Now you can make the function return true when the value was found, otherwise return false to indicate that the value was not found. Note that you must #include <stdbool.h> to have access to bool, true and false.
Although we have made the function more powerful by adding the boolean return value, it is just as simple as what we had before.
bool DeleteWordElement( LinkedList **pp_head, char* value )
{
LinkedList **pp = pp_head, *p;
while ( (p=*pp) != NULL )
{
if ( strcmp( p->data, value ) == 0 )
{
//found node, so unlink and remove it, and then return true
*pp = p->next;
free( p );
return true;
}
pp = &p->next;
}
//return false because we did not find any matching node in the list
return false;
}

Link list program crash on malloc

I'm fairly new to C and coding in general so please bear with me. I've been trying to implement a linked list recently and this is the code i came up with
typedef struct something{
int data;
struct something *next;
} thing ;
int main ()
{
thing *head, *current;
head=malloc(sizeof(thing));
puts("head=malloc(sizeof(thing));");
if (head != NULL)
puts("malloc success");
head=NULL;
current=head;
puts("current=head;");
if (current == NULL)
puts("current is NULL");
puts("while");
while (current!=NULL)
{
current = current->next;
}
puts("end while");
current->next=malloc(sizeof(thing));
puts("current->next=malloc(sizeof(thing));");
//free at end of program
}
While the compiler shows 0 errors, when i run the program it only runs until the final malloc part before crashing. It doesnt run the final puts so i will assume it's something to do with the way i'm trying to use malloc.
I'll gladly appreaciate for someone to tell me what im doing wrong.
The problem is that your while loop goes to far. You want to stop when current points to the last element of the list, so you can add to it. But you're going one step further, and stopping when current == NULL. It's then too late to assign to current->next.
First, you need to initialize head->next to NULL.
head = malloc(sizeof(thing));
head->next = NULL;
Get rid of the line:
head = NULL;
as this is overwriting the result of malloc().
Then your while loop needs to test current->next, not current itself:
while (current->next != NULL) {
current = current->next;
}
And when you add the new node, you have to set its next pointer to NULL as well:
current->next = malloc(sizeof(thing));
current->next->next = NULL;
These should fix your problem.
You allocate head and then immediately after few checks point its pointer to NULL
// Allocation here
head=malloc(sizeof(thing));
puts("head=malloc(sizeof(thing));");
// Not a null
if (head != NULL)
puts("malloc success");
// Point to NULL again ???
head=NULL;
Then your current points to head viz NULL again that makes current NULL
current=head;
puts("current=head;");
if (current == NULL)
puts("current is NULL");
and then you dereference current and try to malloc
puts("while");
while (current!=NULL)
{
current = current->next;
}
puts("end while");
current->next=malloc(sizeof(thing)); //current is NULL here NULL->next is invalid
puts("current->next=malloc(sizeof(thing));");

Avoid Segmentation Fault with Empty Linked List

I have a List in C with the following data structures:
typedef struct node{
int in_id;
struct node *next;
} Node;
typedef struct List{
Node* head;
Node* tail;
}List;
My function for viewing the front of the list works fine if the list is occupied, however, if the list is empty and I take a peek inside the list, I receive a segmentation error. Which is completely understandable. However, I have been trying to think of a way to either prevent this or circumvent the segmentation error.
Node* front(List *q){
Node *temp;
temp = NULL;
if(q->head == NULL && q->tail == NULL){
printf("front function: this is empty \n");
return temp;
}
else{
temp = q->head;
return temp;
}
}
First idea is if I need to use front in an if(front(Node)->value == x), I get a segmentation error if its empty. However, I short circuit this by putting something else I need to test before front, if( something == TRUE && front(Node)->value == x).
What I also thought about doing was malloc() some dynamic memory to temp within front and assigning the relevant field that I'm testing for a value that I know is false if the head && tail == NULL. However, I feel this is memory leakage becuase I wouldn't be able to free() temp.
Is there a better way for me to handle peeking into this queue and not getting a segmentation fault if its empty?
I think you're trying to do too much in your one-liner function call. front(Node)->value is always going to try to dereference whatever is returned from that function, even if it is NULL, hence the seg fault when the list is empty and it returns NULL. You need to split that line up.. first retrieve the pointer from a call to front(...), then check it for NULL, and if not NULL, then proceed with the dereference:
Node* temp = front(list);
if (temp != NULL)
{
// proceed with dereference
if (temp->value == x) // this won't seg fault, do whatever with it
{
// ...
}
}
else
{
// print error or do nothing
}
There is probably a more clever way to one-line it, but if you're stuck and not constrained with a strict line requirement is it really worth it?
If the linked list is empty then head node is always null. And in your function your checking head and tail element of the empty node. that's why your getting segmentation fault .
just try below function
Node* front(List *q){
Node *temp;
temp = NULL;
if(q == NULL){
printf("front function: this is empty \n");
return temp;
}
else{
temp = q->head;
return temp;
}
}

How do I get rid of a NULL segmentation fault?

I am creating a linked list program in C and I keep on getting a segmentation fault. I've narrowed the problem down to a few lines of code and I believe it has to do with checking for NULL. How can I fix this? Here's the code:
typedef struct node
{
int contents;
struct node *nextNode;
} Node;
deleteNode(Node *currentNode)
{
while((currentNode->contents) != NULL)
{
//.....Do Stuff.....
currentNode = currentNode->nextNode;
}
}
Thanks
Try checking to make sure that currentNode isn't NULL at the start of deleteNode(). I.e.
deleteNode(Node *currentNode)
{
if (currentNode == NULL) return;
// ...
// ...
}
If the problem is as I suspect, currentNode is a null pointer. Just ensure that currentNode is not null before you attempt to access it.
deleteNode(Node* currentNode)
{
while ((currentNode != NULL) && (currentNode->contents != NULL))
{
/* ... */
currentNode = currentNode->nextNode;
}
}
Well, I'm suspicious that this line:
while((currentNode->contents) != NULL)
is comparing the contents field of your Node structure, which is an int, with NULL... I would guess that this was supposed to be checking currentNode->nextNodeinstead!
So, probably: none of your contents are zero, so this test is true for every item in the list. Then the last item has a NULL currentNode->nextNode, which is assigned to currentNode, and it blows up dereferencing it the next time round the loop.
what happens when currentNode is NULL?. It is dereferencing a NULL memory in the while condition.

Resources