This question already has answers here:
Why are arrays of references illegal?
(14 answers)
Closed 8 years ago.
I write a code like this:
void Print(const int & dataArray[], const int & arraySize) { // problem
for(int i = 0; i<arraySize; i++) {
cout << dataArray[i] << " ";
}
cout << endl;
}
in mian() function:
`
int iArray[14] = { 7, 3, 32, 2, 55, 34, 6, 13, 29, 22, 11, 9, 1, 5 };
int numArrays = 14;
Print(iArray, numArrays);
....
`
the compiler says that arrays of references are illegal, why it is illegal ??
I see the <effective c++>, it says recommend we use the const and reference, I just try to implement it(I'm a beginner), I also want to know in the void Print(const int dataArray[], const int & arraySize) parameter I use const, & to qualify the arraySize, is it right?(or is it much better than int arraySize or const int arraySize?), I want also use const,& to dataArray[], but I failed.
An array requires its elements to be default-constructible and references are not, hence array of references are illegal. This:
const int & dataArray[]
is an array of references. If you want a reference to an array instead you need this:
const int (&dataArray)[]
Pedantically, the reason why arrays of references are illegal is because the Standard explicitly forbids them.
C++03:8.3.2/4
There shall be no references to references, no arrays of references,
and no pointers to references.
Emphasis mine.
One reason the Standard explicitly forbids arrays of references (maybe there are more) is because of how arrays are indexed. Suppose you do:
Gizmo& gizmos[] = {...};
Gizmo&* g3 = &gizmos[2];
There are several things wrong here. First you have a pointer to a reference, which is illegal. Second, in order to evaluate gizmos[2] the compiler must do an implicit conversion-to-pointer, and then do pointer arithmetic based on that. How big is a Gizmo&?
According to the Standard, the sizeof a reference is, itself, unspecified. However when sizeof is applied to a reference, the result is the size of the referred-to type.
C++03:5.3.3/2 Sizeof
When applied to a reference or a reference type, the result is the
size of the referenced type.
Try running this code and see what happens:
#include <iostream>
#include <iomanip>
using namespace std;
struct Gizmo { int n_[100]; };
int main()
{
typedef Gizmo& GR;
size_t n = sizeof(GR);
cout << n << endl;
}
When I run this on my machine, (MSVC10, Win7x64), the result is 400.
This is why arrays of references are illegal.
Related
#include<iomanip>
using namespace std;
void displaySeats(bool taken[][]){
for (int i = 0; i < 15; i++) {
for (int j = 0; j < 30;j++)
if (taken[i][j])
cout << '*';
else
cout << '#';
cout << '\n';
}
}
int main()
{
bool taken[15][30];
int rows, clm;
rows = 15;
clm = 30;
displaySeats(taken);
system("PAUSE");
}
it is giving me errors like
an array may not have elements of this type line 6
'void displaySeats(bool [][])': cannot convert argument 1 from 'bool [15][30]' to 'bool [][]' line 25
'taken': missing subscript line 6
but if i move the code from the function to the main it works perfectly fine.
I can have a array of type bool.
there is subscript.
i've tried passing through a pointer to the array (which arrays are anyway)
i've tried passing through an array of pointers
a 2d array of pointers
a pointer of an array of pointers.
scoured stack exchange and looks at other peoples code and i am doing it almost line for line.
does it not work with bools? because it doesn't work with ints either.
When expecting an array argument on a function you don't need to know how many elements it has, since you can index it freely. However, you need to know how big each element is, to know how many bytes to skip for each index, when indexing.
In this case your element is a bool[30] with size 30 bytes. You need to signify this on your function signature.
void displaySeats(bool taken[15][30]){ // array 15*30 bool
// OR
void displaySeats(bool taken[][30]){ // array with elements bool[30]
// OR
void displaySeats(bool (*taken)[30]){ // pointer to element(s) bool[30]
See below on how 2d arrays are structured in memory and this will make sense.
This is a big topic. You need to research how arrays really work in C++. But the short (and surprising) answer is that you cannot have an array as a parameter to a function in C++. This code void func(int a[]) is actually an alternative for the pointer code void func(int* a).
But this simple rule only works for one dimension. With two dimensions only the first dimension is turned into a pointer. So the equivalent for your case would be
void displaySeats(bool (*taken)[30]){
or
void displaySeats(bool taken[][30]){
or
void displaySeats(bool taken[15][30]){
But the important part is that in all cases taken is a pointer not an array.
Because arrays are so useless in C++ we prefer to use std::vector, which doesn't have the same limitations (and has many other advantages besides).
The taken array must have some size defined like so taken[15][30].
Also, you have to include <iostream> in order to use cout.
try specifying size of array, or use reference see here
#include<iomanip>
#include <iostream>
using namespace std;
// template <typename t>
void displaySeats(bool taken[][30]){
for (int i = 0; i < 15; i++) {
for (int j = 0; j < 30;j++)
if (taken[i][j])
cout << '*';
else
cout << '#';
cout << '\n';
}
}
int main()
{
bool taken[15][30];
int rows, clm;
rows = 15;
clm = 30;
displaySeats(taken);
system("PAUSE");
}
As mentioned, bool taken[][] isn't valid. Only the left-most (outer) array extent may be left unspecified.
I prefer the longest form to be explicit and to take the argument by reference. Motivation: Taking it as a pointer would lead to a runtime problem if you happen to pass in a nullptr by mistake (unless you check if(taken==nullptr) return; in the function). With a reference, you'd get a compilation error instead so there's no need to check if it's a nullptr.
Also, make the function argument const since you're not making changes to the array in the display function.
constexpr size_t ROWS = 15;
constexpr size_t COLS = 30;
void displaySeats(const bool (&taken)[ROWS][COLS]) {
using std::cout;
for (size_t i = 0; i < ROWS; i++) {
for (size_t j = 0; j < COLS;j++)
if (taken[i][j])
cout << '*';
else
cout << '#';
cout << '\n';
}
}
You can then easily turn this into a function template to accept arbitrary 2D arrays of bool:
template<size_t ROWS, size_t COLS>
void displaySeats(const bool (&taken)[ROWS][COLS]) {
// same as above
}
If you start to study language rules, not their interpretation, you'll come to realization that neither C nor C++ document doesn't mention an array with multiple dimensions at all, not like FORTRAN or flavors of Basic. It speaks about just an array as a form of object.
Array is an object which has a continuous storage containing multiple objects of same type. Array is an object. Thus we may have an array of arrays. That's what bool taken[15][30] is. It can be read this way
bool (taken[15])[30]; //Array of 15 arrays of 30 bools each
While this line is correct
void foo(bool arg[]) // same as void foo(bool *arg) for all purposes
And this one gives compiler some information:
void foo(bool arg[30]) // sizeof(arg) would return size of array,
// not size of pointer type
This line is ill-formed.
void boo(bool arg[][]) //
It would suggest an unknown type of array elements (how big is the element of array?), which contradicts ideology of strongly-typed language.
Two correct styles can be mixed:
void foo(bool arg[][30]) // same as void foo(bool (*arg)[30])
Here the parameter of function is a pointer to an array of bools.
Functions in C or C++ never could take an array or return an array. The reason to that is that C (and subsequently, C++) by default can pass parameters and return results by value, which means loading those values into stack. Doing that to array would be ineffective because of stack possible limitations. There were also logical conundrums in syntax, where name of array decays to a pointer. Thus arrays supposed to be passed by their address, by a pointer and can be returned only by pointer as well.
But you can pass structures by value and you can return them as result, even if they contain arrays. C++ classes expands functionality of original aggregate type struct and std::array is an example of template for such aggregate.
I am wondering how come the # number1 code not working
as I am trying to use increment operator to display the next following element in the array.
But the # number2 code works , and it was the same code but in a function
//# number 1 code
using namespace std;
int main(){
int arrays[5]={2,4,6,8,10};
for(int x=0;x<5;x++){
cout<<*arrays<<endl;
arrays++; //error: lvalue required as increment operand
}
}
//# number 2 code
using namespace std;
void display(int *arr,int size){
for(int x=0; x<5;x++){
cout<<*arr<<endl;
arr++; //This time no error!!!
}
}
int main(){
int arrays[5]={2,4,6,8,10};
display(arrays,5);
return 0;
}
That's because you cannot change the address of an array.
In # number 1 code when you do array++, you are actually trying to operate directly on the variable which is storing the base address of the array.
What you can try instead is something like below:
int *p = array;
p++;
Whereas in the case when you are calling a function passing the array's base address # number 2, you are implicitly doing what has been shown in the above code snippet.
This is a common problem for beginners. Arrays are not pointers!. Arrays are implicitly converted to pointers. That is where the confusion lies. Consider this:
int array[] = {1, 2, 3};
std::cout << *array << '\n';
What do you think is happening when we do *array. Does it really make sense to dereference an array? The array is being implicitly converted to a int * and then dereferenced. What about this:
int array[] = {1, 2, 3};
array++;
std::cout << *array << '\n';
This doesn't compile (as you found out for yourself). In this statement array++, the array is not implicitly converted to a pointer.
Arrays are converted to pointers when you pass them to functions that accept pointers. That makes it possible to do this:
int array[3] = {1, 2, 3};
display(array, 3);
An array is a sequence of objects stored on the stack. You access this sequence of objects as a pointer to the first object. Both arrays and pointers can be subscripted. They share many similarities but are fundamentally different.
To make your first example compile, subscript the array with x:
for (int x = 0; x < 5; x++) {
std::cout << arrays[x] << '\n';
}
Use :
int *arr = arrays;
arr++;
in code #1. It will work. This is because you need first to create a pointer to the base of the array which you can increment as in the second code, you have the pointer in the form of the passed argument to the function.
Here are two lines of code:
int (*parry)[10] = &arr // Line # 1
int *(&arrRef)[10] = ptrs // Line # 2
Line # 1:
parry is a pointer that points to an int array of size 10.
So does it mean:
parray[1] points to the address of arr,
parray[2] points to address of arr
...
parray[10] points to address or arr?
When would I use Line # 1?
Solution:
#include <iostream>
int main(
{
int arr[10] = { 3, 54 };
int (*parry)[10] = &arr;
std::cout << (*parry)[0] << " " << (*parry)[1] << " " << (*parry)[3] << " " << parry[4] << std::endl;
return 0;
}
Output:
3, 54, 0, hex address of arr at index 4.
It seems like what inside parry[0] is a pointer that points to arr associated with the index. So, parry[0] ---> arr[0].
Line # 2:
arrRef is a reference to an int array of size ten pointers. arrRef is referred to by ptrs.
So does it mean:
arry[1] is an int pointer? ...
arry[10] is an int pointer?
What example can this been used in?
When in doubt, see the Clockwise/Spiral Rule.
int (*parry)[10] = &arr;
parry is a pointer to an array of 10 ints.
int *(&arrRef)[10] = ptrs;
arrRef is a reference to an array of 10 pointers to int.
Example:
int main()
{
int arr[10];
int* ptrs[10];
int (*parry)[10] = &arr;
int *(&arrRef)[10] = ptrs;
}
Now I've cleaned up your question, I can see it wasn't what I originally thought. You say:
parray is a pointer that points to an int array of size 10
so clearly you figured out the clockwise/spiral/cdecl stuff already.
So does it mean: ... parray[10] points to address of arr
Firstly, arrays in C++ are indexed starting from zero, so you can access arr[0] .. arr[9] if there are 10 elements; arr[10] would be the eleventh, so is out of bounds.
Now, let's take your sentence apart:
parray is a pointer
right, it isn't an array, it's a pointer. Now, let's consider what it is a pointer to:
an int array of size 10
ok, if it points to that, then *parray must be (a reference to) the original array.
So, (*parray)[0] is the first element of the array, etc.
Note that you can easily test your intuition about all this by just printing things out, and seeing what you get. You'll either see pointers, and be able to compare the addresses, or you'll see integer values, or you'll get (hopefully informative) compile errors. Try it out!
Oh, and:
When would I use line 1?
Only if you need to re-seat it, in general. For example, if you want to choose one of two different arrays based on some logic, and then ... perform further logic on whichever was selected.
Next, you said
arrRef is a reference to an int array of size ten pointers.
Correct!
arrRef is refer to by ptrs
No, arrRef refers to an array, the array has size 10, and its 10 elements are pointers-to-int. Note this is not the same type as the first array!
Since references can be used with the same syntax as the thing they refer to, we can use arrRef as an array.
So, arrRef[0] is the first element of the array, and it is a pointer-to-int.
What example can this been used in?
The only common reason for using reference-to-array is to avoid pointer decay, allowing templates to deduce the number of elements.
I think that in this statement
//line1// int (*parry)[10] = $arr
^^^ ^^
there is a typo
There must be
//line1// int (*parry)[10] = &arr;
^^^ ^^
It is assumed that arr is an array of type int[10]. For example
int arr[10];
And this declaration
int (*parry)[10] = &arr;
declares a pointer to this entire array.
As for this declaration
//line2// int *(&arrRef)[10] = ptrs;
^^^
then it is assumed that ptrs is an array of type int *[10] That is elements of the array have type int *. They are pointers.
And this declaration
int * (&arrRef)[10] = ptrs;
declares a reference to this array. A reference is in fact is an alias of an array.
In C++ 2014 you could define a reference to an array simpler.
For example
decltype( auto )arrRef = ( ptrs );
Here is a demonstrative program
#include <iostream>
int main()
{
int a[10];
decltype( auto )ra = ( a );
std::cout << sizeof( a ) << std::endl;
std::cout << sizeof( ra ) << std::endl;
ra[0] = 10;
std::cout << a[0] << std::endl;
std::cout << ra[0] << std::endl;
}
The program output is
40
40
10
10
For parsing C declarations it is valuable to remember, in the words of Kernighan and Ritchie, that "the syntax is an attempt to make the declaration and the use agree" (K&R, TCPL, 5.12). In other words, you can treat a declaration as an expression and simply apply the operators in the proper order. That will show you what type the declared identifier must have.
For example, in int (*parry)[10] you first apply the * operator, because it is in parentheses. This indicates that parray is a pointer. Then you apply the [] operator, indicating that the result of the dereferencing was an array; the 10 indicates the number of elements. The obtained element is of type int. Summing up: parray was a pointer to an array of int.
Declarations of references in C++ can not be solved that way because there is actually no operator which would create a reference, or dereference one; both operations are implicit in C++. The & symbol is used to signify references in declarations only (perhaps somewhat confusingly, because in expressions it's used to take an address). But if you think of the & in declarations as a * substitute to signify a reference instead of a pointer you should still be able to parse any declaration.
What is the difference, if it exists, between "double a[]" and "double *a" when passing arguments in c++ functions? I mean, are those two functions bellow the same?
void do_somethingA (double a[], size_t size_a)
{
// ... do something
}
void do_somethingB (double *a, size_t size_a)
{
// ... do something
}
int main()
{
double X[] = {1.,2.,3.,4.,5.};
double *Y;
Y = new double[5];
for(int i = 0; i < 5; i++)
Y[i] = (double) i;
do_somethingA(X,5);
do_somethingA(Y,5);
do_somethingB(X,5);
do_somethingB(Y,5);
delete [] Y;
}
No error in the code above. I'm just curious about this and I couldn't find a way to "google" it, sorry.
I'm passing both static and dynamic arrays as arguments to functions from which one uses "double a[]" and the other uses "double *a" and everything compiles and executes fine. Is it just a matter of style?
In that context double a[] and double *a are defined to be absolutely, 100% identical. This is a C++ question but a C FAQ is still relevant.
From the C++11 standard:
8.3.5
After determining the type of each parameter, any parameter of type
"array of T" or "function returning T" is adjusted to be "pointer to
T" or "pointer to function returning T," respectively.
Semantically, there is a difference.
To the reader, a function requiring double a[] is expecting an array.
A function requiring a double * a, is a pointer to a one or more double values. There is some ambiguity as to whether the function will be operating on more than one contiguous double. All the reader can assume is that one double, pointed to by the given pointer*, may be accessed; the reader can't assume that an array of double is required.
See also the MISRA C and MISRA C++ coding guidelines.
Arrays passed by value decay to pointers, so in your case double a[] (or even double a[256]) is just syntactic sugar for double* a. However, arrays are not pointers, and the difference appears when you pass arrays by reference. In that case, you can even deduce their size, such as:
#include <iostream>
#include <cstddef>
template<typename T, std::size_t N>
std::size_t get_arr_size(T (&arr)[N]) // pass array by reference
{
return N;
}
int main()
{
int arr[] = {1,2,3,4};
int* p = new int[256];
std::cout << get_arr_size(arr) << std::endl; // displays 4
// std::cout << get_arr_size(p) << std::endl; // does not compile, not the same as array
delete[] p;
}
This question already has answers here:
How do I find the length of an array?
(30 answers)
Closed 2 years ago.
I have
int list[] = {1, 2, 3};
How to I get the size of list?
I know that for a char array, we can use strlen(array) to find the size, or check with '\0' at the end of the array.
I tried sizeof(array) / sizeof(array[0]) as some answers said, but it only works in main? For example:
int size(int arr1[]){
return sizeof(arr1) / sizeof(arr1[0]);
}
int main() {
int list[] = {1, 2, 3};
int size1 = sizeof(list) / sizeof(list[0]); // ok
int size2 = size(list_1); // no
// size1 and size2 are not the same
}
Why?
Try this:
sizeof(list) / sizeof(list[0]);
Because this question is tagged C++, it is always recommended to use std::vector in C++ rather than using conventional C-style arrays.
An array-type is implicitly converted into a pointer-type when you pass it to a function.
Have a look at this.
In order to correctly print the sizeof an array inside any function, pass the array by reference to that function (but you need to know the size of that array in advance).
You would do it like so for the general case
template<typename T,int N>
//template argument deduction
int size(T (&arr1)[N]) //Passing the array by reference
{
return sizeof(arr1)/sizeof(arr1[0]); //Correctly returns the size of 'list'
// or
return N; //Correctly returns the size too [cool trick ;-)]
}
The "standard" C way to do this is
sizeof(list) / sizeof(list[0])
You could use boost::size, which is basically defined this way:
template <typename T, std::size_t N>
std::size_t size(T const (&)[N])
{
return N;
}
Note that if you want to use the size as a constant expression, you'll either have to use the sizeof a / sizeof a[0] idiom or wait for the next version of the C++ standard.
You can't do that for a dynamically allocated array (or a pointer). For static arrays, you can use sizeof(array) to get the whole array size in bytes and divide it by the size of each element:
#define COUNTOF(x) (sizeof(x)/sizeof(*x))
To get the size of a dynamic array, you have to keep track of it manually and pass it around with it, or terminate it with a sentinel value (like '\0' in null terminated strings).
Update: I realized that your question is tagged C++ and not C. You should definitely consider using std::vector instead of arrays in C++ if you want to pass things around:
std::vector<int> v;
v.push_back(1);
v.push_back(2);
std::cout << v.size() << std::endl; // prints 2
Since you've marked this as C++, it's worth mentioning that there is a somewhat better way than the C-style macro:
template <class T, size_t N>
size_t countof(const T &array[N]) { return N; }
This has the advantage that if you accidentally try to pass something other than an array to it, the code simply won't compile (whereas passing a pointer to the C macro will compile but produce a bad result. The disadvantage is that this doesn't give you a compile-time constant, so you can't do something like this:
int a[20];
char x[countof(a)];
In C++11 or newer, you can add constexpr to get a compile-time constant:
template <class T, size_t N>
constexpr size_t countof(const T &array[N]) { return N; }
If you really want to support the same on older compilers, there is a way, originally invented by Ivan Johnson, AFAIK:
#define COUNTOF(x) ( \
0 * sizeof( reinterpret_cast<const ::Bad_arg_to_COUNTOF*>(x) ) + \
0 * sizeof( ::Bad_arg_to_COUNTOF::check_type((x), &(x)) ) + \
sizeof(x) / sizeof((x)[0]) )
class Bad_arg_to_COUNTOF
{
public:
class Is_pointer;
class Is_array {};
template<typename T>
static Is_pointer check_type(const T*, const T* const*);
static Is_array check_type(const void*, const void*);
};
This uses sizeof(x)/sizeof(x[0]) to compute the size, just like the C macro does, so it gives a compile-time constant. The difference is that it first uses some template magic to cause a compile error if what you've passed isn't the name of an array. It does that by overloading check_type to return an incomplete type for a pointer, but a complete type for an array. Then (the really tricky part) it doesn't actually call that function at all -- it just takes the size of the type the function would return, which is zero for the overload that returns the complete type, but not allowed (forcing a compile error) for the incomplete type.
IMO, that's a pretty cool example of template meta programming -- though in all honesty, the result is kind of pointless. You really only need that size as a compile time constant if you're using arrays, which you should normally avoid in any case. Using std::vector, it's fine to supply the size at run-time (and resize the vector when/if needed).
Besides Carl's answer, the "standard" C++ way is not to use a C int array, but rather something like a C++ STL std::vector<int> list which you can query for list.size().
when u pass any array to some function. u are just passing it's starting address, so for it to work u have to pass it size also for it to work properly. it's the same reason why we pass argc with argv[] in command line arguement.
You can make a template function, and pass the array by reference to achieve this.
Here is my code snippet
template <typename TypeOfData>
void PrintArray(TypeOfData &arrayOfType);
int main()
{
char charArray[] = "my name is";
int intArray[] = { 1,2,3,4,5,6 };
double doubleArray[] = { 1.1,2.2,3.3 };
PrintArray(charArray);
PrintArray(intArray);
PrintArray(doubleArray);
}
template <typename TypeOfData>
void PrintArray(TypeOfData &arrayOfType)
{
int elementsCount = sizeof(arrayOfType) / sizeof(arrayOfType[0]);
for (int i = 0; i < elementsCount; i++)
{
cout << "Value in elements at position " << i + 1 << " is " << arrayOfType[i] << endl;
}
}
You have to use sizeof() function.
Code Snippet:
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
int arr[] ={5, 3, 6, 7};
int size = sizeof(arr) / sizeof(arr[0]);
cout<<size<<endl;
return 0;
}
int arr1[] = {8, 15, 3, 7};
int n = sizeof(arr1)/sizeof(arr1[0]);
So basically sizeof(arr1) is giving the size of the object being pointed to, each element maybe occupying multiple bits so dividing by the number of bits per element (sizeof(arr1[0]) gives you the actual number of elements you're looking for, i.e. 4 in my example.
This method work when you are using a class: In this example you will receive a array, so the only method that worked for me was these one:
template <typename T, size_t n, size_t m>
Matrix& operator= (T (&a)[n][m])
{
int arows = n;
int acols = m;
p = new double*[arows];
for (register int r = 0; r < arows; r++)
{
p[r] = new double[acols];
for (register int c = 0; c < acols; c++)
{
p[r][c] = a[r][c]; //A[rows][columns]
}
}
https://www.geeksforgeeks.org/how-to-print-size-of-an-array-in-a-function-in-c/
Assuming you merely want to know the size of an array whose type you know (int) but whose size, obviously, you don't know, it is suitable to verify whether the array is empty, otherwise you will end up with a division by zero (causing a Float point exception).
int array_size(int array[]) {
if(sizeof(array) == 0) {
return 0;
}
return sizeof(array)/sizeof(array[0]);
}
If you want to know how much numbers the array have, you want to know the array length. The function sizeof(var) in C gives you the bytes in the computer memory. So if you know the memory the int occupy you can do like this:
int arraylength(int array[]) {
return sizeof(array) / sizeof(int); // Size of the Array divided by the int size
}