Split linked list shows empty outside the function scope - c

I have a C program which splits a linked list. The logic is this - If the linked list has even number of nodes, split it into equal halves. Else split it with the the parent linked list having one node more than the child linked list.
When I run the below code, the display_LL function in the main loop prints the 'p' linked list correctly.i.e. its split correctly. But the display_LL function prints the 'r' linked list NULL.
Whereas when I am printing the linked lists from inside the 'frontbacksplit_LL' function, 'p' and 'r' linked lists are displayed correctly.
Why this different behavior, I cannot understand.
Is this a scoping problem? If so, what changes do I need to make in the code?
Pls assume linked list 'p' is not an empty linked list. It has nodes. I just omitted the code for clarity. Also the display_LL function code is also not shown.
struct node {
int data;
struct node *link;
};
void main()
{
struct node *p,*q,*r;
p=NULL;
q=NULL;
frontbacksplit_LL(p,r,count(p)); //Imagine p has nodes. count(p) gives number of
printf("Front_Back Splits:\n"); //nodes in the linked list.
display_LL(p); //displays split linked list correctly
display_LL(r); //Shows EMPTY linked list.
getch();
}
frontbacksplit_LL(struct node *a,struct node *b,int node_count)
{
struct node *temp;
int i,t;
temp=a;
if(node_count%2==0) //even
{
for(i=0;i<node_count/2;i++)
temp=temp->link;
b=temp->link;
temp->link=NULL;
}
else
{
for(i=0;i<(ceil(node_count/2));i++)
temp=temp->link;
b=temp->link;
temp->link=NULL;
}
display_LL(a); //Displays split linked list correctly.
display_LL(b); //Displays split linked list correctly.
}

You problem is that you pass pointers p and q by value. So when you change them inside frontbacksplit_LL these changes aren't visible outside the function. You should pass the pointers by pointers rather by value, like
frontbacksplit_LL(struct node **a,struct node **b,int node_count)
Of course, you have to replace all a and b in the function code with *a and *b.

