1

Why are arrays considered as pointers in function arguments of a function in C++ . Here, I have a few snippets of Code to illustrate my concern:

#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
void test(uint32_t x[3])
{
    cout << "Inside test : "<< sizeof(x) << endl; 
}
int main()
{
    uint32_t n[3];
    cout << "Size of array in bytes : " << sizeof(n) << endl;
    test(n);
    return 0;
}

This is the output that I get:

Size of array in bytes : 12
Inside test : 4

In the first case I get the actual size of the array , but when test() is called the output is 4 bytes which is same as sizeof(uint32_t *) .

What is the reason for this behaviour ?

Every help is appreciated!

pzaenger
  • 11,381
  • 3
  • 45
  • 46
Vivekanand V
  • 340
  • 2
  • 12
  • 2
    Arrays are not copyable, so it's not possible to pass an array by value. – Igor Tandetnik Apr 12 '20 at 03:11
  • @Igor Tandetnik Thankyou for your reply ! So in all cases should I stick to using ```sizeof(uint32_t) * 3 ``` for calculating the size of my array ? – Vivekanand V Apr 12 '20 at 03:14
  • 1
    Well, yes, if you have reasons to believe that the caller always passes a pointer to a buffer exactly 3 elements large. – Igor Tandetnik Apr 12 '20 at 03:16
  • @Igor Tandetnik Yes, its three in my case ! But what difference does the compiler see when ```uint32_t x[3]``` is used as opposed to ```uint32_t * x``` ? – Vivekanand V Apr 12 '20 at 03:17
  • duplicate, but in C: [Why do arrays in C decay to pointers?](https://stackoverflow.com/q/33291624/995714). Possible duplicate: [why does the array decay to a pointer in a template function](https://stackoverflow.com/q/7797839/995714) – phuclv Apr 12 '20 at 03:17
  • Because that's how it is specified in the C and C++ standards. An array argument in the function is treated as a pointer (to the first element), and no length information is passed unless the programmer deliberately passes a second argument that contains the length. If the caller passes an array, it is converted to a pointer (to its first element) before being passed. If the caller passes a pointer (e.g. the result of a `malloc()` call in C, or an array `new` expression in C++) then that pointer is passed verbatim. – Peter Apr 12 '20 at 03:17
  • 1
    in C++ just avoid plain arrays and pass a `std::array` (by pointer or reference) if you have a fixed size. That case there's no decaying to worry about – phuclv Apr 12 '20 at 03:19
  • I have linked this to a C language question but this "feature" is identical in both languages (and we could even say C++ only retains it for legacy reasons) – M.M Apr 12 '20 at 03:19
  • 1
    You can pass an argument of the form `uint32_t (*x)[3]` (the address of an array of three elements) which means the call in `main()` needs to pass `&n`, and `*x` (or `(*x)`) inside the function is the array with three elements. In C++ (not C) it is possible to pass ` `uint32_t (&x)[3]` (reference to an array of three elements). HOWEVER, in both cases, the length of the array is fixed (a compile time constant), so it is not possible to pass an array with 4 elements to a function that expects a pointer/reference to an array with three elements. – Peter Apr 12 '20 at 03:22

1 Answers1

2

This is C99 standard 6.3.2.1/3 Other operands - Lvalues, arrays, and function designators.

Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue.

And this is C++ standard. Array-to-pointer conversion.

An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to an rvalue of type “pointer to T.”

This is not mandatory to pass an array as a pointer in C++, it can be pasted as a reference.

#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
void test(uint32_t (&x)[3])
{
    cout << "Inside test : "<< sizeof(x) << endl; 
}
int main()
{
    uint32_t n[3];
    cout << "Size of array in bytes : " << sizeof(n) << endl;
    test(n);
    return 0;
}

Output

Size of array in bytes : 12
Inside test : 12
273K
  • 29,503
  • 10
  • 41
  • 64