Uninitialized local variable error - c

Here is the function which getting me into troubles and I actually can't understand why.
This function supposes to removes all the odd elements from a given linked-list and also returns an address of a new linked list of the odd elements removed.
typedef struct node {
int data;
struct node* next;
} Node;
Node* removeOddValues(Node **source)
{
Node *curr = *source;
Node *even;
Node *even_curr;
Node *odd;
Node *odd_curr;
Node *next;
even->next=NULL;
odd->next=NULL;
even_curr = even;
odd_curr = odd;
while(curr)
{
next = curr->next;
curr->next = NULL;
if(curr->data % 2!=0)// odd//
odd_curr = odd_curr->next = curr;//node add to last//
else //even//
even_curr = even_curr->next = curr;
curr = next;
}
*source= even->next;//update source//
return odd->next; //the new list of odd elements removed//
}
When I try to compile it, I get the following error:
warning C4700: uninitialized local variable 'even' used
warning C4700: uninitialized local variable 'odd' used

Two things:
First, you get warnings (and your program contains undefined behaviour and would probably crash) because you access/dereference uninitialised variables:
Node *even;
Node *odd;
even->next=NULL; // even has not been initialised
odd->next=NULL; // odd has not been initialised
Second, your code does not "remember" the roots of the new lists, i.e. you manage odd_curr and even_curr, each pointing to the last node of the respective list, but you do not have something like odd_root and even_root.
The following code shows how this could work. The logic for appending a node at the end while additionally considering a root node is the same for both lists, odd and even, and therefore factored out into a separate function:
void appendNode(Node **root, Node** lastNode, Node *curr) {
if (!*root) { // root not yet assigned?
*root = curr;
*lastNode = curr;
} else {
(*lastNode)->next = curr; // append curr after lastNode
*lastNode = curr; // let curr become the lastNode
}
(*lastNode)->next = NULL; // terminate the list at lastNode
}
Node* removeOddValues(Node **source)
{
Node *curr = *source;
Node *evenRoot = NULL;
Node *oddRoot = NULL;
Node *evenLast = NULL;
Node *oddLast = NULL;
while(curr)
{
Node *next = curr->next;
if(curr->data % 2!=0) {
appendNode(&oddRoot, &oddLast, curr);
}
else {
appendNode(&evenRoot, &evenLast, curr);
}
curr = next;
}
*source= evenRoot;
return oddRoot;
}

curr = next;
Gives you the first warning, because next is not initialized.
odd_curr = odd;
Gives you the second warning, because odd is not initialized.
You should consider using malloc to allocate structures, because you are just allocating pointers, not the actual nodes. You can start learning more about linked lists from this interactive guide. Even if you somehow fix these two warnings, it still won't work.

The simplest case, using only two variables. The even nodes stay in the original list; the odd nodes are removed from the chain and returned as a linked list.
#include <stdio.h>
struct llist {
struct llist * next;
int data;
};
struct llist *chop_odds(struct llist **source)
{
struct llist *odd = NULL;
struct llist **target = &odd;
while ( *source) {
if((*source)->data %2) { /* odd */
*target = *source; // steal the pointer
*source = (*source)->next; // source skips this node
target = &(*target)->next; // advance target
}
else source = &(*source)->next; /* even */
}
*target = NULL;
return odd;
}

Related

Printing doubly linked list in C goes into infinite loop

