LinkedList Traversal crashing randomly - c

I am working on a Graph problem, so my program has an initialization which sets all connection using an adjacencyList. Currently encountering a really weird bug and was wondering if anyone could give some insights as to what may be happening.
So I have a function that sets a connection
void setConnection(Graph g, int sVertex, int eVertex){
ListNode *newNode = (ListNode *) malloc(sizeof(ListNode*));
newNode->vertex = eVertex;
ListNode *temp = g.list[sVertex-1];
if (temp == NULL){ // Corresponding list is empty
newNode->next = NULL;
g.list[sVertex-1] = newNode;
}
else{ // Insert new node to the front
newNode->next = temp; // set newNode's next to current 'head'
g.list[sVertex-1] = newNode; // Replace head as newNode
}
//printf("Connection set from %d to %d\n", sVertex, g.list[sVertex-1]->vertex);
return;
}
After initialization, I usually attempt to print out the adjacencyList to check if the logic is correct. The function is as follow:
void printGraphList(Graph g){
int i;
ListNode* temp;
for(i=0;i<g.V;i++)
{
printf("|");
printf("%d:\t",i+1);
temp = g.list[i];
while(temp != NULL){
printf("%d -> ",temp->vertex);
temp = temp->next;
}
printf("\n");
}
}
So here's the weird part, the code works fine most of the time, but occasionally crashes randomly when printing the adjancencyList. I debugged it down to
printf("%d -> ", temp->vertex);
For some reason, there are cases where the first node inserted does not have its ->next set to NULL properly. hence in the list traversal, it does not exit properly, and as such the temp->vertex is unobtainable, therefore causing the crash.
I have also debugged setConnection to ensure the links are properly set, like the actual pointer values themselves T.T
Below is an example of a working run, and a problem run. I printed an & before printing the vertex and and # after. As shown in the image, for vertex 7, it should be linked to only vertex 9 and 10, but in the problem run, it looks like the node for 9's next is not set to NULL properly, causing the program to crash in attempt to get node 9's->next->vertex as it does not exist...
As mentioned before, this happens once every 3 to 4 runs and i have no clue whats causing this inconsistency. Any help is appreciated! Thanks in advance.
Problem Example
Working Example

Related

C linked list define how to reimplement a list

Hi this is probably a stupid question to ask with a simple solution but I just can't find an answer in the internet.
So I was exercising for an exam and worked on an assignment. The program has the job to find out what the value in the center of a linked list is (if the length of the list is an odd number)
The structdef is:
typedef struct IntList IntList;
struct IntList {
int value;
IntList* next;
};
and my exact problem right now is that I get a segmentation fault when I try using:
list = list->next;
I want to go step by step in a loop to go to the wished list at the nth position (the center) of the linked list.
Someone knows how I have to rewrite this? If you need more Information to help just say so and I will explain more.
With that function I check the length of the list and in my other function I have a loop which only goes to the mid of the length.
int length_list(IntList* list) {
int n = 0;
for(IntList* node = list; node != NULL; node = node->next) n++;
return n;
}
After this loop ends for(IntList* node = list; node != NULL; node = node->next) n++; you surely have node==NULL.
That is not immediatly a problem.
But depending on what you do with the value of n which you return you might have an off-by-one problem. E.g. in a list with exactly one entry (1 is odd after all), the attempt to use a value which is 1 too high could result in an attempt to access a non-existing node.
Because of this I suspect that your problem might be solved by changing the loop to
for(IntList* node = list; node->next != NULL; node = node->next) n++;, so that it ends on the last existing node, instead of behind. The return value will be lower, whatever you do with it will be "more-careful".
That or try something similar with the small code fragment you show and ask about, list = list->next; only do that if the next is not NULL, not if only list is not NULL.

Segmentation fault while finding middle element in a linked list

