Technicalities involved with array of references - c++

I wrote this code for the following problem. My compiler is givin me the following error- [Error] declaration of 'a' as array of references. What is the problem?
void repfunc(int& a[],int size){
for(int i=size-1;i>=0;--i){
if(a[i]==0){
a[i]=1;
return;
}
for(int j=i-1;j>=0;--ji){
if(a[i]==a[j]&&a[i]!=9){
++a[i];
a[i]%=10;
return;
}
else if(a[i]==a[j]&&a[i]==9){
a[j-1]++;
a[j-1]%=10;
FOR(k, 1,size-j){
a[k]=k;
}
return;
}
}
}
}

As the error says, you can't have an array of references. It looks like you're actually trying to pass an array by reference. You can (sort of) do that by changing it to take a pointer to the start of the array:
void repfunc(int a[], int size) // equivalent to "int * a"
Since arrays are convertible to pointers, this will do the right thing if the argument is an array
int a[4] = {1,2,3,4};
repfunc(a, sizeof a / sizeof a[0]);
Alternatively, you could accept a reference to an array of the correct size:
template <size_t size>
repfunc(int (&a)[size])
allowing the size to be deduced automatically
int a[4] = {1,2,3,4};
repfunc(a);
but note that this will only work if a is actually an array; not, for example an pointer to a dynamically allocated array.

C++ Standard 8.3.2/4 clearly says that:
There shall be no references to references, no arrays of references, and no pointers to references
Actually a reference must always refer to something - there is no such thing as a null reference. This is why there can be no arrays of references, as there is no way to default instantiate references inside an array to a meaningful value.
-Source is Here.
And also By origin array is accessed via pointer arithmatic. So if we want to support array of reference we have to support pointer to reference, as per standard which is not possible.
These are reason array of reference is not possible. Which is what you were doing. And as Mike Seymour mentioned :
void repfunc(int a[], int size) is perfectly ok for your case.

Related

Is this reinterpret_cast to get a reference to dynamically allocated c-array well defined?

The more I learn about c-arrays, the less I know about c-arrays. Is it defined to cast like in following example and dereference the casted pointer to get a valid reference to the array?
void foo(int (&x)[5]){}
int main() {
int* arr = new int[5];
foo(*reinterpret_cast<int(*)[5]>(arr));
}
After rereading cppreference/reinterpret_cast I think not. Is it possible to get a valid reference to a dynamically allocated c-array in this way?
Optionally: What other casts would be defined?

Is it legal c++ to use reference as array/pointer?

