In the example below, both functions return the same result. Can someone please explain what the difference is between them?
#include <iostream>
void func1( int (&a)[4]) {
int b = a[3];
std::cout << b << std::endl;
}
void func2( int a[4]) {
int b = a[3];
std::cout << b << std::endl;
}
int main()
{
int b[4] = {3,2,3,4};
func1(b);
func2(b);
return 0;
}
In func2, int a[4] is equivalent to int *a, in other words, 4 does not matter at all. You can pass an array of any size to to this function.
However, for func1, you have to pass it an array of size 4 or you will get a compilation error.
For example, if you feed func1 an array of size 8, you will get this compliation error,
main.cpp:26:12: error: invalid initialization of reference of type ‘int (&)[4]’ from expression of type ‘int [8]’ regardless of what the array size you feed to the function is.
Also, if you print the output of sizeof(a) function in func1, it will return the size of the input array in bytes, in this case, 16=4*4 bytes. For func2, it retunrs the size of a, which is a pointer to int (in my case that size is 8 bytes).
The first one won't accept any type except a reference to an array of 4 int elements while the second will accept a pointer to int or an array of unspecified size of int because it will be passed as an array.
Note also the first approach doesn't accept temporaries arguments so you can't do something like :
func1({1, 2, 3, 4});
But if you want to use temporaries you could write :
void func1( int (&&a)[4])
Related
I was brushing up on my C++ (using eclipse and cygwin) by writing functions over arrays.
I have the following code:
int getArraySize(int a[]){
int size = sizeof(a)/sizeof(a[0]);
return size;
}
int main(void) {
int arr[5] = {0, 1, 2, 3, 4};
string s = "size of array: ";
cout << s << getArraySize(arr) << endl;
cout << s << sizeof(arr)/sizeof(arr[0]) << endl;
return EXIT_SUCCESS;
}
I expect to get this output:
size of array: 5
size of array: 5
but instead I get this:
size of array: 2
size of array: 5
I've tried this program with other sizes of arrays, and the function getArraySize()
always returns 2. Anyone know what's up?
This looks like an array declaration, but it is not:
int getArraySize(int a[]){
This is just a pointer-to-int. Therefore sizeof(a) / sizeof(a[0]) will just give you the ratio between the size of a pointer and the size of the pointed-to thing. The situation does not change if you put a number between the brackets, like this:
int getArraySize(int a[5]){
To the C++ compiler, that is the same as int getArraySize(int *a). C++ does not pass arrays by value. It passes a pointer to the first element of the array. When you give an array argument, the argument decays to a pointer.
The sizeof() operator will give you the total number of bytes in an array when you pass it an actual array variable, as in this:
int arr[5] = {0, 1, 2, 3, 4};
int arr_size = sizeof(arr) / sizeof(arr[0]);
Unfortunately the C++ syntax here is a bit misleading.
You cannot pass an array to a C++ function, you can only pass a pointer to the first element.
In C++ the declaration
void foo(int x[])
is EXACTLY the same as
void foo(int *x)
Even if you put a size between brackets as in
void foo(int x[10])
the number 10 is not a syntax error but will be completely ignored.
You however infer an array size from a template function, using a somewhat weird syntax:
template<typename T, size_t N>
size_t ArraySize(T (&)[N])
{
return N;
}
The sizeof(x)/sizeof(x[0]) trick works only if used in a macro... it cannot be placed in a function.
You are taking the size of int a[] which is really a pointer
it looks like you are on a 64 bit machine so:
sizeof(64 bit pointer) = 8
sizeof (int) = 4
8/4 = 2
On a 32 bit machine you would get a 1
The problem is that you are not getting the size of arr and there really isn't a way to do that until c++11 where you can use a std::array instead
I think your problem is that c++ passes arrays by reference hence you are simply dividing the size of addresses.
Question is make an array of 10 integers that's fine
int array[10];
Now question is
how to make a reference to an array which I have declared above ?
I tried this
int &ra = a;
But it's giving me error...
Please provide me details about this error and how to make reference of an array.
int (&ra)[10] = a;
Alternatively, you can use a typedef to separate this into the type for "array of 10 ints" and having a reference there-to, as in:
typedef int int10[10];
int10& my_ref = a;
The problem with your int &ra = a; is that it tells the compiler to create a reference of type int that refers to an array of 10 ints... they're just not the same thing. Consider that sizeof(int) is a tenth of the size of an array of ten ints - they occupy different amounts of memory. What you've asked for with the reference's type could be satisfied by a particular integer, as in int& ra = a[0];.
I appreciate it's a bit confusing that int* p = a; is allowed - for compatibility with the less type-safe C, pointers can be used to access single elements or arrays, despite not preserving any information about the array size. That's one reason to prefer references - they add a little safety and functionality over pointers.
For examples of increased functionality, you can take sizeof my_ref and get the number of bytes in the int array (10 * sizeof(int)), whereas sizeof p would give you the size of the pointer (sizeof(int*)) and sizeof *p == sizeof(int). And you can have code like this that "captures" the array dimension for use within a function:
template <int N>
void f(int (&x)[N])
{
std::cout << "I know this array has " << N << " elements\n";
}
The reference to array will have type int (&a)[10].
int array[10];
int (&a)[10] = array;
Sometimes it might be useful to simplify things a little bit using typedef
typedef int (&ArrayRef)[10];
...
ArrayRef a = array;
This is a reference to an array of of ints of size 10:
int (&ra)[10];
so
int (&ra)[10] = a;
You can typedef the array type (the type should not be incomplete) as follow:
#define LEN 10
typedef int (array)[LEN];
int main(void)
{
array arr = {1, 2, 3, 4, 5}; //define int arr[10] = {1, 2, 3, 4, 5};
array arr2; //declare int arr[10];
array *arrptr = &arr; // pointer to array: int (*arrptr)[10] = &arr;
array &&arrvef; // declare rvalue reference to array of 10 ints
array &ref = arr; // define reference to arr: int (&ref)[10] = arr;
}
here is some code
class DengkleTryingToSleep{
public:
int minDucks(int ducks[]);
int temp(int ducks[]){
int size=sizeof(ducks);
cout<<"sizeof="<<size<<"\n";
}
};
int main (int argc, const char * argv[])
{
DengkleTryingToSleep dt;
int arr[]={9,3,6,4};
cout<<"sizeof "<<sizeof(arr);
cout<<"\nsizeof from function "<<dt.temp(arr);
return 0;
}
and output of this is
sizeof 16
sizeof from function sizeof=8
and i have no idea how this is working because it returns 16 (as expected when called inside main)
and returns 8 when called from the function
Because arrays decay to pointers when passed to a function. You're getting the size of a pointer in your temp function.
If you need to know the length of an array in a function ... you have to pass that in as well.
Actually this function:
int temp(int ducks[])
is exactly equivalent this function:
int temp(int *ducks)
There is NO DIFFERENCE at all. No difference. So no matter what you pass, whether an array or a pointer, it will become a pointer inside the function.
That means, when you write sizeof(ducks) in your function, it is exactly equivalent to sizeof(int*), which returns 8 on your machine (I guess, your machine has 64-bit OS where the size of pointer is 8 bytes).
If you want to pass an array, and don't it decay into pointer type, then do this:
template<size_t N>
int temp(int (&ducks)[N])
{
int size=sizeof(ducks);
cout<<"sizeof="<<size<<"\n";
}
Now it will print 16. Note that inside the function N represents the count of items in the array. So in your case, it would be 4, as there are 4 elements in the array. It means, if you need the length of the array, you don't need to calculate it as sizeof(bucks)/sizeof(int), as you already know the length of the array which is N.
Also note that there is a limitation in this approach: now you cannot pass dynamically allocated array:
int *a = new int[10];
dt.temp(a); //compilation error
//but you can pass any statically declared array
int b[100], c[200];
dt.temp(b); //ok - N becomes 100
dt.temp(c); //ok - N becomes 200
But in C++, you've a better option here: use std::vector<int>.
int temp(std::vector<int> & ducks)
{
std::cout << ducks.size() << std::endl;
}
//call it as
std::vector<int> v = {1,2,3,4,5,6}; //C++11 only, or else : use .push_back()
dt.temp(v);
When print_array is called, the size of the int array[] parameter (count) isn't what was expected. It seems sizeof is not returning the size of the entire array which would be 5*sizeof(int) = 20.
namespace Util
{
void print_array(int array[])
{
size_t count = (sizeof array)/(sizeof array[0]);
cout << count;
// int count = sizeof(array)/sizeof(array[0]);
// for (int i = 0; i <= count; i++) cout << array[i];
}
}
int array_test[5]={2,1,5,4,3};
Util::print_array(array_test);
int array[] here becomes int* array, and sizeof(array) returns the same thing sizeof(int*). You need to pass an array by reference to avoid that.
template <size_t N>
void print_array(int (&array)[N]) {
std::cout << N;
}
int array[] = { 2, 1, 5, 4, 3 };
print_array(array);
Read this: it says the way to fix this, but for a quick description:
When a function has a specific-size array parameter, why is it replaced with a pointer?
Using sizeof(array) will work in the scope that the array is statically defined in. When you pass it into a function though the type gets converted into a pointer to the array element type. In your case, when you're in print_array it is an int*. So, your sizeof in in the function will be the size of a pointer on your system (likely 32 or 64 bits).
You can get around this with some fancy syntax like so (from the link above):
If you want that the array type is preserved, you should pass in a
reference to the array:
void foo ( int(&array)[5] );
but I'd say just pass the size in as well as another parameter, its more readable.
As this array is implemented as a thin overlay on pointers, the variable you have is just a pointer, so sizeof will return the size of your pointer.
The only way to know the length of an array is to place a terminating object, as the null character in C strings.
There is no other way to determine the size of an array if you only have a pointer to it.
Here's a trick: you can take a reference to an array of fixed size. You can use this to template-deduce the size.
#include <iostream>
char a [22];
char b [33];
void foo (char *, size_t size)
{
std :: cout << size << "\n";
}
template <size_t N>
void foo (char (&x) [N])
{
foo (x, N);
}
int main () {
foo (a);
foo (b);
}
This prints 22\n33\n
void print_array( int array[] ) is synonymous with void print_array( int *array ). No size information is passed when the function call is made, so sizeof doesn't work here.
For an algorithm like this, I like to use iterators, then you can do what you want... e.g.
template <typename Iterator>
void print(Interator begin, Iterator end)
{
std::cout << "size: " << std::distance(begin, end) << std::endl;
std::copy(begin, end, std::ostream_iterator<std::iterator_traits<Iterator>::value_type>(std::cout, ", "));
}
to call
print(a, a + 5); // can calculate end using the sizeof() stuff...
just an addition to all the answers already posted:
if you want to use an array which is more comfortable (like an ArrayList in java for instance) then just use the stl-vector container which is also able to return its size
All the following declarations are exactly same:
void print_array(int array[]);
void print_array(int array[10]);
void print_array(int array[200]);
void print_array(int array[1000]);
void print_array(int *array);
That means, sizeof(array) would return the value of sizeof(int*), in all above cases, even in those where you use integers (they're ignored by the compiler, in fact).
However, all the following are different from each other, and co-exist in a program, at the same time:
void print_array(int (&array)[10]);
void print_array(int (&array)[200]);
void print_array(int (&array)[1000]);
int a[10], b[200], c[1000], d[999];
print_array(a); //ok - calls the first function
print_array(b); //ok - calls the second function
print_array(c); //ok - calls the third function
print_array(d); //error - no function accepts int array of size 999
If I write
int main()
{
int a[100] = {1,2,3,4,};
cout<<sizeof(a)/sizeof(a[0])<<endl; //a is a pointer to the first elem of array,
//isn't it
return 0;
}
I get 400!
If I write
void func(int *a);
int main()
{
int a[100] = {1,2,3,4,};
func(a);
return 0;
}
void func(int *a)
{
cout<<sizeof(a)/sizeof(a[0])<<endl; //a is a pointer to the first elem of array
}
Then I get 1!
So why function does not know the array size?
Arrays decay to pointers when passed to functions, so all you will get is the size of the pointer.
sizeof returns the size of the type. In the second example, func( int *a ), a is a pointer and sizeof will report it as such. Even if you did func( int a[100] ), a would be a pointer. If you want the size of the array in func, you must pass it as an extra argument.
This isn't working because sizeof is calculated at compile-time. The function has no information about the size of its parameter (it only knows that it points to a memory address).
Consider using an STL vector instead, or passing in array sizes as parameters to functions.
This was answered by Marcel Guzman in Calculating size of an array!
When passing your array as a parameter to a function taking a pointer, the array decays as a pointer.
void bar(int *a)
{
std::cout << sizeof(a) << std::endl; // outputs "4" (on a 32 bit compiler)
}
void foo()
{
int a[100] ;
std::cout << sizeof(a) << std::endl; // outputs "400" (on a 32 bit compiler)
bar(a);
}
So perhaps the solution is to provide a correct function taking a reference to an array as a parameter :
template <size_t T_Size>
void bar(int (&a)[T_Size])
{
std::cout << T_Size << std::endl; // outputs "100" (on ALL compilers)
std::cout << sizeof(a) << std::endl; // outputs "400" (on a 32 bit compiler)
}
void foo()
{
int a[100] ;
std::cout << sizeof(a) << std::endl; // outputs "400" (on a 32 bit compiler)
bar(a);
}
Of course, the function must be templated.
No. You are wrong.
If I run your second part of code, it gives 1 on my computer. It's not 400.
#include <iostream>
void func(int *a);
using namespace std;
int main()
{
int a[100] = {1,2,3,4,};
func(a);
return 0;
}
void func(int *a)
{
cout<<sizeof(a)/sizeof(a[0])<<endl;
}
Produces
1
You get 400 the first time because you are passing only sizeof(a), not sizeof(a)/sizeof(a[0]), to cout. You need to wrap that calculation with parenthesis to get the correct value outputted, ie:
cout << (sizeof(a)/sizeof(a[0])) << endl;
For the second time, you should be getting 2, 4, or 8 (depending on architecture), definately not 400, since you are essentially outputting this:
cout << sizeof(int*) << endl;
Where the size of a generic pointer is always a fixed value.
A pointer is a pointer. That means, it simply points to memory, and that's all about it. Creating a pointer to an array (which usually means a pointer to the first element of the array, but not necessarily) is still only a pointer to some memory location. As a memory address is simply a memory address there is also no way for the pointer to know that the memory it is pointing to originally was an array, or how long that array was.
It's simply how pointers work. They point to memory, and that's all.
The function does not know the array size in your example because you took explicit steps to convert your array to pointer type, thus completely stripping the function parameter of its original array nature. Once again, you yourself took deliberate steps to make sure that the function does not know the size of the array. Under these circumstances, it is rather strange to see you ask the question about why the function doesn't know the array size.
If you what the function to receive its argument as an array, you have to pass it as an array, not as a mere pointer, and declare the corresponding function parameter accordingly. Arrays in C++ cannot be passed "by value", which means that you'll have to pass it "by reference", as one possibility
void func(int (&a)[100])
{
cout << sizeof a / sizeof a[0] << endl;
}