Are double pointers necessary? - c++

void test(int *p2) {
*p2 = 3;}
int main()
{
int* p1, x = 5;
p1 = &x;
test(p1); // p1 and p2 are pointing to the same address which is x's address
printf("%d", x); //prints 3
this example 2 pointers pointing to the same address, which passing to the function by reference.
Now take this 2nd example
void test(int **p2) {
**p2 = 3;
}
int main()
{
int* p1, x = 5;
p1 = &x;
test(&p1); // p2 is pointing to p1 address
printf("%d", x);
so are double pointers necessary in these type of situations? especially with structured linked lists?
typedef struct NOde {
int data;
struct NOde* next;
}node;
void test(node *head) {
node* new_node = (node*)malloc(sizeof(node));
new_node->data = 5;
new_node->next = head;
head= new_node;
}
int main()
{
node* head=NULL;
test(head);
and why in this one, the head values in the main still NULL if it same concept as above?

Pointers (*p) are sufficient when you want to change the contents of the address the pointer is pointing at.
Double star pointers (**p) are necessary when you want to change the address the pointer is pointing at.
In the following code, inspect the outcome of the second printf statements especially.
#include <stdio.h>
#include <stdlib.h>
void swapValues(int *p, int val) {
*p = val;
}
void swapPointers(int **p, int *val) {
*p = val;
}
int main() {
int x, y;
int *p1 = &x;
int *p2 = &x;
x = 3;
y = 5;
printf("x = %d y = %d p1 = %d p2 = %d\n", x, y, *p1, *p2);
printf("p1 = %p p2 = %p\n", p1, p2);
swapValues(p1, y);
printf("x = %d y = %d p1 = %d p2 = %d\n", x, y, *p1, *p2);
printf("p1 = %p p2 = %p\n", p1, p2);
x = 3;
y = 5;
swapPointers(&p2, &y);
printf("x = %d y = %d p1 = %d p2 = %d\n", x, y, *p1, *p2);
printf("p1 = %p p2 = %p\n", p1, p2); // observe value of p2 here
return 0;
}

In C, all function calls are made by value. Which essentially means that the called function always gets its own copy of the arguments you pass to it. Same goes with the value you return from the function. There is always a copy of this value given back to the caller. The moment a function finishes execution, all arguments passed to it and local variables declared within it cease to exist.
For example:
int add(int a, int b)
{
int result = a + b;
return result;
}
int main()
{
int p = 3, q = 5;
int r = add(p,q);
}
In this case, a and b are copies of p and q respectively, and r is a copy of result. p, q and result no longer exist after add() has finished execution.
Now, this is fine for many common use-cases as in the example above. But what if you want to change the value of one of the variables in the calling function from within the called function? You then need to pass the address of the variable, so that the called function can indirectly access the variable in the calling function and update it.
Example:
void inc(int *p)
{
*p = *p + 1;
}
int main()
{
int a = 5;
inc(&a);
}
In this case, the called function gets a copy of the address of a, called p, using which it is able to update the memory location holding a indirectly. This is called dereferencing a pointer.
Now, to address your question, we need to take this one step further - what if we need to update a pointer in the calling function? We need to pass a pointer to the pointer - also called a double pointer.
In your example, we need to update head, which is already a pointer to a Node. So we need to pass the address of head, for which we need a double pointer.
Hence your code should be:
void test(node **phead)
{
node* new_node = (node*)malloc(sizeof(node));
new_node->data = 5;
new_node->next = *phead;
/* Note the dereferencing here - we update `head` indirectly through a pointer */
*phead = new_node;
}
test(&head);
Otherwise, we would be passing around a copy of head, which is a pointer, using which you can access the node that head points to, but not head itself. If you increment this pointer within your function, the change is not reflected outside, because this copy ceases to exist the moment the function returns.
PS: C++, unlike C, supports call by reference, which means the language transparently handles the pointer management and lets you directly update variables passed to you 'by reference'.

In your case no, because to assign the value you only need one pointer.
void test(int *p2) {
*p2 = 3;
}
Pointers to pointers are useful when you want to change the pointer.
A common use of pointers to pointers is methods that create something, but want to return something other than the pointer itself, e.g.
myerror_t create_foo(foo_t **p, int a, int b, int c)
{
if (a < 0 || b < c) return MYERR_INVALID_ARG;
*p = malloc(sizeof foo_t);
p->x = a * b * c;
return MYERR_SUCCESS;
}
Note that in C++, sometimes references are used when changing the value, and they can function in a very similar way.
void test(int &p2) {
p2 = 3;
}
Also note in C++, that throwing an exception, often from a constructor, is more common that a create_foo style method.
Foo::Foo(int a, int b, int c)
{
if (a < 0) throw std::invalid_argument("Foo a < 0");
if (b < c) throw std::invalid_argument("Foo b < c");
x = a * b * c;
}
If a factory function is desired, it might return the pointer and throw exceptions.

double pointers are needed if you are going to change the pointer itself in the function
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int value1 = 10;
int value2 = 20;
void choose(int x, int **pointerToValue)
{
switch(x)
{
case 0:
*pointerToValue = &value1;
break;
case 1:
*pointerToValue = &value2;
break;
default:
*pointerToValue = NULL;
}
}
int main()
{
int *ptr;
int choice;
choose(choice = rand() & 1, &ptr);
//ptr value was changed in the function
printf("Choice = %d, value = %d\n", choice, ptr ? *ptr : 0);
}

Are double pointers necessary?
TL;DR:
The moment a function shall change the value of a pointer defined by the calling function, then yes, they are (and can even become triple, quatuple, ... pointers).
Longish answer:
To have a function change a variable of type T and this variable is defined by the caller, the caller needs to pass to the function a pointer to T, that is a T*.
The function then needs to dereference the T* variable using the * operator as shown in your 1st snippet:
void test(int *p2) {
*p2 = 3; /* p2 is dereferenced, so the assignment works on the variable it is pointing to. */
}
So if then T already is a pointer type then T* would be a pointer to a pointer.
This latter case should be the appearing within the last snippet you show. And it shall be handled exactly as in the 1st snippet. node * head shall be changed within test2(). So pass the address of head;
test2(&head);
To be able to do so the parameter of test2 need to be defined as a pointer to the type of head. head is node*, so a pointer to is is node**.
void test2(node ** phead)
To then change the value of the caller's head inside the function the pointer to head, namely phead needs be dereferenced:
*phead = ....
why in this one, the head values in the main still NULL if it same concept as above?"
Comparing the lines of your last snippet to the versions in my answer, you see that your code in fact is not using the "same concept" but misses a level of indirection, which your 1st snippet indeed uses ...;)

You would only pass a double (or triple, or whatever) pointer to a function if you need the function to write a new pointer value to the parameter, or if you're dealing with multiple-dimensioned data (an array of pointers to arrays (of pointers to arrays of ...)).
If you want a function to write to a parameter of type T, then you need to pass a pointer to T:
void foo( T *p )
{
*p = new_T_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
}
Now let's replace T with the pointer type P *:
void foo( P **ptr )
{
*ptr = new_pointer_to_P_value;
}
void bar( void )
{
P *var;
foo( &var ); // write a new pointer value to var
}
Once more for emphasis, replace P with Q *:
void foo( Q ***ptr )
{
*ptr = new_pointer_to_pointer_to_Q_value;
}
void bar( void )
{
Q **var;
foo( &var ); // write a new value to var
}
The semantics are the same in all three cases, all that's changed is the level of indirection. For N levels of indirection in bar, you need N+1 levels of indirection in foo.
The other case for multiple indirection is multiple-dimensioned data (arrays of pointers to arrays of pointers to ...). For example:
void create_2d_arr( int ***arr, size_t rows, size_t cols )
{
*arr = malloc( rows * sizeof *(*arr) );
if ( *arr )
{
for ( size_t i = 0; i < rows; i++ )
{
(*arr)[i] = malloc( cols * sizeof *(*arr)[i] )
{
for ( size_t j = 0; j < cols; j++ )
{
(*arr)[i][j] = initial_value;
}
}
}
}
}
As to your example:
void test(node *head) {
node* new_node = (node*)malloc(sizeof(node));
new_node->data = 5;
new_node->next = head;
head= new_node;
Yes, in this case, if you want the change to head to be seen in main, you have to pass a pointer to the pointer:
void test(node **head) {
node* new_node = (node*)malloc(sizeof(node));
new_node->data = 5;
new_node->next = *head;
*head= new_node;
}
int main( void )
{
...
test( &head );
...
}

It's not necessary double pointer because p2 is in the scope of the function so in the main function is not visibile. And you don't want to change the pointer address but only the value of the pointed variable.

If ypu want to change a variable in a function you should pass it by reference in C or C++ meaning.
Consider your example of a singly-linked list. The variable head has a pointer type.
node* head=NULL;
So to change it in the function test you need to pass the variable by reference. For example
A C implementation passing by reference
void test( node **head, int data )
{
node *new_node = ( node* )malloc( sizeof( node ) );
new_node->data = data;
new_node->next = *head;
*head= new_node;
}
and a C++ implementation passing by reference
void test( node * &head, int data )
{
head = new node { data, head };
}
Without passing the head node by reference in the C function implementation the function deals with a copy of the value stored in head. You can imagine the function and its call the following way
test( head, 5 );
//...
void test( /*node *parm_head, int data*/ )
{
node *parm_head = head;
int data = 5;
node *new_node = ( node* )malloc( sizeof( node ) );
new_node->data = data;
new_node->next = *head;
*head= new_node;
}
That is function parameters are its local variables.
Consider another example when you need ay first to allocate an array to pointers to strings. For example
char **strings = malloc( 10 * sizeof( char * ) );
for ( size_t i = 0; i < 10; i++ )
{
strings[i] = malloc( 100 );
}
Now if you want to reallocate the original array by adding one more string then you gave to pass a pointer to this double pointer. For example
void add_one_more_string( char ***strings )
{
char **tmp = realloc( *strings, 11 ( sizeof( char * ) );
if ( tmp != NULL ) *stringvs = tmp;
//…
}
and call the function like
add_one_more_string( &strings );

Related

what happens when a pointer is passed as a pointer to a pointer inside another function?

So can someone explain what would happen if I pass ...*p as the argument name for the foo function
int main()
{
int i = 10;
int *const p = &i;
foo(&p);
printf("%d\n", *p);
}
void foo(int **p)
{
int j = 11;
*p = &j;
printf("%d\n", **p);
}
Don't do that. You'll have a pointer to an undefined memory location on the stack. Any other function call between foo(&p); and printf("%d\n", *p); is bound to overwrite that memory location with new data.
Let's look at a simple example here! We have a function print_address, which takes an address and prints it. We're gonna print the address of an int, as well as the address of a pointer to that int, and a pointer of a pointer to that int.
#include <stdio.h>
void print_address(void* addr) {
printf("Address: %p\n", addr);
}
int main()
{
int value = 0;
int* value_ptr = &value;
int** value_ptr_ptr = &value_ptr;
print_address(&value);
print_address(&value_ptr);
print_address(&value_ptr_ptr);
return 0;
}
When I run this code, I get the following output:
Address: 0x7fffa4936fec
Address: 0x7fffa4936ff0
Address: 0x7fffa4936ff8
The first address is to value, the second address is to value_ptr, and the third address is to value_ptr_ptr. Each address is a little higher than the previous one, because each variable has been stored a little higher up on the stack.
The same thing happens with function calls. When we call a function, the memory for all the local variables in that function is stored a little higher up on the stack then the memory for all the local variables in the current function:
#include <stdio.h>
void print_address(void* addr) {
printf("Address: %p\n", addr);
}
void f3(int*** ptr) {
print_address(ptr);
}
void f2(int** ptr) {
print_address(ptr);
f3(&ptr);
}
void f1(int* ptr) {
print_address(ptr);
f2(&ptr);
}
int main()
{
int value = 0;
f1(&value);
return 0;
}
This time when I ran it, the output was
Address: 0x7ffeca71dc2c
Address: 0x7ffeca71dc08
Address: 0x7ffeca71dbe8
If you notice, the gaps between addresses are higher, but that's because of the extra stack space it takes to do a function call.
j is destoyed after exiting foo, so doing anything with it after foo calling in main is incorrect, until you reset it on another object (I mean printf("%d\n", *p)).
Well, what you're doing is passing pointer on pointer on integer.
As you could see, pointers are often used to pass arrays:
void print_array(int* a, int n) {
for (int i = 0; i < n; i++)
printf("%d ", a[i]);
printf("\n");
}
And pointers on pointers are used to pass two-dimensional arrays, for example in int main(int argc, char** argv) { ... } argv is array of strings or array of arrays of char-s.
You can't pass *p, but let's say you could...
It looks like you are trying to get your function to update a parent variable - and passing &p is the correct way to do it. But you are adding one too many dereference. I highly recommend you read this: https://boredzo.org/pointers/
// Let's assume you only have 4 memory locations for variables: 1 2 3 and 4.
// let's call these m[1] m[2] m[3] and m[4]
// i is at 1, p is at 2, j is at 3, and the p inside the function is at 4.
// let's call that second p, q rather
// so you have: m[1..4] = { i, p, j, q }
// now execute the code in your head:
int main()
{
int i = 10; // m[1] = 10
int *const p = &i; // m[2] = 1
foo(&p); // foo(2)
printf("%d\n", *p); // printf m[2]
}
void foo(int **q) // q = m[m[2]] = m[1] = 10
{
int j = 11; // m[3] = 11
*q = &j; // m[10] = 3 // segfault!
printf("%d\n", **q); // printf m[m[10]] = m[3] = 11 // if it didnt' segfault
}
It looks like this is what you are trying to do:
#include <stdio.h>
void b(int *q,int n) {
*q=n;
}
int main() {
int i=123;
int *p=&i; // *p and i are now synonymous
printf("%i ",i);
printf("%i ",*p); // same thing
b(p,111);
printf("%i ",i);
b(&i,111);a // same thing
printf("%i ",i);
}

Pointers and pointers to reference

Having a structure
struct Person{
Person( int i):id(i){};
Person * next;
int id;
};
class Test{
public:
void addList( Person *&f , Person *&l , int i){
Person *tmp = new Person(i);
if( f == nullptr ){
f = tmp;
l = tmp;
return;
}
first -> next = tmp;
last = tmp;
}
void addArr( int *arr , int i ){
arr[index++] = i;
}
void print( ){
for( int i = 0; i < index; i ++)
cout << arr[i] << " ";
cout << endl;
}
Person *first = nullptr;
Person *last = nullptr;
int index = 0;
int *arr = new int[10];
};
function addList add node into linked list and addArr adds element into arr.
My question is about pointer and reference pointer.
in
void addList( Person *&f , Person *&l , int i){
Person *tmp = new Person(i);
if( f == nullptr ){
f = tmp;
l = tmp;
return;
}
first -> next = tmp;
last = tmp;
}
I need to pass pointer as reference. Otherwise , the local copy of pointer would be changed not outer. I assume compilator creates something like
Person *temporary = new Person(*f);
But would I not have to pass array by reference?
I am quite confused by this fact.
But would i do not have to pass array by reference?
Not in this case, by passing your Person pointer by reference in the addList function, you are able to alter the pointer itself. That is like saying, "Pointer, use a different address". This is possible, as it was passed by reference.
Whereas in your addArr function, you are not altering the pointer to the array itself. Rather, you are altering the data that is pointed to. "Pointed to data, use a different value". This data arr is pointing to is the same data outside the scope of the function.
So, no, you don't have to pass the array by reference.

Compiler Error, Linked list: error: base operand of ‘->’ has non-pointer type ‘IntNodeType’

Below I have some basic code and I am learning about linked lists. This function passes an array and created a linked list from it. However, when I try to compile it I get an error about a non-pointer type. Can anyone tell me what I am doing wrong? Thanks
struct IntNodeType {
int value;
IntNodeType * next;
IntNodeType (int v=0, IntNodeType * p=NULL):value(v),next(p)
{
}
};
IntNodeType * InitList (int a[], int size)
{
IntNodeType *p;
p = new IntNodeType[size];
int i = 0;
while ( i < size )
{
p[i]->value = a[i];
if ( i == size - 1)
{
p[i] -> next = NULL;
break;
}
else
p[i] -> next = p[i+1];
i++;
}
return p;
}
To correctly compile your code, InitList's body should be:
// ..
IntNodeType *p;
p = new IntNodeType[size];
int i = 0;
while ( i < size )
{
p[i].value = a[i]; // here
if ( i == size - 1)
{
p[i].next = nullptr; // here + nullptr
break;
}
else
p[i].next = &(p[i+1]); //here
i++;
}
return p;
Notice the usage of the period operator instead of the -> operator.
Although p is an array type (can be decayed into a pointer), its contents aren't pointers. p contains size many IntNodeTypes.
For the last noted line you need to pass it a reference to the non-pointer p[i+1]
It's also worth noting you should use nullptr over NULL.

Try to modify const reference

I've got an argument with my co-workers.
Once I did try to modify constant reference.
Sample of code is below:
#include <cstdio>
#include <cstdlib>
using namespace std;
int main(int argc, char const *argv[])
{
const int* A = NULL;
printf("A = %p\n", A);
int** pA = const_cast<int**>(&A);
*pA = new int(5);
if (pA != NULL)
printf("pA = %p, value = %d\n", pA, *pA);
else
printf("pA null pointer\n");
if (A != NULL)
printf("A = %p, value = %d\n", A, *A);
else
printf("A null pointer\n");
return 0;
}
Everything works fine and the log is
A = 00000000
pA = 0028FED8, value = 4068760
A = 003E1598, value = 5
I think it works that way:
I create a const pointer variable A with '0' (zero) value is stack. It is local variable wich occupies 4 bytes of memory in stack.
then I create a pointer to pointer variable, I cast away constant modification and take address of the variable
I think this code works fine and will not lead to a bug. But I need some kind of explanations. Am I right?
const int *a and int * const a are different.
Case 1
[const is used on *a]
Here the value of a is constant. The address pointed by a can be changed.
const int *a = malloc(sizeof (int));
if (a)
{
//*a = 10; //not allowed
a = malloc(sizeof (int));; //allowed
}
Case 2
[const is used on a]
Here the address of a is constant. The value of a can be changed.
int * const a = malloc(sizeof (int));
if (a)
{
*a = 10; //allowed
//a = malloc(sizeof (int));; //not allowed
}
EDIT:
As suggested by #lifeOfPI, read about using const_cast .

What's the proper way to pass a pointer to a function for deletion?

I have a matrix declared like int **matrix, and I know that the proper way to pass it to a function to allocate memory should be like this:
void AllocMat(int ***mat, int size);
But now I need to delete these memory in another function and am not sure about what to pass:
void DeallocMat(int **mat, int size);
or
void DeallocMat(int ***mat, int size);
I think the second one should be right, but neither way gives me segmentation fault as I tried.
The question is tagged C++, and yet the answers only use the C subset...
Well, first of all, I would recommend against the whole thing. Create a class that encapsulates your matrix and allocate it in a single block, offer operator()(int,int) to gain access to the elements...
But back to the problem. In C++ you should use references rather than pointers to allow the function to change the argument, so your original allocate signature should be:
void AllocMat(int **&mat, int size);
And call it like:
int **matrix = 0;
AllocMat( matrix, 5 );
Or better, just return the pointer:
int **AllocMat( int size );
int **matrix = AllocMat( 5 );
For the deallocation function, since you don't need to modify the outer pointer, you can just use:
void DeallocMat( int**mat, int size ); // size might be required to release the
// internal pointers
Now, for a sketch of the C++ solution:
template <typename T> // no need to limit this to int
class square_matrix {
const unsigned size;
T * data;
public:
square_matrix( unsigned size ) : size(size), data( new T[size*size]() ) {}
square_matrix( matrix const & m ) : size( m.size ), data( new T[m.size*m.size] ) {
std::copy( m.data, m.data+size*size, data );
}
~matrix() {
delete [] data;
}
T const & operator()( unsigned x, unsigned y ) const {
// optional range check and throw exception
return data[ x + y*size ];
}
void set( unsigned x, unsigned y, T const & value ) {
// optional range check and throw exception
data[ x + y*size ] = value;
}
};
First is correct. But your real problem is that you are using pointers when there are better alternatives. For a 2d matrix you should use a vector of vectors
#include <vector>
typedef std::vector<std::vector<int> > Matrix;
Matix m;
Now there is no need to delete anything, so one less thing to go wrong.
void DeallocMat(int **mat, int size) - allows you to deallocate memory (since you have passed the value of mat only allowing to deallocate memory but not change mat)
void DeallocMat(int ***mat, int size) - allows you to deallocate memory and change the value of mat to NULL (since you have now passed a pointer to mat allowing you to change its value)
The extra "*" just handles the pointer to be behaved as call by reference. If you want to get the output from your function, you need an extra "*" in your declaration. In this case, you should pass the reference of your pointer (using &) to these functions.
The reason why you required to pass a pointer to double pointer because your local variable must required to reflect with the new updated memory
void Foo(int * a)
{
a = new int[10];
}
int main()
{
int *a = 0;
Foo( a );
}
Now the memory will be allocated but the pointer A will not be update because the value of pointer A is simply copied to another pointer variable which is parameter of Foo. Once the Foo is returned, a will remain 0. To make it refect that, you should write code like follows
void Foo(int ** a)
{
*a = new int[10];
}
int main()
{
int *a = 0;
Foo( &a );
}
Here you're passing the address of a pointer. The which means that, the value which contains in the pointer will be updated from the Foo function.You can debug through and see how it works.
If you're sure that you will not access the pointer anymore, please use the first type. Otherwise use the second one. Make sure that you set the pointer to NULL to avoid further memory corruptions or dangling pointers.
The thing that confuses me about your question is that most people would not declare a matrix as an int **. The reason for this is that you would be forced to then allocate it in a loop. Your allocation function would require two parameters, which are the dimensions of the array like this:
void AllocMat(int *** mat, int n, int m) {
int ** result = new int * [ n ];
for (int x=0; x<n; x++) {
result[x] = new int [ m ];
}
*mat = result;
}
If this were the case, the corresponding deallocation function would require knowledge of the size of n as follows:
void DeallocMat(int *** mat, int n) {
if (mat == NULL || *mat == NULL) return;
int ** tmp = *mat;
for (int x=0; x<n; x++) {
if (tmp[x] != NULL) delete [] tmp[x];
}
delete [] tmp;
*mat = NULL;
}
With this approach, you could access your matrix like this:
int ** mat = NULL;
AllocMat(&mat, n, m);
for (int x=0; x<n; x++) {
for (int y=0; y<m; y++) {
mat[x][y] = 1;
}
}
DeallocMat(&mat, n);
Usually, people allocate matrices as a single buffer of memory to avoid extra allocations and pointer indirections, which is how I recommend you do it. In that case, you allocation function would look like this:
void AllocMat2(int ** mat, int n, int m) {
*mat = new int [ n * m ];
}
And the corresponding deallocation function like this:
void DeallocMat2(int ** mat) {
if (mat != NULL && *mat != NULL) {
delete [] *mat;
*mat = NULL;
}
}
And you would access it follows:
int * mat2 = NULL;
AllocMat2(&mat2, n, m);
for (int x=0; x<n; x++) {
for (int y=0; y<m; y++) {
mat2[x * n + y] = 1;
}
}
DeallocMat2(&mat2);
Either way works, but if you pass a pointer to the pointer you need to dereference it first. And the size parameter is redundant.
void DeallocMat(int **mat)
{
delete[] mat;
}
void DeallocMat(int ***mat)
{
delete[] *mat;
*mat = NULL;
}