alright, im looking at a code here and the idea is difficult to understand.
#include <iostream>
using namespace std;
class Point
{
public :
int X,Y;
Point() : X(0), Y(0) {}
};
void MoveUp (Point * p)
{
p -> Y += 5;
}
int main()
{
Point point;
MoveUp(&point);
cout << point.X << point.Y;
return 0;
}
Alright, so i believe that a class is created and X and Y are declared and they are put inside a constructor
a method is created and the argument is Point * p, which means that we are going to stick the constructor's pointer inside the function;
now we create an object called point then call our method and put the pointers address inside it?
isnt the pointers address just a memory number like 0x255255?
and why wasnt p ever declared?
(int * p = Y)
what is a memory addres exactly? that it can be used as an argument?
p was declared.
void MoveUp (Point * p)
{
p -> Y += 5;
}
is a function that will take a pointer to a Point and add 5 to its Y value. It's no different to the following:
void f(int n) {
printf ("%d\n", n);
}
:
int x = 7;
f(x);
You wouldn't say n wasn't defined in that case. It's the same for p in your case.
Perhaps some comments in the code would help:
#include <iostream>
using namespace std;
class Point
{
public :
int X,Y;
Point() : X(0), Y(0) {} // Constructor sets X and Y to 0.
};
void MoveUp (Point * p) // Take a Point pointer p.
{
p -> Y += 5; // Add 5 to its Y value.
}
int main()
{
Point point; // Define a Point.
MoveUp(&point); // Call MoveUp with its address.
cout <<point.X << point.Y; // Print out its values (0,5).
return 0;
}
Pointers are simply a level of indirection. In the code:
1 int X;
2 int *pX = &X;
3 X = 7;
4 *pX = 7;
the effect of lines 3 and 4 are identical. That's because pX is a pointer to X so that *pX, the contents of pX, is actually X.
In your case, p->Y is the same as (*p).Y, or the Y member of the class pointed to by p.
A pointer is simply a variable like any other but it holds a memory address.
Read that line about 6 times. The name pointer itself seems scary to people, but it is really just called this to make it easier for ourselves to think about what is happening.
The type of a pointer (for example char*, int*, Point*) simply tells the compiler what is stored at that memory address.
So all pointers are alike in that they all store a simple memory address. But they are different in that the type of the pointer will tell you what will be contained at that memory address.
and why wasnt p ever declared?
p is declared:
//p is declared to be a variable that holds an address
// and at that address it holds a type Point
//p itself only holds an address not the actual data of the Point.
void MoveUp (Point * p)
{
//The -> operator when applied to a pointer, means give me the object at
// that address and then access the following member
p->Y += 5;
}
what is a memory addres exactly? that it can be used as an argument?
You can think of a memory address simply as a number. On 32-bit programs this number is 4 bytes long. On 64-bit programs this number is 8 bytes long.
Consider the following code:
Point point;
Point *p = &point;
The point variable is of type Point. It holds an object of the class Point.
The &point expression returns an address of the Point variable point. The expression &point is of type Point*.
The p variable holds a address of type Point, the type of p is Point*. p holds the address in memory of the object point.
p is declared in the function definition
void MoveUp (Point * p)
Before you look at pointers, you have to clarify for yourself the meaning of "class", "instance" and "constructor". Your sentence
a class is created and X and Y are
declared and they are put inside a
constructor
shows the need for such clarification. Here is a discussion on books you may want to read: Books to refer for learning OOP through C++
Think about memory as contiguous small blocks.
Now, think about the Point class as something that is 2 blocks width, and you put it in any place of the memory. It doesn't matter where, the important thing is that it is placed in only ONE starting point. You can move it and change that staring point, but irrevocably will start in ONE starting point.
Then the pointer is the number of that ONE starting point.
When you pass a pointer as an argument, you doing
you: 'hey function, take this Point and do what you know!'
function: 'ok, but where is the Point!?'
you: 'oh, sorry, i don't take it with me, it's located there, in that block!'
And the function will know now that THERE is a Point, and with the magic of the compiler, the function will know that its 2 blocks width. Then the function takes it, change its Y (thanks again, compiler), and leave it where it was before (in fact, it didn't even take it away from there).
Minutes later, you go there, and see Point.Y has changed. You say 'thanks', and you go.
p was declared as a method parameter.
Pointers are a special kind of variable that hold the memory address of a value. The * symbol is the dereference symbol, which tells your code to go lookup the value IN the memory address held by the pointer. Now is also a good time to introduce the & symbol, which tells your code to get the memory address of a value. For example:
int i = 5; //int
int *pointer; //int pointer
pointer = &i; //sets pointer to the memory address of i
doMath(&i); //passes a memory address, value inside that address is being used
doMath(pointer); //same as above
dontMath(i); //value of x will be 207, value of i is still 7 since a copy is being modified
//value of pointer is a memory address
//value of *pointer is the value stored inside that memory address, 7
//value of &pointer is the memory address of pointer, which itself holds the memory address
void doMath(int *p) {
*p++;
}
void dontMath(int x){
x=x+200;
}
The confusion I had early on was the meaning of the * symbol. In variable declaration, it means that your are declaring a pointer for a certain datatype (a variable that holds a memory address). Elsewhere, it is the dereference symbol telling your code to resolve the value.
Related
What is the difference between int* i and int** i?
Pointer to an integer value
int* i
Pointer to a pointer to an integer value
int** i
(Ie, in the second case you will require two dereferrences to access the integer's value)
int* i : i is a pointer to a object of type int
int** i : i is a pointer to a pointer to a object of type int
int*** i : i is a pointer to a pointer to a pointer to object of type int
int**** i : i is a pointer to a pointer to a pointer to a pointer to object of type int
...
int* pi
pi is a pointer to an integer
int **ppi
ppi is a pointer to a pointer to an integer.
EDIT :
You need to read a good book on pointers. I recommend Pointers on C by Kenneth Reek.
Let's say you're a teacher and have to give notes to one of your students.
int note;
Well ... I meant the whole class
int *class_note; /* class_note[0]: note for Adam; class_note[1]: note for Brian; ... */
Well ... don't forget you have several classes
int **classes_notes; /* classes_notes[0][2]: note for Charles in class 0; ... */
And, you also teach at several institutions
int ***intitute_note; /* institute_note[1][1][1]: note for David in class 1 of institute 1 */
etc, etc ...
I don't think this is specific to opencv.
int *i is declaring a pointer to an int. So i stores a memory address, and C is expecting the contents of that memory address to contain an int.
int **i is declaring a pointer to... a pointer. To an int. So i contains an address, and at that memory address, C is expecting to see another pointer. That second memory address, then, is expected to hold an int.
Do note that, while you are declaring a pointer to an int, the actual int is not allocated. So it is valid to say int *i = 23, which is saying "I have a variable and I want it to point to memory address 23 which will contain an int." But if you tried to actually read or write to memory address 23, you would probably segfault, since your program doesn't "own" that chunk of RAM. *i = 100 would segfault. (The solution is to use malloc(). Or you can make it point to an existing variable, as in int j = 5; int *i = &j)
Imagine you have a few friends, one of them has to give you something (a treasure... :-)
Say john has the treasure
int treasure = 10000; // in USD, EUR or even better, in SO rep points
If you ask directly john
int john = treasure;
int you = john;
If you cannot join john, but gill knows how to contact him,
int john = treasure;
int *gill = &john;
int you = *gill;
If you cannot even join gill, but have to contact first jake who can contact gill
int john = treasure;
int *gill = &john;
int **jake = &gill;
int you = **jake;
Etc... Pointers are only indirections.
That was my last story for today before going to bed :-)
I deeply believe that a picture is worth a thousand words. Take the following example
// Finds the first integer "I" in the sequence of N integers pointed to by "A" .
// If an integer is found, the pointer pointed to by P is set to point to
// that integer.
void f(int N, int *A, int I, int **P) {
for(int i = 0; i < N; i++)
if(A[i] == I) {
// Set the pointer pointed to by P to point to the ith integer.
*P = &A[i];
return;
}
}
So in the above, A points to the first integer in the sequence of N integers. And P points to a pointer that the caller will have the pointer to the found integer stored in.
int Is[] = { 1, 2, 3 };
int *P;
f(3, &Is[0], 2, &P);
assert(*P == 2);
&P is used to pass the address of P to the function. This address has type int **, because it's the address of a pointer to int.
int* i is the address of a memory location of an integer
int** is the address of a memory location of an address of a memory location of an integer
int* i; // i is a pointer to integer. It can hold the address of a integer variable.
int** i; // i is a pointer to pointer to integer. It can hold address of a integer pointer variable.
Neither is a declaration. Declaration syntax does not allow () around the entire declaration. What are these () doing there? If this is supposed to be a part of function declaration, include the whole function declaration thing in your question, since in general case the actual meaning of a declaration might depend on that. (Not in this one though.)
As for the difference... There is one * in the first and there are two *s in the second. Does it help? Probably not. The first one declares ias a pointer to int. The second one declares i as a pointer to int *. Does this help? Probably not much either. Without a more specific question, it is hard to provide a more meaningful answer.
Provide more context, please. Or, if this is actually as specific as it can get, read your favorite C or C++ book about pointers. Such broad generic questions is not something you ask on the net.
Note that
int *i
is not fully interchangeable with
int i[]
This can be seen in that the following will compile:
int *i = new int[5];
while this will not:
int i[] = new int[5];
For the second, you have to give it a constructor list:
int i[] = {5,2,1,6,3};
You also get some checking with the [] form:
int *i = new int[5];
int *j = &(i[1]);
delete j;
compiles warning free, while:
int i[] = {0,1,2,3,4};
int j[] = {i[1]};
delete j;
will give the warnings:
warning C4156: deletion of an array expression without using the array form of 'delete'; array form substituted
warning C4154: deletion of an array expression; conversion to pointer supplied
Both of these last two examples will crash the application, but the second version (using the [] declaration type) will give a warning that you're shooting yourself in the foot.
(Win32 console C++ project, Visual studio 2010)
Textual substitution is useful here, but beware of using it blindly as it can mislead you (as in the advanced example below).
T var; // var has type T
T* var; // var has type "pointer to T"
This works no matter what T is:
int* var; // pointer to int
char* var; // pointer to char
double* var; // pointer to double
// advanced (and not pure textual substitution):
typedef int int3[3]; // confusing: int3 has type "array (of size 3) of ints"
// also known as "int[3]"
int3* var; // pointer to "array (of size 3) of ints"
// aka "pointer to int[3]"
int (*var)[3]; // same as above, note how the array type from the typedef
// gets "unwrapped" around the declaration, using parens
// because [] has higher precedence than *
// ("int* var[3];" is an array (size 3) of pointers to int)
This works when T is itself a pointer type:
typedef int* T; // T is a synonym for "pointer to int"
T* var; // pointer to T
// which means pointer to pointer to int
// same as:
int** var;
When a variable is created such as:
int x = 5;
it will be stored somewhere in memory, cool.
However when I change the value of the variable by doing the following:
x = 10;
What happens in memory?
Does the new value of x overwrite the old value using the same memory address?
or is it that the new value is stored in a new memory address and then the old address is deleted?
This question arose when I came across pointers. It seems that using pointers to change the value of a variable is the same as defining the variable with another value.
this is my code (most of it are comments (lol)):
#include "iostream"
int main()
{
int x = 5; // declaring and defining x to be 5
int *xPointer = &x; // declare and define xPointer as a pointer to store the reference of x
printf("%d\n",x); // print the value of x
printf("%p\n",xPointer); // print the reference of x
x = 10; //changing value of x
printf("%d\n",x); //print new value of x
printf("%p\n",xPointer); //print the reference of x to see if it changed when the value of x changed
*xPointer = 15; //changing the value of x using a pointer
printf("%d\n",x); //print new value of x
printf("%p\n",xPointer); //print reference of x to see if it changed
return 0;
}
this is the output:
5
00AFF9C0
10
00AFF9C0
15
00AFF9C0
As you can see the memory addresses are the same, hence what is the point of pointers (pun intended).
When you declare int x = 5; you are saying that x has automatic storage duration and is initialised with the value 5.
For the lifetime of x, a pointer to x (i.e. &x) will have the same value.
You can change the value of x with the assignment x = 10 or via a pointer dereference *xPointer = 15 having set int* xPointer = &x;.
The language standard mentions nothing about the pointer value being a memory address, although it might be. That's a common misconception as to how the language works.
(Indeed a new value of x might cause the location in memory to change. That's permitted by the language so long as the pointer value doesn't change. An operating system may well do something similar to this, in the interests of obviating memory defragmentation.)
This question already has answers here:
What are the differences between a pointer variable and a reference variable?
(44 answers)
Closed 7 years ago.
I have a few questions. This isn't homework. I just want to understand better.
So if I have
int * b = &k;
Then k must be an integer, and b is a pointer to k's position in memory, correct?
What is the underlying "data type" of b? When I output it, it returns things like 0x22fe4c, which I assume is hexadecimal for memory position 2293324, correct?
Where exactly is memory position '2293324'? The "heap"? How can I output the values at, for example, memory positions 0, 1, 2, etc?
If I output *b, this is the same as outputting k directly, because * somehow means the value pointed to by b. But this seems different than the declaration of b, which was declared int * b = k, so if * means "value of" then doesn't mean this "declare b to the value of k? I know it doesn't but I still want to understand exactly what this means language wise.
If I output &b, this is actually returning the address of the pointer itself, and has nothing to do with k, correct?
I can also do int & a = k; which seems to be the same as doing int a = k;. Is it generally not necessary to use & in this way?
1- Yes.
2- There's no "underlying data type". It's a pointer to int. That's its nature. It's as data type as "int" or "char" for c/c++.
3- You shouldn't even try output values of memory which wasn't allocated by you. That's a segmentation fault. You can try by doing b-- (Which makes "b" point to the "int" before it actual position. At least, to what your program thinks it's an int.)
4- * with pointers is an operator. With any data type, it's another data type. It's like the = symbol. It has one meaning when you put == and another when you put =. The symbol doesn't necesarilly correlates with it meaning.
5- &b is the direction of b. It is related to k while b points to k. For example, if you do (**(&b)) you are making the value pointed by the value pointed by the direction of b. Which is k. If you didn't changed it, of course.
6- int & a = k means set the direction of a to the direction of k. a will be, for all means, k. If you do a=1, k will be 1. They will be both references to the same thing.
Open to corrections, of course. That's how I understand it.
In answer to your questions:
Yes, b is a pointer to k: It contains the address of k in the heap, but not the value of k itself.
The "data type" of b is an int: Essentially, this tells us that the address to which b points is the address of an int, but this has nothing to do with b itself: b is just an address to a variable.
Don't try to manually allocate memory to a specific address: Memory is allocated based of the size of the object once initialized, so memory addresses are spaced to leave room for objects to be allocated next to each other in the memory, thus manually changing this is a bad idea.
* In this case is a de-reference to b. As I've said, b is a memory address, but *b is what's at b's address. In this case, it's k, so manipulating *b is the same as manipulating k.
Correct, &b is the address of the pointer, which is distinct from both k and b itself.
Using int & a = k is creating a reference to k, which may be used as if it were k itself. This case is trivial, however, references are ideal for functions which need to alter the value of a variable which lies outside the scope of the function itself.
For instance:
void addThree(int& a) {
a += 3;
}
int main() {
int a = 3; //'a' has a value of 3
addThree(a); //adds three to 'a'
a += 2; //'a' now has a value of 8
return 0;
}
In the above case, addThree takes a reference to a, meaning that the value of int a in main() is manipulated directly by the function.
This would also work with a pointer:
void addThree(int* a) { //Takes a pointer to an integer
*a += 3; //Adds 3 to the int found at the pointer's address
}
int main() {
int a = 3; //'a' has a value of 3
addThree(&a); //Passes the address of 'a' to the addThree function
a += 2; //'a' now has a value of 8
return 0;
}
But not with a copy-constructed argument:
void addThree(int a) {
a += 3; //A new variable 'a' now a has value of 6.
}
int main() {
int a = 3; //'a' has a value of 3
addThree(a); //'a' still has a value of 3: The function won't change it
a += 2; //a now has a value of 5
return 0;
}
There are compliments of each other. * either declares a pointer or dereferences it. & either declares a (lvalue) reference or takes the address of an object or builtin type. So in many cases they work in tandem. To make a pointer of an object you need its address. To use a pointer as a value you dereference it.
3 - If k is a local variable, it's on the stack. If k is a static variable, it's in the data section of the program. The same applies to any variable, including b. A pointer would point to some location in the heap if new, malloc(), calloc(), ... , is used. A pointer would point to the stack if alloca() (or _alloca()) is used (alloca() is similar to using a local variable length array).
Example involving an array:
int array_of_5_integers[5];
int *ptr_to_int;
int (*ptr_to_array_of_5_integers)[5];
ptr_to_int = array_of_5_integers;
ptr_to_array_of_5_integers = &array_of_5_integers;
I found a code snippet on the internet. When I compile and run it, the output is 70. but i don't know whats happening in the code. please help me out.
#include <iostream>
using namespace std;
void doubleNumber (int *num )
{
*num = *num * 2;
}
int main ()
{
int num = 35;
doubleNumber (&num) ;
cout <<num ;
return 0;
}
void doubleNumber (int *num ) takes a pointer to an integer as parameter, which permits the method to modify the original variable.
Calling *num dereferences the pointer, while *num = *num * 2 assigns the value of the variable of the pointer num multiplied by 2 to the memory cell where num points to.
And in the main, where you have declared the integer, by calling the function doubleNumber with &num, you reference the variable and the return value of that is the pointer to the variable.
int num = 35;
doubleNumber(&num);
Is equivalent to:
int num = 35;
int* num_pointer = #
doubleNumber(num_pointer);
You should probably take a look at this site to read about referencing and dereferencing.
In your main function you call doubleNumber() passing a pointer to num.
The doubleNumber() function receives the pointer and doubles his value.
*num = *num * 2
The code defines a function which "doubles" an number. The main program passes the pointer to the variable num in to the function, and the function doubles the variable using the pointer passed in.
Pointers in C++ are my favorite (and - for newer programmers - are often confusing because they are learned in tandem with referencing (& operator). The * symbol is used for a lot of 'stuff' in C++, and it is not helped by the fact that, with pointers, the * symbol does two different things, for which we have two (2) names: dereferencing and indirection.
When we declare a pointer to a type, e.g. int *intPtr = //CODE HERE, we enable the variable to accept an address *intPtr and assign the address in memory of the rvalue (that on the right side of the binary operator) to the variable intPtr. intPtr - or, the address of the rvalue - can then, itself, be passed around and used as an lvalue. We call this "dereferencing".
Then, when we want to access the value of the thing stored at the memory address, we use the indirection operator * in the body of the code to access the stored value. So, let's say we do this:
int num = 35;
int num2 = 0;
int *intPtr = # // here using the reference operator & to assign the address
// of num to intPtr
We can then access the value stored behind num by going:
num2 = *intPtr;
Here, the * indirection operator is actually doing something else: it is used to access the value stored at the address stored in intPtr.
WHERE THE CONFUSION HAPPENS:
So, when we see a function header with a pointer as an argument, it's like "Wha'? Which * is being used?"
returntype functionIdentifier(type *num)
In this case, what is received as an argument is a memory address. Then, the argument can be used throughout the body of the function. Too, the indirection operator * can be used to access the value stored at the memory address stored in the passed-in argument (pointer - in this came num).
What is the difference between int* i and int** i?
Pointer to an integer value
int* i
Pointer to a pointer to an integer value
int** i
(Ie, in the second case you will require two dereferrences to access the integer's value)
int* i : i is a pointer to a object of type int
int** i : i is a pointer to a pointer to a object of type int
int*** i : i is a pointer to a pointer to a pointer to object of type int
int**** i : i is a pointer to a pointer to a pointer to a pointer to object of type int
...
int* pi
pi is a pointer to an integer
int **ppi
ppi is a pointer to a pointer to an integer.
EDIT :
You need to read a good book on pointers. I recommend Pointers on C by Kenneth Reek.
Let's say you're a teacher and have to give notes to one of your students.
int note;
Well ... I meant the whole class
int *class_note; /* class_note[0]: note for Adam; class_note[1]: note for Brian; ... */
Well ... don't forget you have several classes
int **classes_notes; /* classes_notes[0][2]: note for Charles in class 0; ... */
And, you also teach at several institutions
int ***intitute_note; /* institute_note[1][1][1]: note for David in class 1 of institute 1 */
etc, etc ...
I don't think this is specific to opencv.
int *i is declaring a pointer to an int. So i stores a memory address, and C is expecting the contents of that memory address to contain an int.
int **i is declaring a pointer to... a pointer. To an int. So i contains an address, and at that memory address, C is expecting to see another pointer. That second memory address, then, is expected to hold an int.
Do note that, while you are declaring a pointer to an int, the actual int is not allocated. So it is valid to say int *i = 23, which is saying "I have a variable and I want it to point to memory address 23 which will contain an int." But if you tried to actually read or write to memory address 23, you would probably segfault, since your program doesn't "own" that chunk of RAM. *i = 100 would segfault. (The solution is to use malloc(). Or you can make it point to an existing variable, as in int j = 5; int *i = &j)
Imagine you have a few friends, one of them has to give you something (a treasure... :-)
Say john has the treasure
int treasure = 10000; // in USD, EUR or even better, in SO rep points
If you ask directly john
int john = treasure;
int you = john;
If you cannot join john, but gill knows how to contact him,
int john = treasure;
int *gill = &john;
int you = *gill;
If you cannot even join gill, but have to contact first jake who can contact gill
int john = treasure;
int *gill = &john;
int **jake = &gill;
int you = **jake;
Etc... Pointers are only indirections.
That was my last story for today before going to bed :-)
I deeply believe that a picture is worth a thousand words. Take the following example
// Finds the first integer "I" in the sequence of N integers pointed to by "A" .
// If an integer is found, the pointer pointed to by P is set to point to
// that integer.
void f(int N, int *A, int I, int **P) {
for(int i = 0; i < N; i++)
if(A[i] == I) {
// Set the pointer pointed to by P to point to the ith integer.
*P = &A[i];
return;
}
}
So in the above, A points to the first integer in the sequence of N integers. And P points to a pointer that the caller will have the pointer to the found integer stored in.
int Is[] = { 1, 2, 3 };
int *P;
f(3, &Is[0], 2, &P);
assert(*P == 2);
&P is used to pass the address of P to the function. This address has type int **, because it's the address of a pointer to int.
int* i is the address of a memory location of an integer
int** is the address of a memory location of an address of a memory location of an integer
int* i; // i is a pointer to integer. It can hold the address of a integer variable.
int** i; // i is a pointer to pointer to integer. It can hold address of a integer pointer variable.
Neither is a declaration. Declaration syntax does not allow () around the entire declaration. What are these () doing there? If this is supposed to be a part of function declaration, include the whole function declaration thing in your question, since in general case the actual meaning of a declaration might depend on that. (Not in this one though.)
As for the difference... There is one * in the first and there are two *s in the second. Does it help? Probably not. The first one declares ias a pointer to int. The second one declares i as a pointer to int *. Does this help? Probably not much either. Without a more specific question, it is hard to provide a more meaningful answer.
Provide more context, please. Or, if this is actually as specific as it can get, read your favorite C or C++ book about pointers. Such broad generic questions is not something you ask on the net.
Note that
int *i
is not fully interchangeable with
int i[]
This can be seen in that the following will compile:
int *i = new int[5];
while this will not:
int i[] = new int[5];
For the second, you have to give it a constructor list:
int i[] = {5,2,1,6,3};
You also get some checking with the [] form:
int *i = new int[5];
int *j = &(i[1]);
delete j;
compiles warning free, while:
int i[] = {0,1,2,3,4};
int j[] = {i[1]};
delete j;
will give the warnings:
warning C4156: deletion of an array expression without using the array form of 'delete'; array form substituted
warning C4154: deletion of an array expression; conversion to pointer supplied
Both of these last two examples will crash the application, but the second version (using the [] declaration type) will give a warning that you're shooting yourself in the foot.
(Win32 console C++ project, Visual studio 2010)
Textual substitution is useful here, but beware of using it blindly as it can mislead you (as in the advanced example below).
T var; // var has type T
T* var; // var has type "pointer to T"
This works no matter what T is:
int* var; // pointer to int
char* var; // pointer to char
double* var; // pointer to double
// advanced (and not pure textual substitution):
typedef int int3[3]; // confusing: int3 has type "array (of size 3) of ints"
// also known as "int[3]"
int3* var; // pointer to "array (of size 3) of ints"
// aka "pointer to int[3]"
int (*var)[3]; // same as above, note how the array type from the typedef
// gets "unwrapped" around the declaration, using parens
// because [] has higher precedence than *
// ("int* var[3];" is an array (size 3) of pointers to int)
This works when T is itself a pointer type:
typedef int* T; // T is a synonym for "pointer to int"
T* var; // pointer to T
// which means pointer to pointer to int
// same as:
int** var;