My team (including myself) is new to C++. A piece of our new development is a C++ function that needs to interface with a C function that takes an array as input. Something like the following construct was made to achieve this:
#include "stdio.h"
void the_c_function(double *array, int len)
{
for (int i = 0; i < len; i++)
{
printf("%d: %g\n", i, array[i]);
}
}
void the_cpp_wrapper(double& dref, int len)
{
the_c_function(&dref, len);
}
int main()
{
const int LEN = 4;
double dbl_array[LEN] = { 3,4,5,6 };
the_cpp_wrapper(dbl_array[0], LEN);
return 0;
}
When compiled, this works as expected: it prints the contents of the array:
0: 3
1: 4
2: 5
3: 6
But this feels hardly legal to me or at the best something that should be discouraged.
Is this legal C++, i.e. is it guaranteed that a pointer to a reference of an array points to the original array?
Is there any reason why one would do it like this instead of using a pointer directly instead of using the reference as inbetween?
My team (including myself) is new to C++. ...
[...]
... something that should be discouraged.
You should get in the habit now of using the Standard C++ Library, in your case the best choice is std::vector:
#include <stdio.h>
#include <stdlib>
#include <vector>
void the_c_function(const double *array, size_t len) {/*...*/}
void the_cpp_wrapper(const std::vector<double>& v)
{
the_c_function(v.data(), v.size());
}
// ----------------------------
int main()
{
const std::vector<double> dbl_array { 3,4,5,6 };
the_cpp_wrapper(dbl_array);
return EXIT_SUCCESS;
}
You also should be clearer about const double* vs. double*, C++ intentionally wants you to use a much more verbose const_cast<double*> to cast-away const-ness.
If you want to go "all in" with C++, you can make the_cpp_wrapper() a bit more generic with a template:
template<typename TSpan>
void the_cpp_wrapper(const TSpan& v)
{
the_c_function(v.data(), v.size());
}
With this code, you can pass anything to the_cpp_wrapper that has data() and size() methods. (Note that TSpan "can" be std::span<int> which could cause some obscure compiler errors; there are ways to fix that, but it's more C++.)
Not directly related, but you'll probably find std::span useful too.
The question of code readability aside,
is it guaranteed that a pointer to a reference of an array points to the original array?
Yes, see § 5.5 Expressions:
If an expression initially has the type “reference to T” ([dcl.ref], [dcl.init.ref]), the type is adjusted to T prior to any further analysis. The expression designates the object or function denoted by the reference, and the expression is an lvalue or an xvalue, depending on the expression.
And §8.3.2 References:
4   It is unspecified whether or not a reference requires storage.
5   There shall be no references to references, no arrays of references, and no pointers to references.
In other words, an "address of a reference" isn't a thing; given double& dref, taking an address &dref will give the address of the original element inside the array.
Yes it is legal and it is guaranteed to reference to the original element in the array based on your code.
Some people like to design interface to force the caller to pass by reference to avoid checking whether the argument is a null pointer, which might be required when passing by pointer.

Why can't we pass arrays to function by value?

Apparently, we can pass complex class instances to functions, but why can't we pass arrays to functions?
The origin is historical. The problem is that the rule "arrays decay into pointers, when passed to a function" is simple.
Copying arrays would be kind of complicated and not very clear, since the behavior would change for different parameters and different function declarations.
Note that you can still do an indirect pass by value:
struct A { int arr[2]; };
void func(struct A);
Here's another perspective: There isn't a single type "array" in C. Rather, T[N] is a a different type for every N. So T[1], T[2], etc., are all different types.
In C there's no function overloading, and so the only sensible thing you could have allowed would be a function that takes (or returns) a single type of array:
void foo(int a[3]); // hypothetical
Presumably, that was just considered far less useful than the actual decision to make all arrays decay into a pointer to the first element and require the user to communicate the size by other means. After all, the above could be rewritten as:
void foo(int * a)
{
static const unsigned int N = 3;
/* ... */
}
So there's no loss of expressive power, but a huge gain in generality.
Note that this isn't any different in C++, but template-driven code generation allows you to write a templated function foo(T (&a)[N]), where N is deduced for you -- but this just means that you can create a whole family of distinct, different functions, one for each value of N.
As an extreme case, imagine that you would need two functions print6(const char[6]) and print12(const char[12]) to say print6("Hello") and print12("Hello World") if you didn't want to decay arrays to pointers, or otherwise you'd have to add an explicit conversion, print_p((const char*)"Hello World").
Answering a very old question, as Question is market with C++ just adding for completion purposes, we can use std::array and pass arrays to functions by value or by reference which gives protection against accessing out of bound indexes:
below is sample:
#include <iostream>
#include <array>
//pass array by reference
template<size_t N>
void fill_array(std::array<int, N>& arr){
for(int idx = 0; idx < arr.size(); ++idx)
arr[idx] = idx*idx;
}
//pass array by value
template<size_t N>
void print_array(std::array<int, N> arr){
for(int idx = 0; idx < arr.size(); ++idx)
std::cout << arr[idx] << std::endl;
}
int main()
{
std::array<int, 5> arr;
fill_array(arr);
print_array(arr);
//use different size
std::array<int, 10> arr2;
fill_array(arr2);
print_array(arr2);
}
The reason you can't pass an array by value is because there is no specific way to track an array's size such that the function invocation logic would know how much memory to allocate and what to copy. You can pass a class instance because classes have constructors. Arrays do not.
Summery:
Passing the Address of the array's first element &a = a = &(a[0])
New Pointer (new pointer, new address, 4 bytes, in the memory)
Points to the same memory location, in different type.
Example 1:
void by_value(bool* arr) // pointer_value passed by value
{
arr[1] = true;
arr = NULL; // temporary pointer that points to original array
}
int main()
{
bool a[3] = {};
cout << a[1] << endl; // 0
by_value(a);
cout << a[1] << endl; // 1 !!!
}
Addresses:
[main]
a = 0046FB18 // **Original**
&a = 0046FB18 // **Original**
[func]
arr = 0046FB18 // **Original**
&arr = 0046FA44 // TempPTR
[func]
arr = NULL
&arr = 0046FA44 // TempPTR
Example 2:
void by_value(bool* arr)
{
cout << &arr << arr; // &arr != arr
}
int main()
{
bool a[3] = {};
cout << &a << a; // &a == a == &a[0]
by_value(arr);
}
Addresses
Prints:
[main] 0046FB18 = 0046FB18
[func] 0046FA44 != 0046FB18
Please Note:
&(required-lvalue): lvalue -to-> rvalue
Array Decay: new pointer (temporary) points to (by value) array address
readmore:
Rvalue
Array Decay
It was done that way in order to preserve syntactical and semantic compatibility with B language, in which arrays were implemented as physical pointers.
A direct answer to this question is given in Dennis Ritchie's "The Development of the C Language", see the "Critique" section. It says
For example, the empty square brackets in the function declaration
int f(a) int a[]; { ... }
are a living fossil, a remnant of NB's way of declaring a pointer; a is, in this special case only, interpreted in C as a pointer. The notation survived in part for the sake of compatibility, in part under the rationalization that it would allow programmers to communicate to their readers an intent to pass f a pointer generated from an array, rather than a reference to a single integer. Unfortunately, it serves as much to confuse the learner as to alert the reader.
This should be taken in the context of the previous part of the article, especially "Embryonic C", which explains how introduction of struct types in C resulted in rejection of B- and BCPL-style approach to implementing arrays (i.e. as ordinary pointers). C switched to non-pointer array implementation, keeping that legacy B-style semantics in function parameter lists only.
So, the current variant of array parameter behavior is a result of a compromise: one the one hand, we had to have copyable arrays in structs, on the other hand, we wanted to preserve semantic compatibility with functions written in B, where arrays are always passed "by pointer".
The equivalent of that would be to first make a copy of the array and then pass it to the function (which can be highly inefficient for large arrays).
Other than that I would say it's for historical reasons, i.e. one could not pass arrays by value in C.
My guess is that the reasoning behind NOT introducing passing arrays by value in C++ was that objects were thought to be moderately sized compared to arrays.
As pointed out by delnan, when using std::vector you can actually pass array-like objects to functions by value.
You are passing by value: the value of the pointer to the array. Remember that using square bracket notation in C is simply shorthand for de-referencing a pointer. ptr[2] means *(ptr+2).
Dropping the brackets gets you a pointer to the array, which can be passed by value to a function:
int x[2] = {1, 2};
int result;
result = DoSomething(x);
See the list of types in the ANSI C spec. Arrays are not primitive types, but constructed from a combination of pointers and operators. (It won't let me put another link, but the construction is described under "Array type derivation".)
actually, a pointer to the array is passed by value, using that pointer inside the called function will give you the feeling that the array is passed by reference which is wrong. try changing the value in the array pointer to point to another array in your function and you will find that the original array was not affected which means that the array is not passed by reference.

When Declaring a Reference to an Array of Ints, why must it be a reference to a const-pointer?

Note: I am using the g++ compiler (which is I hear is pretty good and supposed to be pretty close to the standard).
Let's say you have declared an array of ints:
int a[3] = { 4, 5, 6 };
Now let's say you really want to declare a reference to that array (nevermind why, other than the Bjarne says the language supports it).
Case 1 -- If you try:
int*& ra = a;
then the compiler balks and says:
"invalid initialization of non-const reference of type `int*&' from a temporary of type `int*'"
First things first, why is 'a' a temporary variable (i.e. doesn't it have a place in memory?)...
Anyway, fine, whenever I see a non-const error, I try to throw in a const...
Case 2 -- if you try:
int*const&rca = a; //wish I knew where the spaces should go (but my other post asking about this sort of protocol got a negative rank while many of the answers got ranked highly -- aha! there are stupid questions!)
Then everything is cool, it compiles, and you get a reference to the array.
Case 3 -- Now here is another thing that will compile:
int* justSomeIntPointer = a; //LINE 1
int*& rpa = justSomeIntPointer; //LINE 2
This also gives you a reference to the original array.
So here is my question: At what point does the name of a statically declared array
become a const-pointer? I seem to remember that the name of an array of ints is also a pointer-to-int, but I don't remember it ever being a const-pointer-to-int...
It seems like Case 1 fails because the reference declared (ra) is not to a const-pointer, which may mean that 'a' was already a const-pointer-to-int to begin with.
It seems like Case 2 works because the reference declared (rca) is already a const-pointer-to-int.
Case 3 also works, which is neat, but why? At what point does the assumed pointer-to-int (i.e. the array name 'a') become a const-pointer? Does it happen when you assign it to an int* (LINE 1), or does it happen when you assign that int* to a int*& (LINE 2)?
Hope this makes sense. Thanks.
int*& ra = a;
int* is a pointer type, not an array type. So that's why it won't bind to a, which has type int[3].
int* const& ra = a;
works, because it is equivalent to
int* const& ra = (int*)a;
That is, a temporary pointer is conceptually created on the right-hand side of the assignment and this temporary is then bound to ra. So in the end, this is no better than:
int* ra = a;
where ra is in fact a pointer to the first element of the array, not a reference to the array.
Declaring a reference to an array the easy way:
typedef int array_type[3];
array_type& ra = a;
The not-as-easy way:
int (&ra)[3] = a;
The C++11-easy way:
auto& ra = a;
At what point does the name of a statically declared array become a const-pointer? I seem to remember that the name of an array of ints is also a pointer-to-int, but I don't remember it ever being a const-pointer-to-int...
This is the right question to ask! If you understand when array-to-pointer decay happens, then you're safe. Simply put there are two things to consider:
decay happens when any kind of 'copying' is attempted (because C doesn't allow arrays to be copied directly)
decay is a kind of conversion and can happen anytime a conversion is allowed: when the types don't match
The first kind typically happen with templates. So given template<typename T> pass_by_value(T);, then pass_by_value(a) will actually pass an int*, because the array of type int[3] can't be copied in.
As for the second one, you've already seen it in action: this happens in your second case when int* const& can't bind to int[3], but can bind to a temporary int*, so the conversion happens.
The word "array" in C++ is spelled with brackets []. If you want to declare a something-array-something in C++, you have to have brackets in your declaration. If you write an asterisk * instead, you will get a pointer. Pointers and arrays are two different things.
This is a reference to an array:
int (&ra) [3] = a;
The very big mistake (also a very good interview question) that most people make is that they think the name of an array is equivalent to a pointer. That is NOT true. This mistake causes many bugs in C programs especially linking bugs, and they are very hard to debug. The diffrence is this: The name of the array, is a pointer the first element of a structure, the array. The type of the array name is not a pointertype however, but an arraytype. A pointer, on the other hand, is just a pointer to one thing with no other information. The type of a pointer is a pointertype. An arraytype has some other properties like it knows whether its on the stack or not; therefore, "temporary". The temporary error in your case comes from a check that prevents a temporary variable to be assigned to a reference. The const keyword turns that check off. A pointertype on the other hand has no notion of "temporary". Now suppose you want to trick the compiler and assign a reference to something that is in the stack. In that case, you need to make it a pointer. How?
int*& ra = &a[0];
in the above case you first get the value and using a &(address of operator) you make a pointerType. Now a pointertype has no information about whether its on the stack (a temporary variable) or not. This however, will make a reference to a pointer to the first element of the array. (Therefore just a pointer type, not an arraytype)
If you really want a reference to an array, then you should use the following:
int a[3] = { 4, 5, 6 };
int (&ra)[3] = a;
What you are trying to create with int *& is a reference to a pointer to an int. This is not the same type. And as you initialize the reference with a value that cannot change (the address of the array) you have to declare the pointer const (not the ints).
You have an array of ints :
int a[3] = { 4, 5, 6 };
Now, this line :
int*& ra = a;
creates a reference to a pointer. Since you create a temporary pointer (converted from the array a), the compiler complains, because the standard forbids assignment of temporaries to a reference.
So, to fix it, you need to create a pointer, and then assign it to a reference to a pointer :
int *pa = a;
int *& rpa = pa;
Constant references can hold reference to temporaries, but you already found that out.
What you asked (about reference to an array) - the most famous example about creating a reference to an array is this :
template< typename T, size_t N >
size_t ArraySize( T (&)[ N ] )
{
return N;
}
This function takes a reference to an array, and returns it's size.
At what point does the name of a statically declared array become a const-pointer? I seem to remember that the name of an array of ints is also a pointer-to-int, but I don't remember it ever being a const-pointer-to-int...
Because you written the values right there in the cpp file, that's why it's constant.
You can just use:
const int *pToArray = a;
or
const int *pToArray = (const int*)&a[0];
a is a temporary variable because you declared it on the stack and not on the heap using a malloc or a new.

Is it possible to dynamically create an array of constant size in C++?

First of all, I want to reassure you all that I am asking this question out of curiosity. I mean, don't tell me that if I need this then my design has problems because I don't need this in real code. Hope I convinced you :) Now to the question:
For most types T we can write
T* p = new T;
now what if T is an array type?
int (*p)[3] = new ???; //pointer to array of 3 = new ???
I tried this:
typedef int arr[3];
arr* p = new arr;
but this doesn't work.
Is there any valid syntax for this or it is impossible in C++. If it is impossible, then why? Thanks
Edit: i am guessing I wasn't clear enough. I want to be able to use it in this situation:
void f(int(&)[3]);
int (*p)[3] = new ???;
f(*p);
To get a pointer to an array from new, you have to dynamically allocate a two-dimensional array:
int (*p)[3] = new int[1][3];
The reason you can't do it is that new int[3] already allocates exactly what you want, an object of type int[3]. It's just that what the new-expression returns, is a pointer to its first element. 5.3.4/1:
If the entity is a non-array object,
the new-expression returns a pointer
to the object created. If it is an
array, the new-expression returns a
pointer to the initial element of the
array.
Returning a pointer to the first element is what allows the 3 to be unknown until runtime, so I suppose that by knowing it in advance, you've tripped over flexibility that you aren't using.
I guess the ways around this are to reinterpret_cast back to the pointer type you want (not necessarily portable), or to allocate a struct containing an int[3] (and use a pointer to its data member).
[Edit: er, yeah, or FredOverflow's idea, which has neither disadvantage, but requires use of delete[] instead of delete.]
I guess the moral is, if you write templates that naively allocate some unknown type T with new, then the template won't work when someone passes an array type as T. You'll be assigning it to the wrong pointer type, and if you fix that (perhaps with auto), you'll be deleting it wrongly.
Edit in answer to j_kubik's question:
Here's one way to distinguish between array and non-array types. If you write a function like this, that returns an object that holds the pointer and is capable of correctly deleting it, then you have a generic new/delete for any type T.
#include <iostream>
template <typename T>
void make_thing_helper(T *) {
std::cout << "plain version\n";
}
template <typename T, int N>
void make_thing_helper(T (*)[N]) {
std::cout << "array version\n";
}
template <typename T>
void make_thing() {
make_thing_helper((T*)0);
}
int main() {
typedef int T1;
typedef int T2[3];
make_thing<T1>();
make_thing<T2>();
}
You could always use boost::array, which will be in C++0x.
Otherwise, any solution will be awkward at best: arrays are
broken in C, and C++ maintains compatilibity with C in this
respect. Fred Overflow offered one solution; even easier (but
syntactically noisy) would be to wrap the array in a struct:
struct A { int arr[3]; };
and allocate and manipulate this.
You just do
int *p = new unsigned int [3]
You can then use *p as a pointer or an array i.e. *(p+1) or p[1]