pointers to pointers

Hi guys I have a similar thread opened up a little while back but this is a question I never asked and one that surprisingly hasn't been asked much on forums

what is the difference between the following lines of code,are they the same?

1
2
3
4
5
6
7
  int **one;
  one = new int*[3];
  
  for(int i = 0; i < 3; i++){
         one[i] = new int[3]

   }


and

1
2
3
4
5


    const char* a[3] = { "one", "two", "three" };
    const char*(*p)[3] = &a;


obviously one major difference is one is an int and one is a char,and one is dynamically allocated and the other one is allocated on the stack,

but apart from that what is the difference between them both seem to be a pointer to an array of pointers

side question

when I derefenced p2 I expected to get the value which was stored in p1 which is the address of a but instead I got junk values I'm wondering why this occurs


1
2
3
4
5
6
7
8
9
10
11
12
13

int main() {

	char **p1;
	char *p2;
	char a = 'a';

	p2 = &a;
	p1 = &p2;

	cout << *p1 << endl;
}


output -- aþ
Last edited on
It is really helpful to draw pictures when dealing with pointers.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

┌───┐
│'a'│                       cout << a;
└───┘
  a
  
┌───┐    ┌───┐
│   ├───►│'a'│              cout << *p2;
└───┘    └───┘
 p2        a
 
┌───┐    ┌───┐    ┌───┐
│   ├───►│   ├───►│'a'│     cout << **p1;
└───┘    └───┘    └───┘
 p1       p2        a

Hope this helps.
*p1 is the p2. Therefore
cout << *p1
means
cout << p2

The p2 is a char*. The operator<< has two operands: ostream and char*

There is an operator for exact that pair. It outputs a C-string.
It outputs an array of characters, starting from given address and up to first '\0' in the array.

In your case the first address contains 'a', but what is in the following bytes? Undefined.


In the first example the 'one' is a pointer. You set it to point to an array of three elements.
Each of those elements is a pointer. Each of them is set to point to an array of three (int) elements.
You can indirectly access 9 integers via the 'one'. You have one automatic variable and four dynamically allocated arrays.

The second example is very different.
The 'a' is an array of three elements, which again are pointers. Each pointer points to separate array of characters.
The arrays have 4, 4 and 6 elements. They are neither automatic variables nor dynamically allocated. The three arrays are string constants.

The 'p' is an array pointer.
p[k] means *(p + k*3*sizeof(char*))
p[0][0] is a[0]
p[0][1] is a[1]
p[0][2] is a[2]
p[0][3] is beyond the 'a'; non-existent element.
p[1][0] is beyond the 'a'; non-existent element.
I would also re-iterate that c-strings (arrays of char) must end with a 0 byte. Not sure if that will affect your code as you continue to play with it or not, but keep it in mind.
If you do want to print the value of the pointer, then you need to specify that, to avoid the default of std::cout treating a pointer to char as a C-string.

Note - in this example there is no actual string, it may print garbage.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <cstdio>

using namespace std;

int main()
{
    char **p1;
    char *p2;
    char a = 'a';
    
    p2 = &a;
    p1 = &p2;
    
    cout << "pointer: " << (void *)*p1 << endl;
    cout << "string:  " << *p1         << endl;
    cout << "char:    " << **p1        << endl;
    
    cout << "\n\n";
    
    printf("pointer: %p\n", *p1);        
    printf("string:  %s\n", *p1);
    printf("char:    %c\n", **p1);     
}
Last edited on
thanks for the replies guys much appreciated

@keskiverto

Each of them is set to point to an array of three (int) elements.
You can indirectly access 9 integers via the 'one'. You have one automatic variable and four dynamically allocated arrays.


I thought I had 3 dynamically allocated arrays? [0] [1] [2]

and how can you indirectly access them

also wait p is a 2d array?

@chevril

 
cout << "pointer: " << (void *)*p1 << endl;



how come you added (void *)? what this this do?


thanks
Last edited on
how come you added (void *)? what this this do?

There are two answers to that.

The first is that it allows the pointer to be printed, rather than the non-existent string.

The second is that it is a C-style cast which tells the compiler to treat the pointer as a generic pointer, one which can point to any type.

You can read more about 'Type casting' in the tutorial. Generally it is something you'd want to avoid, or keep to a minimum, but it is sometimes useful.
http://www.cplusplus.com/doc/tutorial/typecasting/
I thought I had 3 dynamically allocated arrays?
1
2
3
4
5
  one = new int*[3]; // #1
  
  for(int i = 0; i < 3; i++){
         one[i] = new int[3]; // #2 #3 #4
   }
Four calls to new [], are there not?


Q: What is the name of this array?
new Foo [42];
A: It has no name. It is dynamically allocated and we can use it only if we store the address returned by the new into a pointer variable.

We cannot refer to the array by its name. We can refer to it only via pointer(s). "Indirectly"


wait p is a 2d array?
const T (*p)[3]

The p is a pointer, but its type is not trivial. When we dereference the p we do get what looks like a 3 element array.
Topic archived. No new replies allowed.