Shallow copy in C - c

This is my first question.
I am learning C. And I heard about shallow copy.
As I understood, shallow copy means that you copy the address of the object instead of its value. This means that every change to the copied object will affect the original object.
#include<stdio.h>
struct Person {
char *name;
int age;
};
int main (void)
{
struct Person p1 = {"jon", 20};
struct Person p2 = p1;
p2.name = "mark";
p2.age = 26;
printf ("%s\n", p1.name); // print 'jon' not 'mark'!
printf ("%d\n", p1.age); // prinf 20 not 26
return 0;
}
I tried the above code, and I expeted that the modification of 'p2' will affect 'p1'. But the the content of 'p1' remains the same as if I implemented a deep copy.

I tried the above code, and I expeted that the modification of 'p2' will affect 'p1'. But the the content of 'p1' remains the same as if I implemented a deep copy.
You have indeed performed a shallow copy of p1 onto p2, but that's not what you think it is. Your p1 and p2 are distinct objects with independent members, but pointer members p1.name and p2.name (presently) have the same pointer value, and as long as that is true, if the string to which they both point were modified, then you could observe it through both p1 and p2:
int main(void) {
struct Person p1 = {(char[]) {"jon"}, 20};
struct Person p2 = p1;
// Confirm copying
printf ("%s\n", p2.name); // prints 'jon'
// Confirm shallowness
p2.name[0] = 'R';
printf ("%s\n", p1.name); // prints 'Ron'
printf ("%s\n", p2.name); // prints 'Ron'
return 0;
}
For a deep copy, on the other hand, you would need to make an independent copy of that string for p2.name to point to. Then no modification you can make to one object will be visible via the other. Example:
int main(void) {
struct Person p1 = {(char[]) {"jon"}, 20};
struct Person p2 = p1;
// complete the deep copying:
p2.name = strdup(p2.name);
// Confirm copying
printf ("%s\n", p2.name); // prints 'jon'
// Confirm deepness
p2.name[0] = 'R';
printf ("%s\n", p1.name); // prints 'jon'
printf ("%s\n", p2.name); // prints 'Ron'
return 0;
}
And in this case, that's as deep as you can go, because the objects to which p1.name and p2.name point do not contain any pointers themselves. There is a distinction between shallow and deep copying only for objects that contain pointers.
It is also possible to take the address of an object, and then modify the object indirectly through that address (a pointer), but that's not any form of copying. Creating a copy implies producing a distinct object, not a mere alias for the original.

Here is a real "shallow copy". This example exhibits the consequences you were expecting.
#include <stdio.h>
struct Person {
char *name;
int age;
};
int main( void )
{
char boy[ 16 ] = "jon"; // must be a "mutable" buffer!
struct Person p1 = { boy, 20 };
struct Person p2 = p1;
printf( "{ %s %d } { %s %d }\n", p1.name, p1.age, p2.name, p2.age );
strcpy( p2.name, "mark" ); // Where is p2.name pointing??
p2.age = 26; // change value
printf( "{ %s %d } { %s %d }\n", p1.name, p1.age, p2.name, p2.age );
return 0;
}
{ jon 20 } { jon 20 }
{ mark 20 } { mark 26 }
It's ALWAYS a good idea to add enough debugging print statements to your code to shine light into the black box. Better is to use a debugger to watch the flow of execution and monitor variables' values.