This is because the pointer variables p and r are passed by value to the function frontbacksplit_LL. As a result any changes made inside function frontbacksplit_LL are local to the function ( as you are changing the copies).
Since you want the changes made to variables a and b in function frontbacksplit_LL get reflected in variables p and q in main, you need to pass p and q by address as:
frontbacksplit_LL(struct node **a, struct node **b, int node_count) {
and then access the actual pointers through *a and *b. That is in your existing code replace a with *a and b with *b.
and call it as:
frontbacksplit_LL(&p, &r, count(p));

The problem is here:
struct node *p,*q,*r;
frontbacksplit_LL(p, r, count(p));
In order to do it right, you need to declare r as a pointer to pointer to the second half. In your code r is passed by value, so the result is stored in the local variable b of frontbacksplit_LL. If you pass the address of r (i.e. &r) it would be done correctly.
The function declaration should be:
frontbacksplit_LL(struct node** a, struct node** b, int node_count)
and all the as and bs should be replaced with *a and *b respectively. Then you should call it as
struct node *p = NULL, *q = NULL, *r;
frontbacksplit_LL(&p, &r, count(p));
or
struct node **p = NULL, *q = NULL, **r;
frontbacksplit_LL(p, r, count(p));
In this case you'd need to access the lists through *p and *r.

struct llist {
struct llist *next;
char *payload;
};
struct llist *llist_split(struct llist **hnd );
struct llist *llist_split(struct llist **hnd)
{
struct llist *this, *save, **tail;
unsigned iter=0;
for (save=NULL, tail = &save; this = *hnd; ) {
if ( !this->next) break;
if ( ++iter & 1 ) { hnd = &this->next; continue; }
*tail = this;
*hnd = this->next;
tail = &(*tail)->next;
*tail = NULL;
}
return save;
}
BTW: main() should return int.

Related

What does a function whose 'return type' is a tag do?

I've been learning C for a month now and I've learned/remember that functions are defined like this:
return_type function_name( parameter list ) {
...body
}
But in a lecture about 'list ADTs' the example code which illustrates making and printing a full list there were some pieces of code(function declarations) in a form that I've never seen.
...
typedef struct list{ int data; struct list *next; } list;
list* create_list(int d) {
...
}
To my understanding the return type is ' list '(?) which is a structure tag, and the function name is ' * create_list ' (which is a dereferenced pointer??). I couldn't understand why it was written like that. I want to know how it works and how to use it. How does it differ from other (normal looking)functions like struct create_list(int d) {...}? The instructor didn't mention or explain about these so I'm quite confused.
here is the full code just in case
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
typedef struct list{ int data; struct list *next;} list;
int is_empty(const list *l) { return (l == NULL); }
list* create_list(int d) {
list* head = malloc(sizeof(list));
head -> data = d;
head -> next = NULL;
return head;
}
list* add_to_front(int d, list* h) {
list* head = create_list(d);
head -> next = h;
return head;
}
list* array_to_list(int d[], int size) {
list* head = create_list(d[0]);
int i;
for(i = 1; i < size; i++) {
head = add_to_front(d[i], head);
}
return head;
}
void print_list(list *h, char *title) {
printf("%s\n", title);
while (h != NULL) {
printf ("%d :", h -> data);
h = h -> next;
}
}
int main() {
list list_of_int;
list* head = NULL;
int data[6] = {2,3,5,7,8,9};
head = array_to_list(data, 6);
print_list(head, "single element list");
printf("\n\n");
return 0;
}
any help would be appreciated!
Please correct me if I'm wrong in some point. Thank you
You're close, but reading it wrong. Function names do not have things like * in them, only types do.
This defines a function that returns list* (a.k.a. struct list* which is what typedef establishes earlier) given argument d of type int:
list* create_list(int d) {
// ...
}
In other words, create_list returns a pointer to list. In a type definition * means pointer, but it has a different meaning as an operator, such as:
int x = 0;
int* y = &x;
*y = 5; // Dereference y pointer, make assignment, in other words, assign to x
You can usually spot a dereference operator because it is not part of a type either in a return type specifier, an argument, or a variable declaration. In most other cases it's the dereference operator.
To my understanding the return type is ' list '(?) which is a structure tag
In your example list is both a struct tag and a typedef name. The name space rules of C allow four different categories of identifiers:
lables (for goto etc)
struct/union/enum tags (struct this_is_a_tag).
struct/union members
everything else
It's valid to name identifiers from these different name spaces the same.
In the example
typedef struct list{ int data; struct list *next;} list;
the typedef list identifier isn't available until at the end of the declaration (after the ;). The struct tag struct list is, however. So the struct list *next; member refers to the struct tag, which is a convenient way create a self-referencing struct. Once the typedef is declared, we can either use list to refer to the typedef:ed struct type, or we can use struct list which means the very same thing - when used outside the struct declaration it's just a style preference which form to use.
So list* create_list(int d) is using the typedef list to declare the return type of the function as a pointer to struct, list*. No different from returning any variable by value vs returning a pointer to it.
In this case the function is calling malloc to create a struct variable, so the function needs to return a pointer because anything allocated by malloc is always accessed through pointers.

how does malloc produce an element of a list in C?

This is a code from my programming with C course that prints a list, using ADT structs.
typedef struct list{
int data;
struct list *next;
}list;
int is_empty(const list *l){
return(l==NULL);
}
void print_list(list *h, char *title){
printf("%s\n", title);
while(h!=NULL){
printf("%d :", h -> data);
h = h -> next;
}
}
int main()
{
list list_of_int;
list* head = NULL;
head = malloc(sizeof(list));
printf("size of the list = %lu\n",sizeof(list)); //this has to be an unsigned long
head -> data = 5;
head -> next = NULL;
print_list(head,"single element list");
printf("\n\n");
return 0;
}
My question is, how we used malloc() and the memory it created to create the list pointer head?
The purpose of malloc is "making" legal space and providing a pointer to it.
The following lines in your code make sure that legal space contains values which make a node.
This might seem short, but that's it.
(And I think you confirmed that you now understand. Otherwise I would consider it too short to be polite myself.)

meaning of a struct within a struct in c [duplicate]

This question already has answers here:
What is self-referencing structure in C?
(3 answers)
Closed 3 years ago.
Can someone explain what we mean when we do, like what does struct Node* next do. does it create a pointer of type struct? any help and resources about structures in c would be helpful
struct Node {
int dest;
struct Node* next;
};
"struct" itself is not a type. "struct [tag]" is a type, for example "struct Node" in your code.
In your case you define a structure type. Every structure of that type will contain a pointer to another structure of that type as a member called "next".
This allows you to chain the structures together in a so called linked list. You store a pointer to the first structure in a variable, then you can follow the chain of links down to the structure you need.
For example, you can do
struct Node *start;
start = malloc(sizeof struct Node);
start->dest = 7;
start->next = malloc(sizeof struct Node);
start->next->dest = 13;
start->next->next = malloc(sizeof struct Node);
start->next->next->dest = 19;
printf("%d %d %d\n", start->dest, start->next->dest, start->next->next->dest);
free(start->next->next);
free(start->next);
free(start);
Please note that this code omits all error handling, in real code you have to handle the case when malloc returns NULL.
Also, in real code you would use such a structure in loops that traverse the chain, not directly as above.
As #Serge is pointing out in comments, is not a struct within a struct, is a reference (a pointer) to an object of the same type, an example:
#include <stdio.h>
struct Node {
int dest;
struct Node* next;
};
int main(void)
{
/* An array of nodes */
struct Node nodes[] = {
{1, &nodes[1]}, // next points to the next element
{2, &nodes[2]}, // next points to the next element
{3, NULL} // next points to null
};
/* A pointer to the first element of the array */
struct Node *node = nodes;
while (node) {
printf("%d\n", node->dest);
node = node->next; // node moves to the next element
}
return 0;
}
Output:
1
2
3
Of course, in my example there is no benefit in using a linked list, linked lists are useful when we don't know the number of elements before-hand.
Another example using dynamic memory:
struct Node *head, *node;
node = head = calloc(1, sizeof *node);
node->dest = 1;
while (more_elements_needed) {
node->next = calloc(1, sizeof *node);
node->next->dest = node->dest + 1;
node = node->next;
}
for (node = head; node != NULL; node = node->next) {
printf("%d\n", node->dest);
}

Testing a Linked List

I am reading Skiena's "The Algorithm Design Manual" for personal learning, and I am trying to implement the linked list in C.
How do I use the insert_list() function and then print out my list to verify the values?
/* definition of linked list */
typedef struct list {
int item;
struct list *next;
} list;
/* insert item into list */
void insert_list(list **l, int x) {
list *p;
p = malloc(sizeof(list));
p->item = x;
p->next = *l;
*l = p;
}
I wrote a main function to try and figure out how to use insert_list():
int main(void) {
struct list *root;
struct list *traverse;
root = (struct list *)malloc(sizeof(struct list));
root->next = 0;
root->item = 5;
traverse = root;
insert_list(traverse, 1); /* this is the problem */
printf("%d\n", root->item);
}
I receive an error at compilation with gcc:
expected 'struct list **' but argument is of type 'struct list *
How do I properly use this function to insert items into and then print my list? Without the insert_list() call, it prints root->item as 5, as expected.
You have a nice function. Now: use it.
int main(void) {
// You have a typedef, so you should omit the struct keyword
/*struct */ list *root= NULL, *p;
insert_list(&root, 5);
insert_list(&root, 1);
for (p=root; p; p=p->next){
printf("%d\n", p->item);
}
return 0;
}
As mentioned in the comments, the way to get it to compile is to change the call to insert_list() to this:
insert_list(&traverse, 1);
The insert_list() function takes a pointer to a pointer to a struct list, not just a pointer to a struct list.
You've written the code in an odd way. You're first assigning traverse to be equal to root and then calling the insert_list() function, which will overwrite traverse with the pointer to the new node it creates. At that point, the new node will be the "root" of your tree, not the root node you originally created. This will likely cause confusion when you attempt to traverse the list later.

why two pointers used in structure in c

I read those about tree in c:
struct node
{
int key_value;
struct node *left;
struct node *right;
};
/* insert a value to tree */
insert(int key, struct node **leaf)
{
if( *leaf == 0 )
{
*leaf = (struct node*) malloc( sizeof( struct node ) );
(*leaf)->key_value = key;
/* initialize the children to null */
(*leaf)->left = 0;
(*leaf)->right = 0;
}
else if(key < (*leaf)->key_value)
{
insert( key, &(*leaf)->left );
}
else if(key > (*leaf)->key_value)
{
insert( key, &(*leaf)->right );
}
}
I can't understand here: insert(int key, struct node **leaf) why two pointers **leaf, does *leaf ok? I am confused when to use two pointers.pls help, thank you very much!
In insert(int key, struct node **leaf) you are Passing the Address pointed by *leaf by C version of "Pass By Reference". And in insert(int key, struct node *leaf) you are passing the Address pointed by *leaf by Pass By Value method.Note C Parameter are always Passed by Value.
So, In This particular Case it doesn't matter if you use insert(int key, struct node **leaf) or insert(int key, struct node *leaf) both will achieve the same outputs.The only difference in this case is that in insert(int key, struct node **leaf) your passing the address by C version of Pass by Reference and in insert(int key, struct node *leaf) your passing the address by Pass By Value method.
Example Code A,
#include<stdio.h>
struct node
{
int data;
};
void AddFive(struct node **t);
int main()
{
struct node *n = NULL;
n = new node;
n->data = 5;
printf("%d\n", n->data);
AddFive(&n);
printf("%d\n", n->data);
return 0;
}
void AddFive(struct node **t)
{
(*t)->data = (*t)->data+5;
}
Example Code B,
#include<stdio.h>
struct node
{
int data;
};
void AddFive(struct node *t);
int main()
{
struct node *n = NULL;
n = new node;
n->data = 5;
printf("%d\n", n->data);
AddFive(n);
printf("%d\n", n->data);
return 0;
}
void AddFive(struct node *t)
{
t->data = t->data+5;
}
If you notice both Code A and Code B achieve the same output.
It is call by reference . if we have to change the value of *leaf then we should have its address thats why we used two *'s when is for pointer of leaf and other to get address of *leaf.
When you want to change the value of a variable defined in main() through some function. Think what do you do. You send the address of that variable and then using that address, change the content of that variable.
Now, in an example cases, the variable is of int type, so sending the address of that variable would mean in the function, you have to receive it in a variable of type int *
void test(int* var) {
*var++;
}
int main() {
int integer = 1;
test(&integer);
printf("%d", integer);
return 0;
}
To change the value of the variable integer you send the address of that to the function test().
Now take this same situation, and think if you need to change the content of a variable which is itself a struct node *. Then you send the address of that variable, and receive it with a (struct node *)*. Thats what is happening in the example you posted.
You want the changes that is to be made to the leaf variable in the insert() fucntion to reflect in the calling function. For this to take place you send the address and change the content accordingly.
C has only pass by value. If pointer to node struct is used as parameter then any modification to passed pointer will not be seen in the caller function. In that case you have to return a pointer from the function insert. Pointer to pointer is used here to update the pointer passed to function insert.
Case 1:
When you are passing a address of a variable then a single pointer is enough to access the variable
Example:
struct node a;
func(&a); // calling
In the func() definition:
func(struct node *a);
Here a points to the address of node. And we can access a using its address directly.
Case 2:
When you are sending the address of pointer variable:
struct node *a;
func(&a); // calling
Then in the function definition it should use a double pointer:
func(struct node **a);

Resources