Using traversal by pointers on const array - c++

I'm trying to loop through a constant array of integers using pointers. My code is as follows:
void printArrayPointer(const int arr[], int n){
for (int *i = arr; i < arr + n; i++) {
cout << *i << ' ';
}
}
This gives me an error telling me that there is an invalid conversion from const int* to int*. I know how to do this using traversal by index (as in using the index of the elements in the array) but I'm trying to use pointers for this code.

As the compiler already told you, there is an error in the line:
for (int *i = arr;...
arr is const int[], i is int *. If the compiler allows i to be initialized with a const int * then the subsequent code can change the const values stored in a using i, because i is a pointer to non-const data. That's the reason the code doesn't compile and the compiler tells you in the error message.
You have to declare i as const int *i and it will work.
void printArrayPointer(const int arr[], int n){
for (const int *i = arr; i < arr + n; i++) {
cout << *i << ' ';
}
}

As axiac said, you must write for (const int* i ... because arr is a const int*.
The reason that you can still increment i is that const int* means that what is at i cannot be changed, by you can still change what i points to. So you cannot change the values in the array, but you can change the const pointer that iterates through them.
To make it so that you can't change what a pointer points to, you would have to declare it like this: int* const i. Then you could change what is at i but not what i points to. You could also make it so that neither could be changed, which could be written as const int* const i.

Related

Is it possible to pass a 2D array using a void pointer in C++?

I want to pass a 2D array of characters to another function using a parameter of type "void*" and then have that function have access to the elements inside that array.
This code spits out a "Segmentation Fault:11" at the point where voidPointer tries to std::cout elements inside array2.
#include <iostream>
void voidPointer(void* userdata) {
char** array2 = static_cast<char**>(userdata);
for (int i=0; i<3; ++i) {
for (int j=0; j<3; ++j) {
std::cout << array2[i][j] << ' ';
}
std::cout << std::endl;
}
return;
}
int main() {
char array[3][3];
for (int i=0; i<3; ++i) {
for (int j=0; j<3; ++j) {
array[i][j] = 'a';
}
}
voidPointer(array);
return 0;
}
I've tried lots of different things and can't figure this out at all. I was able to get the above code to work when it's dealing with a 1D array. For example, this code
#include <iostream>
void voidPointer(void* userdata) {
char* array2 = static_cast<char*>(userdata);
for (int i=0; i<3; ++i) {
std::cout << array2[i] << ' ';
}
std::cout << std::endl;
return;
}
int main() {
char array[3];
for (int i=0; i<3; ++i) {
array[i] = 'a';
}
voidPointer(array);
return 0;
}
works as expected with the output "a a a".
Backstory: I'm working on my first project in which I'm trying to use a Mouse Callback function that accepts a parameter in the form "void* userdata". I am attempting to pass a 2D character array to this Callback function so I can then pass it on to other functions that will require access to the elements inside this array. I don't really know if this is good coding practice or not so feel free to let me know some alternatives.
To anyone that responds, thank you!
Firstly, I'll explain why your second example succeeds but your first example fails. Then I'll suggest some options for consideration to make your code work.
In short - your first example has undefined behaviour because the notional equivalence of pointers and arrays only works in one dimension.
The second example relies on the facts that;
The name of a one-dimensional array can be implicitly converted to a pointer to that array's first element. So, in main() of your second example, voidPointer(array) is equivalent to voidPointer(&array[0]). &array[0] has type char *.
A pointer can survive a round trip via a void * conversion - where "round trip" means retrieving the pointer of the original type. i.e. a char * can be converted to a void * AND that void * can be converted back to a char *. So the explicit conversion char* array2 = static_cast<char*>(userdata) done in voidPointer() successfully retrieves the pointer - so array2 in voidPointer() is equal to &array[0] passed by main();
Since the pointer passed by main() is the address of the first element of the array passed, voidPointer() can safely treat that pointer AS IF it is an array (as long as code doesn't try to access elements out of range of the original array).
The logic above is only applicable for pointers and one-dimensional arrays, so breaks down in the first example;
The name of a one-dimensional array can be implicitly converted to a pointer to that array's first element. So, in main() of your second example, voidPointer(array) is equivalent to voidPointer(&array[0]). However, the difference is that - the expression &array[0] has type char (*)[3] (a pointer to an array of three char) and that is NOT equivalent to a char **.
in voidPointer() your code converts the received pointer to a char ** via char** array2 = static_cast<char**>(userdata). This means that the pointer array2 has a different type that the pointer (&array[0]) passed by main();
Since array2 has a different type than the pointer passed by main() the code in voidPointer() which dereferences array2 (treats it as if it is an array of arrays) has undefined behaviour.
Generally speaking, there are two ways you can make the code work. The first is to do the right type of conversion.
void voidPointer(void* userdata)
{
char (*array2)[3] = static_cast<(char (*)[3]>(userdata);
// rest of your function can be used as is
}
As in your code, the array dimensions (which are both 3 in your example) must be known and fixed at compile time. There is no way that userPointer() can obtain any array dimensions from userdata, because a void * does not carry any of that sort of information from the caller.
A second option is to wrap the array in a data structure, for example
#include <iostream>
struct Carrier {char data[3][3];};
void voidPointer(void* userdata)
{
Carrier *package2 = static_cast<Carrier *>(userdata);
for (int i=0; i<3; ++i)
{
for (int j=0; j<3; ++j)
{
std::cout << package2->data[i][j] << ' ';
}
std::cout << std::endl;
}
}
int main()
{
Carrier package;
for (int i=0; i<3; ++i)
{
for (int j=0; j<3; ++j)
{
package.data[i][j] = 'a';
}
}
voidPointer(&package);
return 0;
}
This works because a Carrier * can survive a round trip via a void pointer (i.e. the value of package2 in voidPointer() has the the same type AND the same value as &package in main()) .
A second option is to use the std::array class. Although this is syntactically different, it is actually a modified version of the first option (since std::array is technically a templated data structure that contains an array of fixed dimension).
#include <iostream>
#include <array>
void voidPointer(void* userdata)
{
std::array<std::array<char, 3>, 3> *package2 = static_cast<std::array<std::array<char, 3>, 3> *>(userdata);
for (int i=0; i<3; ++i)
{
for (int j=0; j<3; ++j)
{
std::cout << (*package2)[i][j] << ' ';
}
std::cout << std::endl;
}
}
int main()
{
std::array<std::array<char, 3>, 3> package;
for (int i=0; i<3; ++i)
{
for (int j=0; j<3; ++j)
{
package[i][j] = 'a';
}
}
voidPointer(&package);
return 0;
}
Since your examples both had array dimensions fixed at compile time (3 in each dimension), my examples do the same. I'll leave extending the above to have dimensions fixed at run time (e.g. as user inputs) as a learning example.
It looks like the question is how to make this scenario work instead of why the attempt failed. For those interested in why the attempt failed, see casting void** to 2D array of int.
Note: It would be better to avoid using void*, but sometimes one has to interface with someone else's C-style API where void* is the traditional way to pass data to a callback.
There is a reasonably common trick for simulating a multi-dimensional array with a one-dimensional array. Using the trick reduces your scenario to the case that works. The trick involves how you access the elements. Instead of declaring char array[DIM1][DIM2] and accessing elements via array[i][j], declare the array to be char array[DIM1 * DIM2] and access elements via array[i*DIM2 + j].
However, remembering this formula is intellectual overhead, consuming brainpower that would be better used elsewhere. Not to mention that I get the dimensions reversed half the time. You could relieve the coder of this overhead by wrapping this array in a class, and hiding the formula in a method for accessing elements. This might look like the following.
class Array2D {
static constexpr unsigned DIM1 = 3;
static constexpr unsigned DIM2 = 3;
char data[DIM1 * DIM2];
public:
char& at(unsigned i, unsigned j) { return data[i*DIM2 + j]; }
// And perhaps other methods
};
You could then create an object of this class, then pass the address of that object to your C-style mouse handler. I.e. if your variable is Array2D array then call voidPointer(&array). This version can be adapted to the situation where the dimensions are not known at compile time.
Then again, if you are going to create a class anyway, why not try to preserve the syntax you are used to (using operator[] twice)? This does assume that the dimensions are compile-time constants.
class Array2D {
static constexpr unsigned DIM1 = 3;
static constexpr unsigned DIM2 = 3;
char data [DIM1][DIM2];
public:
auto& operator[] (unsigned i) { return data[i]; }
// And perhaps other methods
};
Of course, this approach locks you into a single size. It would probably be a good idea to make this a template. It would be even better if someone else did all that work for me.
#include <array>
static constexpr unsigned DIM1 = 3;
static constexpr unsigned DIM2 = 3;
using Array2D = std::array< std::array<char,DIM2>, DIM1 >;
// Note the order: ^^^^ ^^^^
Remember: if your variable is Array2D array then call voidPointer(&array).
Why not to use a structure instead of array. You can define everything in a structure, than pass its address to your function.

C++ Passing Static Array and Dynamic Array By Reference

To fully understand how pointers, values, and references work, I am making a basic C++ program that attempts to tamper with some static and dynamic arrays and understand exactly how they should be passed in.
First I generate a static array of 3 elements. I then pass it into a function that modifies all elements. I then pass it into another function with a slightly different signature, but can also alter the array's values.
Next I generate a dynamically sized array, pass it into a function by reference so that all of the values in this dynamically sized array can be altered.
The code is as follows:
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
void changeIndexStaticArrayMethod1(int* stat);
void changeIndexStaticArrayMethod2(int (&stat)[3]);
void changeIndexDynamicArrayMethod1(int* dyn, int size);
int main() {
const int MAX = 3;
int arr[MAX] = { 1,2,3 };
changeIndexStaticArrayMethod1(arr);
cout << arr[0] << endl;
cout << arr[1] << endl;
cout << arr[2] << endl;
cout << endl;
changeIndexStaticArrayMethod2(arr);
cout << arr[0] << endl;
cout << arr[1] << endl;
cout << arr[2] << endl;
int SIZE;
cout << "Please choose a size for the array" << endl;
cin >> SIZE;
int *ne = new int[SIZE];
//Build array
for (int i = 0; i < SIZE; i++) {
ne[i] = i;
}
changeIndexDynamicArrayMethod1(ne, SIZE);
for (int i = 0; i < SIZE; i++) {
cout << "ne[" << i << "] = " << ne[i] << endl;
}
//To hang program
cin >> SIZE;
delete[] arr;
delete[] ne;
return 0;
}
void changeIndexStaticArrayMethod1(int* stat) {
stat[0] = 10;
stat[1] = 20;
stat[2] = 30;
}
void changeIndexStaticArrayMethod2(int (&stat)[3]) {
stat[0] = 40;
stat[1] = 50;
stat[2] = 60;
}
void changeIndexDynamicArrayMethod1(int* dyn, int size) {
for (int i = 0; i < size; i++) {
dyn[i] = i * 10;
}
}
All of the above code works how I want it to, I just have a few questions as to why (some of the methods of passing arrays by reference I have found on other SO questions).
In the changeIndexStaticArrayMethod1() and changeIndexDynamicArrayMethod1() functions, why are we able to use the dereference * operator for our array as reference? My knee jerk reaction is seeing that as practically passing the array in by values since it is the dereference operator. I know that with arrays, it is much different than using variables, but also, why will the following not work for single int variables:
void changeStaticNumber(int* num){
num = 100;
}
Obviously the above will work if we use &num and not int* num, and obviously I don't fully understand the relationship between pointers and arrays, but I cannot figure out why when we pass an array by reference, int* staticArray is ok.
Any explanation for these problems I am having would be much appreciated. Thanks.
why are we able to use the dereference * operator for our array as reference?
The * in C means many things. It can mean the unary indirection ("contents of") operator, it can mean the binary multiplication operator and it can mean a pointer declaration. The int* stat is a pointer declaration.
Since you aren't using the * to dereference the contents of the pointer inside that function, I'm not quite sure what you are asking.
When you take the array name of your array in main(), it "decays" into a pointer to the first element. So what those function do, is to take a pointer by value. If you dereference the pointer by typing *stat = something; you access the actual array in main.
Should you do something weird like changing the pointer itself, for example stat++;, then it will not affect the address used in main. You passed the pointer itself by value, so the pointer is a local copy.
My knee jerk reaction is seeing that as practically passing the array in by values since it is the dereference operator.
You can't really pass arrays by value in C or C++, without resorting to dirty tricks (storing them inside structs or classes). For example, had your function been written as void changeIndexStaticArrayMethod1(int stat[3]) it would still give you a pointer to the first element. It will not pass an array by value, as the syntax might trick you into believing.
why will the following not work for single int variables:
void changeStaticNumber(int* num){ num = 100; }
Because num is the pointer itself, not its contents. In order to write code like that, you could pass the variable by reference int& num. Behind the lines this is really the same thing as passing a pointer, just with simplified syntax.
To understand the relation between pointers and arrays better, start by reading this whole chapter: http://c-faq.com/aryptr/index.html (C and C++ are identical when it comes to pointers).
Let me see if I can take a stab at this.
Pointers are simply address holders. Once you do int * ptr = myarray; --- what you are in tern doing is storing the address of the pointer my array into ptr --- array names are actually pointers to the first memory location in the array. You can use pointer arithmetic to get at everything else for example myarray +1 will point you to the next location or myarray[1].
Passing by value is not very useful when you need to modify your array. Passing in by reference is essentially making a pointer to the array and passing that. Since arrays like vectors are contiguous blocks of memory you can index through them rather easily.
As far as your example goes void changeStaticNumber(int* num){ num = 100; } will not work because what you are attempting to do is store 100 into the pointer's address. If you deference num and make it void changeStaticNumber(int* num){ *num = 100; } it will work because you are actually going one step further and accessing the data that num is pointing to. When you use &num it is essentially the same thing - & just gives you the address of something.
For example if you want to point a pointer to an int what you would do is
int num = 5;
int *ptr = &num;
at this point in time ptr has the same address in num. To print out the data in num or that ptr is pointing to you need to dereference or go one step further as I like to tell myself and dereference to so cout << *ptr;
In both changeIndexStaticArrayMethod1 and changeIndexDynamicArrayMethod1 you are not passing an array there is no pass by reference (which only happens if the parameter type is a reference type -- i.e. with &). The parameter has type int * (pointer to int). You are passing a pointer to int by value. There is no "dereference operator" in either function.
ne is already an int *, so passing it is nothing special. arr is an int [3], an array, not a pointer. In C, when an array-of-T is used in a context that expects a pointer-to-T, it is implicitly converted (without you needing to do anything) to a pointer to its first element. So when you do, changeIndexStaticArrayMethod1(arr), the compiler gets a pointer to the first element of arr, and passes that to the function.
The [] operator works on pointers. a[i] is always guaranteed to be the same as *(a + i). Inside both the changeIndexStaticArrayMethod1 and changeIndexDynamicArrayMethod1 functions, [] is used to access subsequent elements using a pointer to the first element.

Array passing to a method in C++ [duplicate]

This question already has answers here:
How do I use arrays in C++?
(5 answers)
What is array to pointer decay?
(11 answers)
Closed 8 years ago.
As far as I know, in C++ when you pass a non-pointer object to a method, it makes a copy of it to work with in the method. However in my program below, I pass a copy and yet my method actually edits the original character array. Why is this working? :/
#include <iostream>
#include <string>
void Reverse(char s[], int sizeOfArray)
{
for (int i = 0 ; i < sizeOfArray; i++)
{
s[i] = 'f';
}
}
int main()
{
char c[3] = {'g','t','r'};
Reverse(c,3);
for (int t = 0 ; t < 3; t++)
{
std::cout << c[t];
}
return 0;
}
NOTE:
The output is fff
You cannot copy arrays by passing them to functions. The array "decays" into a pointer. Check for yourself by printing the variables' typeid:
#include <iostream>
#include <string>
void Reverse(char s[], int sizeOfArray)
{
std::cout << typeid(s).name() << "\n";
for (int i = 0 ; i < sizeOfArray; i++)
{
s[i] = 'f';
}
}
int main()
{
char c[3] = {'g','t','r'};
std::cout << typeid(c).name() << "\n";
Reverse(c,3);
for (int t = 0 ; t < 3; t++)
{
std::cout << c[t];
}
return 0;
}
Result:
char [3]
char *
Moral of the story:
Use std::vector.
Edit: I should mention that the exact result of the typeid name is implementation-defined. "char [3]" and "char *" is what I get with VC 2013. But the underlying issue is the same on every compiler, of course.
void Reverse(char s[], int sizeOfArray)
Reverse(c,3);
>call by value
>call by reference
here you are doing call by reference operation that means you are passing address of c to int s[]
you are passing a reference of c to reverse function. this is called call by reference not call by value. thats why reverse function overriding your original input
Because char s[] is actually char * pointing to the first element of array.
It means your function Reverse gets the first arg pointer but not copy of array.
If you want to get copy you should use memcpy first and pass new (copy) array to function.
C-array cannot be passed by copy.
It may be passed by reference as void Reverse(char (&a)[3])
or by its decayed pointer as you do void Reverse(char a[], int size)
(which is the same as void Reverse(char* a, int size)).
You may use std::array (C++11) to have a more intuitive behaviour.
if you declare an array then the variable holds the base address of that array, so here char c[3] means c holds the base address of the array c[3].
so, when you are passing Reverse(c,3); actually you are passing the base address.

Arrays as address constants in functions

I'm teaching myself C++ and had some questions about arrays and pointers. My understanding is that arrays are really just pointers, however, arrays are address constants which cannot be changed.
If this is the case, I was wondering why in my function show2() I was able to change the address of the pointer list. Unlike variables, I thought arrays are passed by reference so I was expecting a compiler error when calling function show2() since I incremented the address of list. But the code works just fine. Can someone please explain?
Thank you!
#include<iostream>
#include<iomanip>
using namespace std;
void show1(double *list, int SIZE)
{
for(int i=0; i < SIZE; i++)
{
cout << setw(5) << *(list+i);
}
cout << endl;
return;
}
void show2(double *list, int SIZE)
{
double *ptr = list;
for(int i=0; i < SIZE; i++)
cout << setw(5) << *list++;
cout << endl;
return;
}
int main()
{
double rates[] = {6.5, 7.2, 7.5, 8.3, 8.6,
9.4, 9.6, 9.8, 10.0};
const int SIZE = sizeof(rates) / sizeof(double);
show1(rates, SIZE);
show2(rates, SIZE);
return 0;
}
My understanding is that arrays are really just pointers
Let's get that out of the way. No, arrays are not pointers. Arrays are a series of objects, all of the same type, contiguous in memory.
Arrays can be passed by reference, but that is not what is usually done. What is usually done, which is what you are doing, is passing a pointer to the first element of the array. Arrays can and will "decay" to a pointer to their first element upon demand. And that's what is happening when you pass rates to show1 and show2.
Inside show1 and show2, list starts out as a pointer to rates[0]. You're free to modify this pointer to point at any other double.
If you wanted to pass an array by reference, it would look like this:
void show3(double (&list)[9]) { ... }
Or the more versatile:
template<size_t SIZE>
void show3(double (&list)[SIZE]) { ... }
Note that what you can't do is pass an array by value (unless it is contained within another object). If you write a function which looks like it is taking an array by value, e.g.
void show4(double list[9]) { ... }
It is actually a pointer, and that number 9 is meaningless. Native arrays suck.
First, arrays are converted to a pointer to the first element when passed as the function argument. BTW, arrays are not pointers, as one example, sizeof(rates) in your code isn't the size of a pointer.
Second, arrays are passed by value since you are not using references.
So in the function show2, you are modifying a pointer, which is fine.
Arrays are not pointers. C++ has inherited "Array-Pointer Equivalence" from C which means that a well-known array variable can decay to a pointer, primarily for the purpose of offset math and for avoiding passing arrays by value:
int array[64];
int* a = array; // equivalent to a = &array[0];
Array's aren't pointers. If you use an array variable name in a pointer context, it will "decay" to a pointer - that is, lose the extended attributes available from an array object.
int array[64];
int* a = array;
std::cout << "array size = " << sizeof(array) << "\n";
std::cout << "a size = " << sizeof(a) << "\n";
std::cout << "(int*)(array) size = " << sizeof((int*)array)) << "\n";
"Array size" will be 256 (int is 4 bytes, 64 of them = 256 bytes), "a size" will be 4 or 8 bytes depending on 32/64 bits, and "(int*)(array)" size will be the same size as the pointer.
People often think that arrays are passed by value. This is not true: http://ideone.com/hAeH18
#include <iostream>
void bump(int arr[3]) {
for (size_t i = 0; i < 3; ++i)
arr[i]++;
}
int main() {
int array[] = { 1, 2, 3 };
bump(array);
for (size_t i = 0; i < 3; ++i)
std::cout << array[i] << "\n";
return 0;
}
This outputs "2, 3, 4" not "1, 2, 3".
This occurs because arrays decay to pointers when passed as function arguments. But to support the syntax for receiving arrays as arrays, C has to be able to treat pointers like arrays in some contexts:
void f1(int* a) { a[0]++; }
void f2(int* a) { (*a)++; }
void f3(int a[]) { a[0]++; }
void f4(int a[]) { (*a)++; }
void f5(int a[1]) { a[0]++; }
void f6(int a[1]) { (*a)++; }
All of these functions produce the same code.
In C, this originated from the fact that array information is lost at compile time. So this function:
void f(int array[])
has no way to tell how large the array it is receiving is. They wanted programmers to be conscious of this and be careful about how/if they passed size information - e.g. in the case of char arrays, instead of size, we have the nul terminator byte.
Unfortunately they didn't choose to make it obvious by diasllowing the representation that makes it look like you are receiving an array with size information intact :(

Meaning of *& and **& in C++

I found these symbols in a function declaration several times, but I don't know what they mean.
Example:
void raccogli_dati(double **& V, double **p, int N) {
int ultimo = 3;
V = new double * [N/2];
for(int i=0; i < N/2; i++) {
V[i] = new double[N/2], std :: clog << "digita " << N/2 - i
<< " valori per la parte superiore della matrice V: ";
for(int j=i; j < N/2; j++)
std :: cin >> V[i][j], p[ultimo++][0] = (V[i][j] /= sqrt(p[i][0]*p[j][0]));
}
for(int i=1; i < N/2; i++)
for(int j=0; j < i; j++)
V[i][j] = V[j][i];
}
That is taking the parameter by reference. So in the first case you are taking a pointer parameter by reference so whatever modification you do to the value of the pointer is reflected outside the function. Second is the simlilar to first one with the only difference being that it is a double pointer. See this example:
void pass_by_value(int* p)
{
//Allocate memory for int and store the address in p
p = new int;
}
void pass_by_reference(int*& p)
{
p = new int;
}
int main()
{
int* p1 = NULL;
int* p2 = NULL;
pass_by_value(p1); //p1 will still be NULL after this call
pass_by_reference(p2); //p2 's value is changed to point to the newly allocate memory
return 0;
}
First is a reference to a pointer, second is a reference to a pointer to a pointer. See also FAQ on how pointers and references differ.
void foo(int*& x, int**& y) {
// modifying x or y here will modify a or b in main
}
int main() {
int val = 42;
int *a = &val;
int **b = &a;
foo(a, b);
return 0;
}
That's passing a pointer by reference rather than by value. This for example allows altering the pointer (not the pointed-to object) in the function is such way that the calling code sees the change.
Compare:
void nochange( int* pointer ) //passed by value
{
pointer++; // change will be discarded once function returns
}
void change( int*& pointer ) //passed by reference
{
pointer++; // change will persist when function returns
}
An int* is a pointer to an int, so int*& must be a reference to a pointer to an int. Similarly, int** is a pointer to a pointer to an int, so int**& must be a reference to a pointer to a pointer to an int.
*& signifies the receiving the pointer by reference. It means it is an alias for the passing parameter. So, it affects the passing parameter.
#include <iostream>
using namespace std;
void foo(int *ptr)
{
ptr = new int(50); // Modifying the pointer to point to a different location
cout << "In foo:\t" << *ptr << "\n";
delete ptr ;
}
void bar(int *& ptr)
{
ptr = new int(80); // Modifying the pointer to point to a different location
cout << "In bar:\t" << *ptr << "\n";
// Deleting the pointer will result the actual passed parameter dangling
}
int main()
{
int temp = 100 ;
int *p = &temp ;
cout << "Before foo:\t" << *p << "\n";
foo(p) ;
cout << "After foo:\t" << *p << "\n";
cout << "Before bar:\t" << *p << "\n";
bar(p) ;
cout << "After bar:\t" << *p << "\n";
delete p;
return 0;
}
Output:
Before foo: 100
In foo: 50
After foo: 100
Before bar: 100
In bar: 80
After bar: 80
Typically, you can read the declaration of the variable from right to left. Therefore in the case of int *ptr; , it means that you have a Pointer * to an Integer variable int. Also when it's declared int **ptr2;, it is a Pointer variable * to a Pointer variable * pointing to an Integer variable int , which is the same as "(int *)* ptr2;"
Now, following the syntax by declaring int*& rPtr;, we say it's a Reference & to a Pointer * that points to a variable of type int. Finally, you can apply again this approach also for int**& rPtr2; concluding that it signifies a Reference & to a Pointer * to a Pointer * to an Integer int.
To understand those phrases let's look at the couple of things:
typedef double Foo;
void fooFunc(Foo &_bar){ ... }
So that's passing a double by reference.
typedef double* Foo;
void fooFunc(Foo &_bar){ ... }
now it's passing a pointer to a double by reference.
typedef double** Foo;
void fooFunc(Foo &_bar){ ... }
Finally, it's passing a pointer to a pointer to a double by reference. If you think in terms of typedefs like this you'll understand the proper ordering of the & and * plus what it means.
This *& in theory as well as in practical its possible and called as reference to pointer variable. and it's act like same.
This *& combination is used in as function parameter for 'pass by' type defining. unlike ** can also be used for declaring a double pointer variable.
The passing of parameter is divided into pass by value, pass by reference, pass by pointer.
there are various answer about "pass by" types available. however the basic we require to understand for this topic is.
pass by reference --> generally operates on already created variable refereed while passing to function e.g fun(int &a);
pass by pointer --> Operates on already initialized 'pointer variable/variable address' passing to function e.g fun(int* a);
auto addControl = [](SomeLabel** label, SomeControl** control) {
*label = new SomeLabel;
*control = new SomeControl;
// few more operation further.
};
addControl(&m_label1,&m_control1);
addControl(&m_label2,&m_control2);
addControl(&m_label3,&m_control3);
in the above example(this is the real life problem i came across) i am trying to init few pointer variable from the lambda function and for that we need to pass it by double pointer, so that comes with d-referencing of pointer for its all usage inside of that lambda + while passing pointer in function which takes double pointer, you need to pass reference to the pointer variable.
so with this same thing reference to the pointer variable, *& this combination helps. in below given way for the same example i have mentioned above.
auto addControl = [](SomeLabel*& label, SomeControl*& control) {
label = new SomeLabel;
control = new SomeControl;
// few more operation further.
};
addControl(m_label1,m_control1);
addControl(m_label2,m_control2);
addControl(m_label3,m_control3);
so here you can see that you neither require d-referencing nor we require to pass reference to pointer variable while passing in function, as current pass by type is already reference to pointer.
Hope this helps :-)