The way you've written it now makes p2 a copy of p1. You want to create a pointer to the address of p1 to modify it.
#include <stdio.h>
struct Person {
char *name;
int age;
};
int main(void)
{
struct Person p1 = {"jon", 20};
struct Person *p2 = &p1;
p2->name = "mark";
p2->age = 26;
printf ("%s\n", p1.name);
printf ("%d\n", p1.age);
return 0;
Output:
mark
26
You can use p2->member or (*p2).member to access member variables, since p2 is a pointer and needs to be dereferenced before you can access them.

Related

Increment issue in C (pointer)

I can only change the content of the "birthday" function, the rest must stay the same.
I am having a silly problem trying to increment the age variable...It does get incremented if I use the ++ operator but not by decimal 1, it seems to increment by 4 which is the sizeof an int. What am I doing wrong here ?
#include <stdio.h>
typedef struct {
int* age;
const char* name;
} Person;
void birthday(Person* person);
int main()
{
void(*birthday_ptr)(Person* person) = &birthday;
Person me = {30,"foobar"};
(*birthday_ptr)(&me);
return 0;
}
void birthday(Person* person)
{
printf("%p\n", person);
printf("%d\n", person->age);
person->age = 31; // this works...it sets the value pointed to by the ptr to 31...
printf("%d\n", person->age);
person->age += 1; // this compiles, but it seems to increment by 4 the value pointed to by the ptr, not 1 (relates to int size ?!)
printf("%d\n", person->age);
int* silly = (int*)(person);
(*silly)++; // this works and increments age to 36...
(*person->age)++; // this causes an access violation...why ?!
printf("silly: %d\n", person->age);
}
You must dereference a pointer to change the value it's pointing to. But I reckon the age variable should not be a pointer at all. It should be an int:
typedef struct {
int age;
const char* name;
} Person;
This solves many of your problems, including the fact that you cast 30 to a pointer, and use %d to print the pointer, which causes undefined behavior.
The correct solution is to modify your struct:
typedef struct {
int age;
const char* name;
} Person;
indeed, it is more logical that age is an int and not an int* (age is an integer not an adress of this form 0x1F8C45).
With such a change, your code:
(person->age)++; // this causes an access violation...why ?!
printf("silly: %d\n", person->age);
is correct.
If indeed, you would like to keep your structas it currently is, you need to increment the value of member of the struct int * age but you can only change the content of the "birthday" function.
Here is my proposition.
However, in my opinion, this is not a good C language nor is it a good practice. It is just a hack to bypass the problems'constraints (not to touch the structure) ==> You should be careful concerning the warning (also, your code does not compile if you use -Werror flag with gcc and consider the response of #Ayxan Haqverdili.
Create a pointer pointing to the address of your agemember
// a pointer pointing to the address of person->age
int *p = (&person->age);
// increment the value pointed by the pointer (which is supposed to be age)
++*p; // person->age is 32
++*p; // person->age is 33
(*p)++; // the same -- increment to 34 etc etc
The whole birhday() function is below
void birthday(Person* person)
{
printf("%d\n", person->age);
person->age = 31; // this works...it sets the value pointed to by the ptr to 31...
printf("%d\n", person->age);
int *p = NULL;
p = (int*)(&person->age);
(*p)++; // age =32
printf("value of p=%d\n", *p);
printf("person->age=%d\n", person->age);
(*p)++; // person->age is 33
printf("value of p=%d\n", *p);
printf("person->age=%d\n", person->age);
}
The ouput of the execution displays the following results:
30
31
value of p=32
person->age=32
value of p=33
person->age=33

Am I freeing memory properly?

Okay, so I have a homework assignment for a C programming class and I just finished with the output doing what I expected. However, I am still a bit confused on memory allocation and freeing.
Basically what has me question my self is the freeing of the structure memory and the "Change_name" function. In my program I am just taking the new name and setting the value who.name to the new name. But what happens to the "old" name in this scenario? when I call free(who), is the old name being deleted?
any clarification would be appreciated!
code:
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
struct Person {
char *name;
int age;
int height;
int weight;
};
/* complete this function, which initialize the fileds of the struct, and return a pointer to the initialzied struct */
struct Person *Person_create(char *name, int age, int height, int weight)
{
struct Person *who = malloc(sizeof(struct Person));
assert(who != NULL);
(*who).name = name;
(*who).age = age;
(*who).height = height;
(*who).weight = weight;
return who;
}
/* complete this function, which free memory that was allocated for a struct*/
void Person_destroy(struct Person *who)
{
assert(who != NULL);
free(who);
}
/* complete this function, which print the value of member of struct for the input argument */
void Person_print(struct Person *who)
{
printf("This person have the values of...\n");
printf("name: %s\n", (*who).name);
printf("age: %d\n", (*who).age);
printf("height: %d\n", (*who).height);
printf("weight: %d\n", (*who).weight);
}
/* complete this function, which change the value of filed member of the struct to the value of newName */
void Change_name (struct Person *who, char * newName)
{
(*who).name = newName;
}
int main(int argc, char *argv[])
{
// make two people structures
struct Person *joe = Person_create(
"Joe Alex", 32, 64, 140);
struct Person *frank = Person_create(
"Frank Blank", 20, 72, 180);
// print them out and where they are in memory
printf("Joe is at memory location %p:\n", joe);
Person_print(joe);
printf("Frank is at memory location %p:\n", frank);
Person_print(frank);
// make changes in filed of goe's struct print them again
joe->age += 20;
joe->height -= 2;
joe->weight += 40;
Change_name(joe, "Jack The third Junior Smith Benedickt");
Person_print(joe);
// destroy them both so we clean up
Person_destroy(joe);
Person_destroy(frank);
return 0;
}
Your call to Person_destroy doesn't free any of the names because you're just freeing who. But that's OK because you're also not dynamically allocating any of the names with malloc/strdup/etc...
TL;DR: For your specific example: yes, but there are caveats to what you're doing.
One question that needs addressing WRT change_name is this:
ut what happens to the "old" name in this scenario? when I call free(who), is the old name being deleted?
For reasons that, I hope, will become clear further down, there is no clear answer to this question. Your code assigns a char * blindly. You don't know where that string is stored. If it's a string constant with static storage (either global variable or const char * in main), that old name will remain in memory for as long as your application runs. If it's dynamically allocated, unsetting a pointer doesn't free the memory either. assigning a new pointer can potentially cause you to leak memory. The safest way is to copy the string (strdup), and free the pointer prior to changing the name field.
There's an underlying problem here: You can only free memory in the right way if you allocate it correctly. Strictly speaking, you are doing just that. However, a function that takes a char * shouldn't blindly assign that same pointer. The pointer might be a stack char[] that decayed into a pointer (because it was passed as an argument).
You have no idea where that string was allocated, how, and most importantly: how long the pointer will remain valid. A couple of scenario's where a char * can cause problems:
int main ( void )
{
struct Person *p = foobar();
printf("name => %s?", p->name);
Person_destroy(p);
return 0;
}
struct Person *foobar( void )
{
char bar[] = "this is a local string";
return Person_create(bar, 32, 64, 140);
}
The pointer to bar expires once foobar returns, so this is a problem (stack memory pointers).
A pointer on the heap might suffer from the same problem:
struct Person *foobar( void )
{
const char *x = "Name";
char *bar = strdup(x); // allocates on heap and copies string
// check for null's etc...
struct Person *person = Person_create(bar, 32, 64, 140);
//some more stuff happens, including:
bar = realloc(bar, strlen(x) + 255);
strncat(bar, " has been successfully allocated", 33);
return person;
}
The problem here is that realloc might memmove the original string, and return an entirely new pointer, in which case the name field of the struct will become invalid. If that doesn't happen, person->name now points to Name has been successfully allocated, which is a potential bug.
So I strongly advise you to copy the name string:
// note: const char *name
struct Person *Person_create(const char *name, int age, int height, int weight)
{
struct Person *who = malloc(sizeof *who); // shorter to write, more reliable
if (who == NULL)
exit(1);// or whatever
who->name = strdup(name); // create copy
//etc...
return who;
}
This means, of course that struct Person will need to free the name pointer:
void Person_destroy(struct Person *who)
{
free(who->name);
free(who);
}
Double indirection is a bit risky a lot of the time, but imagine someone doing something like this:
int main( void )
{
struct Person *p = Person_create("Name", 1, 2, 3);
//do stuff
Person_destroy(p);
// more stuff, eg:
printf("%p\n", (void *)p);
Person_destroy(p);
return 0;
}
This is not good,. p should be null'ed after freeing it. Freeing an invalid pointer is bad, mkay. 2 ways to make this a less common problem:
#define FREE_PERSON(p) do {\
Person_destroy(p);\
p = NULL;\
} while(0);
This macro will always set the person variable to NULL after calling Person_destroy. The downside is: it's a clunky macro, and people can (and will) bypass it.
Change Person_destroy a bit:
void Person_destroy(struct Person **p)
{
if (p == NULL)
return; // this is needed now
struct Person *tmp = *p;
free(tmp->name);
free(tmp);
*p = NULL; // set the pointer itself to NULL
}
This forces people to call Person_destroy with a pointer to their pointer, and automatically sets their pointer to NULL.
Again, good practice requires devs to do this themselves, but it's a trivial change and helps prevent problems over time.
Demo using the double-indirection approach