Im trying to learn doubly linked lists. I used the following to print:
typedef struct Node{
int data;
struct Node* prev;
struct Node* next;
}node;
typedef struct List{
node *head;
}list;
node * createNode(int data) {
node * newNode = (node*)malloc(sizeof(node));
newNode->data = data;
newNode->prev = NULL;
newNode->next = NULL;
return newNode;
}
_Bool isEmpty(const list *L)
{
if (L->head == NULL)
return 1;
return 0;
}
_Bool insert(list *L, node *N) {
if(isEmpty(L)) {
L->head = N;
}
else{
L->head->prev = N;
N->next = L->head;
L->head = N;
}
if (L->head==N)
return 1;
return 0;
}
void _print(list *L){
node *temp=L->head;
while(temp!=NULL){
printf("%d ", temp->data);
temp = temp->next;
}
printf("\n");
}
int main(int argc, char *argv[]){
list *L1=(list *)malloc(sizeof(list));
node *N1=createNode(3);
node *N2=createNode(1);
node *N3=createNode(5);
insert(L1, N3);
insert(L1, N2);
insert(L1, N1);
_print(L1);
}
for reference my list struct only contains a pointer "head" and my node struct contains next, prev and data.
It prints the correct data but goes into infinite loop.
What is the reason ?
The problem is that this line in main:
list *L1=(list *)malloc(sizeof(list));
Allocates memory for the list, but does not initialize it.
Without initialization the value of L1->head can be anything.
And if it happens to be different than 0 (i.e. NULL), insert will interpret it as pointing to a valid node (which it isn't).
The result is undefined behavior (UB), which means anything can happen. It might seem to work, it can crash, or get into an infinite loop etc.
In order to fix it, you need to initialize the list pointed by L1.
You can do it at least in 2 ways:
Replace the call to malloc with calloc, which also zeroes the allocated memory:
list* L1 = (list*)calloc(sizeof(list), 1);
Add an explicit initialization after the malloc:
list* L1 = (list*)malloc(sizeof(list));
L1->head = NULL; /* <--- initialization */
You can also add a function for encapsulating the initialization.

Explanation for base case return value in recursive linked list reverse algorithm

I am learning how to reverse a linked list recursively. I am confused with the last 4 lines.
node *reverse_linked_list_rec(node *head){
if (head->next==NULL){
return head;
}
node *smallans= reverse_linked_list_rec(head->next);
node *tail = head->next;
tail->next = head;
head->next = NULL;
return smallans;
}
Let's say I am reversing
1 2 3 NULL
by recursion, it reaches at 3 NULL and then by base case returns
2 3 NULL
here head=2, smallans=2 (not sure).
Why we are returning smallAns here and how it is changing?
smallans is a confusing variable name because it's actually the old tail being passed back through the list to become the new head which is ultimately returned to the caller.
Its next pointer changes when these lines execute in the parent function call:
// when head->next->next == NULL ...
node *tail = head->next; // ... `tail` points to the old tail (new head) ...
tail->next = head; // ... and this sets the new tail's next pointer to
// the old second-to-last node (new second node).
tail is a misleading name here--I associate a "tail" with a single node that terminates the entire list, not a previous node. new_prev or old_next seem more appropriate here depending on whether you want to name things relative to the node roles in the new list or the original list.
As a minor point, I recommend using if (!head || !head->next) to avoid a potential null pointer dereference.
I'd write the function as follows:
node *reverse_linked_list_rec(node *head) {
if (!head || !head->next) {
return head;
}
node *old_tail = reverse_linked_list_rec(head->next);
node *old_next = head->next;
old_next->next = head;
head->next = NULL;
return old_tail;
}
Aside from intellectual curiosity, recursion is a poor choice for linked list operations since it adds function call overhead, you can blow the stack and the logic isn't any easier to follow than iterative, in most cases.
Case in point, here's a complete example with an iterative version:
#include <stdio.h>
#include <stdlib.h>
struct node {
int id;
struct node *next;
};
struct node *make_node(int id) {
struct node *n = malloc(sizeof(*n));
if (!n) exit(1);
n->id = id;
n->next = NULL;
return n;
}
struct node *reverse_linked_list(struct node *head) {
struct node *prev = NULL;
for (struct node *curr = head; curr;) {
struct node *old_next = curr->next;
curr->next = prev;
prev = curr;
curr = old_next;
}
return prev;
}
void print_linked_list(struct node *head) {
for (; head; head = head->next) {
printf("%d->", head->id);
}
puts("");
}
void free_linked_list(struct node *head) {
while (head) {
struct node *tmp = head;
head = head->next;
free(tmp);
}
}
int main() {
struct node *head = make_node(1);
head->next = make_node(2);
head->next->next = make_node(3);
print_linked_list(head); // => 1->2->3->
head = reverse_linked_list(head);
print_linked_list(head); // => 3->2->1->
free_linked_list(head);
return 0;
}
As another minor point, since the linked list is being mutated I'd probably go for a header like void reverse_linked_list(struct node **head);. Otherwise, it seems too easy to call the non-void function, ignore the return value and wind up with a memory leak or crash when head in the caller scope (which has become a tail pointing to null) is dereferenced.

Basic C linked list syntax error

Note: I already got the intended function to work with my own code, but I saw a tutorial on another website and am wondering why it doesn't work.
https://www.eskimo.com/~scs/cclass/int/sx8.html
The premise is as follows:
I'm playing around with a very basic linked list:
typedef struct node {
int val;
struct node * next;
} node_t;
I am trying to have a function remove an entry by value. It is as follows:
int remove_by_value(node_t ** head, int val) {
for(head = &node_t; *head != NULL; head = &(*head)->next){
if ((*head)->val == val) {
*head = (*head)->next;
break;
}
}
}
However, I'm getting an error when calling this function, namely:
"prog.c:35:17: error: expected expression before 'node_t'
for(head = &node_t; *head != NULL; head = &(*head)->next){
^"
Any ideas? Is this just a simple syntax error that I'm not seeing? Thanks!
the root of the problem is that node_t is a type, not a variable and cannot take the address of a type.
The following code cleanly compiles.
be sure to check the logic,
for first iteration of the loop when head = NULL or only one struct in linked list
check logic for when desired struct is either last or next to last in the linked list
here is the code:
typedef struct node
{
int val;
struct node * next;
} node_t;
int remove_by_value(node_t ** head, int val)
{
int retVal = -1; // initialize to failed
node_t *previousNode = *head;
node_t *currentNode = *head;
for(;
previousNode && currentNode; // assure something to test
previousNode = currentNode, // update the pointers
currentNode = currentNode->next )
{
if (currentNode->val == val)
{
previousNode->next = currentNode->next;
retVal = 0; // indicate success
break;
}
}
return retVal;
} // end function: remove_by_value
Since I cannot comment on the accepted answer written by #user3629249:
That code is even worse than the original (except that it would compile).
I'd suggest something like this:
node_t *remove_by_value(node_t **head, int val)
{
node_t *ret = NULL;
for (; *head; head = &((*head)->next))
{
if ((*head)->val == val)
{
ret = *head;
*head = (*head)->next;
break;
}
}
return ret;
}
This code correctly removes the element from the beginning, middle and end of the list. In addition it gives the caller the chance to free the unlinked node.
1) The error you are getting was pointed out by iharob already.
2) I can understand that out of this head =&t_node you want head to point at the head of your list. a static variable may be needed in your file to be able to use this then you can point head correctly

