omar
omar

Reputation: 629

Can a pointer convert to an array during a function call?

Consider the following piece of code:

#include <iostream>
#include <typeinfo>

void use_pointer(int *ptr)
{
    std::cout << typeid(ptr).name() << std::endl;
}

void use_array(int arr[])
{
    std::cout << typeid(arr).name() << std::endl;
}

int main()
{
    int *ptr = nullptr;
    // std::cout << typeid(int *).name() << std::endl; // output: Pi
    int arr[1];
    // std::cout << typeid(int[]).name() << std::endl; // output: A_i

    use_pointer(arr);
    use_array(ptr);
}

Compiling this program using g++ 6.5.0 outputs:

$ g++ -std=c++11 arrays_2.cpp -Wall
$ ./a.out

Pi
Pi

Now, when calling use_pointer(arr) the array is being decayed to a pointer. (Is that correct? The word "decay" is new to me.)

And the C++ Standard says at [conv.array#1]:

An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to a prvalue of type “pointer to T”. The temporary materialization conversion ([conv.rval]) is applied. The result is a pointer to the first element of the array.

I think I understand that my "array of int" converts to a "pointer to int". (Is that correct?)

Now, what happens exactly when calling use_array(ptr). Since the type of the parameter in this case is array of int, did the "pointer to int" convert to an "array of int"?

A pointer to the standard would be much appreciated.

Upvotes: 2

Views: 119

Answers (3)

Loki Astari
Loki Astari

Reputation: 264639

Can a pointer convert to an array during a function call?

No. See the last example when passing by reference.

An array type has a size (that includes all elements). When it decays into a pointer this size information is lost. So there is no way to convert a pointer back into an array (as you don't know how big the array is).

You probably noticed that array and pointer parameters are actually synonyms for each other to the compiler:

> cat b.cpp
void use_pointer(int *ptr)
{}
void use_pointer(int (arr)[])
{}

> g++ b.cpp
b.cpp:8:6: error: redefinition of 'use_pointer'
void use_pointer(int (arr)[])
     ^
b.cpp:4:6: note: previous definition is here
void use_pointer(int *ptr)

It does not matter to the compiler these are both the same thing.

So when you pass an array as a parameter it will usually decay into a pointer (for the address of the first element of the array).

Now you can pass an array by reference but the syntax is different.

void use_pointerref(int (&arr)[1])  // You have to specify the exact size
{}                                  // And lace the ampersand in there.

But you will notice that a pointer will not bind to this function.

use_arrayref(arr);
use_arrayref(ptr);

> g++ b.cpp
b.cpp:31:5: error: no matching function for call to 'use_arrayref'
    use_arrayref(ptr);
    ^~~~~~~~~~~~
b.cpp:14:6: note: candidate function not viable: no known conversion from
      'int *' to 'int (&)[1]' for 1st argument
void use_arrayref(int (&arr)[1])

Some notes:

But let us think about that. C++ semantics are normally pass by value. So if you had succeeded (or should I say if the language allowed) in passing the array you would have made a copy of the array that would have been passed to the function. This is probably not desirable so apssing the pointer is an efficient way of passing by value (though you do . get a type change).

Note that the pass by reference is very limited as it must know the exact type. We usually get around the size issue by making it a template.

template<int S>
void use_pointerref(int (&arr)[S])
{
    std::cout << typeid(arr).name() << " Size: " << S << std::endl;
}

Upvotes: 1

n. m. could be an AI
n. m. could be an AI

Reputation: 120059

Your code has little to do with pointer decay. Rather, it demonstrates type adjustment of function parameters.

When used as a type of a function parameter, T[] is being adjusted to T*. This is not a decay, not a conversion, it's a rewrite. The program is rewritten to use T*, as if no T[] was ever there in the source code.

To reiterate, there are no function parameters of type T[] in C++. When the programmer writes one, the compiler immediately substitutes T* and forgets that T[] was ever there. This is in contrast with normal arrays and their decay to pointers. There are most definitely arrays in C++ which are very different from pointers. They decay to pointers only in (many but not all) expressions. It's a one way street: a pointer never un-decays to an array

Upvotes: 2

Some programmer dude
Some programmer dude

Reputation: 409432

Pointers are pointers, and arrays are arrays. However, arrays naturally decays to pointers to their first element. So when you pass the array arr to any of the function you have, it will decay to &arr[0].

Also note that when declaring function arguments, array-notation (like int arr[]) doesn't mean that it's an array, it's still translated by the compiler as a pointer (i.e. int* arr).

Regarding the decay from array to pointer, it can't happen the other way. Once you have a pointer, all you have is that pointer and the single element it points to.

Upvotes: 5

Related Questions