Getting sizeof pointer to an array

I am playing around with pointer to array. Saw this tutorial's code as below.
I understand that sizeof(int) returns the number of bytes used to store an int, while sizeof(int*) returns the number of bytes used to store a pointer. But why is it sizeof(*ptr) = 20? Why is it bigger than the ptr's size?

1
2
3
4
5
6
7
8
9
10
  int main()
{
    int arr[] = { 3, 5, 6, 7, 9 };
    int *p = arr;
    int (*ptr)[5] = &arr;
     
    printf("sizeof(p) = %lu, sizeof(*p) = %lu\n", sizeof(p), sizeof(*p));
    printf("sizeof(ptr) = %lu, sizeof(*ptr) = %lu\n", sizeof(ptr), sizeof(*ptr));
    return 0;
}


Output:

sizeof(p) = 8, sizeof(*p) = 4
sizeof(ptr) = 8, sizeof(*ptr) = 20


P.S I may be asking a stupid question but thanks in advance for any explanation!!
Last edited on
decltype(p) == int *, sizeof(int *) == 4
decltype(ptr) == int[5] *, sizeof(int[5] *) == 4
decltype(*ptr) == int[5], sizeof(int[5]) == 5 * sizeof(int) == 5 * 4 == 20

Note that in your particular platform, sizeof(T *) == 4 for any type T.
@helios, meaning size of *ptr is sum of size of the whole array's int? While size of ptr and p is only one int? Am i right?
In your platform sizeof(T *) == 4 and sizeof(int) == 4, but this is not the case everywhere. In some platforms the following is true instead:

decltype(p) == int *, sizeof(int *) == 8
decltype(ptr) == int[5] *, sizeof(int[5] *) == 8
decltype(*ptr) == int[5], sizeof(int[5]) == 5 * sizeof(int) == 5 * 4 == 20
If we have some object type T, and we have a pointer T* ptr which points to an object of type T, sizeof(ptr) would give us the size of the pointer and sizeof(*ptr) would give us the size of the object ie. sizeof(T).
If the object type T is an array, then sizeof(*ptr) would give us the size of the array.

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>

int main()
{
    using T = int[5] ; // type T is 'array of 5 int'
    std::cout << sizeof(T) << '\n' ; // size of 'array of 5 int'

    T* ptr = nullptr ; // type T* is 'pointer to array of 5 int'
    std::cout << sizeof(ptr) << '\n' ; // size of 'pointer to array of 5 int'
    std::cout << sizeof(*ptr) << '\n' ; // size of 'array of 5 int'
}
decltype(p) == int *, sizeof(int *) == 8
decltype(ptr) == int[5] *, sizeof(int[5] *) == 8
decltype(*ptr) == int[5], sizeof(int[5]) == 5 * sizeof(int) == 5 * 4 == 20


@helios, oh then isn't decltype(*ptr) == int[5], sizeof(int[5]) ==5 * 8 == 20 instead?
Would you like to run the following code and tell me if its output can be of any help?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <vector>

int main()
{
    std::vector<double> v(100);
    std::vector<double>* ptov = &v;
    char c = 'x';
    char* ptochar = &c;
    double d = 1.0;
    double* ptodouble = &d;
    std::string s {"Lorem ipsum dolor sit amet, vis id quis invenire imperdiet, "
                   "in delectus adolescens eum, per in vide omnesque."};
    std::string* ptostring = &s;
    std::cout <<   "         sizeof(v): " << sizeof(v)          << "\ta std::vector"
              << "\n      sizeof(ptov): " << sizeof(ptov)       << "\tpointer (to whatever)"
              << "\n     sizeof(*ptov): " << sizeof(*ptov)      << "\ta std::vector"
              << "\n         sizeof(c): " << sizeof(c)          << "\ta char"
              << "\n   sizeof(ptochar): " << sizeof(ptochar)    << "\tpointer (to whatever)"
              << "\n  sizeof(*ptochar): " << sizeof(*ptochar)   << "\ta char"
              << "\n         sizeof(d): " << sizeof(d)          << "\ta double"
              << "\n sizeof(ptodouble): " << sizeof(ptodouble)  << "\tpointer (to whatever)"
              << "\nsizeof(*ptodouble): " << sizeof(*ptodouble) << "\ta double"
              << "\n         sizeof(s): " << sizeof(s)          << "\ta std::string"
              << "\n sizeof(ptostring): " << sizeof(ptostring)  << "\tpointer (to whatever)"
              << "\nsizeof(*ptostring): " << sizeof(*ptostring) << "\ta std::string\n";
    int arr[5] {};
    int *p = arr;
    int (*ptr)[5] = &arr;

    // On my machine int is 4 bytes and pointers are 8 bytes:
    std::cout << "\n  sizeof(arr): "  << (sizeof(arr)) << "\tarray of 5 ints --> 5 x 4"
              << "\n  sizeof(p)  : "  << (sizeof(p))   << "\tpointer (to whatever)"
              << "\n sizeof(*p)  : " << (sizeof(*p))   << "\tint --> 1 x 4"
              << "\n  sizeof(ptr): "  << (sizeof(ptr)) << "\tpointer (to whatever)"
              << "\n sizeof(*ptr): " << (sizeof(*ptr)) << "\tarray of 5 ints --> 5 x 4\n";
    return 0;
}

@Enoizat, yup, the output is very clear. just to make sure sizeof(*p) : 4 int --> 1 x 4 means that size of 1 int, right?

One int in my machine, yes. In other machines an int could be different, for example 8.

@helios, oh then isn't decltype(*ptr) == int[5], sizeof(int[5]) ==5 * 8 == 20 instead?
No, sizeof(int) and sizeof(T *) are independent. In portable code it's an error to assume that they're always the same.
Just FWI, if it's available, sizeof(uintptr_t) == sizeof(T *). uintptr_t is an integer type provided for temporary storage of pointers.
@helios, oh i got it!! Thanks alot for explaining.
One more puzzle for you:
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>

class Foo {
    double a;
    bool b;
};

int main()
{
    std::cout << sizeof(double) << '\n' ;
    std::cout << sizeof(bool) << '\n' ;
    std::cout << sizeof(Foo) << '\n' ;
}

Is the whole merely a sum of its parts?

Put other way:
1
2
T * foo = ...
++foo;

How much did the foo advance?
Logically +1, but how much in bytes?
sizeof(T)

1
2
3
4
5
6
7
8
9
#include <iostream>

int main()
{
    int bar[][2] { 1, 2, 3, 4, 5, 6 };
    int (* ptr)[2] { bar + 1 }; // How much is "+1" here?
    std::cout << ptr[0][0] << '\n';
    return 0;
}

@keskiverto, you stumped me....
1
2
3
4
5
6
7
int foo = 3;
	std::cout << sizeof(foo) << '\n';
	int* T = &foo;
	std::cout << sizeof(T) << '\n';
	++foo;	
	std::cout << sizeof(foo) << '\n';
	std::cout << sizeof(T) << '\n';


4
4
4
4


Am I right? All the sizes are 4 bytes.
Remember that sizeof is evaluated at compile time and the result is a constant that's hard-coded into the final executable, while normal expressions are evaluated at run time. Therefore,
1
2
3
4
T x = /*whatever*/;
size_t n = sizeof(x);
x = /*whatever else*/;
size_t m = sizeof(x);
at the end of this snippet, regardless of what you do in the commented sections, n == m.

Read keskiverto's post more carefully.
Topic archived. No new replies allowed.