Manipulating linkedlists in C - c

Why do we have to pass a pointer to a pointer to manipulate a linked list? Why can't we just pass the pointer? I just dont understand the internals of what is happening logically.
I see it as passing in the pointer to the list would suffice, but apparently not.

It depends on your linked list implementation, but for the sake of argument, if you have implemented, say, a push function, like this:
typedef struct linked_list linked_list;
struct linked_list
{
int value;
linked_list *next;
};
void push(linked_list **head, int value)
{
linked_list *temp = *head;
*head = malloc(sizeof(linked_list));
(*head)->value = value;
(*head)->next = temp;
}
then the pointer to a pointer is necessary because, otherwise, you would be modifying push's local head variable, and not the caller's.

In C if you want to pass a parameter which is possibly modified by the function you pass a pointer to the variable containing the modified value:
void swap(int *i, int *j) // modifies the two parameter.
Now if this parameter is itself a pointer, you have to pass a pointer to a pointer. Take for example the function insert which insert a cell in front of a list. If you represent the list as a pointer to its first element, then this pointer has to be modified. So you pass a pointer to it:
with
typedef struct cell *list
void insert(list *pl, struct cell *pc)
^^
Since list is a pointer itself it is a pointer to a pointer since list * is the same as struct cell **.

There's no one line answer to this
Have at look at page no.12 (push()) in this document: http://cslibrary.stanford.edu/103/LinkedListBasics.pdf
Best explanation according to me.

Related

How to use struct array in a function as a parameter in C?

I am trying to fill an array with linkedlist nodes.But I get some errors.
List struct
fillArray method
struct List
{
char frequency[STRING_LEN];
char word[STRING_LEN];
char lineOrder[STRING_LEN];
struct List *next;
};
void fillArray(struct List *nodesArr[50]){
int a=0;
struct List *ptr = head; // head is my first node for linkedlist. I have created this earlier.
while(ptr->next!=NULL){
*nodesArr[a]->frequency=ptr->frequency; // I get error here
*nodesArr[a]->word=ptr->word; // and here *assignment to 'char' from 'char *' makes integer from* //*pointer without a cast*
ptr=ptr->next;
a++;
}
}
*assignment to 'char' from 'char *' makes integer from pointer without a cast [-Wint-conversion]gcc* error
[error][1]
[error2][1]
Also I am declaring nodesArr in main func like this:
struct List *nodesArr[length()];
I am calling fillArray method like this:
fillArray(*nodesArr); // How should I put an array as a parameter?
I don't know how to use struct array as a parameter in a function and what to do to get away from casting error.
Any help would be appreciated
Thanks in advance
Edit
I have transformed fillArray method like this to be more clear.
void fillArray(struct List **nodesArr){
int a=0;
struct List *ptr = head;
while(ptr->next!=NULL){
strcpy(nodesArr[a]->frequency,ptr->frequency);
strcpy(nodesArr[a]->word,ptr->word);
ptr=ptr->next;
a++;
}
}
edit2
head is defined global
struct List *head = NULL;
I fill head linkedlist with this method:
void insertFirst(char *data, char *frequency, char *lineOrder)
{
struct List *link = (struct List *)malloc(sizeof(struct List));
strcpy(link->word, data); // To copy the elements of data to new node's word
strcpy(link->frequency, frequency);
strcpy(link->lineOrder, lineOrder);
link->next = head;
head = link;
}
The confusion that your running into is due to the fact that arrays are not first-class types in C, and there are a lot of things you can't do with them. In particular:
You can't declare a function parameter as an array. If you do, the compiler will silently turn it into a pointer with no warning or error. This is a frequent source of confusion for programmers new to C. In your case, when you declare fillArray(struct List *nodesArr[50]) it is as if you declared fillArray(struct List **nodesArr)
You can't pass an array as a parameter. If you do so, it will silently be converted into a pointer to the array's first (0th) element.
Now the above silent conversions may seem odd, but they usually work out, as array indexing is silenty converted to pointer arithmetic under the hood, so as far as most uses are concerned, you use a pointer to an array's first element the same way you would use the array. So within the function, you can use the double pointer as if it was an array of pointers and things will work out. The only real fly in the ointment is that sizeof does not work properly -- it gives the size of the pointer rather than the size of the array.

Does passing "pointer to structure" to a function create local copies of it in C?

