5

Does using index brackets for a pointer also dereference it? And why does printing the 0th index of this pointer twice end up printing two different things?

#include <cstdlib>
#include <iostream>
#include <cstring>

using namespace std;

int *p;

void fn() {
    int num[1];
    num[0]=99;
    p = num;
}

int main() {
    fn();
    cout << p[0] << "  " << p[0];
}
artm
  • 17,291
  • 6
  • 38
  • 54
Austin
  • 6,921
  • 12
  • 73
  • 138

3 Answers3

17

does using index brackets for a pointer also dereference it?

Correct, pointer arithmetic is equivalent to array index. p[index] is the same as *(p+index).

Why does printing the 0th index of this pointer twice end up printing two different things?

Because you are using p to point to a local variable (num) whose scope ends when the fn() function ends. What you observed is undefined behavior. Returning a pointer to local variable is bad practice and must be avoided.

Btw, just to see the scope effect, if you move the definition of the num array to outside the fn() function, then you will see consistent cout behavior.

Alternatively, as @Marc.2377 suggested, to avoid global variables (which is bad practice), you can allocate the variable in the heap (int* num = new int[1];). It would then be ok to return pointer p from fn(), but DON'T forget to call delete[] p in main() afterwards.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
artm
  • 17,291
  • 6
  • 38
  • 54
  • 1
    Or also `int* num = new int[1];` within `fn()` (though that is definitely not recommended and should only be used to confirm the scope effect) – Marc.2377 Nov 13 '16 at 02:53
  • @Marc.2377 that's a good point to avoid global vars, I edited the answer following your comment - tks – artm Nov 13 '16 at 02:59
  • @artm Hah nice, thanks for including it. It's important to point out, however, that relying on main() to execute `delete` - or, for that matter, not having `new` and `delete` encapsulated as dictated by RAII [(1)](http://stackoverflow.com/q/2321511/3258851), [(2)](http://stackoverflow.com/q/712639/3258851) - is error-prone and not best practice. But of course `unique_ptr num(new int[1]);` would not work for demonstration purposes... – Marc.2377 Nov 13 '16 at 03:40
  • @Marc.2377 `unique_ptr` supports arrays, you just have to specify an array type in the template parameter, eg: `std::unique_ptr num(new int[1]);` This specialization uses `delete[]` instead of `delete`. – Remy Lebeau Nov 13 '16 at 05:23
  • @RemyLebeau Oh yeah, but my point is that using `unique_ptr` will defeat the purpose of my previous suggestion, which was intended as a "hack" to make `num` survive the end of `fn()` scope. – Marc.2377 Nov 13 '16 at 05:32
  • Doesn't `p[i]` also take the type of `p` into consideration? Like `p[i]` and `*(p + sizeof(int) * i)` would be equivalent if `p` is an `int*`? – sisisisi Apr 30 '18 at 12:24
  • 1
    @sisisisi that's incorrect. `p[i]` is the same as `p + i` because pointer arithmetic already takes into account of the type, so you never have to apply the `sizeof` as you wrote – artm May 01 '18 at 04:39
3

does using index brackets for a pointer also dereference it?

yes, it does. ptr[i] is equivalent to *(ptr + i).

It is undefined behavior to access the out of scope local variable num. Essentially p is pointing to a local variable num. After returning from fn(), num goes out of scope, so anything can be stored at its address.

Saurav Sahu
  • 13,038
  • 6
  • 64
  • 79
3

Arrays are allocated contiguous memory location ( all elements are stored contiguously), so A[i] ( the element present at ith index of the array) will be i memory units away from the base address of the array A.
Hence A[i] is equivalent to *( A + i ).

The pointer stores the address and not the contents within. So, the local variable ceases to exist outside the function ( local scope), thereby giving different results outside the function.

Akash Mahapatra
  • 2,988
  • 1
  • 14
  • 28