I'm trying to find the middle element of a linked List, but I'm getting a segmentation fault, and I'm not sure what is going wrong. This is my implementation of the hare rabbit algorithm:
//fast slow pointer method
void ptMiddle(struct node **head_ref)
{
struct node *fast = (*head_ref);
struct node *slow = (*head_ref);
fast = fast->next;
while(fast!=NULL)
{
// printf("%d%d",slow->data,fast->data);
slow = slow->next;
fast = fast->next->next;
}
printf("Middle elemnet is:%d\n",slow->data);
}
int main()
{
struct node * head=NULL;
push(&head,1);
push(&head,2);
push(&head,3);
push(&head,4);
printList(&head);
printf("M:%d\n",middleNode(&head)->data);
printf("here");
append(&head,5);
append(&head,6);
printList(&head);
printf("M:%d\n",middleNode(&head)->data);
printf("here");
ptMiddle(&head);
return 0;
}
Please help out.
Your problem is in the line:
fast = fast->next->next;
Imagine you have two elements in the linked list: A -> B -> NULL, first you start by executing fast = fast->next, which results in fast pointing to B node.
When you enter the while loop, you try to get B->next->next, which results in NULL->next, which clearly doesn't exist.
The implementation is plain wrong, you should make sure to avoid this case. The while could be changed to:
while(fast!=NULL && fast->next != NULL)
and this would fix it.
Keep in mind that in case of a pair number of elements, you'll always get the middle one which is more left. So in A -> B -> NULL you'd get node A.

C - Error in Deleting an Entire BST

I can't seem for the life of me figure out what the is wrong with my code in the deletion of a whole BST.
I figure since there doesn't seem to be a problem with this:
void emptyTree(BST **root){
if((*root)!=NULL){
emptyTree(&(*root)->left);
emptyTree(&(*root)->right);
free(*root);
}
}
Then the whole problem lies with the initial entry of each node in the tree. Can anyone point out what's wrong here?
void insertNode(BST **root, BST *temp){
if((*root)!=NULL){
temp->parent = *root;
if(((*root)->value) < (temp->value))
insertNode(&(*root)->right,temp);
else if(((*root)->value) > (temp->value))
insertNode(&(*root)->left,temp);
else if(((*root)->value) == (temp->value)){
printf("The number %i is already in the tree.\n",temp->value);
return;
}
} else {
*root = temp;
printf("%i was added to the tree.\n",temp->value);
return;
}
}
void newNode(BST **root, int x){
BST *newnode;
newnode = (BST *)malloc(sizeof(BST));
newnode->value = x;
newnode->left = newnode->right = newnode->parent = NULL;
insertNode(root,newnode);
}
It compiles, it runs, it does absolutely every function right(including one that deletes one node at a time). Except the 'Delete All'(emptyTree) one. It doesn't delete everything(?). It doesn't even show an error when I run through the emptyTree function. It only errors when I printf the whole tree.
The error occurs because you do free all data, but forget to indicate that your elements no longer contain valid data.
That is, after deleting, all elements' left and right members, and your own root itself still contain a value; they still contain the original values, but these no longer point to valid, allocated, memory.
The error does not directly occur within emptyTree because this works from the end nodes up to the top, and there is no reason to check "down". But as soon as you attempt to print root (and its descendants), you are accessing unallocated memory.
Insert
*root = NULL;
in your emptyTree function after
free(*root);
to fix it inside the emptyTree function, or set root to NULL after calling emptyTree.
Personally, I prefer the former, even though it's a minor overhead. That way, you only have a single function to delete a tree, instead of the recursive one plus a wrapper that also sets the root to NULL.

C - Linked Lists

I am trying to understand the code of linked lists. I understand how they work.
I am looking at some code to do with dynamic memory and linked lists, I have simplified it here:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
char *word;
struct node *next;
} node;
void display_word(node *start) {
node *start_node = start;
puts("");
for(; start_node != NULL; start_node = start_node->next) {
printf("%s", start_node->word);
}
}
node* create_node(char *input) {
node *n = malloc(sizeof(node));;
n->word = strdup(input);
n->next = NULL;
return n;
}
int main() {
node *start_node = NULL;
node *n = NULL;
node *next_node = NULL;
char word_holder[20];
for(; fgets(word_holder,80,stdin) != NULL; n = next_node) {
next_node = create_node(word_holder);
if(start_node == NULL)
start_node = next_node;
if(n != NULL)
n->next = next_node;
}
display_word(start);
}
So the program creates a linked list of each word the user enters and then it prints it out.
What I dont understand is in the main() function where next_node is assigned to a new node everytime to create a new one, but start_node points to next_node, so it will point to every new node that next_node creates each time? So how is it possible to still keep the list? Shouldn't we lose the old node each time?
Can someone explain please.
When the first node is created, a pointer to it is saved in start.
When subsequent nodes are created, they are added at the end of the list, so start still points to the first node, and through it, the rest of the list.
Step through the code with a debugger, or get out a pencil and paper and draw what's happening as you step through in your brain, and you'll see how it all gets put together.
When the first node is created, a pointer to it is saved in start.
After every iteration of the loop, "n" is set to the node just created, because the last piece of the for loop (;n = next) is executed after every iteration of the loop. So mid loop execution "n" will always be pointing to the previous node. Therefore the statement n->next = next is setting the previous node's "next" pointer to the new node.
So during the second iteration of the loop, n = start, and start->next is set to "next" the node you just created.
I hope this answers your question - every time you are updating "next", you're setting that to be yet another new node. Each node has their own "next" that leads to the next node, so you aren't going to lose anything by doing it this way. I didn't actually test your code but since "Start" points to the first node always, you aren't going to lose any nodes along the way. A debugger should help if you're curious to learn more about how this works!

