0

I am learning C++. If I want to declare pointer to array I will use:

int (*p)[10];

but if I want to declare array of pointers I will use:

int *(p[10]);

But if I use new operator there is no variable name, like p, instead of that I must write:

x = new int *[10];

The question is: how compiler is determining the size of the memory allocated by this statement, is it array of pointers or is it pointer to array. Also how can I force compiler to interpret the meaning of int *[10] to my needs?

eike
  • 1,314
  • 7
  • 18
  • 1
    `new int* [10];` will allocate an array of 10 pointers to `int`. You cannot allocate a pointer to an array of 10 `int`s, since `int[10]` is not exaclty a type (it is a bit complicate). With `int **p = new int*;` you can allocate at pointer to an pointer to `int` and then write `*p = new int[10];` to allocate an array and let the pointer `*p` point to it. – n314159 Dec 01 '19 at 21:57
  • @n314159 Please make an answer out of this. – eike Dec 01 '19 at 21:59
  • 1
    @n314159 since you deleted you answer, I'd like to answer your comment from there here: No, array types are also real types in C. Unfortunately, the rules of C and C++ concerning the `[]` array syntax are full of exceptions that lead to arcane behavior. As a result, there is a lot of myth, confusion, and misinformation about arrays out there. Unfortunately, the space in a comment will not suffice to discuss this topic at the level of detail required. [This answer here](https://stackoverflow.com/a/4810668/2064761) would seem to contain quite a lot of information you may be interested in… – Michael Kenzel Dec 02 '19 at 00:45
  • @MichaelKenzel Sorry, I didn't want to keep the wrong answer and didn't want to forget to delete it. Thank you very much for the link, it made things much clearer. It is a bit sad that such a fundamental part of the language can generate so much confusion (because i have the discussion array vs. pointer seen often, with differing results etc.) – n314159 Dec 02 '19 at 01:09
  • 1
    @n314159 Yes, that's very unfortunate. Arrays are the way they are in C++ because they were inherited from C and that's not really gonna change at this point. A general recommendation would probably be to just use [`std::array`](https://en.cppreference.com/w/cpp/container/array) instead of plain arrays. `std::array` is nothing but a wrapper around a plain array. But by using that wrapper instead of using array syntax directly, you opt out of all the weird behavior associated with array syntax and get something that behaves consistent with the way everything else behaves… – Michael Kenzel Dec 02 '19 at 01:15

1 Answers1

1

To declare an array of pointer to int, you don't need parentheses:

int* p[10];

will do. To declare a pointer to an array of 10 integers, you do need parentheses:

int (*p)[10];

This is simply a question of operator precedence. [] binds more strongly than * in a declarator. Thus, without parentheses, int *p[10]; is going to be an array of ten ([10] applies first) pointers to (* applies second) int. The parentheses in int *(p[10]); are superfluous. int (*p)[10]; on the other hand, declares a pointer to (* applies first due to the ()) an array of 10 ([10] applies second) int.

A new expression is no different. The only difference is that your declarator contains no identifier because you're not declaring a variable that is to be given a name, you're just spelling out a type. new figures out how much storage it needs based on the type of the object you asked it to create.

To simply declare the type "array of ten pointers to int", you'd write int* [10]. And to declare the type "pointer to array of ten int", you'd write int (*)[10].

There is one problem in the context of new, however. That problem is that the bounds of an array type in C++ have to be constant expressions (i.e., compiletime constants). Arrays of dynamic size do not exist in the C++ type system. However, the whole point of new is to create objects dynamically, arrays of dynamic size in particular.

To get around this problem, new must avoid to ever require naming an array of dynamic size as a type. The way this is currently achieved in the C++ specification is by having a completely separate declarator grammar for new-expressions [expr.new]/1. What happens there is that top-level array bounds are peeled off and treated separately. When you write new int[n], you create an array of n objects of type int, where n does not have to be a constant-expression. Contrary to the way new operates on other types, if you ask new to create an object of array type, new does not return a pointer to the array of the given type, but a pointer to the first element of the array it created instead. Thus, even if you create an array of a size that is not a constant-expression, the type of the result of the new-expression is never going to be "array of dynamic size", but always something that actually exists in the type system…

There is one escape hatch thought. The grammar for a new-expression is [expr.new]/1

new-expression:
::opt new new-placementopt new-type-id new-initializeropt
::opt new new-placementopt ( type-id ) new-initializeropt

As you can see, a new-expression can be given either a new-type-id (which is the separate grammar that allows for creating arrays of dynamic size) or a normal type-id in parentheses.

Thus, it is actually possible to create a single pointer to an array of ten int via new:

int (**p)[10] = new (int(*)[10]);
Michael Kenzel
  • 15,508
  • 2
  • 30
  • 39
  • Now it is clear to me why new int (*)[10] //without parentheses (Most important) is not working the way I was thinking it will work. Thanks for your answer. –  Dec 02 '19 at 00:46