Removing node from singly linked list

I need to remove a node from a singly linked list. I know this is a simple thing to do, but my mind is blank and I've searched both Google and Stackoverflow, but I seriously haven't found anything that will help me.
basically the list of nodes is contained in a bucket; like this:
struct node{
unsigned char id[20];
struct node *next;
};
struct bucket{
unsigned char id;
struct node *nodes;
};
and I have a function
struct bucket *dht_bucketfind(unsigned char *id); // return bucket with id[20]
to find the correct bucket. So I know how to find the correct bucket, but I don't know how to remove a given node. I would like to remove the node by nodeid (I think, I haven't really written the code that will call the remove function yet ;) but I think I'll be able to modify the code if necessary). I think that's all that's needed to solve this. Thanks in advance.
If you know the item you want to remove, you must do two things:
Change all pointers that point to the target item to point to the target item's next member. This will be the preceding item's next pointer, or the head of the list bucket.nodes.
Free the node you just made unreachable.
The code for manipulating a linked list is really not that tricky, once you understand what you are doing.
Your nodes don't have any payload other than an id, so, depending on the data payload of a node, you might not actually need to iterate the list in the standard way. This is useful if deleters are going to know the address of only the node they want to delete.
If your payload is a pointer to other data:
struct _node {
void *data;
unsigned char id[20];
struct _node *next
}
Then you could "delete" a node by stealing the payload of the next node, and then delinking the next node:
int delete (struct _node *node)
{
struct _node *temp;
memcpy(node->id, node->next->id, 20);
free_function(node->data);
node->data = node->next->data;
temp = node->next;
node->next = node->next->next);
free(temp);
return 0;
}
/* define your two pointers, prev and cur */
prev=NULL;
cur=head;
/* traverse the list until you find your target */
while (cur != NULL && cur->id != search_id) {
prev=cur;
cur=cur->next;
}
/* if a result is found */
if (cur != NULL) {
/* check for the head of the list */
if (prev == NULL)
head=cur->next;
else
prev->next=cur->next;
/* release the old memory structure */
free(cur);
}
public void Remove(T data)
{
if (this.Head.Data.Equals(data))
{
this.Head = this.Head.Next;
this.Count = this.Count - 1;
}
else
{
LinkedListNode<T> node = this.Head;
bool found = false;
while (node.Next != null && !found)
{
if (node.Next.Data.Equals(data))
{
found = true;
node.Next = node.Next.Next;
this.Count = Count - 1;
}
else
{
node = node.Next;
}
}
}
}
Its been a long time ago since I worked with C, but this should be compile clean.
Basically, you need to keep track of the previous pointer while you iterate through the linked list. When you find the node to delete, just change the previous pointer to skip the delete node.
This function deletes all nodes with id (find). If you want to delete only the first occurrence, then put a return after the free statement.
void delete(struct bucket *thisBucket, unsigned char find[20]) {
struct node *prev = null;
struct node *curr = thisBucket->nodes;
while (curr != null) {
if (!strcmp(curr->id, find)) { // found the node?
if (prev == null) { // going to delete the first node (header)?
thisBucket->nodes = curr->next; // set the new header to the second node
} else {
prev->next = curr->next;
}
free(curr);
// if deleted the first node, then current is now the new header,
// else jump to the next
curr = prev == null? thisBucket->nodes : prev->next;
} else { // not found, keep going
prev = curr;
curr = curr->next;
}
}
}
The following does not contain any error checking and only removes the current node from the list ...
pPrev->next = pCurrent->next;
Your preferences may vary, but I tend to put my linked list node at the start of the structure (whenever practical).
struct node{
struct node *next;
unsigned char id[20];
};
struct bucket{
struct node *nodes;
unsigned char id;
};
I find this generally helps to simplify pointer arithmetic and allows simple typecasting when needed.
This removes a node given its address; you can modify it to remove a node given its id, but you haven't specified the form of an id -- is it a NUL-terminated string, or is it 20 bytes?
// remove node from bucket and return true
// or return false if node isn't in bucket
int dht_rmnode(struct bucket* bucket, struct node* node)
{
struct node** ppnode = &bucket->nodes;
for( ;; ){
struct node* pnode = *ppnode;
if( pnode == NULL ) return 0;
if( pnode == node ){
*ppnode = pnode->next;
return 1;
}
ppnode = &pnode->next;
}
}
Or, more compactly,
// remove node from bucket and return true
// or return false if node isn't in bucket
int dht_rmnode(struct bucket* bucket, struct node* node)
{
struct node** ppnode = &bucket->nodes;
struct node* pnode;
for( ; (pnode = *ppnode); ppnode = &pnode->next )
if( pnode == node ){
*ppnode = pnode->next;
return 1;
}
return 0;
}
typedef struct node
{
int id;
struct node* next;
}Node;
void delete_element(void)
{
int i;
Node* current=head;
Node* brev=NULL;
if(i==head->id){
head=current->next;
free(current);}
else{
while(NULL!=current->next)
{
if(i==current->next->id){
brev=current;
current=current->next;
break;}
else
current=current->next;
}
if(i==current->id)
{
if(NULL==head->next){
head=NULL;
free(current);}
else
brev->next=current->next;
free(current);
}
else
printf("this id does not exist\n");
}
}