What is causing this segfault?

I get a segfault after calling mygets(). Here is my code:
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct _charlist{
char ch;
struct _charlist *next;
}charlist;
static struct termios old, new;
void mygets(char** p);
char getche(void);
char getch_(int echo);
void resetTermios(void);
void initTermios(int echo);
int main(void){
char *p;
printf("\nWho loves orange soda?: ");
mygets(&p);
printf("'%s' loves orange soda!", p);
}
void mygets(char** p){
char c;
charlist *root, *curr;
unsigned i, count=0;
root=NULL;
while((c = getche()) != '\n'){
count++;
if(!root){
root = (charlist*) malloc(sizeof(charlist));
root->ch = c;
root->next = NULL;
curr = root;
}
else{
curr
->next = (charlist*) malloc(sizeof(charlist));
curr->next->ch = c;
curr->next->next = NULL;
curr = curr->next;
}
}
//now request string space.
*p = (char*) malloc((count+1)*sizeof(char));
printf("\np is now malloced"); //This line doesn't get printed!
//move linked list into string space.
curr = root;
for(i=0; i<=count; i++){
*p[i] = curr->ch;
curr = curr->next;
}
//null-terminate the string.
*p[i] = '\0';
}
Can someone tell me why I get a segfault?
I can't post this question unless the ratio of code to question is lower than some arbitrary threshold. Therefore, there now follows the first paragraph of Alice in Wonderland, for your consideration.
Alice was beginning to get very tired of sitting by her sister on the
bank, and of having nothing to do: once or twice she had peeped into
the book her sister was reading, but it had no pictures or
conversations in it, 'and what is the use of a book,' thought Alice
'without pictures or conversation?'
When func is called, it is passed a copy of the local variable p in main. This copy is then assigned the malloced area in func. The original p in the main is never modified, so its contents remain undefined, causing a segmentation fault when printf dereferences p in order to print the string.
You may want func to return a char* pointing to the newly malloc'd area.
You pass the argument to the function by value. So according to the function declaration
void func(char* p);
parameter p is a local variable of the function that will be destroyed after exiting the function. Any changes of the local variable do not influence on the argument.
You could define the function the following ways
char * func(){
unsigned count = 10;
char *p = (char*) malloc(sizeof(char)*(count+1));
//p is given a string after this, but problem is the above line.
return p;
}
and call it as
p = funct();
or
void func(char ** p){
unsigned count = 10;
*p = (char*) malloc(sizeof(char)*(count+1));
//p is given a string after this, but problem is the above line.
}
and call it as
func( &p );
The problem is with:
*p[i] = curr->ch;
Should be:
(*p)[i] = curr->ch;
You want to access the i'th character of where p is pointing to. Not dereference the ith pointer in an array of pointers.
Same problem with *p[i] = '\0'; later.
Also you did not malloc enough space, as your loop writes count + 1 characters and then you write an extra null terminator, so you should either malloc count + 2 or adjust your loop to finish at i<count, not i<=count. (probably the latter).
Also, it'd be useful to check curr != NULL before dereferencing it, so that if you do have an off-by-one error then you don't get undefined behaviour.

subtracting from an array in a struct