I have a structure like this
struct node
{
int data;
struct node* next;
};
Which I use to create singly linked list.
I created other functions like
int push(struct node* head,int element);
which pushes data onto stack created using node structs.
The function then tries to update the struct node* head passed to it using code(it does other things as well)
head=(struct node*)malloc(sizeof(struct node));
The call is made as such
struct node* stack;
push(stack,number);
It looks like this code created copy of the pointer passed to it. So I had to change the function to
int push(struct node** head,int element)
and
*head=(struct node*)malloc(sizeof(struct node));
The call is made as such
struct node* stack;
push(&stack,number);
So my question is, what was the earlier function doing? Is it necessary to pass struct node** to the function if I want to update original value of pointer or is my approach wrong?
Sorry I cannot provide complete code as it is an assignment.
C always passes by value. To change a variable passed to a function, instead of passing the variable itself, you pass a reference(its address).
Let's say you're calling your function with the old signature
int push(struct node* head,int element);
struct node *actual_head = NULL;
push(actual_head, 3);
Now before calling push, your variable actual_head will have value as NULL.
Inside the push function, a new variable head will be pushed to stack. It will have the same value as passed to it, i.e. NULL.
Then when you call head = malloc(...), your variable head will get a new value instead of actual_head which you wanted to.
To mitigate the above, you'll have to change the signature of your function to
int push(struct node** head,int element);
struct node *actual_head = NULL
push(&actual_head, 3);
Now if you notice carefully, the value of actual_head is NULL, but this pointer is also stored somewhere, that somewhere is its address &actual_head. Let's take this address as 1234.
Now inside the push function, your variable head which can hold the address of a pointer(Notice the two *), will have the value of 1234
Now when you do *head = malloc(...), you're actually changing the value of the object present at location 1234, which is your actual_head object.
C always passes parameters by value (i.e., by copying it). This applies even to pointers, but in that case, it is the pointer itself that is copied. Most of the times you use pointers, that is fine, because you are interested in manipulating the data that is pointed to by the pointer. However, in your situation, you want to modify the pointer itself, so you do indeed have to use a pointer to a pointer.
Yes.
The first version of your program was passing the pointer by value. Although it passed an address (held by the pointer to struct) it didn't pass the pointer's address - necessary to update the value.
Whenever you want to update a variable's value you must pass the variable's address. To pass a pointer address, you need a parameter pointer to pointer to type.
In your case, pointer to pointer to struct node.
The code is not doing what you think but not because it creates a copy of the node, it creates a copy of the pointer.
Try printing
fprintf(stdout, "Address of head: %p\n", (void *) head);
both, inside push() and in the caller function.
The pointer you pass in and the parameter have different addresses in memory although they both point to the same address, storing the result of malloc() in it doesn't persist after the funcion has returned.
You need to pass a pointer to the pointer like this
int push(struct node **head, int element)
{
/* Ideally, check if `head' is `NULL' and find the tail otherwise */
*head = malloc(sizeof(**head));
if (*node == NULL)
return SOME_ERROR_VALUE;
/* Do the rest here */
return SOME_SUCCESS_VALUE_LIKE_0;
}
And to call it, just
struct node *head;
head = NULL;
push(&head, value);
/* ^ take the address of head and pass a pointer with it */
of course, the push() implementation should be very differente but I think you will get the idea.
Everything everybody has said is absolutely correct in terms of your question. However, I think you should also consider the design. Part of your problem is that you are conflating the stack itself with the internal structures needed to store data on it. You should have a stack object and a node object. i.e.
struct Node
{
int data;
struct Node* next;
}
struct Stack
{
struct Node* head;
}
Your push function can then take a pointer to the Stack without any double indirection. Plus there is no danger of pushing something on to a node that is in the middle of the stack.
void push(struct Stack* stack, int value)
{
struct Node* node = malloc(sizeof node);
node->data = value;
node->next = stack->head;
stack->head = node;
}
The function
int push(struct node* head,int element) {
head=(struct node*)malloc(sizeof(struct node));
}
allocate some memory and throw it away (cause memory leak).
Passing “pointer to structure” to a function do create local copies of it.
It is necessary to pass struct node** to the function if you want to update original value of pointer. (using global variables is generally considered as a bad idea)
When you pass stack to your function push(struct node* head,int element)
and do
head=(struct node*)malloc(sizeof(struct node));
The pointer head will update to the memory allocated by malloc() and stack is unaware of this memory as you just passed the value.(which is uninitialized here)
When you pass the address then you have a pointer to pointer which makes the changes inside push() to be reflected on stack
So my question is, what was the earlier function doing?
Your earlier function was defined to receive a pointer to an object. You passed your function an uninitialized struct node pointer. A function can't do anything with a value representing an uninitialized pointer. So your function was passed garbage, but no harm was done because your function immediately ignored it by overwriting with a pointer to allocated memory. Your function is not using the value you passed for anything except temporary local storage now. Upon return from your function, your parameters to the function are thrown away (they are just copies), and the value of your stack variable is as it was before, still uninitialized. The compiler usually warns you about using a variable before it is initialized.
By the way, the pointer value to the allocated memory was also thrown away/lost upon function return. So there would now be a location in memory with no reference and therefore no way to free it up, i.e., you have a memory leak.
Is it necessary to pass struct node** to the function if I want to update original value of pointer or is my approach wrong?
Yes, it is necessary to pass the address of a variable that you want filled in by the function being called. It must be written to accept a pointer to the type of data it will supply. Since you are referencing your object with a pointer, and since your function is generating a pointer to your object, you must pass a pointer to a pointer to your object.
Alternatively, you can return a pointer as a value from a function, for example
struct node * Function() { return (struct node *)malloc(sizeof(struct node)); }
The call would be...
struct node *stack;
stack = Function();
if(stack == NULL) { /* handle failure */ }
So, your approach is not wrong, just your implementation (and understanding) need work.

