Related
please excuse my bad english,
let me clarify, here is an example,
this is our main :
main()
{
int a1 []= {1,2,3,4,5,6,7,8,9} ;
int size = sizeof(a1) /sizeof(a1[0]) ;
point (a1 , size);
return 0 ;
}
and this is the function:
void point(int a[] , int size)
{
int i ;
for (i = 0 ; i<size ; i++)
printf("%d\n", a[i])) ;
}
From my knowledge, when an array is passed as an argument to a function, we are actually sending a pointer to the first element to the array..
With that being said, how come the function "point"'s parameter is an ARRAY variable, NOT a POINTER variable...?
The reason I thought this was weird, so for example in main we pass int* to some function :
int* a = &b ;
point2(a) ;
The function:
void point2 (int a) // this would be invalid, it has to be int* a
{
.
.
}
We would have to specify that the function receives a pointer, How are arrays an exception?
PLEASE NOTE: I do understand that arrays decay to pointers; that's why my question never was "why can we send arrays as arguments, to functions that have pointers of that same type?". My question is, "How come even though arrays decay to POINTERS, its fine to keep the parameter of the function as an ARRAY?". Hope it is clear how this is different that the first question.
Thank you!
The language specifications of both C and C++ state that a function parameter of type array of T is adjusted to type pointer to T. So these function declarations are one and the same:
void foo(int a[42]);
void foo(int a[]);
void foo(int* a);
All of these will accept a pointer parameter, be it the result of an array decay or not.
Syntactic sugar.
Like juanchopanza noticed, in function arguments it's equivalent to have an array or a pointer.
For fun, try this:
void foo(int a[42])
{
printf("%zu\n", sizeof(a));
}
int main(int argc, char **argv)
{
int a[42];
printf("%zu\n", sizeof(a));
foo(a);
}
This question already has answers here:
C sizeof a passed array [duplicate]
(7 answers)
Closed 4 years ago.
In the program below the length of the array ar is correct in main but in temp it shows the length of the pointer to ar which on my computer is 2 (in units of sizeof(int)).
#include <stdio.h>
void temp(int ar[]) // this could also be declared as `int *ar`
{
printf("%d\n", (int) sizeof(ar)/sizeof(int));
}
int main(void)
{
int ar[]={1,2,3};
printf("%d\n", (int) sizeof(ar)/sizeof(int));
temp(ar);
return 0;
}
I wanted to know how I should define the function so the length of the array is read correctly in the function.
There is no 'built-in' way to determine the length inside the function. However you pass arr, sizeof(arr) will always return the pointer size. So the best way is to pass the number of elements as a seperate argument. Alternatively you could have a special value like 0 or -1 that indicates the end (like it is \0 in strings, which are just char []).
But then of course the 'logical' array size was sizeof(arr)/sizeof(int) - 1
Don't use a function, use a macro for this:
//Adapted from K&R, p.135 of edition 2.
#define arrayLength(array) (sizeof((array))/sizeof((array)[0]))
int main(void)
{
int ar[]={1,2,3};
printf("%d\n", arrayLength(ar));
return 0;
}
You still cannot use this macro inside a function like your temp where the array is passed as a parameter for the reasons others have mentioned.
Alternative if you want to pass one data type around is to define a type that has both an array and capacity:
typedef struct
{
int *values;
int capacity;
} intArray;
void temp(intArray array)
{
printf("%d\n", array.capacity);
}
int main(void)
{
int ar[]= {1, 2, 3};
intArray arr;
arr.values = ar;
arr.capacity = arrayLength(ar);
temp(arr);
return 0;
}
This takes longer to set up, but is useful if you find your self passing it around many many functions.
As others have said the obvious solution is to pass the length of array as parameter, also you can store this value at the begin of array
#include <stdio.h>
void temp(int *ar)
{
printf("%d\n", ar[-1]);
}
int main(void)
{
int ar[]= {0, 1, 2, 3};
ar[0] = sizeof(ar) / sizeof(ar[0]) - 1;
printf("%d\n", ar[0]);
temp(ar + 1);
return 0;
}
When you write size(ar) then you're passing a pointer and not an array.
The size of a pointer and an int is 4 or 8 - depending on ABI (Or, as #H2CO3 mentioned - something completely different), so you're getting sizeof(int *)/sizeof int (4/4=1 for 32-bit machines and 8/4=2 for 64-bit machines), which is 1 or 2 (Or.. something different).
Remember, in C when pass an array as an argument to a function, you're passing a pointer to an array.If you want to pass the size of the array, you should pass it as a separated argument.
I don't think you could do this using a function. It will always return length of the pointer rather than the length of the whole array.
You need to wrap the array up into a struct:
#include<stdio.h>
struct foo {int arr[5];};
struct bar {double arr[10];};
void temp(struct foo f, struct bar g)
{
printf("%d\n",(sizeof f.arr)/(sizeof f.arr[0]));
printf("%d\n",(sizeof g.arr)/(sizeof g.arr[0]));
}
void main(void)
{
struct foo tmp1 = {{1,2,3,4,5}};
struct bar tmp2;
temp(tmp1,tmp2);
return;
}
Inside the function ar is a pointer so the sizeof operator will return the length of a pointer. The only way to compute it is to make ar global and or change its name. The easiest way to determine the length is size(array_name)/(size_of(int). The other thing you can do is pass this computation into the function.
Say I have the following code:
#include <iostream>
using namespace std;
int defaultvalue[] = {1,2};
int fun(int * arg = defaultvalue)
{
arg[0] += 1;
return arg[0];
}
int main()
{
cout << fun() << endl;
cout << fun() << endl;
return 0;
}
and the result is:
2
3
which make sense because the pointer *arg manipulated the array defaultvalue. However, if I changed the code into:
#include <iostream>
using namespace std;
int defaultvalue[] = {1,2};
int fun(int arg[] = defaultvalue)
{
arg[0] += 1;
return arg[0];
}
int main()
{
cout << fun() << endl;
cout << fun() << endl;
return 0;
}
but the result is still:
2
3
Moreover, when I print out the defaultvalue:
cout << defaultvalue[0] <<endl;
It turn out to be 3.
My question is, in the second example, should the function parameter be passed by value, so that change of arg will have no effect on defaultvalue?
My question is, in the second example, should the function parameter be passed by value, so that change of arg will have no effect on defaultvalue?
No.
It is impossible to pass an array by value (thanks a lot, C!) so, as a "compromise" (read: design failure), int[] in a function parameter list actually means int*. So your two programs are identical. Even writing int[5] or int[24] or int[999] would actually mean int*. Ridiculous, isn't it?!
In C++ we prefer to use std::array for arrays: it's an array wrapper class, which has proper object semantics, including being copyable. You can pass those into a function by value just fine.
Indeed, std::array was primarily introduced for the very purpose of making these silly and surprising native array semantics obsolete.
When we declare a function like this
int func(int* arg);
or this
int (func(int arg[])
They're technically the same. It's a matter of expressiveness. In the first case, it's suggested by the API author that the function should receive a pointer to a single value; whereas in the second case, it suggests that it wants an array (of some unspecified length, possibly ending in nullptr, for instance).
You could've also written
int (func(int arg[3])
which would again be technically identical, only it would hint to the API user that they're supposed to pass in an int array of at least 3 elements. The compiler doesn't enforce any of these added modifiers in these cases.
If you wanted to copy the array into the function (in a non-hacked way), you would first create a copy of it in the calling code, and then pass that one onwards. Or, as a better alternative, use std::array (as suggested by #LightnessRacesinOrbit).
As others have explained, when you put
int arg[] as a function parameter, whatever is inside those brackets doesn't really matter (you could even do int arg[5234234] and it would still work] since it won't change the fact that it's still just a plain int * pointer.
If you really want to make sure a function takes an array[] , its best to pass it like
template<size_t size>
void func (const int (&in_arr)[size])
{
int modifyme_arr[100];
memcpy(modifyme_arr, in_arr, size);
//now you can work on your local copied array
}
int arr[100];
func(arr);
or if you want 100 elements exactly
void func (const int (&arr)[100])
{
}
func(arr);
These are the proper ways to pass a simple array, because it will give you the guaranty that what you are getting is an array, and not just a random int * pointer, which the function doesn't know the size of. Of course you can pass a "count" value, but what if you make a mistake and it's not the right one? then you get buffer overflow.
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;
}