Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

declared as array of references of type float&

Tags:

c++

c

I'm getting declared as array of references of type float& error in XCode when I declare a function as :

void calcCoeff(float sigma, float& ap[], float& bp[], float& an[], float& bn[]);

can anyone tell me what could be the problem? I also tried

void calcCoeff(float sigma, float &ap[5], float &bp[5], float &an[5], float &bn[5]);

thanks...

like image 629
Abhishek Thakur Avatar asked Feb 18 '23 21:02

Abhishek Thakur


1 Answers

The problem is exactly as described by the error message: float& ap[] declares an array of references, and that's not a legal type in C++, just as pointers to references and references to references are prohibited.

If it were legal you can think of what it would mean by thinking of an array of pointers. A reference is in some ways conceptually similar to a pointer; a reference is meant to refer to another entity and when a reference requires a runtime representation C++ implementations typically use pointers.

So, if you were to pass an array of pointers to a function you would need to construct an initialize it:

float a, b, c;
float *arr[] = {&a, &b, &c};    // or in fictional array-of-references syntax: float &arr[] = {a, b, c};

Or if you already have an array of floats, and you want an array of pointers to those elements:

float a[3];
float *b[] = {&a[0], &a[1], &a[2]);     // or in fictional array-of-references syntax: float &b[] = {a[0], a[1], a[2]};

Presumably what you actually want is to pass an array, by reference, to a function so that the function can write into the array and the changes will be visible to the caller. (or simply because you want to avoid copying the array). Since normally function parameters are passed by value, and the way to pass by reference is to stick & in there you did the same for an array type. This is a pretty good instinct, but there are a few wrinkles in C++ that messed it up for you.

The first is simply the odd syntax for declaration in C++. You can read about the 'spiral rule' or 'declaration mimics use' elsewhere, but suffice it to say that it matters whether that & is 'closer' (syntactically) to the variable name or float. float &arr[] is an array of references. You need a couple parentheses to put the ampersand closer to the variable: float (&arr)[] declares a reference to an array.

Next is that C++ unfortunately inherits some strange behaviors from C intended to make arrays and pointers pretty much interchangeable. The relevant behavior in your case is that if you declare a function that takes an array parameter:

void foo(int arr[], int size);

the language specifically says that the type is 'adjusted' to be a pointer. The result is the same as:

void foo(int *arr, int size);

What this means is that arrays do not behave like value types. Trying to pass an array 'by value' does not result in a modifiable copy of the array being passed to the function; instead the function effectively receives the array 'by reference'.

A second consequence is that array parameters do not need to have complete array types, i.e. the array size can be omitted, because the array type is adjusted and the size is never used anyway. This means that if you naively convert an 'array parameter' that doesn't specify a size into a reference to an array, you have to specify the size in addition to adding the &. float (&arr)[10].


Using raw array as parameters is highly undesirable in my opinion. First because it discards type information:

void foo(int arr[10]) { // same as void foo(int *arr)
    int x = arr[9];
}

int bar[3];
foo(bar); // no compile error! the special array rules discarded the size of the array

And because raw arrays are not consistent with other built-in types, all of which have value semantics. For these reasons raw arrays should be avoided. Instead you can use std::array which avoids all the 'special' rules for built-in arrays and therefore behaves as built-in arrays ought to.

void foo(std::array<int, 10> arr); // Takes arr by value, modifications will not be visible externally

std::array<int, 3> bar;
foo(bar); // compile error

And if you need a dynamically sized array then you can use std::vector instead.

like image 72
bames53 Avatar answered Feb 28 '23 11:02

bames53