3

I am learning C++, and read that when an array is passed into a function it decays into a pointer. I wanted to play around with this and wrote the following function:

void size_print(int a[]){
    cout << sizeof(a)/sizeof(a[0]) << endl;
    cout << "a ->: " << sizeof(a) << endl;
    cout << "a[0] ->" << sizeof(a[0]) << endl;
}

I tried inputting an array with three elements, let's say

int test_array[3] = {1, 2, 3};

With this input, I was expecting this function to print 1, as I thought a would be an integer pointer (4 bytes) and a[0] would also be 4 bytes. However, to my surprise the result is 2 and sizeof(a) = 8.

I cannot figure out why a takes up 8 bytes, but a[0] takes up 4. Shouldn't they be the same?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
APM500
  • 85
  • 1
  • 7
  • 2
    Fun fact: `a[0]` is not a pointer and thus cannot reasonably be expected to be the same size as a pointer. – user4581301 Nov 17 '21 at 00:02
  • 2
    `sizeof(a)` is the size of the pointer that the array passed decays to. The function has no way of knowing the size of the array. – Weather Vane Nov 17 '21 at 00:04
  • 3
    @WeatherVane: I think they understand that (they're clearly aware it would decay to a pointer). I think they just didn't realize 64 bit systems have eight byte pointers (a lot of older C++ teaching materials still assume everything is a 32 bit system). – ShadowRanger Nov 17 '21 at 00:06
  • Side note for future readers: [Finding length of array inside a function](https://stackoverflow.com/questions/17590226/finding-length-of-array-inside-a-function). Trace the duplicates back if you want the gory details. – user4581301 Nov 17 '21 at 00:06
  • removed the [tag:C] tag, because: arrays as argument types are different between C and C*+, and your code is clearly C++. (the answers are the same, the sizeof a pointer-decayed array is the sizeof a pointer, but this simply isn't C) – Marcus Müller Nov 17 '21 at 00:07
  • @ShadowRanger Yes exactly, thank you I didn't know this. This leads to my next question, how come it odesn't decay to an integer pointer of 4 bytes but instead 8 bytes? – APM500 Nov 17 '21 at 00:07
  • 1
    @APM500 because all pointers are the same size, regardless of their type. You have a pointer to an `int`. The pointer is 8 bytes, because you are compiling for a 64bit system. The `int` it is pointing at is 4 bytes. – Remy Lebeau Nov 17 '21 at 00:08
  • 1
    @APM500 there's nothing special about an integer pointer, char pointer, float pointer or say, ifstream pointer. All pointers. All 64 bit on your system. `int` tells you something about what is pointed to, not about the pointer itself. – Marcus Müller Nov 17 '21 at 00:08
  • @MarcusMüller Got it, thanks for all the help everyone! – APM500 Nov 17 '21 at 00:09
  • Are you sure you are running it on a 32-bit platform? Otherwise how could an `int *` have 4 bytes? It will normally have 8 bytes on a 64-bit platform. – Andrej Podzimek Nov 17 '21 at 02:29

3 Answers3

10

Shouldn't they be the same?

No. a is (meant to be) an array (but because it's a function argument, has been adjusted to a pointer to the 1st element), and as such, has the size of a pointer. Your machine seems to have 64 bit addresses, and thus, each address (and hence, each pointer) is 64 bits (8 bytes) long.

a[0], on the other hand, is of the type that an element of that array has (an int), and that type has 32 bits (4 bytes) on your machine.

Marcus Müller
  • 34,677
  • 4
  • 53
  • 94
  • `but because it's a function argument, has been decayed to a pointer to the 1st element` nothing has decayed here, as there are no arrays here. It is simply a pointer. – 0___________ Nov 17 '21 at 00:11
  • @0___________ hm, I don't want to language-lawyer this, but I don't think `typeid(int[])==typeid(int*)`, right? – Marcus Müller Nov 17 '21 at 00:13
  • @MarcusMüller It's just bit of a nitpick. Decaying is an implicit conversion that occurs when array is used as an operand. What happens here is "adjustment". The parameter is adjusted to be a pointer type. – eerorika Nov 17 '21 at 00:32
  • ah, not so insignificant, words do matter! Let me fix that! – Marcus Müller Nov 17 '21 at 00:33
  • Why we need declare type of pointer although they just store address – Đăng Khôi Nov 17 '21 at 00:43
  • 1
    @ĐăngKhôi because we need to know what it points to so we know how to interpret what is at the address. Also, because that's how C++ simply works. – Marcus Müller Nov 17 '21 at 00:44
  • 1
    Array type function parameters are one of the biggest lies ever produced by a programming language. They are actually pointers, and even if you provide a size it is simply ignored with no effect. This behavior brings further confusion between arrays and pointers novices always encounter. Arrays are arrays. Pointers are pointers. Except for function parameters, where what looks like an array is a pointer.:(. – François Andrieux Nov 17 '21 at 00:44
  • @FrançoisAndrieux if it is of any solace to you, check out `std::span` :) – Marcus Müller Nov 17 '21 at 00:45
  • @Marcus Müller you mean when we call *a – Đăng Khôi Nov 17 '21 at 00:47
2

A pointer is just an address of memory where the start of the variable is located. That address is 8 bytes.

a[0] is a variable in the first place of the array. It technically could be anything of whatever size. When you take a pointer to it, the pointer just contains an address of memory (integer) without knowing or caring what this address contains. (This is just to illustrate the concept, in the example in the question, a[] is an integer array but the same logic works with anything).

Note, the size of the pointer is actually different on different architectures. This is where the 32-bit, 64-bit, etc. comes in. It can also depend on the compiler but this is beyond the question.

eglease
  • 2,445
  • 11
  • 18
  • 28
  • `it technically could be anything of whatever size` it technically has a very well defined size – 0___________ Nov 17 '21 at 00:09
  • I meant the value stored in the array could be anything, using a random array as an example to illustrate the point. As is, it is not related the the size of the integer. It could be a char or it could be a double, or a nested array. The pointer does not care. – eglease Nov 17 '21 at 00:10
  • No definition shows the exact type referenced by the pointer – 0___________ Nov 17 '21 at 00:12
  • I added the explanation to the question. The example can be confusing to the understanding of the concept. – eglease Nov 17 '21 at 00:13
2

The size of the pointer depends on the system and implementation. Your uses 64 bits (8 bytes).

a[0] is an integer and the standard only gives an indication of the minimum max value it has to store. It can be anything from 2 bytes up. Most modern implementations use 32 bits (4 bytes) integers.

sizeof(a)/sizeof(a[0]) will not work on the function parameters. Arrays are passed by the reference and this division will only give you information how many times size of the pointer is larger than the size of an integer, but not the size of the object referenced by the pointer.

0___________
  • 60,014
  • 4
  • 34
  • 74
  • "Arrays are passed by the reference" is an unfortunate choice of wording in C++ (where references are a separate thing from the pointers you get from array->pointer decay). – ShadowRanger Nov 17 '21 at 00:14