4

Suppose I declare int v[]={1,2,3,4,5};

I have been taught that v is a pointer to the first element in the v array. When I call apply sizeof to v, it returns 20, which I know is 5*sizeof(int), because there are 5 elements in the array.

v+0 is also a pointer to the first element in the array, but sizeof(v+0) is 4.

Why is sizeof(v)=20 and sizeof(v+0)=4?

I would expect that sizeof(v) also returned 4, as v is a pointer, but instead it somehow also contains the information regarding the number of elements stored in the array. What is the explanation for this?

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
Andrei
  • 57
  • 4
  • 6
    *"I have been taught that v is a pointer"* - You were taught wrong. Shame on your teachers. – StoryTeller - Unslander Monica Nov 27 '17 at 18:31
  • 2
    `v` is an array, not a pointer. The thing about arrays is that they decay to pointers, but they are not exactly pointers. `v+0` decays the `v` to a pointer to do pointer arithmetic, and as that expression is a pointer rather than an array, the `sizeof` operator treats it as such. – Christian Gibbons Nov 27 '17 at 18:33
  • 3
    I've seen it said that the first step to understanding C is to know that arrays are pointers. The second step to understanding C is to know that arrays are not pointers. – Christian Gibbons Nov 27 '17 at 18:34
  • 3
    I suggest you read section 6 of the [c-faq](http://c-faq.com/). – pmg Nov 27 '17 at 18:42
  • @StoryTeller I was partially wrong. I've just checked my lecture and it says "the name of an array is a constant pointer to the first element in it" – Andrei Nov 27 '17 at 18:56
  • @ChristianGibbons Thank you. Pointer decaying was not mentioned in our lectures but I'll look more into it. – Andrei Nov 27 '17 at 18:57
  • 1
    @Andrei - The name of the array is not a pointer at all. – StoryTeller - Unslander Monica Nov 27 '17 at 18:57
  • No offense, the most technically correct comment here is by @pmg. I don't understand why it's not upvoted. – Sourav Ghosh Nov 27 '17 at 20:30
  • @Andrei: While it's not a good *learning* resource (it has no tutorial information in it), you might want to bookmark the [online version](http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1570.pdf) of the C language standard. It's not easy reading, but you might want to compare your notes against it as you go through your class. C is often taught poorly by people who were themselves taught poorly, and a lot of misinformation and bad practice have been passed down. The standard is the primary reference - if your notes disagree, go with what the standard says. – John Bode Nov 27 '17 at 21:46
  • @JohnBode All right, thank you for the help! – Andrei Nov 28 '17 at 17:19

4 Answers4

5

I have been taught that v is a pointer to the first element in the v array.

You have been taught incorrectly. v is not a pointer - no space for a pointer is materialized as part of the array. What you get is something like this:

   +---+
v: | 1 | v[0]
   +---+
   | 2 | v[1]
   +---+
   | 3 | v[2]
   +---+
   | 4 | v[3]
   +---+
   | 5 | v[4]
   +---+

and not this:

   +---+
v: |   |
   +---+
     |
     |
     V
   +---+
   | 1 | v[0]
   +---+
   | 2 | v[1]
   +---+
   | 3 | v[2]
   +---+
   | 4 | v[3]
   +---+
   | 5 | v[4]
   +---+

Except when it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array.

When you write something like foo( v ), or printf( "%p\n", (void *) v), or even just v[i], the expression v is converted from type "5-element array of int" to "pointer to int", and the value of the expression is the same as &v[0].

However, when you write sizeof v, that conversion doesn't happen - sizeof evaluates to the number of bytes in the entire array (5 * sizeof (int)). Similarly, the type of the expression &v is int (*)[5] (pointer to 5-element array of int), not int **.

This is why sizeof v yields 20, while sizeof (v + 0) yields 4 - in the second case, v is not the operand of sizeof, the expression (v + 0) is the operand of sizeof. In the expression (v + 0), v decays to type int *. Note that you will get a different result if you write sizeof v + 0 - sizeof has higher precedence than the addition operator +, so that expression would be parsed as (sizeof v) + 0.

John Bode
  • 119,563
  • 19
  • 122
  • 198
3

sizeof v = 20 because there are 5 elements each of size 4 byte in your system. Upto this everything is right. But then you mentioned v is a pointer. Is it so?

Nope. Array is different from a pointer. Why there is confusion?

In context of sizeof(v+0) this will explain a bit:

There are two things that you may find helpful from standard (Under pointer arithmetic) §6.5.6.2

For addition, either both operands shall have arithmetic type, or one operand shall be a pointer to a complete object type and the other shall have integer type. (Incrementing is equivalent to adding 1.)

And also from §6.5.6.7

For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.

So here v decays into pointers as an operand to + not an operand to the sizeof operator. In fact array doesn't decay into pointer when used as an operand of sizeof operator. Now sizeof a pointer variable is 4 bytes on yoru system. That's what you saw.


Long story short Arrays are not pointers. They are different. The second case might give you a wrong impression of that they are or even if your teacher said but it's not the case. Array decays into a pointer that doesn't make array a pointer.

user2736738
  • 30,591
  • 5
  • 42
  • 56
2

Pointers and arrays are closely related, but they are not equivalent.

In most contexts, the name of an array will decay to a pointer to the first element. There are a few instances however where this does not happen, specifically when the array is the operand of the sizeof operator (yes, it is an operator, not a function).

So in the expression sizeof(v), the name v does not decay because it is the operand of the sizeeof operator. As a result, size of the entire array is given. In contrast, sizeof(v+0) is different because v is an operand of the + operator. In this case, v does in fact decay to a pointer and pointer arithmetic is performed. This gives an expression of type int * which is then the operand to sizeof.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • Thank you. I'll have to look more into decaying, as it hasn't been mentioned in my lectures. I would also like to apologize for the bad formatting and thank you for correcting it. – Andrei Nov 27 '17 at 19:06
1

I would expect that sizeof(v) also returned 4

No.

To start with, v is not a pointer, it's an array. Arrays decay to pointers. Read more in What is array decaying?

When you call sizeof(v), you will get the size of your array in bytes.

20 is equal to 4 * 5 = 4 * N, where N is the number of elements in your array.

Moreover notice, that in your system an int is of size 4 bytes.

gsamaras
  • 71,951
  • 46
  • 188
  • 305