C: Creation of ordered list by checking 2 values

I'm new to C so be patient with me if you see some really newbie error in my code!
As part of a homework, I need to create an ordered list in order to store some data. What I've done so far is to create the struct which will represent each node of the list (firstNode is a global variable that points to the first node of the list):
typedef struct Node {
struct Node *next;
int id;
int value;
}Node;
Node *firstNode = NULL;
After that I created a function that inserts a new node into the list by checking the values of the nodes. Nodes with smaller values should be before others. So what I did was this:
void addNewNode(int nodeId, int nodeValue) {
Node *newNode = (Node*) malloc(sizeof(Node));
Node *temp, *tempPrev;
newNode->id = nodeId;
newNode->value = nodeValue;
if(firstNode == NULL) {
newNode->next = firstNode;
firstNode = newNode;
}
temp = firstNode;
tempPrev = NULL;
while(temp->value < newNode->value) {
tempPrev = temp;
temp = temp->next;
}
if(tempPrev == NULL) {
newNode->next = firstNode;
firstNode = newNode;
}
else {
tempPrev->next = newNode;
newNode->next = temp;
}
}
The problem with the code above is that sometimes the program crashes, but I can't find the error!
Also, what I'm trying to do next is, if some nodes have the same value, then they are ordered according to their id (nodes with smaller IDs come first). How can I do this? I'm really confused!
The program crashes because in the while loop condition, you don't check whether the temp equals to NULL. In other words, if you try to insert a new node with a greater value than all the others already inside the list, temp reaches to the end of the list (so temp equals to NULL) and you try to get the value of that node! So a fix would be:
while(temp!=NULL && temp->value>newNode->value)
{
....
}
As for the id of the nodes, you could extend your while loop condition like this:
while(temp!=NULL && (temp->value<newNode->value || (temp->value==newNode->value && temp->id<newNode->id))
{
....
}
Also, the first if-statement, where you check whether firstNode is NULL, is not necessary in your case. If it's NULL, the program will not get into the while-loop and will go directly to the first if-statement after the while-loop.
By the way, nice code for a new programmer in C :-)
1.
if(firstNode == NULL) {
newNode->next = firstNode;
firstNode = newNode;
return; // done with inserting the first node...need not continue.
}
2.
// ensure temp is not null only then access its value.
while(temp && (temp->value < nodeId->value)) {
tempPrev = temp;
temp = temp->next;
}
for one thing, you have nodeID -> value in there. NodeID is an int, so this won't work.
As a method of debugging, I would create a simple test harness. In other words, a test program you write that runs through all the common scenarios you can think of (aka unit testing). Each unit test checks to ensure that it runs properly and generates the expected output. This way, you can be confident that if everything checks ok, you're good to go. If a unit test fails, you know exactly what's broken.
I would suggest constructing a couple of test cases that check your boundary conditions (e.g. add an element to an empty list; add an element that should end up at the front of an existing list; add an element that shold end up at the end of an existing list; add an element that should end up somewhere in the middle of an existing list). Make a "print" function that will print the elements in the list to the console for debug. That will at least help you narrow down what the context of your crash is. One possibility (I don't know how many adds you're doing) is that the program runs out of memory and malloc fails. You can check for that because I think malloc returns NULL if it fails to allocate the requisite memory.
Node *newNode = (Node*) malloc(sizeof(Node));
if(newNode == NULL)
{
printf("Out of Memory!");
return;
}

Resources