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;
}
Related
I am just starting to learn C. Any help is appreciated!
I have an array of pointers to a struct, and I want to use the built-in qsort function to sort the array according to values in the structs the pointers point to. I am trying to use a compare function as demonstrated in the official docs.
The following version fails:
int compare_nodes(const void* a, const void* b){
const struct ListNode * ptr1 = ((const struct ListNode *) a);
const struct ListNode * ptr2 = ((const struct ListNode *) b);
// const struct ListNode * ptr1 = *((const struct ListNode **) a);
// const struct ListNode * ptr2 = *((const struct ListNode **) b);
int arg1 = ptr1 -> val;
int arg2 = ptr2 -> val;
if(arg1 < arg2) return -1;
if(arg1 > arg2) return 1;
return 0;
}
This version succeeds:
int compare_nodes(const void* a, const void* b){
// const struct ListNode * ptr1 = ((const struct ListNode *) a);
// const struct ListNode * ptr2 = ((const struct ListNode *) b);
const struct ListNode * ptr1 = *((const struct ListNode **) a);
const struct ListNode * ptr2 = *((const struct ListNode **) b);
int arg1 = ptr1 -> val;
int arg2 = ptr2 -> val;
if(arg1 < arg2) return -1;
if(arg1 > arg2) return 1;
return 0;
}
I do not understand the difference between the two versions:
If casting only tells the compiler how to interpret the address the pointer points to, what is the problem in version 1? Is it not enough to tell the compiler to interpret the pointer to void as a pointer to struct ListNode? Why do I need to add a layer of indirection with casting, just to then remove one layer with dereferencing?
Does C's pass-by-value play any role here? I could not think of any reason why by myself.
I found the following resources about this question. Although they seemed to explain this problem (especially resource 6), I did not understand them:
What are the rules for casting pointers in C?
Typecasting of pointers in C
Pointer type casting and dereferencing
What are the rules for casting pointers in C?
What does a C cast really do?
https://cboard.cprogramming.com/c-programming/102056-casting-pointer-pointer.html
Here's the full code:
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
struct ListNode {
int val;
struct ListNode *next;
};
int calc_list_length(struct ListNode * head){
int target = 0;
struct ListNode * tmp = head;
while (tmp)
{
target++;
tmp = tmp -> next;
}
return target;
}
int compare_nodes(const void* a, const void* b){
// const struct ListNode * ptr1 = ((const struct ListNode *) a);
// const struct ListNode * ptr2 = ((const struct ListNode *) b);
const struct ListNode * ptr1 = *((const struct ListNode **) a);
const struct ListNode * ptr2 = *((const struct ListNode **) b);
int arg1 = ptr1 -> val;
int arg2 = ptr2 -> val;
if(arg1 < arg2) return -1;
if(arg1 > arg2) return 1;
return 0;
}
struct ListNode* sortList(struct ListNode* head){
if(!head) return NULL;
int list_length = calc_list_length(head);
struct ListNode * tmp = head;
struct ListNode * arr[list_length];
for (int i = 0; i < list_length; i++)
{
arr[i] = tmp;
tmp = tmp -> next;
}
for (int i = 0; i < list_length; i++) {
printf("%d ", arr[i] -> val);
}
printf("\n");
qsort(arr, list_length, sizeof(struct ListNode *), compare_nodes);
for (int i = 0; i < list_length; i++) {
printf("%d ", arr[i] -> val);
}
printf("\n");
}
int main(){
// [2,1,4,3]
struct ListNode node4 = {.val = 3, . next = NULL};
struct ListNode * ptr4 = &node4;
struct ListNode node3 = {.val = 4, .next = ptr4};
struct ListNode * ptr3 = &node3;
struct ListNode node2 = {.val = 1, .next = ptr3};
struct ListNode * ptr2 = &node2;
struct ListNode node1 = {.val = 2, .next = ptr2};
struct ListNode * ptr1 = &node1;
sortList(ptr1);
getchar();
return 0;
}
Thanks in advance. I hope you point me in the right direction.
The qsort passes pointers to the array elements using the pointer-to operator &.
So it can pass, for example, &arr[0] and &arr[1] as arguments to your comparison function.
Since arr is an array of pointers, where every element is a pointer, then a pointer to one element must by definition be a pointer to a pointer.
So the arguments passed to your compare_nodes structure are pointers to pointers to ListNode structures.
The function qsort is declared like
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
That is the function deals with pointers of the type void *. It passes to the comparison function two pointers of the type const void * that point to elements of the underlying array.
You declared an array of pointers
struct ListNode * arr[list_length];
Its elements of the type ListNode * are passed to the comparison function by reference through pointers to them.
In fact the function passes to the comparison function pointers of the type
ListNode ** that are passed as pointers of the type const void *. You may imagine this the following way
const void *p = &arr[i];
where the expression &arr[i] has the type ListNode **.
Of course the function qsort actually does not know the actual type of elements of the array. It uses the following pointer arithmetic
const void *p = ( char * )base + i * size;
Thus within the comparison function you need to do the "reverse" casting like
const struct ListNode * ptr1 = *((const struct ListNode **) a);
where ptr1 is an element of the original array that is passed to the comparison function by reference trough a pointer to it..
The fact that the qsort() function passes pointers to the array elements to your comparator function, rather than passing the array elements directly by value, is due to how qsort() was designed, and is not required by the core C language itself.
I can easily write a sorting function that sorts an array of pointers, with the following signature:
void my_sort_pointers(const void **array, size_t nmemb,
int (*compar)(const void *, const void *));
and it accepts a comparator function that is passed the array elements (the pointers) directly. Then your comparator function would not have to dereference the argument to get the actual values to be compared.
However, my sorting function above would not be able to sort, say, an array of floats, because it would not be able to pass two float arguments to a comparator function that is supposed to take two pointers. Even if you made a comparator function that took two floats, you would not be able to pass it to the function above, because the function pointer types are incompatible, and even if you somehow casted the type, it would still not work because the C code inside the function, which thinks it is calling a function that takes two pointers, cannot call a function that actually takes two floats, because the function signatures are incompatible.
So to be able to sort arrays of different types under this design, I would have to have another sorting function that sorts an array of floats:
void my_sort_floats(float *base, size_t nmemb,
int (*compar)(float, float));
and another sorting function that sorts an array of ints, etc. And since there can be an unlimited types of structs, with different sizes, you can never make functions that can handle all of them. Even if only basic types are supported, it would require several different functions. The designers of the C standard library decided that it would be a better design to make a single sorting function that works for all types, by passing a pointer to the array element to the comparator functon instead.
This design makes a lot of sense when you understand the limitations of C. (In C++, it would be possible to use generics to write a generic sorting function that works for any type, and has a comparator that is passed the array elements by value. But C doesn't have generics.) But it is a design decision of the qsort() function API nevertheless, and sorting functions in C (at least if they only accept a particular type) do not necessarily have to work this way. So you would only know that qsort() is supposed to be used in this way by reading the specification of qsort().
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.
I am creating a simple array of structures in C, but the first structure is always jibberish. How do i fix this?
I have tried to set the first element of the double pointer to struct in many ways but it always fails.
This is my graph.h file:
#ifndef GRAPH_H
#define GRAPH_H
#include "set.h"
typedef struct urlNode * URLList;
typedef struct GraphRep * Graph;
struct urlNode {
int id;
char* URL_NAME;
URLList next; // link to next node
};
struct GraphRep {
int nV;
URLList * collections;
};
Graph newGraph(Set s);
int nameToId(Graph g, char *name);
void showGraph(Graph g);
#endif
And my newGraph(Set s) function looks like this:
Graph newGraph(Set s){
int size = nElems(s);
Graph new_graph = malloc(sizeof(struct GraphRep));
if (new_graph == NULL) {
printf("ERROR: COULDNT ALLOCATE GRAPH\n");
}
new_graph->nV = size;
char *name = getNextVal(s);
// THIS IS THE NODE TO BE ADDED TO THE GRAPH
URLList list_to_add = malloc(sizeof(struct urlNode));
list_to_add->URL_NAME = strdup(name);
list_to_add->id = 0;
list_to_add->next = NULL;
// HERE I ADD THE NODE TO THE GRAPH.
new_graph->collections[0] = list_to_add;
// PRINT OUT THE VALUES OF THE NEWLY ADDED NODE TO MAKE SURE IT WORKS
// THE URL_NAME IS PRINTED OUT FINE
// BUT THE ID IS JIBBERISH.
printf("%s\n", new_graph->collections[0]->URL_NAME);
printf("%d\n", new_graph->collections[0]->id);
if(new_graph->collections[0]->next != NULL) {
printf("%s\n", new_graph->collections[0]->next->URL_NAME);
printf("%d\n", new_graph->collections[0]->next->id);
}
printf("\n");
return new_graph;
}
I expect new_graph->collections[0]->id to be 0 but it keeps on giving me random ints.
Also even if the next for the newly declared pointer to struct is NULL, it still gives me a jibberish next value too.
Any help would be appreciated, thanks!
The data member collections of the object *new_graph is not initialized.
There is initialized only this data member
new_graph->nV = size;
So this statement
new_graph->collections[0] = list_to_add;
results in undefined behavior.
If you need an array of pointers of the type URLList you have to allocate the memory and its address assign to the pointer collections.
For example
new_graph->collections = malloc( new_graph->nV * sizeof( URLList ) );
And after that this statement
new_graph->collections[0] = list_to_add;
could be valid.
(I suppose that the data member nV corresponds to the number of elements in the dynamically allocated array though it may not be truth)
Pay attention to that as the string pointed to by the pointer name is not changed in the function then it is better to declare it like
const char *name = getNextVal(s);
I cannot understand the meaning of a C code about linked lists that is using double pointers. Here is the code I am reading
struct list
{
int value;
struct list *next;
};
//Insert an element at the begining of the linked list
void insertBegin(struct list **L, int val)
{
//What does **L mean?
//Memory allocation for the new element temp
struct list *temp;
temp = (struct list *)malloc(sizeof(temp));
//The new element temp points towards the begining of the linked list L
temp->next = *L;
//Set the beginning of the linked list
*L = temp;
(*L)->value = val;
}
void loop(struct list *L)
{
printf("Loop\n");
//Run through all elements of the list and print them
while( L != NULL )
{
printf("%d\n", L->value);
L = L->next;
}
}
struct list* searchElement(struct list *L,int elem)
{
while(L != NULL)
{
if(L->value == elem)
{
printf("Yes\n");
return L->next;
}
L = L->next;
}
printf("No\n");
return NULL;
}
int main()
{
struct list *L = NULL;
insertBegin(&L,10); // Why do I need
return 0;
}
What does **L in the insertElement mean and what is the difference between the **L and the *L in the loop function? Why in the main when struct list *L = NULL is declared I should call the function insertBegin with the argument &L and not a simple L?
I guess *L is a pointer towards the first node of the linked list while **L may point toward any element of the list. However, I am not sure this is correct.
Thank you for your help!
It means "pointer to a pointer". In C pointers are passed by value, so if you want to be able to modify a pointer passed to a function outside of that function, you have to pass a pointer to it. Passing the pointer will only pass another value for it, which will be modified in the function but will not reflect a change to the value outside of it. Passing as a pointer to pointer essentially allows you to modify the value at the address passed rather than just to modify the local.
Consider those two functions:
void foo(int * p, int * t) {
p = t;
}
void foo2(int ** p, int * t) {
*p = t;
}
And the code:
int a = 1, b = 2;
int * p = &a;
foo(p, &b);
// in foo *p == 2, but here *p is still == 1, because p didn't change, only the copy that was passed to foo changed
foo2(&p, &b); // now *p == 2, p was changed in foo2
The type **L is read as pointer to a pointer to L. So if you have a pointer to an L and takes its address, that is what you get. The pattern of **L in a function argument (in C) is usually used to implement an "out parameter" - a parameter the code can update. To insert at the beginning, you need to update the pointer to the head of the list - that is why that function takes a pointer to the head as a parameter. When assigning to *L, the function updates the parameter.
L stores address of the first link in the list. Thus:
*L is contents of the first link in the list, and
&L is the address of the variable that stores the address of the first link in the list.
In other words, your only way to allocate memory for and initialize a list by passing the argument into a function is by providing &L as an argument. If you pass L as an argument, the function will receive the address of the first link, whereas instead it needs a place where to store the address of the first link.
If you want a function to write to a parameter and have that new value reflected in the caller, then you must pass a pointer for that parameter:
void foo( T *p ) // for any type T
{
*p = new_value(); // write a new value to the thing p points to
}
void bar( void )
{
T var;
foo( &var ); // foo writes a new value to var
}
If we substitute T with a pointer type Q *, then the code is
void foo( Q **p ) // for any type Q
{
*p = new_value(); // write a new value to what p points to
}
void bar( void )
{
Q *var;
foo( &var ); // foo writes a new value to var
}
The semantics in both cases are exactly the same; we want foo to update the value stored in var through the pointer p. The only difference is that in the second case var already has a pointer type, so p has to be a pointer to that pointer type.
In the code you posted, the insertBegin function updates the value stored in L, which is a pointer to the head of the list. Since the variable L in main has type struct list *, the type of the parameter L in insertBegin needs to be struct list **.
The double pointer in insertBegin is for when you are changing the location of L from where ever L is to the node you are inserting. When calling the function you need &L because you need to pass it by reference because you are changing L
#include "stdafx.h"
#include <stdio.h>
struct s
{
char *st;
struct s *sp;
};
struct s *p1,*p2;
void swap(struct s *p1,struct s *p2);
int main()
{
int i;
struct s *p[3];
static struct s a[]={
{"abc",a+1},{"def",a+2},{"ghi",a}
};
for(i=0;i<3;i++)
{
p[i]=a[i].sp;
}
swap(*p,a);
printf("%s %s %s\n",p[0]->st,(*p)->st,(*p)->sp->st);
return 0;
}
void swap(struct s *p1,struct s *p2)
{
char *temp;
temp = p1->st;
p1->st = p2->st;
p2->st = temp;
}
This program outputs as abc,abc,ghi. My doubt is what does p[0]->st,(*p)->st,(*p)->sp->st outputs.we havent intialised st with abc or ghi.How does it outputs the string?
We havent intialised st with abc or ghi. How does it outputs the
string?
The value of the st member for each structure in the statically allocated array a is actually initialized through an initialization list. Writing
static struct s a[]={
{"abc",a+1},{"def",a+2},{"ghi",a}
};
has the same effective meaning after its execution as writing the following:
static struct s a[3];
a[0].st = "abc";
a[0].sp = a+1;
a[1].st = "def";
a[1].sp = a+2;
a[2].st = "ghi";
a[2].sp = a;
And what's effectively happened after both methods of initialization is you have a statically-allocated circular linked list of struct s, where the data-members of each node in the list (the st member) is pointing to a string literal like "abc", "def", etc. The sp data member is pointing to the next node in the linked list.
I haven't analysed all the statements, but assignment to ->st and ->sp happens here:
static struct s a[]={
{"abc",a+1},{"def",a+2},{"ghi",a}
};
the rest are games with pointers so the output is what you see. So, say:
the a array is created and initialized;
in the for loop the p array is also initialized;
noticing that sp recursively points to struct s instances, p and a have the same structure;
each elements of p is made point to a struct s instance taken from one of the elements of a.