In regards to array size calculation [duplicate] - c++

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Can someone explain this template code that gives me the size of an array?
Hi, I am looking at the answer posted here:
Computing length of array
Copied here:
template <typename T, std::size_t N>
std::size_t size(T (&)[N])
{
return N;
}
Can some one pls explain me the significance of (&) ?

The & says the array is passed by reference. That prevents the type from decaying to pointer. Without passing by reference you would get that decay, and no information about the array size.
Non-template example:
void foo( int (&a)[5] )
{
// whatever
}
int main()
{
int x[5];
int y[6];
foo( x ); // ok
//foo( y ); // !incompatible type
}
Cheers & hth.,

The & means that the array is to be passed by reference. Arrays can't be passed by value, because in this case they decay to a pointer to the first item. If that happens, the size information associated with the array type is lost.
It is in parenthesis, because otherwise that would mean the function accepts a pointer to reference. Although such a thing is not legal in C++, the syntax is consistent with how you declare a pointer to array.
int (*arr)[3]; // pointer to array of 3 ints
int* p_arr[3]; // array of pointers
int (&arr)[3]; // reference of array of 3 ints
int& r_arr[3]; //array of references (not legal in C++)

Related

Why is that you can modify an array inside a function without using any reference or pointer [duplicate]

This question already has answers here:
Array changed in a void function, is still changed outside! why? (scope)
(4 answers)
Passing an array as a parameter in C
(3 answers)
Passing Arrays to Function in C++
(5 answers)
Passing an array as an argument to a function in C
(11 answers)
Closed 11 months ago.
I don't get it why you can alter the values inside the array, without using a reference or a pointer (&, *), I'm a freshmen student, and I don't know the reason behind, I hope someone can provide a logical answer, please refer to the code below, Thank You in Advance.
#include <iostream>
using namespace std;
void a(int x[]){
for(int i = 0; i < 5; i++){
x[i] += 2;
}
}
int main(){
int x[5] = {1,2,3,4,5};
a(x);
for(auto b : x){
cout << b << " ";
}
return 0;
}
A function parameter is never an array in C++. When you declare a function parameter as an array, it is automatically adjusted to be a pointer to element of such array. These declarations are effectively identical:
void a(int x[]); // looks like an array of int of unknown bound
void a(int* x); // declaration above is adjusted to this
void a(int x[1234]); // the size is ignored completely
An array implicitly converts to a pointer to the first element of the array (such conversion is called decay). Hence, you can call the function that doesn't accept an array parameter by passing an array argument:
int* ptr1 = x; // implicit conversion
int* ptr2 = &x[0]; // same conversion explicitly
a(x); // same conversion happens here
These two rules (function parameter adjustment and array to pointer decay) make it so that what syntactically looks like passing arrays by value, is actually done using indirection. Within the function, you modify the elements by indirecting through the pointer parameter that points to the array that exists outside of the function.
Important note: The adjustment of array to pointer in function parameter does not apply in other contexts. Arrays and pointers are distinct types with different properties.
Another note: The adjustment does not apply to parts of compound types. For example, a function parameter of type "pointer to array" will not be adjusted to be "pointer to pointer" and "reference to array" will not be adjusted to be "reference to pointer".
The parameter having the array type in this function declaration
void a(int x[]){
is adjusted by the compiler to pointer type to array elements type. That is the above declaration is equivalent to
void a(int *x){
In this call of the function
a(x);
the array designator is implicitly converted to pointer to its first element. That is the call is equivalent to
a( &x[0]);
So within the function you have a pointer to the first element of the array declared in main.
Using the pointer arithmetic you can access elements of the array. That is the elements of the array are passed to the function by reference in the C meaning indirectly through a pointer to them.
Within the function the variable x has the type int *. And this expression statement
x[i] += 2;
is equivalent to
*( x + i ) += 2;
Beacuse
void a(int x[]){
is the same as
void a(int *x){
and so you are using a pointer
Why?
Because an array like
int x[10];
'decays' to a pointer when passed to a function (and in other places). This can be very confusing but at the same time is very flexible
It mens that I can have a function like strlen that can accpet a 'real' array, or a pointer. These 'strings'
char *s1 = malloc(10);
strcpy(s1, "hello");
char s2[] = "hello";
char *s3 = "hello";
store their data in different ways but all can be handled by
size_t strlen(const char *s);
note that this is exactly the same as
size_t strlen(const char s[]);
they are 2 different ways of writing the same thing. Personal preference is for the second type if its really is an 'array' vs a pointer to maybe an array.
One issue with this 'decay' is that inside strlen (or any pointer/array accepting function) it is impossible to 'know' the length just from the parameter. The compiler knows that the size of s2 is 6 but this information is not carried forward to the function.
Regularly SO sees this
void my_func(int *arr){
int len = sizeof(arr)/sizeof(arr[0]);
....
}
int a[10];
my_func(a);
This will give len = 1 or 2 (depending on 32 or 64 bit machine), never 10
The flexibility costs a litle power

How do I pass an array as an reference to a pointer of const char? [duplicate]

How does passing a statically allocated array by reference work?
void foo(int (&myArray)[100])
{
}
int main()
{
int a[100];
foo(a);
}
Does (&myArray)[100] have any meaning or its just a syntax to pass any array by reference?
I don't understand separate parenthesis followed by big brackets here. Thanks.
It's a syntax for array references - you need to use (&array) to clarify to the compiler that you want a reference to an array, rather than the (invalid) array of references int & array[100];.
EDIT: Some clarification.
void foo(int * x);
void foo(int x[100]);
void foo(int x[]);
These three are different ways of declaring the same function. They're all treated as taking an int * parameter, you can pass any size array to them.
void foo(int (&x)[100]);
This only accepts arrays of 100 integers. You can safely use sizeof on x
void foo(int & x[100]); // error
This is parsed as an "array of references" - which isn't legal.
It's just the required syntax:
void Func(int (&myArray)[100])
^ Pass array of 100 int by reference the parameters name is myArray;
void Func(int* myArray)
^ Pass an array. Array decays to a pointer. Thus you lose size information.
void Func(int (*myFunc)(double))
^ Pass a function pointer. The function returns an int and takes a double. The parameter name is myFunc.
It is a syntax. In the function arguments int (&myArray)[100] parenthesis that enclose the &myArray are necessary. if you don't use them, you will be passing an array of references and that is because the subscript operator [] has higher precedence over the & operator.
E.g. int &myArray[100] // array of references
So, by using type construction () you tell the compiler that you want a reference to an array of 100 integers.
E.g int (&myArray)[100] // reference of an array of 100 ints
The following creates a generic function, taking an array of any size and of any type by reference:
template<typename T, std::size_t S>
void my_func(T (&arr)[S]) {
// do stuff
}
play with the code.
Arrays are default passed by pointers. You can try modifying an array inside a function call for better understanding.

Get length of static array [duplicate]

This question comes from this one:
c++ pass array to function question
but since the OP accepted an answer I guess nobody will read it now.
I tried this code on g++. It seems that the array does not decay to a pointer when passed to this function (the function returns the proper result):
#include <iostream>
template <typename T>
std::size_t size_of_array (T const & array)
{
return sizeof (array) / sizeof (*array);
}
int main ()
{
int a [5];
std::cout << size_of_array (a) << '\n';
}
Another user (sharptooth) said he have the same behavior on VC++ 10 with inlining off.
Can somebody explain? Thanks.
Array decay doesn't just happen -- it only happens when the program would fail to compile without it. When you pass an array by reference, there simply is no need for decay to kick in.
Note that the function template can also be written without dividing ugly sizeof expressions:
template <typename T, std::size_t N>
std::size_t size_of_array(T (&array)[N])
{
return N;
}
When a client calls size_of_array, T and N are automatically deduced by the template machinery.
You haven't written the function to accept a pointer, you've written it to accept a const reference to exactly the type of argement that's passed to it. Pointer decay only happens if you try to assign to a pointer the value of an array.

Template function array loop [duplicate]

How does passing a statically allocated array by reference work?
void foo(int (&myArray)[100])
{
}
int main()
{
int a[100];
foo(a);
}
Does (&myArray)[100] have any meaning or its just a syntax to pass any array by reference?
I don't understand separate parenthesis followed by big brackets here. Thanks.
It's a syntax for array references - you need to use (&array) to clarify to the compiler that you want a reference to an array, rather than the (invalid) array of references int & array[100];.
EDIT: Some clarification.
void foo(int * x);
void foo(int x[100]);
void foo(int x[]);
These three are different ways of declaring the same function. They're all treated as taking an int * parameter, you can pass any size array to them.
void foo(int (&x)[100]);
This only accepts arrays of 100 integers. You can safely use sizeof on x
void foo(int & x[100]); // error
This is parsed as an "array of references" - which isn't legal.
It's just the required syntax:
void Func(int (&myArray)[100])
^ Pass array of 100 int by reference the parameters name is myArray;
void Func(int* myArray)
^ Pass an array. Array decays to a pointer. Thus you lose size information.
void Func(int (*myFunc)(double))
^ Pass a function pointer. The function returns an int and takes a double. The parameter name is myFunc.
It is a syntax. In the function arguments int (&myArray)[100] parenthesis that enclose the &myArray are necessary. if you don't use them, you will be passing an array of references and that is because the subscript operator [] has higher precedence over the & operator.
E.g. int &myArray[100] // array of references
So, by using type construction () you tell the compiler that you want a reference to an array of 100 integers.
E.g int (&myArray)[100] // reference of an array of 100 ints
The following creates a generic function, taking an array of any size and of any type by reference:
template<typename T, std::size_t S>
void my_func(T (&arr)[S]) {
// do stuff
}
play with the code.
Arrays are default passed by pointers. You can try modifying an array inside a function call for better understanding.

sizeof() operator returns different value for an array and pointer to an array [duplicate]

This question already has answers here:
How to find the size of an array (from a pointer pointing to the first element array)?
(17 answers)
Closed 7 years ago.
Below is a C program:
#include<stdio.h>
void func(int a[])
{
printf("%d\n",sizeof(a));
}
int main()
{
int arr[10];
printf("%d\n",sizeof(arr));
func(arr);
return 0;
}
Now the problem is that the sizeof() operator returns 40 when I use sizeof(arr) but 8 when I use sizeof(a).
What is the reason for this behavior?
Simple, yet confusing: A function parameter such as int a[] or int a[42] gets adjusted to int* a. func(int a[]) is adjusted to
void func(int* a)
Here, a really is no more than a pointer. So sizeof(a) is sizeof(int*).
On top of that, arrays can decay to pointers in many situations, such as when you pass arr to func. That allows this to happen
func(arr);
even if func's parameter is a pointer.
You are comparing size of a "pointer" to the actual size of an array.