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.
Related
I'm trying to write a function generate_list which will generate a list with one node initialized to with val as 0 and next as NULL. generate_list should not take any arguments.
Here are the requirements:
define a struct datatype named node which contains an integer number and a pointer to the next node of the list.
define a new datatype named list, defined as a pointer to the node. list represents the list's head.
define a function of type list called generate_list which takes no parameters and returns a list with a dummy node (integer number = 0, pointer = NULL).
I tried something like this:
typedef struct list_node {
int val;
struct list_node *next;
}
typedef struct a_list {
node *head;
}
list generate_list() {
list *l = malloc(sizeof(*l));
node d_node;
l->head = &d_node;
d_node.val = 0;
d_node.next = NULL;
return *l;
}
I am not sure if I did correctly the second part and how could I implement the function?
what should I return from it?
There are some problems in your code:
you should include <stdlib.h>
the type definitions must include the type name and end with a ;
the argument list of generate_list should be defined as (void), not () which has a different meaning in C (unlike C++).
the first node should be allocated, not an automatic variable that will become invalid as soon as the function returns.
the list itself should not be allocated, but returned by value, a peculiar requirement that is explicit in the problem specification.
Here is a modified version:
#include <stdlib.h>
typedef struct node {
int val;
struct node *next;
} node;
typedef struct list {
node *head;
} list;
list generate_list(void) {
list l;
l.head = malloc(sizeof(*n));
if (l.head == NULL) {
/* abort with an error message */
perror("generate_list");
exit(1);
}
l.head->val = 0;
l.head->next = NULL;
return l;
}
you actually did pretty well. But, you must return a pointer to the list from your generate_list function.
It should be like this:
a_list *generate_list(void)
{
a_list *list = (a_list *)malloc(sizeof(a_list));
list_node *head_node = (list_node *)malloc(sizeof(list_node);
list->head = head_node;
head_node->val = 0;
head_node->next = NULL;
return list;
}
now you want to generate your list inside the function. but, you also want to return an accessible list. Hence, you must malloc it all (the list and the node) so it wouldn't be a local variable (allocated on the stack and disappear after the function returns).
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);
}
In a program I'm writing I need a linked list, so it's a pretty specific implementation. It needs:
the ability to add a node to the end
the ability to remove a node whose data matches a specified value
The data is a cstring, no more than 20 characters in length. I'm not very experienced with C and am getting errors with the following signature void addToEnd(llist root, char entery[51]). I tried replacing llist with node but then the error is "unknown type name node". How can I get rid of this?
Here's the code
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
typedef struct node
{
char entery[51];
struct node* next;
} llist;
/*may be losing root address permanently*/
void addToEnd(llist root, char entery[51])
{
while(root->next != NULL)
root = root->next;
node last = malloc(sizeof(struct node));
root->next = last;
strcpy(last, entery);
}
int main()
{
struct node *root = malloc(sizeof(struct node));
root->next = NULL;
strcpy(root->entery, "Hello");
struct node *conductor = root;//points to a node while traversing the list
if(conductor != 0)
while(conductor->next != 0)
conductor = conductor->next;
/* Creates a node at the end of the list */
conductor->next = malloc(sizeof(struct node));
conductor = conductor->next;
if (conductor == NULL)
{
printf( "Out of memory" );
return EXIT_SUCCESS;
}
/* initialize the new memory */
conductor->next = NULL;
strcpy(conductor->entery, " world\n");
addToEnd(root, " at the");
addToEnd(root, " end");
/*print everything in list*/
conductor = root;
if(conductor != NULL)
{
while(conductor->next != NULL)
{
printf("%s", conductor->entery);
conductor = conductor->next;
}
printf("%s", conductor->entery);
}
return EXIT_SUCCESS;
}
One thing I'm unclear about, is in all the examples I've seen is they typedef the struct. Why? Let me elaborate: how do you know if you want to be passing just node or struct node. Also I don't really see the point, struct node isn't that much longer than a single typedef'd name.
Problems:
line 12: void addToEnd(llist root, char entery[51]) shall be void addToEnd(llist *root, char entery[51]). Here root must be a pointer type or you actually can not modify its value inside the function and make it visible outside the function.
line 16: node last = malloc(sizeof(struct node)); shall be struct node *last = malloc(sizeof(struct node));. Since in C you must reference a type name with the keyword struct, and also it shall be a pointer or it cannot be initialized with malloc.
As for your typedef question, I believe it is optional and people use it only for convenience. Personally I don't use typedef on a struct very often.
EDITED:
Also your code comes with bugs. Sorry I was only focusing on the syntax before.
Please notice that malloc in C don't assure you that the allocated memory is zeored, it's actually could be anything inside. So you need to fill it manually: to add a line last->next = NULL; at the end of addToEnd.
To refer to your struct of the linked list, use struct node, after the typedef, you can also use llist. You can also ues, as the linked question uses.
typedef struct node
{
char entery[51];
struct node* next;
} node;
In this style, you can use node the same as struct node.
The syntax error you are facing is, you misused the arrow operator ->, it's used with pointers of struct. For struct, use the dot operator .
So for the function
void addToEnd(llist root, char entery[51])
{
while(root->next != NULL)
root = root->next;
You should pass in a pointer:
void addToEnd(llist* root, char entery[51])
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.
I've been trying to figure out pointers in C most of today, even asked a question earlier, but now I'm stuck on something else. I've got the following code:
typedef struct listnode *Node;
typedef struct listnode {
void *data;
Node next;
Node previous;
} Listnode;
typedef struct listhead *LIST;
typedef struct listhead {
int size;
Node first;
Node last;
Node current;
} Listhead;
#define MAXLISTS 50
static Listhead headpool[MAXLISTS];
static Listhead *headpoolp = headpool;
#define MAXNODES 1000
static Listnode nodepool[MAXNODES];
static Listnode *nodepoolp = nodepool;
LIST *ListCreate()
{
if(headpool + MAXLISTS - headpoolp >= 1)
{
headpoolp->size = 0;
headpoolp->first = NULL;
headpoolp->last = NULL;
headpoolp->current = NULL;
headpoolp++;
return &headpoolp-1; /* reference to old pointer */
}else
return NULL;
}
int ListCount(LIST list)
{
return list->size;
}
Now in a new file I have:
#include <stdio.h>
#include "the above file"
main()
{
/* Make a new LIST */
LIST *newlist;
newlist = ListCreate();
int i = ListCount(newlist);
printf("%d\n", i);
}
When I compile, I get the following warning (the printf statement prints what it should):
file.c:9: warning: passing argument 1 of ‘ListCount’ from incompatible pointer type
Should I be worried about this warning? The code seems to do what I want it to, but I'm obviously very confused about pointers in C. After browsing questions on this site, I found that if I make the argument to ListCount (void *) newlist, I don't get the warning, and I don't understand why, nor what (void *) really does...
Any help would be appreciated, thanks.
You're getting confused because of multiple typedefs. LIST is a type representing a pointer to struct listhead. So, you want your ListCreate function to return a LIST, not a LIST *:
LIST ListCreate(void)
The above says: ListCreate() function will return a pointer to a new list's head if it can.
Then you need to change the return statement in the function definition from return &headpoolp-1; to return headpoolp-1;. This is because you want to return the last available head pointer, and you have just incremented headpoolp. So now you want to subtract 1 from it and return that.
Finally, your main() needs to be update to reflect the above changes:
int main(void)
{
/* Make a new LIST */
LIST newlist; /* a pointer */
newlist = ListCreate();
int i = ListCount(newlist);
printf("%d\n", i);
return 0;
}