0

How do pointers work with arrays? I find the syntax a bit of a mystery, example (16x1):

int* a = new int[16];
a[16] = 33;
cout << a[16] << endl;

The above example works. Usually * needs to be in front of a pointer to write/read the value, but not with vectors?

The case is more complicated for multidimensional arrays, which I found the following a way to create (16x3):

int** a = (int**)new int[16];
for (int i = 0; i < 16; i++)
{
    a[i] = (int*)new int[3];
}
a[15][2] = 4;
cout << a[15][2] << endl;

Again, the above works, but it's hard to grasp how the syntax relates to pointers. The syntax also works with malloc. With malloc there is an option "memset" which automatically initializes the multidimensional array (put in the for loop). Is there similar option with new?

Dole
  • 339
  • 4
  • 16
  • 6
    You allocate an "array" of 16 `int` element, and then you write to element number 17? That's out of bounds and will lead to *undefined behavior*. – Some programmer dude Aug 15 '17 at 08:31
  • "The above example works" - `:s/works/invoked-undefined-behavior/g` – WhozCraig Aug 15 '17 at 08:31
  • I'm not familiar with pointer arrays and `malloc`, but wouldn't be `a[16]` out of bounds in the first example? – Post Self Aug 15 '17 at 08:32
  • As for your second snippet of code, have you thought about allocating an array of *pointers*? Like `int** a = new int*[16]`? – Some programmer dude Aug 15 '17 at 08:32
  • 2
    And ***don't cast!*** Your casting hides a lot of the problems you have, problems that the compiler would be able to detect for you (and report as errors). – Some programmer dude Aug 15 '17 at 08:33
  • 2
    `*(a + b)` is `a[b]`. This should be covered in the chapter on pointers in your favourite C++ book. And don't cast the result of `new`, ever. – molbdnilo Aug 15 '17 at 08:33
  • And lastly, what is the reason you handle your memory allocations yourself? Why don't you use [`std::vector`](http://en.cppreference.com/w/cpp/container/vector)? – Some programmer dude Aug 15 '17 at 08:34
  • I think you should read a good beginners [book](https://stackoverflow.com/a/388282/4711812) specifically about arrays. You are constantly accessing your arrays outside their specified bounds. If you allocate an array with `new int[16]` the highest valid index would be 15, since C++ uses 0-indexed arrays (indices from 0 to 15). – muXXmit2X Aug 15 '17 at 08:39
  • As @Someprogrammerdude - Avoid casts like the plague. Always think twice about using a cast. Usually when thinking about using a cast you are usually doing something wrong – Ed Heal Aug 15 '17 at 08:41
  • Ok, ok, I take it that the casting is not very smart here :). But then, how do I create the multi-array? – Dole Aug 15 '17 at 08:44
  • 2
    You do it using `std::vector> a(16, std::vector(3))`. Or if the sizes are fixed at time of compilation then perhaps `std::array<16, std::array<3, int>> a`. – Some programmer dude Aug 15 '17 at 08:45

2 Answers2

3

Usually * needs to be in front of a pointer to write/read the value, but not with vectors?

You always need to dereference a pointer to get the pointed value. The subscript operator is just another way to dereference it. a[b] is equivalent to *(a+b) (unless a is a class with overloaded subscript operator).


int** a = (int**)new int[16];

This is a bug. You've allocated an array of int, but try to point to first element as if it was an int*. If you want an array of pointers, then you must specify the correct type (int*) in the new-expression. A way to avoid bugs like this is to never ever cast the return value of new. Then the compiler will tell you when you make a mistake.

Again, the above works

The behaviour is undefined.

With malloc there is an option "memset" which automatically initializes the multidimensional array (put in the for loop). Is there similar option with new?

memset is in C++ standard library as well, but you don't need it for initialization. Simpler is to use value initialization. Also note the correct type and lack of casting:

int** a = new int*[16]();
//                    ^ syntax for value initialization

P.S. You don't deallocate the memory that you allocated. Therefore you leak the memory.

P.P.S It is a bad idea to store pointeres to dynamic objects in bare pointers. It's better to use a RAII container like std::vector.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • What is the meaning of a[b][c] then? – Dole Aug 15 '17 at 09:22
  • 1
    @Dole The subscript operator is left-associative, so you can convert each into the explicit dereference form step by step form left to right: `a[b][c]` == `(*(a+b))[c]` == `*(*(a+b) + c)` – eerorika Aug 15 '17 at 09:26
1

This syntax works because operator[], called offset operator, works just the same as operator*, but increments the pointer by some amount. So a[5] is just the same as *(a+5).

If you want to learn a little bit more about it I would suggest checking article about pointer, where they also mention this operator and provide more technical explanation.

Daniel Jodłoś
  • 316
  • 1
  • 5