3

If I write int* a = new int[5]; and then I call sizeof(a) or sizeof(*a), I don't get the information I want because the array has decayed into a pointer. However, I'm wondering if there's a way we can do something like this:

int[5]* a = new int[5];

I'm pretty sure we're able to do this with stack memory but I'm not sure if there's any way to do it for heap memory, since the above will not compile. And if there isn't a way, is there a reason for not having this as a possibility?

rb612
  • 5,280
  • 3
  • 30
  • 68

3 Answers3

5

There's no getting around the fact that C++ was originally just a front end for C and, as such, carries a fair amount of baggage from the original language. Such as many things in the <cXXX> headers, and the behaviour of many operations, like array decay(a).

If you want a more convenient array type, C++ has such a beast in std::vector. If you pass that around, you will not be subject to the decay you may see when using the more low-level memory allocation methods. See, for example:

#include <iostream>
#include <vector>

void someFunction (const std::vector<int> &myVec) {
    std::cout << myVec.size() << std::endl;
}

int main() {
    std::vector<int> myVec({ 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 9, 0 });
    std::cout << myVec.size() << ' ';
    someFunction(myVec);
}

which outputs 13 13, showing that the size is the same outside and inside the function (it's also the size in elements rather than bytes as given bt sizeof, the former usually being a far more useful measure).


When mentoring or training C++ programmers, I always warn them about being a "C+" programmer, one who was raised on C and never really made the full transition to C++ (things like continuing to use raw arrays instead of vectors, rolling you own data structures when perfectly adequate ones are in the standard library, using malloc/free or printf, and so on).

You would be wise thinking of C and C++ as related but totally different languages, and adopting the C++ way of thinking as much as possible.


(a) Interestingly, your specific question does not have an array decaying into a pointer. The new call actually returns a pointer directly so there's no decay involved.

Where you would see decay is in something like:

void someFunction (int x[]) {
    // Pointer to first element here, size is int-pointer-size.

    std::cout << sizeof(x) << std::endl;
}

:

// Array here, size is 13 * int-size.

int xyzzy[] = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 9, 0 };
std::cout << sizeof(xyzzy) << std::endl;

someFunction(xyzzy);
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
3

There is no way to store this information in the pointer. And there is no separate construct that will let you do this the way you want. Your options are:

  1. Store the size of the array separate to the array: const int a_size = 5; int *a = new int[a_size].
  2. Use a C++ construct to handle this for you: std::vector<int> a(5); a.size()

I would highly recommend option 2. Not simply because its easier and std::vector gives more functionality. But because the RAII style construct manages the memory for you meaning you don't need to remember to call delete[] on the memory later. You also can't accidentally call delete on the memory later since you might have forgotten that it is an array.

Tas
  • 7,023
  • 3
  • 36
  • 51
Fantastic Mr Fox
  • 32,495
  • 27
  • 95
  • 175
  • Thank you! Is there any reason why we can declare a pointer to an array on the stack of type `int[5]`, for example, but not on the heap? – rb612 Jan 29 '18 at 04:45
  • 1
    @rb612 Yes, you can have a pointer to whatever you want. eg. `int a[5]; int *pa = &a[0]`. But if you are using automatic storage duration memory, you should use `std::array` instead of `int a[5]`. – Fantastic Mr Fox Jan 29 '18 at 04:46
-1

Of course you can, via a two-dimension array, e.g.

int (*a)[5] = new int[1][5];

Note: this code is just for language-lawyer purpose and is not recommended in practice. If this is an XY problem, you should use std::vector or std::array instead as other answers suggested.

One of the reasons why new int[N] returns a pointer to its first element instead of a pointer to itself like non-array new, is to make the use of the array easier. For example, with auto a = new int[5], you can access the array by simple a[n] instead of (*a)[n].

xskxzr
  • 12,442
  • 12
  • 37
  • 77
  • This isn't like storing the information in the pointer, you are making a totally unnecessary array! Further more you are assigning to a pointer, not an array. This is very different. See https://stackoverflow.com/a/3960723/1294207 – Fantastic Mr Fox Jan 29 '18 at 06:17
  • @FantasticMrFox But the OP neither requires storing information in the pointer, nor forbids `a` to be a pointer. Note he says "then I call `sizeof(a)` or `sizeof(*a)`, I don't get the information I want". Now he **can** with call of `sizeof(*a)`. – xskxzr Jan 29 '18 at 06:22
  • Could downvoters please interpret why downvote? The OP asks for a way to allocate an array with dynamic storage duration that is able to access the array length information. My answer indeed does this: it indeed allocate an array (though a subobject of another two-dimension array), and the array length information can be accessed by `sizeof(*a)`. – xskxzr Jan 29 '18 at 06:39
  • Mine is because, while technically this is possible and works. It is not a good way to achieve this. If a future user reads this and decided to do it, even if it is technically correct, they will be using a dangerous construct that they need not use when `std::vector` exists and it uses 5 pointers to do the job of 1 + 1 int. I know you have the disclaimer but new people rarely read that deep into any question. I would remove down vote if you provide a way that you should do it. This could be a passing thought at the bottom of the answer. – Fantastic Mr Fox Jan 29 '18 at 06:44
  • @FantasticMrFox I don't think I have added **extra** danger to the way the OP does. Do you mean any question about `new` or C-style array should be answered by a recommendation of `std::vector` or `std::array`? – xskxzr Jan 29 '18 at 06:50
  • 1
    The OP didn't do it correctly. You are doing it in a way that provides the right answer but is not a good thing to teach anybody who reads this. IMO, the answer that you give could(and should) be 1. This is the right way to do this. 2. This is an alternative way to do this. 3. Here is an interesting point about how the size of a array of pointers, happens to be the same as an array of 5 ints. Because think about when the OP expands this. What if they want 5000 ints? Are you going to allocate 5000 pointers just so you can get the number 5000 as the size? – Fantastic Mr Fox Jan 29 '18 at 07:16
  • @FantasticMrFox Why 5000 pointers? Just a simple `int (*a)[5000] = new int[1][5000];`. This only allocates 5000 `int`s in total. – xskxzr Jan 29 '18 at 07:20
  • @FantasticMrFox this does answer the question as asked and states that it's a bad idea to use this. Imo it's a valid answer. – krzaq Jan 29 '18 at 08:44