Why does n not equal to 8 in the following function?
void foo(char cvalue[8])
{
int n = sizeof (cvalue);
}
But n does equal to 8 in this version of the function:
void bar()
{
char cvalue[8];
int n = sizeof (cvalue);
}
Because you can't pass entire arrays as function parameters in C. You're actually passing a pointer to it; the brackets are syntactic sugar. There are no guarantees the array you're pointing to has size 8, since you could pass this function any character pointer you want.
// These all do the same thing
void foo(char cvalue[8])
void foo(char cvalue[])
void foo(char *cvalue)
C and C++ arrays are not first class objects; you cannot pass arrays to functions, they always decay to pointers.
You can, however, pass pointers and references to arrays. This prevents the array bounds from decaying. So this is legal:
template<typename T, size_t N>
void foo(const T(&arr)[N])
{
int n = sizeof(arr);
}
In the first example, cvalue as passed parameter is in really just a pointer to a character array and when you take the sizeof() of it, you get the size of the pointer. In the second case, where you've declared it as a local variable, you get the size of the the entire array.
The size of the parameter on 32-bit systems will be 4 and on 64-bit systems compiled with -m64 will be 8. This is because arrays are passed as pointers in functions. The pointer is merely a memory address.
Related
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.
When you pass an array in C++, they get passed as a pointer. So we have to pass the size of that array explicitly.
// This will not work.
int GetSize(int* arr){
return sizeof(arr)/size(int);
}
But if we don't use a function to get its size and use "sizeof" in the same function where the array was initialized, now we get the correct result.
int main(){
int arr[5];
int size = sizeof(arr)/sizeof(int);
cout << size << endl;
}
So is it adequate for me to look at the array as a class with a pointer, its size and type of elements in it?
Now that I think about it, I'm not sure how C++ knows array's size in the latter code if it's just handled the same as a pointer.
So is it adequate for me to look at the array as a class with a pointer, its size and type of elements in it?
No, because it is not. A C-style array is just a chunk of contiguous memory holding elements of a given type, nothing more, nothing less.
Now that I think about it, I'm not sure how C++ knows array's size in the latter code if it's just handled the same as a pointer.
That is not how arrays are handled.
In your first example, the function only accepts a pointer, it doesn't care where that pointer comes from. Passing in an array will decay the array into a pointer to the 1st element. All size information is lost, and the size of the array can't be determined from the pointer alone. That is why sizeof(arr) doesn't work in that context. It only knows the size of the pointer itself, not the size of the array that the pointer came from.
In your second example, the actual array is in scope where sizeof() is being used. The compiler knows the declaration of the array, so sizeof(arr) can know the actual byte size of the array.
If you really want to know the size of a passed array in a function, and don't want to pass the size explicitly as a parameter, then pass the array by reference instead of by pointer so the array's size is not lost:
template<size_t N>
int GetSize(int (&arr)[N]){
return N;
}
In first case as I understand correctly, you're taking the size of a int* type which is a pointer to int and in most cases it will result in 4 bytes (depending on architecture and probably other factors).
In the second case, compiler also have all the information necessary to compute sizeof(arr) as there are explicitly given 5 elements of int as defined by int arr[5]; and as a result in most cases will equal 4 bytes * 5 elements, 20 bytes
The declaration
int *arr; // arr = ptr to int
is different than the declaration
int arr[5]; // arr = base ptr to array of 5 ints
Note the arr resolves to an address (ptr) in each case, but in the second case the compiler can resolve that arr is a base ptr to an array of 5 int's. Things get a little trickier if the second declaration is for a function parameter:
void foo(int arr[5]) { ... }
then this is really no different than
void foo(int *arr) { ... }
void foo(int arr[]) { ... }
i.e., only a ptr is passed and sizeof(arr) will return the number of bytes in a ptr.
Why sizeof() when in the same scope? - It's because the compiler sees that you have declared int arr[5], it gets that the size is 5 at the compile time. sizeof() is computed at compile time.
Why it doesn't work when array is passed as a pointer? - It's because an array decays into a pointer here. Hence, it loses the information of size. Infact, sizeof(arr) here will give you the size of a pointer on your system - 8 bytes for 64-bit machine, 4-byte for 32-bit machine.
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.
I am learning c pointer and I follow c4learn as tutorial. In pointer to array of string section, which has following code:
char *arr[4] = {"C","C++","Java","VBA"};
char *(*ptr)[4] = &arr;
I didn't get what is
*(*ptr)[4]
? Wasn't it possible to use it like
**ptr
instead?
Update1:
Currently I am in the next section, function pointer and I saw again similar code:
void *(*ptr)();
char *(*ptr)[4]
is a pointer to a length 4 array of pointers to char (char*). Since arr is a length 4 array of char*, ptr can be made to point to arr by assigning it the address of arr, &arr.
void *(*ptr)();
Is a pointer to a parameterless function returning void*. For example
void* fun(); // function
void *(*ptr)(); // function pointer
p = fun; // function pointer points to function
C syntax can be quite confusing, so it may be easier to illustrate this with some examples. Note that whitespaces between T and ; make no difference.
T name[N]; // size N array of T
T * name[N]; // size N array of pointer to T
T (*name)[N]; // pointer to size N array of T
T ** name[N]; // size N array of pointer to pointer to T
T *(*name)[N]; // pointer to size N array of pointer to T
char *ar[4];
Declares ar as an array of four pointers to chars.
To declare a pointer, you take the declaration of something it can point to, and replace the variable name with (*some_other_name).
So char *(*ptr)[4]; declares ptr as a pointer to an array of four pointers to chars. Normally you can drop the brackets, but in this case, char **ptr[4]; would declare ptr as an array of four pointers to pointers to chars which is not what we want.
Similarly for a function pointer. void *fn() declares a function. void *(*ptr)() declares a pointer that could point to fn. void **ptr() would declare a function with a different return type.
Wasn't it possible to use it like **ptr instead?
Yes, assuming you mean like ptr2 below:
const char* arr[4] = {"C","C++","Java","VBA"};
const char* (*ptr)[4] = &arr;
const char** ptr2 = arr;
There is a difference though... with ptr the type still encodes the array length, so you can pass ptr but not ptr2 to functions like the one below:
template <size_t N>
void f(const char* (&arr)[N]) { ...can use N in implementation... }
Currently I am in the next section, function pointer and I saw again similar code: void *(*ptr)();
That creates a pointer to a function - taking no arguments - returning a void* (i.e. the address of an unspecified type of data, or nullptr).
char *(*ptr)[4] is an array pointer to an array of pointers.
With less obfuscated syntax: if you have a plain array int arr[4]; then you can have an array pointer to such an array by declaring int (*arr_ptr)[4].
So there are arrays, regular pointers and array pointers. Things get confusing because when you use the array name by itself, arr, it decays into a regular pointer to the first element. Similarly, if you have a regular pointer and let it point at the array, ptr = arr; it actually just points at the first element of the array.
Array pointers on the other hand, points at the "whole array". If you take sizeof(*arr_ptr) from the example above, you would get 4*sizeof(int), 4*4=16 bytes on a 32-bit machine.
It should be noted that an array pointer a mildly useful thing to have. If you are a beginner, you don't really need to waste your time trying to understand what this is. Array pointers are mainly there for language consistency reasons. The only real practical use for array pointers is pointer arithmetic on arrays-of-arrays, and dynamic allocation of multi-dimensional arrays.
I have found myself unable to explain why the following piece of code works. Needless to say, I am quite new to C++...
#include <cstdio>
void foo(char* p)
{
p[0] = 'y';
}
int main()
{
char a[1];
a[0] = 'x';
printf("a[0] = %c\n", a[0]);
foo(a);
printf("a[0] = %c\n", a[0]);
return 0;
}
This program outputs
a[0] = x
a[0] = y
What intrigues me us that I am not passing a pointer, but an array, to foo. So how can foo change the value of the array a? Does this apply only to arrays of char?
The answer to Difference between char and char[1], confirms my observation, but it does not go into detail about why this is the case.
Thanks!
When you're passing an array to a function it decays to a pointer to the first element.
The following are completely equivalent:
void foo(char* p);
void foo(char p[]);
void foo(char p[42]); /* Or any other number. */
Does this apply only to arrays of char?
It applies to any array. I recommend the aryptr section of the C FAQ.
In C, arrays, in most contexts (*), decay into a pointer to their first element.
In your case, the array a decays into a pointer to a[0].
The array int arr[12][23], when used just by its identifier, decays to a pointer to its first element, namely arr[0], which is of type int (*)[23] (pointer to array of 23 ints).
(*) Arrays do not decay when used as the argument to the sizeof operator, or when used as argument to the & operator or when used as initializer (a string literal) for a character array.
When You say
char a[5];
the compiler allocates 5 sequential blocks of memory, and the address of the first block is assigned to a. So by definition name of the array (a in our case) is just a pointer to a memory location.
Now when we say a[0], compiler manipulates it as *(a+0*sizeof(array datatype i.e. char, int etc.)), symbolically a[i] is represented as *(a+i*sizeof(array datatype i.e. char, int etc.))
As far as function parameter passing is concerned When we pass an array to a function basically it is just the address of the first element which is passed. For more details regarding this plz follow this link or read the #cnicutar's answer (as he has already posted a correct answer there is no point repeating that again)...
You can try this to convince yourself how this works.
int a[8], *p;
p = a;
printf("%p, %p, %p\n", a, &a[0], p);
An array is nothing more than a pointer (to the first element), at least for argument passing sake.
The three prototypes here are equivalent:
void foo(char *p);
void foo(char p[]);
void foo(char p[42]);
C says a declaration of parameter of type array of T is adjusted to a declaration of type pointer to T.
Array name points to the address of the first element of the array. Please refer: Is an array name a pointer?