I have a quick question concerning func1 and the first paragraph of the main program. Essentially, I don't understand a.word-- (in func1) does.
I've commented it out and nothing in the output for a.word changes, but I don't understand why it's irrelevant.
Is it moving all values down 1? Or does it just cycle from the last letter to the second-to-last letter, and if so why, when a.word is printed, does the entire "myword" print out?
I'm new to pointers and that whole thing.
Thanks!
#include <stdio.h>
struct foo{
int num;
char *word;
struct foo *ptr;
};
void func1(struct foo);
void func2(struct foo*);
void func3(struct foo);
int main() {
struct foo a;
a.num = 5;
a.word = "myword";
func1(a);
printf("1 %d %s\n", a.num, a.word);
a.num = 100;
a.word = "secondword";
func2(&a);
printf("2 %d %s\n", a.num, a.word);
a.ptr = &a;
a.num = 50;
a.word = "mylastword";
func3(a);
printf("4 %d %s\n", a.num, a.word);
}
void func1(struct foo a)
{
while(*(a.word) != '\0')
{
putchar(*(a.word));
a.word++;
}
putchar('\n');
if(a.num % 10 != 0)
{ a.num *= 2; }
a.word--;
printf("num is %d\n", a.num);
}
void func2(struct foo *a)
{
while(*(a->word) != '\0')
{
putchar(*(a->word));
a->word++;
}
putchar('\n');
if(a->num % 10 != 0)
{ a->num *= 2; }
a->word--;
printf("num is %d\n", (*a).num);
}
void func3(struct foo a)
{
if(a.num > a.ptr->num)
{ a.num = 500; }
else
{ a.num = a.ptr->num + 1; }
a.word = "myotherword";
a.ptr->word = "yetanotherword";
printf("3 %d %s\n", a.num, a.word);
}
The code is show the differences between calling function by-value or by-pointer.
void func1(struct foo a) // call by value
In this case every changes on a will not apply to caller's input variable.
void func2(struct foo *a) // call by pointer
It's same as func1 but in this case every changes on a will be affected to the a in caller side.
struct foo {
int num;
char *word;
struct foo *ptr;
};
This structures is an one way linked list, each element points to the next element.
About a.word--; which you asked, since this code has many flaws and the logic is unclear. I just can say it will decrease the pointer which is pointing to somewhere is the memory as a char.
a.word--;
Since aword is a pointer in your program ,all that the above statement does is make aword point to the previous element,instead of the current one it is pointing to. This is basic pointer arithmetic, but since you say you are new to pointers,hence I am "pointing" it out.
It's different from the decrement operator in that,it doesn't just subtact 1 from aword but makes it point to the previous element which could be N bytes away from the current element.Had you used
a.word++;
It would now be the address of/pointer to the next element.In your program, a.word is used to store the base address of strings.So a.word++ will point to the "next character" of the string.

Why use double indirection? or Why use pointers to pointers?

