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));");
Related
I was trying to remove the duplicate element in a sorted linked list using recursion concept.
I wanna see how to remove the elements in a sorted linked list. I made a code in which if head->data == head->next->data than head->next should be freed until we get the different element.
Now I have made so many changes I am confused how I am supposed to do it. It is deleting every value that is duplicate and only leaving the one that was only appeared in the entire code only once.
Please also tell me why this code is doing this and also what can wrong with code and if any optimal way possible to do the same thing.
(I am only providing the deleteduplicate function if there is a need to provide the whole code like print the list or insert in the list I will edit it if told).
Thanks.
Node *deleteDuplicates(Node *head) {
if (head == NULL || head->next == NULL) {
return head;
}
if (head->data == head->next->data) {
struct Node *x = head->next;
head->next = head->next->next;
free(x);
return deleteDuplicates(head);
} else
return deleteDuplicates(head->next);
}
Input: 11 11 11 13 13 20
Output: 20
Expected output: 11 13 20
It is deleting every value that is duplicate and only leaving the one value that was only appeared in the entire code only once.
No. It is deleting only duplicate values but you always return pointer to the last node.
if(head==NULL ||head->next==NULL){
return head;
}
You don't need to return the new head, since only duplicates are going to be removed, there is no way head is going to change.
There is no need for recursion in this function. Just iterate in a loop either removing the next element or skipping to the next element:
Node *deleteDuplicates(Node *head) {
if (head != NULL) {
Node *p = head;
while (p->next) {
if (p->next->data == p->data) {
Node *x = p->next;
p->next = x->next;
free(x);
} else {
p = p->next;
}
}
}
return head;
}
You could fix your recursive function, but it should be modified to not return the head node as this prevents tail recursion, therefore requiring a potentially huge amount of stack space. A sufficiently long list would cause a Stack overflow.
Here is a modified recursive function:
void deleteDuplicates(Node *head) {
if (head != NULL && head->next != NULL) {
if (head->data == head->next->data) {
struct Node *x = head->next;
head->next = x->next;
free(x);
deleteDuplicates(head);
} else {
deleteDuplicates(head->next);
}
}
}
The problem in your code is you store the return value of deleteDuplicates into your head pointer, but the function returns the pointer to the last node in the list, not the head node.
I am doing the pset4 of CS50 which basically needs you to create 26 nodes (each node for every letter of the alphabet) and created a linked list within these nodes to connect words from a dictionary.
So, for example, node 0 will store every word of the dictionary that starts with A, node 1 wills store every word of the dictionary that starts with B, etc...
So, here is the main piece of code:
// Insert words into hash table
while (fscanf(file, "%s", word) != EOF)
{
// for every word, we allocate enough memory for a node, that will carry the word
node *new_node = malloc(sizeof(node));
if(new_node == NULL) { printf("could not allocate memory.\n"); return false; }
strcpy(new_node->word, word);
new_node->next = NULL;
if(!hashtable[alphabetPosition(word[0])]){
hashtable[alphabetPosition(word[0])] = new_node;
}
else
{
for(node *ptr = hashtable[alphabetPosition(word[0])]; ptr != NULL; ptr = ptr->next){
hashtable[alphabetPosition(word[0])]->next = new_node;
}
}
}
alphabetPosition() is basically a function that will return the first character of the word.
the main problem is this:
else
{
for(node *ptr = hashtable[alphabetPosition(word[0])]; ptr != NULL; ptr = ptr->next){
hashtable[alphabetPosition(word[0])]->next = new_node;
}
}
Because every thing else is working. The nodes are been created, but the linked lists are not.
I'm pretty sure there is something wrong with this piece of code but I can't seem to understand. If someone could help me (explaining how to solve it), it would help me so much.
Thanks!
The main flaw is: hashtable[index] is only and always pointing to the last node created. I.E. hashtable[alphabetPosition(word[0])]->next is always set to new_node.
The for loop is basically wrong. The program simply needs to point the new_node to the current head of the list (ie hashtable[alphabetPosition(word[0]) and then make new_node the new head.
so I have some questions on how to do correct memory management.
Basically my question is, what happens when for example I take this code(shown below). Does this need to be freed to prevent memory leaks?
void traverseLeftRight(struct node *head){
current = head;
if(current == NULL){
printf("There are no nodes within the list\n");
}
while(1){
if(current != NULL){
printf("left to right output: %d\n", current -> value);
current = current -> next;
}else{
break;
}
}
}
Also, would free(current) and current = NULL break the list if i were do it within the break section of the list. Also, would something like this just break the pointing variable and not effect the node that it corresponds to?
void traverseLeftRight(struct node *head){
current = head;
if(current == NULL){
printf("There are no nodes within the list\n");
}
while(1){
if(current != NULL){
printf("left to right output: %d\n", current -> value);
current = current -> next;
}else{
free(current);
current = NULL;
break;
}
}
}
I think you are confused about memory management.
In the examples you've shown, there's no need for any freeing, because nothing has (as far as we can see) been allocated.
If you allocate memory with malloc(3) or friends, then you will typically need to free it later, exactly once. In general, failing to free something leaks memory (ie, the memory is still allocated, but you're not pointing to it any more, so can't use it), and freeing more than once is an error (in the sense that this opens the possibility of two bits of the code both believing they've been allocated exclusive use of the same bit of memory). Using a bit of memory (ie, dereferencing a pointer) after it's been freed is the classic ‘use-after-free’ error. Each of these results in somewhat hard-to-find bugs (but valgrind is your friend).
The call to free in your second would (unfortunately) not cause an error, because free doesn't report such errors.
You don't need to free memory if it's in use all the way to the end of the program – that's (in effect) freed automatically when the program finishes.
Almost the only case where you'd call free within a function like this is if you were writing a function to walk along a linked list (or something like that), freeing as it went. A traverse of a list (as your function name suggests) would not be expected to result in the list being freed.
here is your first code, corrected, so an empty list does not enter the 'while()' loop
void traverseLeftRight(struct node *head)
{
current = head;
if(current == NULL)
{ // then list empty
printf("There are no nodes within the list\n");
}
while( current != NULL )
{ // then, another node to print
printf("left to right output: %d\n", current -> value);
current = current->next; // step to next node in list
}
}
here is your second code, with comments
while(1)
{
if(current != NULL)
{ // then, not at end of list
printf("left to right output: %d\n", current -> value);
current = current->next; // step to next entry in list
}
else
{ // else, current == NULL ,, I.E. past end of list
free(current); // nothing will happen because Current == NULL
current = NULL; // already NULL, so nothing will change
break; // exit the 'while()' loop
}
}
proposed code that free's the linked list as it traverses it.
Note that the 'head' needs to be updated as the list is 'free'd
// note the 'pointer to pointer parameter, so 'head' can be modified
void traverseLeftRight(struct node **head)
{
if( *head == NULL)
{ // then, list is empty
printf("There are no nodes within the list\n");
}
while( *head != NULL)
{ // while another node to process
struct node *temp = *head; // remember current node pointer
printf("left to right output: %d\n", current -> value);
*head = (*head)->next; // step to next node
free( temp ); // eliminate current node
}
}
Can anyone identify what is happening in my code that is causing the segmentation fault? Please modify/correct the wrong part.
void InsertAtMid (Node *head){
int num,count=0,i;
Node *ptr=head;
Node *newnode=NULL;
Node *newnode2=head;
printf("Enter node to be inserted: ");
scanf("%d", &num);
if (head==NULL){
newnode = head;
newnode=(Node *)malloc(sizeof(Node));
newnode->x=num;
newnode->next=NULL;
newnode->prev=NULL;
} else {
ptr=head->next;
while(ptr->x!=(count/2)){
ptr=ptr->next;
}
newnode->next=ptr->next;
newnode->prev=ptr;
ptr->next->prev=newnode;
ptr->next=newnode;
}
}
So, based on my understanding of your code - the following should [mostly] work:
void InsertAtMid (Node **head){
int num = 0;
int count = 0
int advance = 0;
Node *ptr = *head;
Node *newnode = NULL;
printf("Enter node to be inserted: ");
scanf("%d", &num);
if (*head == NULL) {
*head = (Node *)malloc(sizeof(Node));
ptr = *head;
ptr->x = num;
ptr->next = NULL;
ptr->prev = NULL;
} else {
// *** Count the number of items
ptr = *head;
while (ptr != NULL) {
ptr = ptr->next;
count++;
}
// *** Move to the middle of the list
ptr = *head;
while (advance < (count/2)){
ptr = ptr->next;
advance++;
}
// *** Insert the new value
newnode = (Node *)malloc(sizeof(Node));
newnode->x = num;
newnode->next = ptr->next;
newnode->prev = ptr;
ptr->next->prev = newnode;
ptr->next = newnode;
}
}
The following are the issues I fixed:
You are assigning to head at one point, but since "head" isn't passed in as a reference, the value isn't going to be maintained beyond the first time the function is called. Needless to say you need a pointer to a pointer of type node.
You never calculated the number of items in the list. Often "head" pointer would store this information and you would increment when you add a node, but since you don't have that the only way to determine it is to traverse the list till you find the count.
You never allocated space for the new node to insert except if you were initializing the head pointer. This was also an issue.
Hope that helps some. Best of luck!
int num,count=0,i;
...
ptr=head->next;
while(ptr->x!=(count/2)){
ptr=ptr->next;
count is initialized to 0 and never changed.
So unless you enter "0" for x, that while loop is just going to walk off the end of the list, every time.
Test to work out under what circumstances your code segfaults.
You'll find that it works OK when head == NULL, but fails if head is not null.
So you know that your error is somewhere in the else block.
Step through your running code in a debugger (if you don't know how, it's never too early to learn: whenever you solve a problem with a debugger, you think "why didn't I turn to this sooner?").
Work out what you expect to happen, watch the variables in the debugger, and when the actual values deviate from your expectations, reason about why.
It's not clear to me what you expect to happen in your code, but what will actually happen for a list with one node, is that:
it will execute ptr=head->next; -- so ptr is now NULL.
then for the while condition it will try to dereference ptr->x, and since ptr is NULL, it will segfault.
A quick fix for that would be:
while(ptr != NULL && ptr->x ....) {
But you need to think about whether that's the actual logic you want; and once you get past that, you'll hit other problems (for example, count never changes), which can be sorted out with a debugger in the same way.
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.