Rotate a linked list

I want to rotate a linked list that contains a number. 123 should be rotated to 231. The function created 23 but the last character stays empty, why?
typedef struct node node;
struct node{
char digit;
node* p;
};
void rotate(node** head){
node* walk= (*head);
node* prev= (*head);
char temp= walk->digit;
while(walk->p!=NULL){
walk->digit=walk->p->digit;
walk= walk->p;
}
walk->digit=temp;
}
How I create the list:
node* convert_to_list(int num){
node * curr, * head;
int i=0,length=0;
char *arr=NULL;
head = NULL;
length =(int) log10(((double) num))+1;
arr =(char*) malloc((length)*sizeof(char)); //allocate memory
sprintf (arr, "%d" ,num); //(num, buf, 10);
for(i=length;i>=0;i--) {
curr = (node *)malloc(sizeof(node));
(curr)->digit = arr[i];
(curr)->p = head;
head = curr;
}
curr = head;
return curr;
}
Your linked list actually has 4 elements.
You should change this line:
for(i = length; i >= 0 ; i--) {
to:
for(i = length - 1; i >= 0; i--) {
because with the former line you're going out of the array (you're accessing arr[length] on the first iteration).
With this change your rotate function works correctly.
You can solve most problems by breaking them down into simpler ones.
Here, I'd write your rotate as follows:
void rotate(node **list) {
node *head = pop_head(list);
push_at_end(list, head);
}
node *pop_head(node **list) {
assert(*list);
node *head = *list;
*list = head->p;
head->p = 0;
return head;
}
void push_at_end(node **list, node *head) {
node *end = get_end(*list);
if (!end) {
*list = head;
} else {
end->p = head;
}
}
node *get_end(node *head) {
node *last = 0;
while (head) {
last = head;
head = head->p;
}
return last;
}
The problem with your question is that the list is stored backwards, and you have a pointer to previous, instead next. This should have been part of the question (it took me a while to understand that).
Actually, you use head when probably tail would have been better. You should consider storing a pointer to the actual head, and avoid this way copying. In that case, you would only need to adjust pointers. If rotation is going to be a common task, then keeping and updating an extra pointer, may be in a list struct, would pay the effort (could change the task from O(n) to O(1)).
struct _list {
node * tail;
node * head;
};
typedef struct _list list;
In any case, the problem with your rotate function is that you are starting with walk and prev at the same node, head.
void rotate(node** head){
node* walk= (*head);
node* prev=(*head)->p;
char temp= walk->digit;
while(prev!=NULL){
walk->digit=prev->digit;
walk= prev;
prev = prev->p;
}
walk->digit=temp;
}
I have written the code for linked list rotation by k nodes in c++. It worked for me perfectly. If you pass k as 1, it will rotate the liked list by 1 node and here it solves the given problem. If you want to rotate the linked list by k nodes, it will still work fine. Please find it below.
Header file :
public:
typedef struct node {
int data;
node *next;
} *Node;
Node head;
void rotateByk(int k);
Following code is for .cpp file.
void DList::rotateByk(int k){
Node current = head;
Node kthNode;
int count = 1;
while(count<=k && current!=NULL){
kthNode = current;
current = current->next;
count++;
}
Node kthNextNode = current;
while(current->next!=NULL){
current = current->next;
}
current->next = head;
head = kthNextNode;
kthNode->next = NULL;
Node printNode = head;
while(printNode!=NULL){
cout << printNode->data << "\t";
printNode = printNode->next;
}
}
Pass k as argument in main method for linked list d1.
d1.rotateByk(1);
Please let me know if you have any queries.

Resources