I am currently trying to push a struct to list, thing is I have to do this without the use of standard libraries (so no malloc, or calloc etc). Therefore I am struggling a bit, this is what I've got so far.
typedef struct node node_t;
struct node{
int val;
node_t *next;
node_t *prev;
};
node_t nodes[10];
node_t blocked[10];
void init(){
for(int i = 0; i < 10; i++){
nodes[i].val = i;
if(i == 0){
nodes[i].next = &nodes[i+1];
nodes[i].prev = NULL;
}
else if(i == 9){
nodes[i].next = NULL;
nodes[i].prev = &nodes[i-1];
}else{
nodes[i].next = &nodes[i+1];
nodes[i].prev = &nodes[i-1];
}
}
}
node_t *push(node_t **arr, node_t node){
node_t *newhead = &node;
printf("%d\n", newhead->val);
newhead->next = (*arr);
printf("%d\n", (*arr)->val);
return newhead;
}
int main(){
init();
node_t *head = &nodes[0];
node_t *blockhead = &blocked[0];
blockhead = push(&blockhead,nodes[3]);
blockhead = push(&blockhead,nodes[4]);
return 0;
}
The problem I have is that the list only keeps track of the last element I've added to the list, and will crash if trying to access the next value in the list which probably means I am trying to access a NULL pointer but everything seems correct as far as I can tell, but maybe I am missing something super obvious? The point of the "push" function as a whole is to simply add the node to the front of the list ahead of everything else.
Your immediate problem is there is no declaration for node prior to:
node_t *newhead = &node;
You are taking the address of something that doesn't exist -- that's never a good idea (and invokes Undefined Behavior and generally a SegFault).
There is no need for nodes to be declared globally and no need for blocked at all (based on your current code). Avoid using global variables. Declare your variables in main() and pass the variables (or a pointer) to any functions as required.
If you are using an array of type node_t as a linked list without allocation, and are then looking to "push" (e.g. add a new node_t at the beginning as the new list address) then you are essentially just needing to have you newnode.next point to your nodes array (as the address of an array is simply a pointer to its first member) and you need array[0].prev to point to the address of newnode.
From what I can glean from your question, the purpose for the code is an exercise in pointer understanding. Regardless of whether you are dealing with a list stored on the stack or one allocated globally, if you change the first-node in the list, you are changing the list address (because the start of the list is the address of the first node) In order to change the list address within a function, you must pass the address of the list as a parameter to the function --or-- you return a pointer to the new first node and assign address to your list pointer back in the caller. (both are shown below)
Since you are wanting to "push" a locally declared node to the head of the list, in like manner, you must pass the address of that node to your push function so it is working with the actual address of that node rather than the address of the copy of the node created if the node itself is passed as a parameter to your push function. You can do this with something similar to the following to handle addressing your array of nodes as a list through a new node pushed to the head of the list:
/* push takes address of array and address of node as parameters */
node_t *push (node_t **arr, node_t *node)
{
node->next = *arr; /* next for new node is list address */
(*arr)[0].prev = node; /* prev for list is new node address */
*arr = node; /* new node address is new list address */
return node; /* return pointer to new 1st node */
}
Above you are simply setting newnode->next to the current list address, then setting the list->prev to point to the new node, and then setting the list address as the address of the newnode (a pointer to that address is also returned which can be assigned back in the caller, as needed).
The remainder of the changes were really just clean-ups to what you had, adding parameters to your functions as required so that nodes can be properly declared in main() and adding a prn function to print the list. Also node there are no magic numbers used in the code. If you need a constant #define one (or more), or use a global enum to define them (that is a valid use of a global).
Putting it altogether, you could do something like the following:
#include <stdio.h>
#define LMAX 10 /* if you need a constant, define one */
typedef struct node {
int val;
struct node *prev, *next;
} node_t;
void init (node_t *nodes)
{
for (int i = 0; i < LMAX; i++){
nodes[i].val = i;
if (i == 0)
nodes[i].prev = NULL;
else {
nodes[i-1].next = &nodes[i];
nodes[i].prev = &nodes[i-1];
}
}
}
/* push takes address of array and address of node as parameters */
node_t *push (node_t **arr, node_t *node)
{
node->next = *arr; /* next for new node is list address */
(*arr)[0].prev = node; /* prev for list is new node address */
*arr = node; /* new node address is new list address */
return node; /* return pointer to new 1st node */
}
/* simple print list */
void prn (node_t *list)
{
for (; list; list = list->next)
printf (" %d", list->val);
putchar ('\n');
}
int main (void) {
node_t nodes[LMAX], /* array of nodes */
*head = nodes, /* list pointer */
singlenode = { .val = LMAX }; /* new node to push */
init(head); /* init list */
prn (head); /* print list */
push (&head, &singlenode); /* push new node to list */
prn (head); /* print new list */
return 0;
}
Example Use/Output
$ ./bin/lldblstatic
0 1 2 3 4 5 6 7 8 9
10 0 1 2 3 4 5 6 7 8 9
Look things over, paying attention to the use of addresses and pointers. If you have further questions, do not hesitate to ask.
Related
I'm still learning how to program in C and I've stumbled across a problem.
Using a char array, I need to create a linked list, but I don't know how to do it. I've searched online, but it seems very confusing. The char array is something like this char arr[3][2]={"1A","2B","3C"};
Have a look at this code below. It uses a Node struct and you can see how we iterate through the list, creating nodes, allocating memory, and adding them to the linked list. It is based of this GeeksForGeeks article, with a few modifications. I reccommend you compare the two to help understand what is going on.
#include <stdio.h>
#include <stdlib.h>
struct Node {
char value[2];
struct Node * next;
};
int main() {
char arr[3][2] = {"1A","2B","3C"};
struct Node * linked_list = NULL;
// Iterate over array
// We calculate the size of the array by using sizeof the whole array and dividing it by the sizeof the first element of the array
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
// We create a new node
struct Node * new_node = (struct Node *)malloc(sizeof(struct Node));
// Assign the value, you can't assign arrays so we do each char individually or use strcpy
new_node->value[0] = arr[i][0];
new_node->value[1] = arr[i][1];
// Set next node to NULL
new_node->next = NULL;
if (linked_list == NULL) {
// If the linked_list is empty, this is the first node, add it to the front
linked_list = new_node;
continue;
}
// Find the last node (where next is NULL) and set the next value to the newly created node
struct Node * last = linked_list;
while (last->next != NULL) {
last = last->next;
}
last->next = new_node;
}
// Iterate through our linked list printing each value
struct Node * pointer = linked_list;
while (pointer != NULL) {
printf("%s\n", pointer->value);
pointer = pointer->next;
}
return 0;
}
There are a few things the above code is missing, like checking if each malloc is successful, and freeing the allocated memory afterwards. This is only meant to give you something to build off of!
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);
}
i'm having trouble with building a linked list using two structs
node - contains data and pointer to the next, and list which contains pointer to the head of the list.
i managed to implement it with only the node struct.
i have initialized a struct of a list in the main function
than allocated memory for a list struct using malloc
than i allocated memory for the head which is a pointer to the first node
sent it to another function where there the input,allocating,assigning goes,
but im having hard time to understand how to go through the list without changing the pointer to the head.
and after im done with the nodes and assignment how to get the head pointer to
point back at the start of the list.
should i work with copies? (node *temp) ??
thanks everyone!
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
typedef struct node
{
int data;
struct node *next;
}node;
typedef struct list
{
struct node *head;
}list;
void main()
{
list *list_a;
list_a = (list*)malloc(sizeof(list));
list_a->head = (node*)malloc(sizeof(node));
assignment(list_a);
}
void assignment(list *list_a)
{
int data;
printf("please enter the numbers:\n(to stop enter ""-1"")\n\n");
scanf("%d", &data);
while (data != -1)
{
list_a->head->data = data;
list_a->head->next = (node*)malloc(sizeof(node));
list_a->head = list_a->head->next;
printf("enter a number:\n");
scanf("%d", &data);
}
}
There are a number of ways to do a linked list, from the mind-numbingly simple add-at-head (which ends up with a list in reverse order) to a fairly standard add-at-tail where you iterate over your nodes to find the end node, and add the new node there. In all cases, it is just a matter of handling your pointers correctly, allocating storage (for both your list parent struct, and each node) and validating all allocations, and then cleaning up after yourself and freeing the used memory when it is no longer needed.
Nested structures where you have a struct holding the head node (and hopefully other useful data to justify the nested approach) are quite common, but there is no need for a parent struct for the list itself. The list address is simply the address of the first node.
When learning lists, it really helps to break the tasks of managing the list down into simple separate functions. This allows you to concentrate (a bit easier) on each list operation singularly. For example, with your list, you will need to:
create/allocate for each node, initialize next pointer NULL and set the data value;
create/allocate for your list, allocating for head and initializing any additional information contained in the list struct;
add nodes to your list, creating the list if needed and adding the node setting data to the proper value and updating any list information needed;
get data out of your list; and
finally freeing the memory for your nodes and your list when it is no longer needed.
In your case, and continuing from my comment to your question, you can declare your structure and typedefs similar to the following:
typedef struct node {
int data;
struct node *next;
} node_t;
typedef struct list {
struct node *head;
size_t n; /* at least make parent hold list size */
} list_t;
Here we a simply added a counter to track the number of nodes in your list as an additional, useful, piece of data to justify the outer stuct. It gives you the node count without having to iterate over the list each time to obtain in (it's just a small efficiency improvement if you need that data). You have the number of nodes in your list with a simple list->n.
Following our list outline, you need a way to create nodes for your list. Whether it is the first node, or last node, you don't care. When you need a node, your create_node function should handle the allocation/validation and initialization. Nothing fancy is needed, e.g.
/** function to create node and set data value to data.
* returns new node on success, NULL otherwise.
*/
node_t *create_node (int data)
{
node_t *newnode = malloc (sizeof *newnode); /* allocate */
if (newnode == NULL) { /* validate/handle error */
perror ("create_node() malloc-newnode");
return NULL;
}
newnode->data = data; /* initialize members */
newnode->next = NULL;
return newnode; /* return pointer to new node */
}
Your create_list function simply needs to allocate for the list struct (and I also have it allocate the first node and initialize the values and pointer 0/NULL). You can have it do whatever you like, e.g. add another parameter passing data for the fist node, etc. I simply have it create the list and first node.
/** function to create list and allocates/initilizes head, set list->n = 0.
* returns new list on success, NULL otherwise.
*/
list_t *create_list (void)
{
node_t *head = NULL;
list_t *list = malloc (sizeof *list); /* allocate list */
if (!list) { /* validate/handle error */
perror ("create_list() malloc-list");
return NULL;
}
head = create_node (0); /* create the first node */
if (!head) /* validate/handle error */
return NULL;
list->head = head; /* initialize list values */
list->n = 0;
return list; /* return list */
}
Your add_node function can be fairly simple, but for purposes here, rather than just stopping if the list is not yet allocated, we will have the add_node function create the list if it doesn't exists and then add the node. This choice has important implications. Since I will handle the case where the list doesn't exist, that means the list address may change within the function. To handle this potential, I must pass the address-of the list as a parameter (e.g. list_t **list instead of simply list_t *list). By having the actual address of the pointer, I can change where the original pointer points and that change will be visible back in the calling function (rather changing where a copy of the pointer points which would not be seen back in the caller).
The function needs to handle two cases (1) "am I the first node?" and (2) "if I'm not the first node, then iterate to end and add there". You can do something similar to:
/** add node to list, create list if list NULL, set node->data to data.
* return new node on success, NULL otherwise.
*/
node_t *add_node (list_t **list, int data)
{
node_t *node;
if (!*list) { /* handle list doesn't exist */
*list = create_list();
if (!*list)
return NULL;
node = (*list)->head; /* (..)-> required by operator precedence */
node->data = data;
}
else { /* list already exists */
node = (*list)->head; /* set node to list->head */
/* iterate over nodes to find last and add node at end */
while (node->next)
node = node->next;
node->next = create_node (data); /* allocate next node */
node = node->next; /* change to new node */
}
(*list)->n++; /* increment number of nodes in list */
return node; /* return node */
}
By doing it this way, I can simply declare the pointer in main() and initialize it NULL and then simply call add_node(&list, x) in main() letting the list functions handle the pointers and allocation.
Your additional list functions are just functions that iterate over each node in the list doing something with the information like printing the list or freeing all the nodes in the list. (pay careful attention to how the node-to-be-freed (e.g. the victim) is handled in the free_list function)
/** print the value of each node in list */
void prn_list (const list_t *list)
{
/* iterate over list printing data value */
for (node_t *node = list->head; node; node = node->next)
printf (" %d", node->data);
putchar ('\n'); /* tidy up with newline */
}
/** free all nodes in list and free list */
void free_list (list_t *list)
{
node_t *node = list->head; /* set node to head */
while (node) { /* iterate over each nod */
node_t *victim = node; /* setting victim to free */
node = node->next; /* change to next node */
free (victim); /* free victim */
}
free (list); /* free list */
}
(note the two different examples of iterating over the nodes using either a for or while loop)
Putting all the pieces together, adding 25 nodes, and printing them out before freeing all memory associated with the list, you could do something like the following:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#if ! defined (_WIN32) && ! defined (_WIN64)
#include <stdlib.h> /* Linux has malloc/free in the stdlib header */
#endif
typedef struct node {
int data;
struct node *next;
} node_t;
typedef struct list {
struct node *head;
size_t n; /* at least make parent hold list size */
} list_t;
/** function to create node and set data value to data.
* returns new node on success, NULL otherwise.
*/
node_t *create_node (int data)
{
node_t *newnode = malloc (sizeof *newnode); /* allocate */
if (newnode == NULL) { /* validate/handle error */
perror ("create_node() malloc-newnode");
return NULL;
}
newnode->data = data; /* initialize members */
newnode->next = NULL;
return newnode; /* return pointer to new node */
}
/** function to create list and allocates/initilizes head, set list->n = 0.
* returns new list on success, NULL otherwise.
*/
list_t *create_list (void)
{
node_t *head = NULL;
list_t *list = malloc (sizeof *list); /* allocate list */
if (!list) { /* validate/handle error */
perror ("create_list() malloc-list");
return NULL;
}
head = create_node (0); /* create the first node */
if (!head) /* validate/handle error */
return NULL;
list->head = head; /* initialize list values */
list->n = 0;
return list; /* return list */
}
/** add node to list, create list if list NULL, set node->data to data.
* return new node on success, NULL otherwise.
*/
node_t *add_node (list_t **list, int data)
{
node_t *node;
if (!*list) { /* handle list doesn't exist */
*list = create_list();
if (!*list)
return NULL;
node = (*list)->head; /* (..)-> required by operator precedence */
node->data = data;
}
else { /* list already exists */
node = (*list)->head; /* set node to list->head */
/* iterate over nodes to find last and add node at end */
while (node->next)
node = node->next;
node->next = create_node (data); /* allocate next node */
node = node->next; /* change to new node */
}
(*list)->n++; /* increment number of nodes in list */
return node; /* return node */
}
/** print the value of each node in list */
void prn_list (const list_t *list)
{
/* iterate over list printing data value */
for (node_t *node = list->head; node; node = node->next)
printf (" %d", node->data);
putchar ('\n'); /* tidy up with newline */
}
/** free all nodes in list and free list */
void free_list (list_t *list)
{
node_t *node = list->head; /* set node to head */
while (node) { /* iterate over each nod */
node_t *victim = node; /* setting victim to free */
node = node->next; /* change to next node */
free (victim); /* free victim */
}
free (list); /* free list */
}
int main (void)
{
list_t *list = NULL; /* just declare list and set pointer NULL */
for (int i = 0; i < 25; i++) /* add 25 nodes to list */
if (add_node (&list, i + 1) == NULL) /* validate each addition */
break;
/* print list content, beginning with number of nodes in list */
printf ("list contains: %lu nodes\n\n", list->n);
prn_list (list); /* followed by each node value */
free_list (list); /* and then delete list */
return 0;
}
Example Use/Output
$ /bin/llsingle_w_parent
list contains: 25 nodes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/llsingle_w_parent
==14749== Memcheck, a memory error detector
==14749== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==14749== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==14749== Command: ./bin/llsingle_w_parent
==14749==
list contains: 25 nodes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
==14749==
==14749== HEAP SUMMARY:
==14749== in use at exit: 0 bytes in 0 blocks
==14749== total heap usage: 26 allocs, 26 frees, 416 bytes allocated
==14749==
==14749== All heap blocks were freed -- no leaks are possible
==14749==
==14749== For counts of detected and suppressed errors, rerun with: -v
==14749== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Linked-lists come in all different implementation. You should be aware of a couple of basic distinctions. You have lists that use dummy-node (e.g. dummy head and tail node that do not hold data, but just point to the first/last node in the list). You have circular-linked-lists where the last node points back to the first node (this allows iterating from any node in the list, to any node in the list in a circular fashion across the start and end). So when you look at "linked-list" code, understand that there can be many ways that lists are implemented, all have strengths and weaknesses, so you just have to match your list for the job.
Finally, as specified in the comment, your declaration void main() is incorrect and is an ancient throwback to the early days of windows (like DOS 3.3 and Windows 3.1, Trumpet WinSock, and the Borland Turbo C compiler days) The proper declarations for main are int main (void) and int main (int argc, char **argv) (which you will see written with the equivalent char *argv[]). note: main is a function of type int and it returns a value. See: C11 Standard ยง5.1.2.2.1 Program startup p1 (draft n1570). See also: See What should main() return in C and C++?
(note: there are some embedded systems that continue to use void main(), but those are the exceptions, not the rule, and are non-compliant with the C-Standard)
Look things over and let me know if you have further questions.
but im having hard time to understand how to go through the list without changing the pointer to the head
Head itself would be the pointer to the first node.
and after im done with the nodes and assignment how to get the head pointer to point back at the start of the list.
You make the new node point to the first node & then shift the pointer pointing to the first node i.e. head to point to the newly added node.
IMPORTANT - You are missing stdlib.h without which malloc can't be used.
Here is a crude version (just for understanding):
while(/*IF YOU WANT TO ADD NODES?*/)
{
if(head == NULL)
{
head = malloc((sizeof(struct node));
head->data = //USER INPUT;
head->next=NULL;
}
else
{
temp = malloc(sizeof(struct node));
temp->data = //USER INPUT;
temp->next = head;
head=temp;
}
}
This entire this can be seen in several steps:
First: head->[data||NULL]
Second: temp->[data||Pointer pointing to 1st node]->(head)[data||NULL]
MOVING HEAD TO MAKE IT POINT TO THE NEW 1st NODE
Third: head->[data||Pointer pointing to Previous 1st node]->[data||NULL]
Isn't it cowardly behaviour to downvote without a valid reason?
This will most likely seem like I am missing something obvious but when I try to pass a Linked List pointer to my Selection sort I get a NULL pointer problem. In my C code I have this as my linked list:
typedef struct iorb
{
int base_pri;
struct iorb *link;
char filler[100];
} IORB;
Then I pass my new linked list into this function after creating it:
void swapNodes(POINTER *head, POINTER CurrentHead, POINTER CurrentMinimum, POINTER TempSwap);
POINTER SortList(POINTER *head, char *SortMethod[])
{
POINTER TempHead = *head;
//Only one node, no need to sort.
if (TempHead->link == NULL)
{
return head;
}
//Store node with the new minimum value.
POINTER TempMin = *head;
//Store curent node for swapping
POINTER TempSwap = *head;
//Transverse the list.
POINTER TempCurrent;
for (TempCurrent = *head; TempCurrent->link != NULL; TempCurrent = TempCurrent->link)
{
//Check if this node has a lower priority than the current minimum and if so, swap them.
if (TempCurrent->link->base_pri < TempMin->base_pri)
{
TempMin = TempCurrent->link;
TempSwap = TempCurrent;
}
}
//Swap nodes if the head is not the same as the minimum.
if (TempMin != TempHead)
{
swapNodes(&TempHead, TempHead, TempMin, TempSwap);
}
//Recursively sort the rest of the list.
//FOR SOME REASON THE NODE POINTER IS NOT BEING PASSED HERE (EMPTY)
TempHead->link = SortList(TempHead->link, *SortMethod);
return head;
}
void swapNodes(POINTER *head, POINTER CurrentHead, POINTER CurrentMinimum, POINTER TempSwap)
{
//Set new head as the minimum.
*head = CurrentMinimum;
//Link the current temp swap to the head.
TempSwap->link = CurrentHead;
//Swap pointers.
POINTER temp = CurrentMinimum->link;
CurrentMinimum->link = CurrentHead->link;
CurrentHead->link = temp;
}
I am not sure why it is isn't being passed back into the same function, when I debug the linked list seems okay. I suspect that I am missing something in the swap node function, but I don't quite understand what this is. Can someone please offer some insight as to how this code should go for swapping the nodes around?
If you need additional information please let me know.
SortList(TempHead->link, *SortMethod); needs to be listed as SortList(&TempHead, *SortMethod);
To correctly pass the pointer.
#include<stdio.h>
typedef struct Node
{
int data;
struct Node *next;
struct Node *prev;
} node;
void insert(node *pointer, int data)
{
while(pointer->next!=NULL)
{
pointer = pointer -> next;
}
pointer->next = (node *)malloc(sizeof(node));
(pointer->next)->prev = pointer;
pointer = pointer->next;
pointer->data = data;
pointer->next = NULL;
}
int main()
{
node *start;
start = (node *)malloc(sizeof(node));
int data;
scanf("%d",&data);
insert(start,data);
}
Well, I'm trying to understand the basics of lists in C. I have one question here - the 3rd line from the insert()'s bottom - what is this for? It seems like if the first list's element remains empty and the data is being saved into the second one. But only this works.
In main() there's being created first empty element, right?
while() is not executed as the element is null.
Then the second element is being created. (pointer->null)
Pointer pointing to the first element is set to point to the second element (that 3rd line from the bottom)
And the data is being saved to that second element.
Where do I make a mistake?
pointer = pointer->next;
This line changes the current node we're concentrating on from the last node of the original list to the newly allocated last node of the new list (i.e. the node after the last node of the original list). We then set that node's values directly in the next two lines.
You could get rid of this line and change the two lines below it to read
pointer->next->data = data;
pointer->next->next = NULL;
and you would have the same result.
Edit: Looking further into things, I see more issues:
1) You need #include <stdlib.h> to use malloc().
2) You need to explicitly set start->next = NULL; before you call insert().
In your insert function, you have this assignment:
pointer = pointer->next;
This will not work, as the pointer pointer is passed by value. This means that all changes to the value will be lost when the function returns.
You can pass the pointer by reference:
void insert(node **pointer, int data)
{
/* ... */
*pointer = (*pointer)->next;
/* ... */
}
Or return the pointer from the function:
node *insert(node *pointer, int data)
{
/* ... */
return pointer;
}
There is also the problem that you don't initialize the pointers in the node structure. This means that when you allocate a node structure, the fields in it will be pointing to seemingly random locations.
This is solved simply by setting the next and prev pointer to NULL directly after allocation:
start = malloc(sizeof(node));
start->next = NULL;
start->prev = NULL;