Difference Between Passing Array, Fixed-Sized Array and Base Address of Array as a Function Parameter

Difference between passing array, fixed-sized array and base address of array as a function parameter

All these variants are the same. C just lets you use alternative spellings but even the last variant explicitly annotated with an array size decays to a normal pointer.

That is, even with the last implementation you could call the function with an array of any size:

void func3(char str[10]) { }

func("test"); // Works.
func("let's try something longer"); // Not a single f*ck given.

Needless to say this should not be used: it might give the user a false sense of security (“oh, this function only accepts an array of length 10 so I don’t need to check the length myself”).

As Henrik said, the correct way in C++ is to use std::string, std::string& or std::string const& (depending on whether you need to modify the object, and whether you want to copy).

Address of an array different with the address of the first element?

Why address of array a in func() difference with address of a[0]?

Because you're calling the function func() passing a by value. This means the a inside the function func() is actually a copy of the original decayed pointer that you're passing to func() from main(). And since they're different variables, they have different addresses. Thus by writing cout << &a; you're printing the address of this separate local variable named a.

If you want to print the original address, you should write inside func():

void func(int a[])
{
//---------------------------------v---------->removed the &
cout << "address in func: " << a << endl;;
cout << "GT: " << &a[0] << endl;
}

Demo

address in main: 0x7ffcfb0a4320
address in main a[0]: 0x7ffcfb0a4320
address in func: 0x7ffcfb0a4320
GT: 0x7ffcfb0a4320

Use pointer or array in function parameters

Yes, both the versions are effectively same, because, when arrays are passed as function arguments, they essentially decay to the pointer to the first element.

So, making the function parameter as pointer or array will have no behavioral change.

Related, C11, chapter §6.7.6.3, Function declarators

A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’
[...]

So, float scalar_product(float x[], float y[]) ends up being the same as float scalar_product(float *x, float *y).

Use pointer or array in function parameters

Yes, both the versions are effectively same, because, when arrays are passed as function arguments, they essentially decay to the pointer to the first element.

So, making the function parameter as pointer or array will have no behavioral change.

Related, C11, chapter §6.7.6.3, Function declarators

A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’
[...]

So, float scalar_product(float x[], float y[]) ends up being the same as float scalar_product(float *x, float *y).

Does specifying size of array in parameter do anything?

No, if you pass by value, an array type specifier in a parameter is always adjusted to a pointer.

void SetIDs (int IDs[22] );

void SetIDs (int IDs[] );

void SetIDs (int *IDs );

all produce the same code. Even sizeof IDs inside SetIDs will only return the size of a pointer as if IDs was declared as int *IDs.

The array size becomes relevant when you pass by reference or have a multidimensional array:

void SetIDs (int (&IDs)[22] );

This SetIDs will only accept (references to) arrays of int with size 22.

void SetIDs (int IDs[22][42] );
// equivalent to
void SetIDs (int (*IDs)[42]);

This SetIDs will accept pointers to (or an array of) an array of int with size 42.

C++: How to pass array into an instance of a class and get the sizeof() it?

For a static C-style array it is possible to infer its size using the expression

sizeof(info) / sizeof(*info)

This is also commonly implemented via a macro ARRAY_SIZE. Beware however that in the above code there is no check that the actual array is a static one.

Conversely, for a dynamically allocated C-style array, there is no possibility to infer its size, since the variable itself is nothing but a pointer.

In the class constructor, even if you knew the size of the array (for instance by passing the size as parameter), or if you assume that only a static array is used (and you employ the code above to infer its size), your code has a serious bug here:

for(int i=0;i<9;i++){
array[i]=temp[i];
};

You are copying the elements of temp into array, but did you reserve memory for that? Again, array is merely a pointer to float, and if you do not explicitly allocate memory, in the above code you are writing into a part of memory which does not pertain to array. Hence you have UB.

If you know at compile time the size of the array, the right type to use is std::array.
For instance

std::array<float, 10> info = {1.0f,2.3f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,67.8f};

And then you can pass it to the class with something like

class Store{
std::array<float, 10> array;
public:
Store(std::array<float, 10> temp) : array{temp} { }

...

With a std::array you can always know its size with std::array::size.

Are there other ways of passing array in a function?

fun takes a pointer-to-array-of-3-double and it assumes (relying on the caller) that this points to the first element of an array of at least 3 arrays-of-3-doubles. Which it does, because as you say the argument supplied to the call in main is an array. This immediately decays to a pointer to its first element.

One alternative would be for fun to take a pointer-to-3x3-array-of-double, since it assumes that size anyway and the caller does in fact have such a beast:

void fun(double (*p_projective)[3][3])
{
for(int i=0; i<3; i++)
for(int j=0; j<3; j++)
{
(*p_projective)[i][j]= i*100+j;
}
}

Call it with fun(&projective).

Changing the array's base-address

Arrays are objects all on their own, and not pointers. Consider a simpler object:

int a = 0;

Would you expect to be able to change its address? Of course not. An object is a region of storage with a type. The region of storage is identified by its address, so you won't expect to change it. And arrays are objects too. When you declare

int b[8] = {0};

you declare an object, the size of eight integers, that will occupy some storage. You can't change its address any more than you can change the address of any single int.

You have probably been told that arrays are pointers. But they are not! They may be converted, even implicitly, to a pointer more often than not, but they are still object types. Pointers often stand in for arrays because the address of the first element is enough to reach any other element with pointer arithmetic, but the pointer is not the array object itself. The difference becomes apparent when you inspect their object properties. For instance:

sizeof(b) != sizeof(int*)

The object b is not the size of a pointer, indeed it is the size of 8 integers, likely larger than a pointer.



Related Topics



Leave a reply



Submit