Working on a linked list where I'm storing a pointer to head as a global variable. My question is: How can I assign a (new)value (in this case address) to head from within a void function?
EDIT
Alright here's some code:
Note: this is not how i would design this, but we're not supposed to stray from the spec.
typedef struct NODE Node;
typedef Node *NodePtr;
struct NODE{
char *item;
Node *next;
};
NodePtr first = NULL; //global
//insert function
Boolean insert( char *new_string ) {
printf("insert called\n");
if(first == NULL) {
first = malloc(sizeof(Node));
first->next = NULL;
first->item = new_string;
}
else {
NodePtr inserted = malloc(sizeof(Node));
inserted->next = first;
inserted->item = new_string;
first = inserted;
}
return 1;
}
the problem is that when i use insert() in a function. it works fine. i get a working list. but when another function tries to access first, its empty.
Am I right in assuming that modifying the global variables within the function does not alter the actual first ptr? I know I could pass in a pointer to first as an argument, but I'm not supposed to modify the prototype design.
You'll need to pass in the pointer and a pointer to pointer to head.. Update pointer to head, and head-> next to old head
if it is a global variable just assign the value like you would have done if it was a local variable in your void function.
assuming your struct is similar to this:
struct list {
int data;
struct list* next;
};
and you have the global variable
struct list* L
you can make a new node by making a new node, making the next variable to the head, and making your global value point to the new node:
newnode->next = L;
L = newnode
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);
}
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.
I have problems with my insert method, as for some reason I end up with infinite loop. Here is my struct:
struct List {
char element;
struct List *next;
};
And here is my insert method:
void insert(struct List *first, char el){
struct List *new=NULL;
struct List *current = first;
new = (struct List*) malloc (sizeof(struct List));
new->element = el;
new->next = NULL;
if (first == NULL){
first = new;
return;
}
while (1){ //this loop never ends
if (current->next == NULL) break;
if (current->next->element < el){
current = current->next;
}else{
break;
}
}
struct List *ex_next = current->next;
current->next = new;
new->next = ex_next;
}
I am aware of similar question here: C - Inserting into linked list in ascending order but it didn't really help me.
The first argument to insert is a pointer. But you need a pointer to a pointer (struct List **first).
If the list is empty, you pass the VALUE NULL into the function (the variable first inside the method have the value NULL). Then you assign a new malloced value to it and return. The variable on the calling side haven't changed and your memory leaked.
When you pass a pointer of a pointer, the variable first holds the address of the variable of the calling method. This way, you can reassign it's value.
Pointers, Pointers of Pointers, Pointers of Pointers of arrays of functions returning function pointers .... thats the fun part of C ;)
#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;