2

I have a question about pointers and arrays in C++. I'm not sure exactly what this section of code is doing. As the way I see it iarray is declared as a normal array. However q is being accessed like its a 2d array.

    int iarray[10];
    int *p = iarray;
    int **q = &p;
    q[0][2] = 25;

And if I change the iarray to:

    int iarray[10]{3,2};
    int *p = iarray;
    int **q = &p;
    q[0][2] = 25;

    cout << q[0][0] << endl;
    cout << q[1][0] << endl;

The first one will print 3, which I understand as I declared it above. But the second one is blank and I don't understand why.

3
  • 1
    2 is stored in q[0][1], not q[1][0] Commented Nov 4, 2019 at 18:52
  • 1
    Note that dereferencing q[1] causes undefined behavior. Commented Nov 4, 2019 at 18:58
  • The problem is that I do know what it is doing, but don't know how to articulate it in a meaningful way. But basically, it's sort of trying to construct a de facto 2d array, and then dereference memory that is out of bounds. Commented Nov 4, 2019 at 19:15

2 Answers 2

3

Let's look one instruction at a time:

int iarray[10]; will reserve 10 int-sized bytes in memory. If sizeof(int) == 4it will reserve 40 bytes. Let's assume that memory range is set between 0x10 - 0x37.

int *p = iarray reserves 4 bytes (if we assume we're running on a 32 bit processor) and stores the starting address to the 40 bytes reserved in the previous instruction. p is the shorthand we use to refer to those 4 bytes. Let's say those 4 bytes are stored at 0x50 - 0x53.

int **q = &p reserves 4 more bytes which will hold the start address of p (0x50). q can be stored at 0x60-0x63.

The array index operator in c++ on pointers is a shorthand for pointer arithmetic. E.g q[N] is the same thing as *(q + N), so, in my exmple, q[0] will give you the value held at address 0x60-0x63 which is 0x50. If you use the index operator again it will apply on the new address (0x50), so q[0][2] is equivalent with p[2], which is iarray[2].

q[1] is equivalent to *(q + 1) = *(0x60 + 0x4) =*(0x64). If you look above, we never reserver address 0x64, so we're reading from memory we don't own - undefined behaviour.

Sign up to request clarification or add additional context in comments.

4 Comments

Okay I understand this more. Just to be sure the structure of iarray would it be {1,2,3,4,5,6,7,8,9} if we had a list of numbers from 1 to 9. Or would the structure being something like this {*p1, *p2, *p3} where *p1 = {1,2,3} , *p2 = {4,5,6}, *p3 = {7,8,9}.
Could you please rephrase your question? I don't understand it. Are you referring to the case where you define iarray as int iarray[10]{3,2}? int iarray[10]{3,2} reserves 10 contiguous ints and initializes iarray[0] = 3 and iarray[1] = 2.
My apologies, by saying structure I mean how will the data be presented as an array. As i know a normal 2d array is something like {{1,2,3},{4,5,6},{7,8,9}}. If an example can be given that will be great thanks. :)
I don't know the answer, but I suspect you're right. If you declare int arr[3][2], the compiler will reserve 6 contiguous ints and store them as 1,2,3,4,5,6.... When you're using the index operator, the compiler will know how to compute the proper offset: [2][1] would be *(arr + 2 * 3 + 1). Since you're new to C++ I recommend using std::vector<std::vector<int>> to represent a matrix - it's much easier to understand and harder to misuse.
2

Let's take look at this:

int iarray[10]; // declare a array of 10 ints
int *p = iarray; // p is used like an alias for iarray, an int[] is also an int*
int **q = &p; //q is a pointer to pointer p

q points only to a single value. You can think of q like an array with just one entry. You could also write it as int *q[] = { &p };

So q[1][0] is undefined behaviour, since q[1] will already be out of bounds.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.