I want this function to add a point to the beginning of the linked list:
void addPoint(Point *head, int x, int y, SDL_bool dir) {
Point *p = malloc(sizeof *p);
p->x = x;
p->y = y;
p->dir = dir;
p->next = head;
head = p;
}
The head is initialized earlier like so:
Point *down = NULL;
Afterwards I call the function like so:
addPoint(&down, x * grid_cell_width, (y - 1) * grid_cell_height, SDL_FALSE);
Unfortunately this does not work as After after the call the head is still NULL.
You are passing a pointer to head, meaning you are passing a copy of the address of head to function addPoint. In the line where you are changing the value of head you are actually modifying the local pointer. To change that, you need to pass a pointer to a pointer, like so:
void addPoint(Point **head, int x, int y, SDL_bool dir) {
Point *p = malloc(sizeof(Point));
p->x = x;
p->y = y;
p->dir = dir;
p->next = head;
*head = p;
}
You got this part right:
addPoint(&down,...);
but the type of the expression &down is Point **, not Point *, so you need to change the definition of addPoint to
void addPoint(Point **head, int x, int y, SDL_bool dir) {
...
p->next = *head;
*head = p;
}
With this code, you have the following relationships:
head == &down // Point ** == Point **
*head == down // Point * == Point *
So in the addPoint function, writing to *head is the same as writing to down.
Try something like:
void addPoint(Point **head, int x, int y, SDL_bool dir) {
Point* p = malloc(sizeof(p));
p->x = x;
p->y = y;
p->dir = dir;
p->next = head;
*head = p;
}
In C there is no pass-by-reference mechanism per se, you just pass pointers to arguments instead (in this case, a pointer to a pointer). But those pointers are still just values, so a change to them is not visible outside of the function. What will be visible is a change to the value that the pointer points to. That's why you need to assign your p pointer to the location that the pointer head points to, hence you need to dereference it with (*) operator first.
Related
Concerning double indirection (pointer to pointer) and passing those to a function
I cannot change the pointer here in function void test(int **nmbr, int *n);
int n = 5;
int n2 = 555;
int *nPtr = &n;
int *n2Ptr = &n2;
printf("the number = %d\n", *nPtr);
test(&nPtr, n2Ptr);
printf("the number is now = %d\n", *nPtr);
test
void test(int **nPptr, int *n2Ptr) {
int *p = *nPptr;
p = n2Ptr;
}
since the pointer p points to a copy of *nPtr, right?
But what about this code (this time the pointer points to a given struct in a linkedlist
the code snipped is from the site https://www.learn-c.org/en/Linked_lists
int remove_by_index(Person **head, int n) {
int i = 0;
int retval = -1;
Person *current = *head;
Person *temp_node = NULL;
if (n == 0) {
return pop_first(head);
}
for (i = 0; i < n-1; i++) {
if (current->next == NULL) {
return -1;
}
current = current->next;
}
temp_node = current->next;
retval = temp_node->nmbr;
current->next = temp_node->next;
free(temp_node);
return retval;
}
it removes a given node in the list by a given indexnumber
Here one can see that *current is local copy in the function and traversate in the list and lastly merges two nodes, without problem
So why does it work to change the pointer here but not in the function test(int **nPptr, int *n2Ptr)?
To be clear
in the function test:
int *p = *nPptr;
p is local copy and copies the pointer from *nPtr
in the function remove_by_index
Person *current = *head;
current is local copy and copies the pointer from *head. The list lives beyond the scope of the function remove_by_index(..) so I do not understand why it can be manipulated in the function by the local pointer *current, at the same time as it does not work to alter nPtr in function test(..)
In a function, changes to pointer variables or pointer parameters have no effect outside the function. However, if the pointer is pointing to an object outside the function, that object can be modified by dereferencing the pointer.
For example, in OP's test function:
void test(int **nPptr, int *n2Ptr) {
int *p = *nPptr;
p = n2Ptr;
}
p is initialized and then its value is changed by an assignment. This has no effect on any object outside the function. If the function were changed as follows:
void test(int **nPptr, int *n2Ptr) {
int *p = *nPptr;
p = n2Ptr;
*nPptr = p;
*p = 42;
}
Then two objects outside the function will have been modified (an int * and an int).
In OP's remove_by_index function, changes to the current variable as it progresses through the linked list have no external effect, but the line:
current->next = temp_node->next;
is equivalent to:
(*current).next = (*temp_node).next;
The external Person object that current is pointing to on the linked list has been modified by dereferencing of the pointer and assignment to the next member of the Person it is pointing to.
Generally, I know that a pointer stores the memory address of another value located in computer memory, for example:
int firstvalue= 5
int * p1;
p1 = &firstvalue; // p1 = address of firstvalue
What happens if we define an operation like the following in a linked list? Does *current=*list means that the value pointed to by current equals to the value pointed to by list? And what does it mean if we define ecur=current?
int function(struct list_t **list){
struct list_t *ecur=NULL;
struct list_t *current=*list;
ecur=current;
}
Update:
What does it do *list=remove(*list, param1, param2)? And why is that?
remove is a function that returns a modified list of list.
Update 2:
Why do we need to define a pointer to pointer in order to modify the list? Is *list a pointer to pointer?
The variable list is a pointer to a pointer to a struct list_t. If we (just as an example) assume that the struct is placed at address 2000 and that the unnamed pointer is at address 1000 it will look like this:
Then you have the initialization that adds two new variables. Both as pointer to a struct list_t.
struct list_t *ecur=NULL;
struct list_t *current=*list;
So the picture now becomes:
Notice that current got the same value as the "some-pointer" in the middle because it is *list that was assigned to current.
Then you have the assignment:
ecur=current;
which means that ecur gets the same value as current and gives the picture:
Update: What does it do *list=remove(*list, param1, param2) ?
It changes the value of the "some-pointer" in the middle of the picture. This is for instance needed if the remove function removes the first element in a linked list.
Why do we need to define a pointer to pointer in order to modify the list? Is *list a pointer to pointer?
Remember that C passes all function arguments by value - the formal argument in the function definition is a different object in memory from the actual argument in the function call. For example:
void swap( int a, int b )
{
int tmp = a;
a = b;
b = tmp;
}
void foo( void )
{
int x = 1;
int y = 2;
swap( x, y );
}
a is a different object in memory than x, and b is a different object in memory than y, so swapping a and b has no effect on x and y. In order to swap the values of x and y, you must pass pointers to them:
void swap( int *a, int *b )
{
int tmp = *a;
*a = *b;
*b = tmp;
}
void foo( void )
{
int x = 1;
int y = 2;
swap( &x, &y );
}
The expression *a is the same as x, so writing to *a is the same as writing to x. Same for *b and y.
So, in order for a function to write to a parameter, you must pass a pointer to that parameter:
void foo ( T *arg )
{
*arg = new_value(); // writes a new value to the thing arg points to
}
void bar( void )
{
T var;
foo( &var ); // write a new value to var
}
This is true for any non-array type T. Let's replace T with a pointer type P *:
void foo( P **arg )
{
*arg = new_value(); // write a new *pointer* value to the thing arg points to
}
void bar( void )
{
P *var;
foo( &var ); // write a new pointer value to var
}
The semantics are exactly the same - all that's changed is the type.
If a function has the potential to modify a list * object (say pointing it at a new list head), then you must pass a pointer to that list * object:
void add_node( struct list_t **list, struct list_t *node )
{
if ( !*list || (node->value < (*list)->value) ) // make node new head of list
*list = node;
else
// add node somewhere else in the list
}
int main( void )
{
struct list_t *list = NULL;
...
struct list_t *node = newNode( value );
add_node( &list, node );
...
}
TYPE *p = ptype /*variable of type: TYPE * */;
is not an assignment. It's an initialization, which for an auto-matic (=on-the-stack) p can be rewritten as:
TYPE *p;
p = ptype;
(not TYPE *p; *p=ptype; /*would be a type error*/)
In terms of your example:
struct list_t *current=*list;
sets where current will point to (the same place as what *list points to (*list is also a pointer because list is a doubly-indirect pointer)) without doing anything whatsoever with what current will point at (*current) after the initialization.
All of this is just conceptual, though. Your function doesn't have any externally visible effects so an optimizing compiler should completely delete its body.
I had a similar knot in my head with this post. I'd like to rearrange your function a bit, so it's easier to understand what's going on:
int function(struct list_t **list)
{
struct list_t *current = *list;
struct list_t *ecur = current;
}
If we call this function with an element foo we essentially get this:
struct list_t foo = { .data = "foo" };
struct list_t *bar = &foo;
struct list_t **list = &bar;
struct list_t *current = *list;
struct list_t *ecur = current;
We have five declarations and five assignments. For better readability, I'll write everything down without declarations:
foo = { .data = "foo" };
bar = &foo;
list = &bar;
current = *list;
ecur = current;
Now, let's walk through it:
foo is a struct. It contains the above data-field.
bar is a pointer to struct. It contains the address of foo
list is a pointer to a pointer to struct. It contains the address of bar
current is a pointer to struct. It contains the contents of the contents of list, which is the address of foo
ecur is a pointer to struct. It's identical to current and contains the address bar
In the end we can simplify the whole example to this:
struct list_t foo = { .data = "foo" };
struct list_t *ecur = &foo;
What does it all mean?
list: Because list is a pointer to a pointer you are able to modify bar to point to something completely different, by de-referencing it (*list = ...)
current/ecur: that's what bar originally pointed too. By de-referencing you could change the data-field itself ((*ecur).data = "banana" or better ecur->data)
I hope I could clarify things and didn't make it worse ;)
Why do we need to define a pointer to pointer in order to modify the
list?
Let me add a complete program, albeit short, to illustrate it better. It defines a simply linked list and builds it while keeping it ordered. Yes, I know it would be easier to simply call qsort(), but I want to demonstrate how adding one level of indirection —the pointer to pointer— allows to insert elements smoothly, without testing for special cases.
// C pointer exercise: sort arguments
#include <stdio.h>
#include <strings.h>
#include <stdlib.h>
struct list
{
char *arg;
struct list *next;
};
int main(int argc, char *argv[])
{
// pointer to base, running pointer and pointer to pointer
struct list *base = NULL, *p, **pp;
for (int i = 1; i < argc; ++i)
{
struct list *new_entry = malloc(sizeof(struct list));
if (new_entry)
{
new_entry->arg = argv[i];
// find where to insert new entry
for (pp = &base; *pp; pp = &(*pp)->next)
if (strcasecmp(new_entry->arg, (*pp)->arg) < 0)
break;
// insertion in a simply linked list
new_entry->next = *pp;
*pp = new_entry;
}
}
// display and cleanup
for (p = base; p;)
{
struct list * tmp = p->next;
puts(p->arg);
free(p);
p = tmp;
}
return 0;
}
This program contains a typical node struct for a linked list (so a pointer to the next node and an int containing a value). I have the following test functions:
void F(NODE** Y, int value)
{
NODE* X = *Y;
if(!X)
{
printf("case1...\n");
X = (NODE*)malloc(sizeof(NODE));
X->Data = value;
return;
}
printf("case2...\n");
X->Next = (NODE*)malloc(sizeof(NODE));
X->Next->Data = value;
return;
}
void myPrint(NODE** Y)
{
NODE* X = *Y;
printf("printing...\n");
printf("%d %d\n", X->Data, X->Next->Data);
return;
}
int main()
{
NODE* n = NULL;
F(&n, 5);
F(&n, 10);
myPrint(&n);
}
This code produces the following output in Linux:
case1...
case1...
printing...
Segmentation fault
I don't understand why passing a null pointer to the function will always cause the first case to occur. It seems like the pointer is being passed by value, but I don't think that's what's going on. If I call malloc() on the node inside of main() and then pass it to F(), the second case will be hit but never the first. This at least makes partial sense to me, since the node will never be null when it is passed to F() from main(), but obviously allocating the node before passing it to F() means that the null check inside F() will never be true.
Is what I'm trying to do even possible? Is there a way to pass n to F() while it's null and have it behave the way I want it to? Or do I have to allocate n outside of F() and remove the null check inside of F()?
After allocation for X you need to set it in *Y in the function F(). Otherwise, it does not get reflected once F() returns.
So I would change code to
void F(NODE** Y, int value)
{
NODE* X = *Y;
if(!X)
{
printf("case1...\n");
X = (NODE*)malloc(sizeof(NODE));
X->Data = value;
*Y = X; //set the allocated pointer
return;
}
printf("case2...\n");
X->Next = (NODE*)malloc(sizeof(NODE));
X->Next->Data = value;
return;
}
In the function F() when the 'n' in main() contains NULL;
the code is not setting the contents of 'n' to point to the malloc'd memory.
Changing the value contained in the local variable 'X' has no effect on the 'n' in main()
I am new to C, now I am making a linked list for face detection.
Below is the struct and the method for appending face at the end of linked list.
//Structure for storing a face with x, y and window size
typedef struct Face {
int window;
int x;
int y;
struct Face* next;
} Face;
//Append face(window, x, y) to the end of linked list starting from head
void push(Face* head, int window, int x, int y) {
Face* temp = (Face *)malloc(sizeof(Face));
temp->window = window;
temp->x = x;
temp->y = y;
temp->next = NULL;
Face* cur = head;
if (head == NULL) {
printf("Called\n");
head = temp;
} else {
while (cur->next != NULL) {
cur = cur->next;
}
cur->next = temp;
}
}
In another file, the executable, I called push(head, 1, 2, 3)[head here is initialized to NULL].
Only "Called' is printed on the screen. And the head is still NULL in the executable when I examine the linked list.
I have no idea why the head is not updated, but when I have it in the same file, it seems to work fine.
It's a guessing game since you don't show the relevant code.
Luckily, it's quite easy to guess well in this case...
The parameter you pass into the function is of type Face * and you set it to a new value (the new struct you allocated). Unfortunately, you're not returning this value, nor are you making sure the input parameter is capable of "transferring" data back to the calling context. What you should do is:
void push(Face** head, int window, int x, int y) {
// all you code here...
*head = temp
// rest of code...
}
And when you call the function:
push(&head, 1, 2, 3);
if (head == NULL) {
printf("Called\n");
head = temp;
}
The assignment head = temp only modifies the local copy of the head pointer. So it is not propagated to the code that called push(). If head was NULL in the code that calls push(), then it will remain so.
You could for example return the list head, as in:
Face *push(Face* head, int window, int x, int y) {
Face* temp = (Face *)malloc(sizeof(Face));
temp->window = window;
temp->x = x;
temp->y = y;
temp->next = NULL;
Face* cur = head;
if (head == NULL) {
printf("Called\n");
head = temp;
} else {
while (cur->next != NULL) {
cur = cur->next;
}
cur->next = temp;
}
return head;
}
And then use it like this:
/* ... */
head = push(head, window, x, y);
/* ... */
Another alternative is to pass a pointer to pointer to head (Face **), and replace that assignment with *head = temp;, but if you're a beginner I'd stick to the previous approach (and in my opinion, using double indirection is not necessary in most of the cases, but this can be subjective).
Finally, you might want to handle possible malloc(3) errors: the allocation can fail, you should check and handle that case.
I believe it is because you are passing in the value of the pointer head, which creates a copy of the pointer. By setting head to another address, you're not modifying head outside of scope, but rather the head within the method scope.
You'd need to pass in a pointer to the pointer to change it.
Function parameters are local variables of function. They are copies of the arguments. So the function parameter head is a copy of the argument head. Any changes of the parameter (of the copy of the argument) does not influence on the argument. You have to pass the head by reference.
Define the function the following way
//Append face(window, x, y) to the end of linked list starting from head
void push( Face **head, int window, int x, int y )
{
Face *temp = malloc( sizeof( Face ) );
if ( temp != NULL )
{
temp->window = window;
temp->x = x;
temp->y = y;
temp->next = NULL;
while ( *head ) head = &( *head )->next;
*head = temp;
}
}
And call the function like
push( &head, 1, 2, 3 );
Is there a way to point to the pointer variable instead of it's address space so that it can be changed to NULL. Something like this. Apologies for the poor question I can't think of a better way of expressing what I'm trying to do.
Thanks.
typedef struct Node
{
int val;
struct Node *r;
struct Node *l;
} Node;
Node* del(Node *N, int v)
{
Node *n = N;
Node **p = NULL;
while (n != NULL)
{
if (something)
{
p = n.r;
n = n->r;
}
else {
p = n.l;
n = n->l;
}
free(n);
*p = NULL;
}
}
You can use & on a pointer just like on any other variable. In your case, it looks like you might want to change del to:
Node *del(Node **N, int v)
And then call it like:
x = del(&someNode, 12);