"Illegal use of selector" in C

As part of a larger project, I am trying to write a C function that searches an implemented sorted linked list for a value in the struct olnode. I'm receiving a few errors, however. I'm new to C and I'm struggling with pointers and double pointers and when to use what, so I think that's part of the problem, but I'm not sure how to fix the problem. All necessary headers are included. This is on Minix 2.0.4 using cc as the compiler.
I can provide any additional necessary code; as I'm unfamiliar with C I'm not sure how much I need to show so I'm providing what I think is needed and nothing more to keep it short.
Global code (other than headers):
#define POOLSZ 53
struct olnode {
int eventnr;
int eventfq;
struct olnode *next;
};
typedef struct olnode olnode;
olnode pool[POOLSZ];
olnode *avail; /* points to first available node */
Function that is returning errors (searches for the passed int, after completion *current should be the olnode that holds the current value):
void
srchfreq(olnode *list, int xfrequency, olnode **current)
{
olnode *previous, *newnext;
while(current->eventfq > xfrequency) {
*previous = &current;
*newnext = current->next;
*current = *newnext;
}
}
Function call of srchfreq() (in a different function):
/* *list points to the first node in the list
(*current).eventfq is the value being searched for
*/
srchfreq(*list, (*current).eventfq, &current);
Errors (line numbers are edited to be with respect to lines in srchfreq() as given above):
line 6: illegal use of selector eventfq
line 7: cannot convert pointer to struct
line 8: illegal use of selector next
line 8: cannot convert pointer to struct
line 9: cannot convert struct to pointer
void
srchfreq(olnode *list, int xfrequency, olnode **current)
{
olnode *previous, *newnext;
while((*current)->eventfq > xfrequency) {
previous = *current;
newnext = (*current)->next;
*current = newnext;
}
}
Second part depends on types of arguments. If list declared as olnode *list, there is no need to dereference it, since function expects a pointer. Second and third arguments are wrong (one of them - to determine which one we need to know how current is declared).
current has type olnode**, or pointer to pointer to oldnode. To get a pointer to an olnode, dereference the pointer once:
*current;
To get the olnode itself, dereference the pointer you got from dereferencing the pointer to the pointer
**current;
So in your case, to grab the field eventfq
(**current).eventfq
C also provides a shortcut where the operation (*ptr).field, is exactly equivalent to prt->field.
In your case, you could apply this with
(*current)->eventfq
Errors, in order of appearance:
Since current is a pointer to a pointer to a olnode, it can't refer to any fields directly; but *current can.
*previous is an olnode, &current is a pointer to a pointer to a pointer to a olnode.
See the first error
*newnext is a olnode
*current is a pointer to a olnode

pointer to pointers for singly linked list in C [duplicate]

