4

I understand that when we use sizeof operator on an array name, it gives the total size of the array in bytes. For example

int main(int argc, const char * argv[]) {
    int a[][5] = {
        {1,2,3,4,5},
        {10,20,30,40,50},
        {100,200,300,400,500}
    };

    int n=sizeof(a);
    printf("%d\n",n);

}

It gives 60 as output for 15 elements of the array. But when I write

int n=sizeof(*a);

It gives 20 as the output that is the size of the first row while *a is the base address of the 0th element of the 0th row, and its type is a pointer to an integer. And a points to the first row itself. Why is this happening?

Student
  • 805
  • 1
  • 8
  • 11

6 Answers6

5

*a is row 0 of a, and that row is an array of five int.

In most expressions, an array is automatically converted to a pointer to its first element. Thus, when you use *a in a statement such as int *x = *a;, *a is converted to a pointer to its first element. That results in a pointer to int, which may be assigned to x.

However, when an array is the operand of a sizeof operator, a unary & operator, or an _Alignof_ operator, it is not converted to a pointer to its first element. Also, an array that is a string literal being used to initialize an array is not converted to a pointer (so, in char foo[] = "abc";, "abc" is used as an array to initialize foo; it is not converted to a pointer).

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
4

*a is not a pointer, it's an int[5], which is coherent with your reading of 20 assuming a 4-byte int.

Quentin
  • 62,093
  • 7
  • 131
  • 191
  • You can check the type of *a. It is int * – Gaurav Mishra Jul 23 '18 at 12:22
  • 1
    @GauravMishra if observing the size is not enough for you, you can convince yourself by taking its address and storing it in another variable. `int **p = &*a;` won't compile, but `int (*p)[5] = &*a;` will. – Quentin Jul 23 '18 at 12:28
  • When I write printf("%d",*a) the compiler is saying "Format specifies type 'int' but the argument has type int * " . Also when you use &*a together you get the variable itself . In this case you get a which is of type pointer to a 1d array ! – Gaurav Mishra Jul 23 '18 at 12:38
  • 1
    @GauravMishra that's because passing an array as parameter to a function decays it into a pointer to its first element. – Quentin Jul 23 '18 at 12:46
  • Sorry didn't get you . Please explain as I am confused ! – Gaurav Mishra Jul 23 '18 at 12:50
1

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.

The expression a has type "3-element array of 5-element array of int"; thus, sizeof a should yield 3 * 5 * sizeof (int).

The expression *a is the same as the expression a[0] (a[i] is defined as *(a + i) - *a is the same as *(a + 0), which is the same as a[0]). Both *a and a[0] have type "5-element array of int"; thus sizeof *a and sizeof a[0] should both yield 5 * sizeof (int).

However...

If you pass a to a function, such as

foo( a );

then a is not the operand of the sizeof or unary & operators, and the expression will be converted from type "3-element array of 5-element array of int" to "pointer to 5-element array of int":

void foo( int (*a)[5] ) { ... }

If you computed sizeof a in function foo, you would not get 5 * sizeof (int), you would get sizeof (int (*)[5]), which, depending on the platform, would be 4 to 8 bytes.

Similarly, if you passed *a or a[i] to a function, what the function actually receives is a pointer to int, not an array of int, and sizeof will reflect that.

John Bode
  • 119,563
  • 19
  • 122
  • 198
  • What if we pass a and print the sizeof(*a) ? In this case it is again giving 20 ! – Gaurav Mishra Jul 23 '18 at 14:55
  • @GauravMishra: Remember, `a` "decays" to "pointer to 5-element array of `int`"; when you dereference it with `*a`, the type of the result is "5-element array of `int`". – John Bode Jul 23 '18 at 14:59
  • Can you please tell me how to calculate the size of the whole array in the function when we pass a pointer to it ? void foo( int (*a)[5] ) { ... } – Gaurav Mishra Jul 24 '18 at 07:30
  • @GauravMishra: You can’t. That information is lost as part of the conversion. – John Bode Jul 25 '18 at 02:35
0

In this 2d array *a is a pointer because when you print it, its seems an address (but it is the 1st column address) :

printf("%d\n", *a);

Output : 9435248

So :

for(int i = 0;i < 3;i++)
    printf("%d\n", *a[i]);

The output is :

1
10
100

When you use of *a like this : *a[3] its means you are in 3rd row and 1st column by default.

*a is the address of 1st column and we have 5 column, so when you try this :

sizeof(*a);

Output will be 20 => (5 column) * (int pointer which is 4 byte)).

0

A 2D array is viewed as an array of 1D arrays. That is, each row in a 2D array is a 1D array. For a given 2D array A, int A[m][n] you can think of

  • A[0] as the address of row 0
  • A[1] as the address of row 1 etc & so on.

Dereferencing can be thought of as below,

 A[i][j] = *(A[i] + j) = *(*(A+i) + j)

So when you say *A, it means A[0] which gives you the address of 1st row & not the 1st element of the matrix.

  • Dereference of A or *A gives the address of row 0 or A[0].
  • Dereference of A[0] gives the first entry of A or A[0][0] that is

    **A = A[0][0].

& since you have 5 elements in the 1st row the size if 20 bytes.

RamBo
  • 15
  • 4
-1

Sizeof returns the size of the variable in memory expressed in bytes. This includes padding (unused bytes added by a compiler to a structure to improve performance). Your array has 15 elements of size 4. The sizeof an integer in memory is 4 in you case. You can easily verify this by running:

printf("sizeof an integer: %zu\n", sizeof(int));

It is always a good idea to use standard int types.

#inlcude <stdint.h>
uint32_t a[][5] = {
    {1,2,3,4,5},
    {10,20,30,40,50},
    {100,200,300,400,500}
};

This will produce exactly the same code but wil clearly show the memory size of the (32 bit) integer. In your case uint8_t (unsigned int of 8 bit) might be more appropriate. You can read more here. To get the number of elements you should devide the total memory of the array by the sizeof an element.

sizeof(a)/sizeof(a[0])

You can also use a macro to do this:

#define ARRAY_LENGTH(array)(sizeof(array)/sizeof(array[0]))
/*ARRAY_LENGTH(a) will return 15 as expected.*/

You can also look for an answer here: How can I find the number of elements in an array?

  • 1
    `printf("sizeof an integer: %ld\n", sizeof(int));` is undefined behavior. The proper format string modifier for `size_t` - what `sizeof()` returns - is `"z"`, so for decimal output `printf("sizeof an integer: %zd\n", sizeof(int));` would be correct. – Andrew Henle Jul 23 '18 at 12:31
  • The question asks about `sizeof(*a)`. This answer does not speak to that at all. – Eric Postpischil Jul 23 '18 at 14:23