0

Once I encountered following code:

int s =10;
int *p=&s;
cout << p[3] << endl;

And I can't understand why am I able to access p[3] that doesn't exist (only p exists that is single pointer but I still get access to p[3] that is array that I have never created).

Is it some compiler bug or it is a feature or I don't know some basics of C++ that covers this?

Thank you

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
qwertyu uytrewq
  • 299
  • 1
  • 4
  • 13
  • Undefined Behavior is [Undefined Behavior](https://en.wikipedia.org/wiki/Undefined_behavior). – bolov Feb 21 '16 at 22:02
  • 1
    Code that has bugs will do strange things, so don't write code with bugs. The compiler cannot catch every bug. – David Schwartz Feb 21 '16 at 22:03
  • 1
    There is no array of pointers here. There is a pointer to int being treated as an array of int. This is inherited from C and possibly its predecessors. – user207421 Feb 21 '16 at 22:03
  • [Undefined, unspecified and implementation-defined behavior](https://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior) and [Does “Undefined Behavior” really permit *anything* to happen?](https://stackoverflow.com/questions/32132574/does-undefined-behavior-really-permit-anything-to-happen) – kaylum Feb 21 '16 at 22:05
  • All this commentary about UB wouldn't apply if the OP had used an index of 0 instead of 3. – user207421 Feb 21 '16 at 22:07

4 Answers4

3

Why does C++ consider pointer and array of pointers as same thing?

It doesn't. You're asking why it treats pointers and arrays as the same.

The [] operator is just an abbreviated form of pointer arithmetic. a[b] is equivalent to *(a + b). Array names can decay into pointers, and then pointer arithmetic is applied. It's the programmers job to make sure they don't go out of bounds. The compiler can't possibly stop you from shooting your foot off.

Also, claiming to be able to "access" it is a strong assertion. That is UB, and is most likely going to either read the wrong memory or get a segfault.

Weak to Enuma Elish
  • 4,622
  • 3
  • 24
  • 36
2

No, it's not a compiler bug, its a very useful feature... but lets not get ahead of ourselves here, the consequence of your code is called Undefined Behaviour

So, what's the feature? All naked arrays are actually pointer to the first element. Except un-decayed arrays (See What is array decaying?).

Consider this code:

int s =10;
int* array = new int[12];

int *p;
p = array; // p refers to the first element
int* x = p + 7; //advances to the 7th element, compiler never checks bounds
int* y = p + 700; //ditto ...this is obviously undefined

p = &s;  //p is now pointing to where s
int* xx = p + 3; //But s is a single element, so Undefined Behaviour

Once an array is decayed, it's simply a pointer... And a pointer can be incremented, decremented, dereferenced, advanced, assigned or reassigned.

So,

cout << p[7] << endl;

is a valid C++ program. but not necessarily correct.

It's the responsibility of the programmer to know whether a pointer points to a single element or an array. but thanks to static analyzers and https://github.com/isocpp/CppCoreGuidelines, things are changing for good.

Also see What are all the common undefined behaviours that a C++ programmer should know about?

Community
  • 1
  • 1
WhiZTiM
  • 21,207
  • 4
  • 43
  • 68
1

From here, section array-to-pointer decay:

There is an implicit conversion from lvalues and rvalues of array type to rvalues of pointer type: it constructs a pointer to the first element of an array. This conversion is used whenever arrays appear in context where arrays are not expected, but pointers are

skypjack
  • 49,335
  • 19
  • 95
  • 187
1

Inherited from C, C++ allows you to treat any pointer like the first element of an array starting at that address. That's in part because it passes arrays by reference as pointers and so for that to make sense you need to be able to treat a pointer as an array. It also enables some quite neat and very efficient code in various circumstances.

The upshot is that p[3] is a valid construct in this context. Obviously however it has undefined behaviour because p isn't pointing to an array! Unfortunately the language rules (and compiler) aren't smart enough to work that out. C is a very low level language and doesn't enforce nice things like range checking either during compilation or execution.

Persixty
  • 8,165
  • 2
  • 13
  • 35