This question already has answers here:
What is the reason for using a double pointer when adding a node in a linked list?
(15 answers)
Closed 9 years ago.
I have a question about signly linked lists in C. I've created a linked list with the code shown below :
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node* next;
};
struct node *mknode(int data)
{
struct node* np=malloc(sizeof(struct node));
np->data=data;
np->next=NULL;
return np;
}
struct node * insert (struct node* list,int data)
{
struct node *np;
struct node*curr=list;
struct node* prev=NULL;
np=mknode(data);
for(;curr &&data<curr->data;curr=curr->next )
prev=curr;
np->next=curr;
if(prev)
prev->next=np;
else
list=np;
return list;
}
int main()
{
struct node* head;
head=malloc(sizeof(struct node));
head=insert(head,7);
head=insert(head,2);
head=insert(head,4);
printf("%d",head->data);
printf("%d",head->next->data);
printf("%d",head->next->next->data);
return 0;
}
However,While I search on internet, I've realized that, the double pointer is used for creating linked list instead of a normal pointer.I mean, struct node **list , not struct node * list . I wonder why ? Which one is correct , and If both of them is true , what is the differences between them, I used my implementation with the sample main I wrote here, and it works fine but I dont know why should I use pointer to pointers ? Thanks in advance.
The reason some people use a pointer to a pointer is so that the nodes can be updated without returning a new pointer. In your example, if you wanted to change the head pointer, you would have to create a new pointer and then make head equal to that pointer. With the double pointer, you only have to free the space that the second pointer points to, and then update the second pointer to your new data structure, which keeps your original head pointer
I just use the single pointer in my implementations.
Read here, In this way you can change elements without creating new ones.
What is the reason for using a double pointer when adding a node in a linked list?
Given
struct node { int x; };
struct node **pplist;
struct node *plist;
pplist is a pointer to a pointer to a struct node, while plist is a pointer to a struct node. To change x, you would need to write
*pplist->x = 3;
plist->x = 4;
You would use a pointer to a pointer if you wanted the same variable to point to, say, different lists, or if you wanted to pass a pointer to a function with a side-effect of changing that pointer.
This looks perfectly fine to me.
All a pointer is, is a memory address to somewhere. A double pointer is just a memory address to another memory address which points to some data.
Maybe you can post where you saw node **list and we can explain it better but for now, your code looks good.
it is a bit of naturally, if you call "head = NULL; insert(&head, data);" that then head points to the first element. All functions, that supose to change the content, should be called indirectly.
BUT: this is a matter of coding convention. Some like it hot, some like it cold. The problem with head=insert(head, data); is, that head is unusable, when you forget "head="

Need some help with Linked Lists;

I have a simple question in understanding the pointers and struct definitions in the linked list code.
1)
typedef struct node
{
struct node* next;
int val;
}node;
here if I use two "node" when i initialize node *head; which node I am referring to?
2) Here I use an int val in the struct. If I use a void* instead of int is there any thing thats going to change ?
3)Also if I pass to a function
reverse(node* head)
{
node* temp = head; or node* temp = *head;
//what is the difference between the two
}
I am sorry if these are silly question I am new to c language.
Thanks & Regards,
Brett
<1>
in C you need to specify struct node for structs
struct node
{
...
} node;
the last 'node' is variable of type struct node
e.g.
node.val = 1;
and not a type.
if you want to use 'node' as a type you need to write
typedef struct node { .. } node;
<2>
if you use void* you will need a mechanism to handle what the pointers point to e.g. if void* points to an integer you need keep the integer either on the stack or the heap.
node n;
int value = 1;
n.val = &value; // pointing to a single integer on stack
int values[]={1,2,3};
n.val = values; // pointing to an array of integers on stack
void* ptr = malloc(sizeof(int));
n.val = ptr; // pointing to a single (uninit) integer allocated on heap
int* ptrval = (int*)ptr; // setting an int ptr to the same memory loc.
*ptrval = value; // ptrval now points to same as n.val does
<3>
reverse(node* head)
head is a pointer to your list, *head is the content of what the pointer points to (first node below)
head->[node next]->[node next]->[node
next]
EDIT: rephrased and edited.
EDITx2: apparently the question got edited and a typedef was added so the question was altered.
*head is the dereference of the pointer : ie the actual place in memory that is pointed to by the pointer head...
Think of head as a coat hanger and *head as the coat itself, if that helps.
ie:
struct * coat c; //this is a coat hanger, not a coat
....
struct coat k = *c;//this is the coat itself, not a coat hanger
For #1:
In C, struct's have a separate name space. So if you wrote:
struct foo { ... };
You then have to use struct foo to reference the type. If you tried just foo after the above definition, the compiler would give an error as it doesn't know anything about that unqualified name.
A typedef gives a type an alternate name. A typedef name does not need to be qualified, so once you do:
typedef struct foo foo;
You can now use an unqualified foo to reference the type. Since it's just an alternate name, you can now use struct foo and foo interchangeably.
For #2.
It's possible that if you changed val to a void * it could change the size of the entire structure. Whether that makes a difference will depend on how you've written the rest of your code.

Resources