When should a double indirection be used in C? Can anyone explain with a example?
What I know is that a double indirection is a pointer to a pointer. Why would I need a pointer to a pointer?
If you want to have a list of characters (a word), you can use char *word
If you want a list of words (a sentence), you can use char **sentence
If you want a list of sentences (a monologue), you can use char ***monologue
If you want a list of monologues (a biography), you can use char ****biography
If you want a list of biographies (a bio-library), you can use char *****biolibrary
If you want a list of bio-libraries (a ??lol), you can use char ******lol
... ...
yes, I know these might not be the best data structures
Usage example with a very very very boring lol
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int wordsinsentence(char **x) {
int w = 0;
while (*x) {
w += 1;
x++;
}
return w;
}
int wordsinmono(char ***x) {
int w = 0;
while (*x) {
w += wordsinsentence(*x);
x++;
}
return w;
}
int wordsinbio(char ****x) {
int w = 0;
while (*x) {
w += wordsinmono(*x);
x++;
}
return w;
}
int wordsinlib(char *****x) {
int w = 0;
while (*x) {
w += wordsinbio(*x);
x++;
}
return w;
}
int wordsinlol(char ******x) {
int w = 0;
while (*x) {
w += wordsinlib(*x);
x++;
}
return w;
}
int main(void) {
char *word;
char **sentence;
char ***monologue;
char ****biography;
char *****biolibrary;
char ******lol;
//fill data structure
word = malloc(4 * sizeof *word); // assume it worked
strcpy(word, "foo");
sentence = malloc(4 * sizeof *sentence); // assume it worked
sentence[0] = word;
sentence[1] = word;
sentence[2] = word;
sentence[3] = NULL;
monologue = malloc(4 * sizeof *monologue); // assume it worked
monologue[0] = sentence;
monologue[1] = sentence;
monologue[2] = sentence;
monologue[3] = NULL;
biography = malloc(4 * sizeof *biography); // assume it worked
biography[0] = monologue;
biography[1] = monologue;
biography[2] = monologue;
biography[3] = NULL;
biolibrary = malloc(4 * sizeof *biolibrary); // assume it worked
biolibrary[0] = biography;
biolibrary[1] = biography;
biolibrary[2] = biography;
biolibrary[3] = NULL;
lol = malloc(4 * sizeof *lol); // assume it worked
lol[0] = biolibrary;
lol[1] = biolibrary;
lol[2] = biolibrary;
lol[3] = NULL;
printf("total words in my lol: %d\n", wordsinlol(lol));
free(lol);
free(biolibrary);
free(biography);
free(monologue);
free(sentence);
free(word);
}
Output:
total words in my lol: 243
One reason is you want to change the value of the pointer passed to a function as the function argument, to do this you require pointer to a pointer.
In simple words, Use ** when you want to preserve (OR retain change in) the Memory-Allocation or Assignment even outside of a function call. (So, Pass such function with double pointer arg.)
This may not be a very good example, but will show you the basic use:
#include <stdio.h>
#include <stdlib.h>
void allocate(int **p)
{
*p = (int *)malloc(sizeof(int));
}
int main()
{
int *p = NULL;
allocate(&p);
*p = 42;
printf("%d\n", *p);
free(p);
}
Let’s say you have a pointer. Its value is an address.
but now you want to change that address.
you could. by doing pointer1 = pointer2, you give pointer1 the address of pointer2.
but! if you do that within a function, and you want the result to persist after the function is done, you need do some extra work. you need a new pointer3 just to point to pointer1. pass pointer3 to the function.
here is an example. look at the output below first, to understand.
#include <stdio.h>
int main()
{
int c = 1;
int d = 2;
int e = 3;
int * a = &c;
int * b = &d;
int * f = &e;
int ** pp = &a; // pointer to pointer 'a'
printf("\n a's value: %x \n", a);
printf("\n b's value: %x \n", b);
printf("\n f's value: %x \n", f);
printf("\n can we change a?, lets see \n");
printf("\n a = b \n");
a = b;
printf("\n a's value is now: %x, same as 'b'... it seems we can, but can we do it in a function? lets see... \n", a);
printf("\n cant_change(a, f); \n");
cant_change(a, f);
printf("\n a's value is now: %x, Doh! same as 'b'... that function tricked us. \n", a);
printf("\n NOW! lets see if a pointer to a pointer solution can help us... remember that 'pp' point to 'a' \n");
printf("\n change(pp, f); \n");
change(pp, f);
printf("\n a's value is now: %x, YEAH! same as 'f'... that function ROCKS!!!. \n", a);
return 0;
}
void cant_change(int * x, int * z){
x = z;
printf("\n ----> value of 'a' is: %x inside function, same as 'f', BUT will it be the same outside of this function? lets see\n", x);
}
void change(int ** x, int * z){
*x = z;
printf("\n ----> value of 'a' is: %x inside function, same as 'f', BUT will it be the same outside of this function? lets see\n", *x);
}
Here is the output: (read this first)
a's value: bf94c204
b's value: bf94c208
f's value: bf94c20c
can we change a?, lets see
a = b
a's value is now: bf94c208, same as 'b'... it seems we can, but can we do it in a function? lets see...
cant_change(a, f);
----> value of 'a' is: bf94c20c inside function, same as 'f', BUT will it be the same outside of this function? lets see
a's value is now: bf94c208, Doh! same as 'b'... that function tricked us.
NOW! lets see if a pointer to a pointer solution can help us... remember that 'pp' point to 'a'
change(pp, f);
----> value of 'a' is: bf94c20c inside function, same as 'f', BUT will it be the same outside of this function? lets see
a's value is now: bf94c20c, YEAH! same as 'f'... that function ROCKS!!!.
Adding to Asha's response, if you use single pointer to the example bellow (e.g. alloc1() ) you will lose the reference to the memory allocated inside the function.
#include <stdio.h>
#include <stdlib.h>
void alloc2(int** p) {
*p = (int*)malloc(sizeof(int));
**p = 10;
}
void alloc1(int* p) {
p = (int*)malloc(sizeof(int));
*p = 10;
}
int main(){
int *p = NULL;
alloc1(p);
//printf("%d ",*p);//undefined
alloc2(&p);
printf("%d ",*p);//will print 10
free(p);
return 0;
}
The reason it occurs like this is that in alloc1 the pointer is passed in by value. So, when it is reassigned to the result of the malloc call inside of alloc1, the change does not pertain to code in a different scope.
I saw a very good example today, from this blog post, as I summarize below.
Imagine you have a structure for nodes in a linked list, which probably is
typedef struct node
{
struct node * next;
....
} node;
Now you want to implement a remove_if function, which accepts a removal criterion rm as one of the arguments and traverses the linked list: if an entry satisfies the criterion (something like rm(entry)==true), its node will be removed from the list. In the end, remove_if returns the head (which may be different from the original head) of the linked list.
You may write
for (node * prev = NULL, * curr = head; curr != NULL; )
{
node * const next = curr->next;
if (rm(curr))
{
if (prev) // the node to be removed is not the head
prev->next = next;
else // remove the head
head = next;
free(curr);
}
else
prev = curr;
curr = next;
}
as your for loop. The message is, without double pointers, you have to maintain a prev variable to re-organize the pointers, and handle the two different cases.
But with double pointers, you can actually write
// now head is a double pointer
for (node** curr = head; *curr; )
{
node * entry = *curr;
if (rm(entry))
{
*curr = entry->next;
free(entry);
}
else
curr = &entry->next;
}
You don't need a prev now because you can directly modify what prev->next pointed to.
To make things clearer, let's follow the code a little bit. During the removal:
if entry == *head: it will be *head (==*curr) = *head->next -- head now points to the pointer of the new heading node. You do this by directly changing head's content to a new pointer.
if entry != *head: similarly, *curr is what prev->next pointed to, and now points to entry->next.
No matter in which case, you can re-organize the pointers in a unified way with double pointers.
1. Basic Concept -
When you declare as follows : -
1. char *ch - (called character pointer)
- ch contains the address of a single character.
- (*ch) will dereference to the value of the character..
2. char **ch -
'ch' contains the address of an Array of character pointers. (as in 1)
'*ch' contains the address of a single character. (Note that it's different from 1, due to difference in declaration).
(**ch) will dereference to the exact value of the character..
Adding more pointers expand the dimension of a datatype, from character to string, to array of strings, and so on... You can relate it to a 1d, 2d, 3d matrix..
So, the usage of pointer depends upon how you declare it.
Here is a simple code..
int main()
{
char **p;
p = (char **)malloc(100);
p[0] = (char *)"Apple"; // or write *p, points to location of 'A'
p[1] = (char *)"Banana"; // or write *(p+1), points to location of 'B'
cout << *p << endl; //Prints the first pointer location until it finds '\0'
cout << **p << endl; //Prints the exact character which is being pointed
*p++; //Increments for the next string
cout << *p;
}
2. Another Application of Double Pointers -
(this would also cover pass by reference)
Suppose you want to update a character from a function. If you try the following : -
void func(char ch)
{
ch = 'B';
}
int main()
{
char ptr;
ptr = 'A';
printf("%c", ptr);
func(ptr);
printf("%c\n", ptr);
}
The output will be AA. This doesn't work, as you have "Passed By Value" to the function.
The correct way to do that would be -
void func( char *ptr) //Passed by Reference
{
*ptr = 'B';
}
int main()
{
char *ptr;
ptr = (char *)malloc(sizeof(char) * 1);
*ptr = 'A';
printf("%c\n", *ptr);
func(ptr);
printf("%c\n", *ptr);
}
Now extend this requirement for updating a string instead of character.
For this, you need to receive the parameter in the function as a double pointer.
void func(char **str)
{
strcpy(str, "Second");
}
int main()
{
char **str;
// printf("%d\n", sizeof(char));
*str = (char **)malloc(sizeof(char) * 10); //Can hold 10 character pointers
int i = 0;
for(i=0;i<10;i++)
{
str = (char *)malloc(sizeof(char) * 1); //Each pointer can point to a memory of 1 character.
}
strcpy(str, "First");
printf("%s\n", str);
func(str);
printf("%s\n", str);
}
In this example, method expects a double pointer as a parameter to update the value of a string.
Pointers to pointers also come in handy as "handles" to memory where you want to pass around a "handle" between functions to re-locatable memory. That basically means that the function can change the memory that is being pointed to by the pointer inside the handle variable, and every function or object that is using the handle will properly point to the newly relocated (or allocated) memory. Libraries like to-do this with "opaque" data-types, that is data-types were you don't have to worry about what they're doing with the memory being pointed do, you simply pass around the "handle" between the functions of the library to perform some operations on that memory ... the library functions can be allocating and de-allocating the memory under-the-hood without you having to explicitly worry about the process of memory management or where the handle is pointing.
For instance:
#include <stdlib.h>
typedef unsigned char** handle_type;
//some data_structure that the library functions would work with
typedef struct
{
int data_a;
int data_b;
int data_c;
} LIB_OBJECT;
handle_type lib_create_handle()
{
//initialize the handle with some memory that points to and array of 10 LIB_OBJECTs
handle_type handle = malloc(sizeof(handle_type));
*handle = malloc(sizeof(LIB_OBJECT) * 10);
return handle;
}
void lib_func_a(handle_type handle) { /*does something with array of LIB_OBJECTs*/ }
void lib_func_b(handle_type handle)
{
//does something that takes input LIB_OBJECTs and makes more of them, so has to
//reallocate memory for the new objects that will be created
//first re-allocate the memory somewhere else with more slots, but don't destroy the
//currently allocated slots
*handle = realloc(*handle, sizeof(LIB_OBJECT) * 20);
//...do some operation on the new memory and return
}
void lib_func_c(handle_type handle) { /*does something else to array of LIB_OBJECTs*/ }
void lib_free_handle(handle_type handle)
{
free(*handle);
free(handle);
}
int main()
{
//create a "handle" to some memory that the library functions can use
handle_type my_handle = lib_create_handle();
//do something with that memory
lib_func_a(my_handle);
//do something else with the handle that will make it point somewhere else
//but that's invisible to us from the standpoint of the calling the function and
//working with the handle
lib_func_b(my_handle);
//do something with new memory chunk, but you don't have to think about the fact
//that the memory has moved under the hood ... it's still pointed to by the "handle"
lib_func_c(my_handle);
//deallocate the handle
lib_free_handle(my_handle);
return 0;
}
Hope this helps,
Jason
Strings are a great example of uses of double pointers. The string itself is a pointer, so any time you need to point to a string, you'll need a double pointer.
Simple example that you probably have seen many times before
int main(int argc, char **argv)
In the second parameter you have it: pointer to pointer to char.
Note that the pointer notation (char* c) and the array notation (char c[]) are interchangeable in function arguments. So you could also write char *argv[]. In other words char *argv[] and char **argv are interchangeable.
What the above represents is in fact an array of character sequences (the command line arguments that are given to a program at startup).
See also this answer for more details about the above function signature.
A little late to the party, but hopefully this will help someone.
In C arrays always allocate memory on the stack, thus a function can't return
a (non-static) array due to the fact that memory allocated on the stack
gets freed automatically when the execution reaches the end of the current block.
That's really annoying when you want to deal with two-dimensional arrays
(i.e. matrices) and implement a few functions that can alter and return matrices.
To achieve this, you could use a pointer-to-pointer to implement a matrix with
dynamically allocated memory:
/* Initializes a matrix */
double** init_matrix(int num_rows, int num_cols){
// Allocate memory for num_rows float-pointers
double** A = calloc(num_rows, sizeof(double*));
// return NULL if the memory couldn't allocated
if(A == NULL) return NULL;
// For each double-pointer (row) allocate memory for num_cols floats
for(int i = 0; i < num_rows; i++){
A[i] = calloc(num_cols, sizeof(double));
// return NULL if the memory couldn't allocated
// and free the already allocated memory
if(A[i] == NULL){
for(int j = 0; j < i; j++){
free(A[j]);
}
free(A);
return NULL;
}
}
return A;
}
Here's an illustration:
double** double* double
------------- ---------------------------------------------------------
A ------> | A[0] | ----> | A[0][0] | A[0][1] | A[0][2] | ........ | A[0][cols-1] |
| --------- | ---------------------------------------------------------
| A[1] | ----> | A[1][0] | A[1][1] | A[1][2] | ........ | A[1][cols-1] |
| --------- | ---------------------------------------------------------
| . | .
| . | .
| . | .
| --------- | ---------------------------------------------------------
| A[i] | ----> | A[i][0] | A[i][1] | A[i][2] | ........ | A[i][cols-1] |
| --------- | ---------------------------------------------------------
| . | .
| . | .
| . | .
| --------- | ---------------------------------------------------------
| A[rows-1] | ----> | A[rows-1][0] | A[rows-1][1] | ... | A[rows-1][cols-1] |
------------- ---------------------------------------------------------
The double-pointer-to-double-pointer A points to the first element A[0] of a
memory block whose elements are double-pointers itself. You can imagine these
double-pointers as the rows of the matrix. That's the reason why every
double-pointer allocates memory for num_cols elements of type double.
Furthermore A[i] points to the i-th row, i.e. A[i] points to A[i][0] and
that's just the first double-element of the memory block for the i-th row.
Finally, you can access the element in the i-th row
and j-th column easily with A[i][j].
Here's a complete example that demonstrates the usage:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
/* Initializes a matrix */
double** init_matrix(int num_rows, int num_cols){
// Allocate memory for num_rows double-pointers
double** matrix = calloc(num_rows, sizeof(double*));
// return NULL if the memory couldn't allocated
if(matrix == NULL) return NULL;
// For each double-pointer (row) allocate memory for num_cols
// doubles
for(int i = 0; i < num_rows; i++){
matrix[i] = calloc(num_cols, sizeof(double));
// return NULL if the memory couldn't allocated
// and free the already allocated memory
if(matrix[i] == NULL){
for(int j = 0; j < i; j++){
free(matrix[j]);
}
free(matrix);
return NULL;
}
}
return matrix;
}
/* Fills the matrix with random double-numbers between -1 and 1 */
void randn_fill_matrix(double** matrix, int rows, int cols){
for (int i = 0; i < rows; ++i){
for (int j = 0; j < cols; ++j){
matrix[i][j] = (double) rand()/RAND_MAX*2.0-1.0;
}
}
}
/* Frees the memory allocated by the matrix */
void free_matrix(double** matrix, int rows, int cols){
for(int i = 0; i < rows; i++){
free(matrix[i]);
}
free(matrix);
}
/* Outputs the matrix to the console */
void print_matrix(double** matrix, int rows, int cols){
for(int i = 0; i < rows; i++){
for(int j = 0; j < cols; j++){
printf(" %- f ", matrix[i][j]);
}
printf("\n");
}
}
int main(){
srand(time(NULL));
int m = 3, n = 3;
double** A = init_matrix(m, n);
randn_fill_matrix(A, m, n);
print_matrix(A, m, n);
free_matrix(A, m, n);
return 0;
}
For example, you might want to make sure that when you free the memory of something you set the pointer to null afterwards.
void safeFree(void** memory) {
if (*memory) {
free(*memory);
*memory = NULL;
}
}
When you call this function you'd call it with the address of a pointer
void* myMemory = someCrazyFunctionThatAllocatesMemory();
safeFree(&myMemory);
Now myMemory is set to NULL and any attempt to reuse it will be very obviously wrong.
For instance if you want random access to noncontiguous data.
p -> [p0, p1, p2, ...]
p0 -> data1
p1 -> data2
-- in C
T ** p = (T **) malloc(sizeof(T*) * n);
p[0] = (T*) malloc(sizeof(T));
p[1] = (T*) malloc(sizeof(T));
You store a pointer p that points to an array of pointers. Each pointer points to a piece of data.
If sizeof(T) is big it may not be possible to allocate a contiguous block (ie using malloc) of sizeof(T) * n bytes.
One thing I use them for constantly is when I have an array of objects and I need to perform lookups (binary search) on them by different fields.
I keep the original array...
int num_objects;
OBJECT *original_array = malloc(sizeof(OBJECT)*num_objects);
Then make an array of sorted pointers to the objects.
int compare_object_by_name( const void *v1, const void *v2 ) {
OBJECT *o1 = *(OBJECT **)v1;
OBJECT *o2 = *(OBJECT **)v2;
return (strcmp(o1->name, o2->name);
}
OBJECT **object_ptrs_by_name = malloc(sizeof(OBJECT *)*num_objects);
int i = 0;
for( ; i<num_objects; i++)
object_ptrs_by_name[i] = original_array+i;
qsort(object_ptrs_by_name, num_objects, sizeof(OBJECT *), compare_object_by_name);
You can make as many sorted pointer arrays as you need, then use a binary search on the sorted pointer array to access the object you need by the data you have. The original array of objects can stay unsorted, but each pointer array will be sorted by their specified field.
Why double pointers?
The objective is to change what studentA points to, using a function.
#include <stdio.h>
#include <stdlib.h>
typedef struct Person{
char * name;
} Person;
/**
* we need a ponter to a pointer, example: &studentA
*/
void change(Person ** x, Person * y){
*x = y; // since x is a pointer to a pointer, we access its value: a pointer to a Person struct.
}
void dontChange(Person * x, Person * y){
x = y;
}
int main()
{
Person * studentA = (Person *)malloc(sizeof(Person));
studentA->name = "brian";
Person * studentB = (Person *)malloc(sizeof(Person));
studentB->name = "erich";
/**
* we could have done the job as simple as this!
* but we need more work if we want to use a function to do the job!
*/
// studentA = studentB;
printf("1. studentA = %s (not changed)\n", studentA->name);
dontChange(studentA, studentB);
printf("2. studentA = %s (not changed)\n", studentA->name);
change(&studentA, studentB);
printf("3. studentA = %s (changed!)\n", studentA->name);
return 0;
}
/**
* OUTPUT:
* 1. studentA = brian (not changed)
* 2. studentA = brian (not changed)
* 3. studentA = erich (changed!)
*/
The following is a very simple C++ example that shows that if you want to use a function to set a pointer to point to an object, you need a pointer to a pointer. Otherwise, the pointer will keep reverting to null.
(A C++ answer, but I believe it's the same in C.)
(Also, for reference: Google("pass by value c++") = "By default, arguments in C++ are passed by value. When an argument is passed by value, the argument's value is copied into the function's parameter.")
So we want to set the pointer b equal to the string a.
#include <iostream>
#include <string>
void Function_1(std::string* a, std::string* b) {
b = a;
std::cout << (b == nullptr); // False
}
void Function_2(std::string* a, std::string** b) {
*b = a;
std::cout << (b == nullptr); // False
}
int main() {
std::string a("Hello!");
std::string* b(nullptr);
std::cout << (b == nullptr); // True
Function_1(&a, b);
std::cout << (b == nullptr); // True
Function_2(&a, &b);
std::cout << (b == nullptr); // False
}
// Output: 10100
What happens at the line Function_1(&a, b);?
The "value" of &main::a (an address) is copied into the parameter std::string* Function_1::a. Therefore Function_1::a is a pointer to (i.e. the memory address of) the string main::a.
The "value" of main::b (an address in memory) is copied into the parameter std::string* Function_1::b. Therefore there are now 2 of these addresses in memory, both null pointers. At the line b = a;, the local variable Function_1::b is then changed to equal Function_1::a (= &main::a), but the variable main::b is unchanged. After the call to Function_1, main::b is still a null pointer.
What happens at the line Function_2(&a, &b);?
The treatment of the a variable is the same: within the function, Function_2::a is the address of the string main::a.
But the variable b is now being passed as a pointer to a pointer. The "value" of &main::b (the address of the pointer main::b) is copied into std::string** Function_2::b. Therefore within Function_2, dereferencing this as *Function_2::b will access and modify main::b . So the line *b = a; is actually setting main::b (an address) equal to Function_2::a (= address of main::a) which is what we want.
If you want to use a function to modify a thing, be it an object or an address (pointer), you have to pass in a pointer to that thing. The thing that you actually pass in cannot be modified (in the calling scope) because a local copy is made.
(An exception is if the parameter is a reference, such as std::string& a. But usually these are const. Generally, if you call f(x), if x is an object you should be able to assume that f won't modify x. But if x is a pointer, then you should assume that f might modify the object pointed to by x.)
Compare modifying value of variable versus modifying value of pointer:
#include <stdio.h>
#include <stdlib.h>
void changeA(int (*a))
{
(*a) = 10;
}
void changeP(int *(*P))
{
(*P) = malloc(sizeof((*P)));
}
int main(void)
{
int A = 0;
printf("orig. A = %d\n", A);
changeA(&A);
printf("modi. A = %d\n", A);
/*************************/
int *P = NULL;
printf("orig. P = %p\n", P);
changeP(&P);
printf("modi. P = %p\n", P);
free(P);
return EXIT_SUCCESS;
}
This helped me to avoid returning value of pointer when the pointer was modified by the called function (used in singly linked list).
OLD (bad):
int *func(int *P)
{
...
return P;
}
int main(void)
{
int *pointer;
pointer = func(pointer);
...
}
NEW (better):
void func(int **pointer)
{
...
}
int main(void)
{
int *pointer;
func(&pointer);
...
}
Most of the answers here are more or less related to application programming. Here is an example from embedded systems programming. For example below is an excerpt from the reference manual of NXP's Kinetis KL13 series microcontroller, this code snippet is used to run bootloader, which resides in ROM, from firmware:
"
To get the address of the entry point, the user application reads the word containing the pointer to the bootloader API tree at offset 0x1C of the bootloader's vector table. The vector table is placed at the base of the bootloader's address range, which for the ROM is 0x1C00_0000. Thus, the API tree pointer is at address 0x1C00_001C.
The bootloader API tree is a structure that contains pointers to other structures, which have the function and data addresses for the bootloader. The bootloader entry point is always the first word of the API tree.
"
uint32_t runBootloaderAddress;
void (*runBootloader)(void * arg);
// Read the function address from the ROM API tree.
runBootloaderAddress = **(uint32_t **)(0x1c00001c);
runBootloader = (void (*)(void * arg))runBootloaderAddress;
// Start the bootloader.
runBootloader(NULL);
I have used double pointers today while I was programming something for work, so I can answer why we had to use them (it's the first time I actually had to use double pointers). We had to deal with real time encoding of frames contained in buffers which are members of some structures. In the encoder we had to use a pointer to one of those structures. The problem was that our pointer was being changed to point to other structures from another thread. In order to use the current structure in the encoder, I had to use a double pointer, in order to point to the pointer that was being modified in another thread. It wasn't obvious at first, at least for us, that we had to take this approach. A lot of address were printed in the process :)).
You SHOULD use double pointers when you work on pointers that are changed in other places of your application. You might also find double pointers to be a must when you deal with hardware that returns and address to you.

Resources