I'm simply trying to get the size of an array passed as a parameter in a function, but I dont understand why the sizeof(k)/sizeof(k[0]) just returns one, when it works fine in the scope where it was declared, what am i missing here?
Heres the code:
#include <iostream>
using namespace std;
int fn(int k[]){
cout << "size in function :" << sizeof(*k) / sizeof(k[0]) << endl; //returns 1 for some reason
//cout << "size in function :" << end(k)-begin(k) << endl; // can't find begin-end fitting function?
int m = *max(&k[0], &k[sizeof(k)/sizeof(int)]);
return m;
}
int main()
{
int k[] = { 1,2,3,4,5,6,7 };
int s = size(k);
cout << "size :" << sizeof(k) / sizeof(k[0]) << endl;
cout << "max: " << fn(k);
return 0;
}
The size of an array only "exists" at compile-time. By the time the code is compiled, arrays are nothing more than pointers.
So if you want a function to accept a sized array, then the size needs to be passed at compile-time, which means it has to be a template parameter.
template<std::size_t N>
int fn(int (&k)[N]){
cout << "size in function :" << N << endl;
cout << "size in function :" << end(k)-begin(k) << endl;
int m = *max(begin(k), end(k));
return m;
}
what am i missing here?
The type of the parameter is int* (after having been adjusted from an array of unknown bound).
sizeof(k)/sizeof(int)
You're dividing the size of a pointer with the size of an integer. That division has nothing to do with the size of the array whose element is being pointed at.
when it works fine in the scope where it was declared
That's because the type of that k isn't int*. The type of the that k is int[7].
find size of parameterized array
The type of a parameter is never an array in C++. If you declare a function parameter to be an array, then the type will be adjusted to be a pointer to element of such array.
If the type of the parameter is pointer, and if that pointer points to element of an array, then there is no general way to find out the size of the array in question.
Some arrays contain a sequence that is terminated by an element with a sentinel value. You can determine the length of such sequence by performing a linear search for the sentinel value. Null terminated strings are a common example of such sequences.
Old fashioned, C style is to pass the size of the array as separate parameter:
int fn(int k[], std::size_t size);
// usage
int k[] = { 1,2,3,4,5,6,7 };
fn(k, std::size(k));
A more modern approach is to combine the pointer and the size in a class. There is a class template for such purpose in the standard library:
int fn(std::span<int> k);
// usage
int k[] = { 1,2,3,4,5,6,7 };
fn(k);
Related
When using the address transfer of function, View address blocks of formal parameters and actual parameters, I find that the arguments and formal parameters of array share one address block, while the arguments and formal parameters of variables use two address block. What is the reason?
The code is as follows:
#include<iostream>
using namespace std;
void test(int *i,int * arr) {
cout << &i << endl;
cout << arr << endl;
}
int main() {
int i = 1, arr[2] = {1,2};
cout << &i << endl;
test(&i, arr);
cout << arr << endl;
system("pause");
return 0;
}
And this is the output:
0000008986B6FC54
0000008986B6FC30
0000008986B6FC78 //Arrays use the same space
0000008986B6FC78
You are passing pointers to the functions. The value of the pointers are not modified, ie in the function they point to the same objects as they do in main.
However, you are not printing what you think you print:
void test(int *i,int * arr) {
cout << &i << endl;
cout << arr << endl;
}
The pointer i gets the parameter &i (the i from main). Hence printing i in main will yield the same value as printing i in test. However, you are printing the adress of i in the function not the value of it. If you change your code to:
void test(int *i,int * arr) {
cout << &i << endl;
cout << i << endl;
cout << arr << endl;
}
You will notice the difference. I suggest you to rename at least one of the is in your code, because using same name for different entities can and does cause confusion. The i in test holds the value of the address of the i in main. That does not mean that they are the same, but rather i in test has the same value as &i in main.
In short: &i == &i but you expect &(&i) to be the same as &i.
There is no difference between passing a pointer to the int or passing a pointer to the first element of the array. From the point of view of the function they are both just pointers to int.
Note that test prints the value of arr but the location of i.
In test, &i is the location of its argument i.
That argument's value is the location of the i in main.
You will see this if you print i instead of &i.
arr, on the other hand, is implicitly converted into a pointer to its first element, and you are both passing &arr[0] to test to print, and printing &arr[0] in main.
Here is the same thing with explicit conversions and without using a function:
int main() {
int i = 1, arr[2] = {1,2};
cout << &i << endl;
// Create the "argument"...
int *p = &i;
// These two lines are 'test'...
cout << &p << endl;
cout << &arr[0] << endl;
// and this is after the function call.
cout << &arr[0] << endl;
}
This question already has an answer here:
When passing an array to a function in C++, why won't sizeof() work the same as in the main function?
(1 answer)
Closed 1 year ago.
Forgive me for this possibly dumb question. Consider this:
int foo(int* arr) {
std::cout << arr << "(" << sizeof(arr) << ")";
}
int main()
{
int x[] = {0, 1, 2, 3, 4};
foo(x);
std::cout << " " << x << "(" << sizeof(x) << ")";
}
Output: 0x7c43ee9b1450(8) 0x7c43ee9b1450(20) - Same address, different size.
My understanding is that the function argument is an address specific to the first element of the array, so the size is 8 bytes, and the same should be true for the variable in main too; So how come the size of the variable outside of the function represent the whole array (4 bytes int times 5 elements = 20)? How could I possibly determine from inside the function how large an array actually is?
This is because the types are not the same inside and out side the function.
If you make sure the type is the same inside and outside the function you should get the same result.
int foo(int (&arr)[5])
{
std::cout << arr << "(" << sizeof(arr) << ")";
return 0;
}
The problem is that arrays decay into pointers at the drop of a hat. So if you pass an array to a function it will easily be converted into a pointer. That is what is happening here.
int foo(int* arr)
// ^^^^ Notice this is not an array.
// It is simply a pointer to an integer
// The array has decayed into a pointer to the
// first element in the array.
{
std::cout << arr << "(" << sizeof(arr) << ")";
return 0;
}
How could I possibly determine from inside the function how large an array actually is?
This is actually a real problem with C. In C they solved this by getting you to pass the size of the array as a second parameter:
int foo(int* arr, std::size_t size);
Then call it from main as:
foo(arr, sizeof(arr)/sizeof(arr[0])); // This always works as it done
// at compile time and not runtime
In C++ we don't usually use C-arrays but prefer std::vector or std::array as the size is easily retrievable. Generally we use a container type C as they are duck types of Container:
template<typename C>
int foo(C& container)
{
std::cout << "(" <<container.size() << ")";
return container.size();
}
When passing an array like that you loose ALL the size information.
So the called function is flying blind with regard to the array size.
In C++ is makes much more sense to use std::array (fixed size arrays), and std::vector (changing size arrays). It is much clearer what your intent is when you pass them to functions. There will be less mistakes and less memory access issues in your code.
I hope I don't scare you too much with the template version.
The vector variant is more easy, but may use a bit more memory at runtime.
#include <array>
#include <vector>
#include <iostream>
template<size_t N>
size_t foo(const std::array<int,N>& arr)
{
for (const auto n : arr) std::cout << n << " ";
std::cout << "(" << arr.size() << ")" << std::endl;
return arr.size();
}
size_t foo(const std::vector<int>& arr)
{
for (const auto n : arr) std::cout << n << " ";
std::cout << "(" << arr.size() << ")" << std::endl;
return arr.size();
}
int main()
{
std::array<int,5> x{ 0, 1, 2, 3, 4 };
std::vector<int> y{ 0, 1, 2, 3, 4 };
auto size_x = foo(x);
auto size_y = foo(y);
}
I am trying to compile the following code:
#include <iostream>
using namespace std;
void show1(string text1[]) {
cout << "Size of array text1 in show1: " << sizeof(text1) << endl;
}
int main() {
string text1[] = {"apple","melon","pineapple"};
cout << "Size of array text1: " << sizeof(text1) << endl;
cout << "Size of string in the compiler: " << sizeof(string) << endl;
show1(text1);
return 0;
}
And the output is shown below:
Size of array text1: 96
Size of string in the compiler: 32
Size of array text1 in show1: 8
I am not able to understand, why is the sizeof operator working on the same array giving two different outputs at two different points? Please explain.
The sizeof() operator returns the compile time size of the objects. It means that if your type allocates a memory chunk at run time from heap, that memory is not taken into account by sizeof().
For your first case, i.e.
string text1[] = {"apple","melon","pineapple"};
You have an array of 3 strings, so sizeof should return 3*sizeof(std::string). (3*32 = 96 in your case)
For your second case:
sizeof(string)
It should simply print the size of an string. (32 in your case).
Finally for your last case, do not forget that arrays are passed using a pointer in C/C++. So, your parameter is simply a pointer and sizeof() should print the size of a pointer on your machine.
Edit: As #ThomasMatthews has mentioned in the comments, if you are interested in getting the real size of an string (i.e. the number of characters inside it), you can use std::string::length() or std::string::size().
Try with member function 'size'.
Write this code:
#include <iostream>
using namespace std;
void show1(string text1[])
{
cout << "Size of array text1 in show1: " << text1->size() << endl;
}
int main()
{
string text1[] = {"apple","melon","pineapple"};
cout << "Size of array text1: " << text1->size() << endl;
cout << "Size of string in the compiler: " << sizeof(string) << endl;
show1(text1);
return 0;
}
Description:
std::vector has a member function size(). And std::string too. In std::vector return size of vector(all elements). In std::string returns all elements in array.
I had the online coding interview today and I really struggled while trying to calculate the size of the array.
Could you please help me with how can I measure the sizeof array here? I tried my best but no luck please help here.
#include<iostream>
#include<map>
#include<vector>
using namespace std;
void arraysize(int* a) {
cout << "size1: "<<sizeof(a) << endl;
cout << "size2: " << sizeof(a[0]) << endl;;
}
int main()
{
int array1[] = { 1,2,3,4,5,6,7,8 };
arraysize(array1);
return 0;
}
Result:
size1: 4
size2: 4
In most cases, when you pass an array to a function, the array will be converted to a pointer. This is called an array-to-pointer decay. Once this decay happens, you lose the size information of the array. That is, you can no longer tell the size of the original array from the pointer.
However, one case in which this conversion / decay will not happen is when we pass a reference to the array. We can take advantage of this property to get the size of an array.
#include<iostream>
template<typename T, size_t N>
size_t asize(T (&array)[N])
{
return N;
}
int main()
{
int array1[] = { 1,2,3,4,5,6,7,8 };
std::cout << asize(array1) << std::endl; // 8
return 0;
}
In the above case, to the template function asize, we pass a reference to an array of type T[N], whose size is N. In this case, it is array type int[8]. So the function returns N, which is size 8.
C style array's decay to pointer's when passed to a function like this.
The first cout statement is printing the size of a pointer on your machine.
The second cout statement is printing the size of an integer.
Use one of the following solutions in order to pass the size of the array to the function.
template<std::size_t N>
void ArraySize( int ( &array )[ N ] )
{
std::cout << "Array size: " << N << '\n';
}
void ArraySize( int* array, std::size_t size )
{
std::cout << "Array size: " << size << '\n';
}
template<std::size_t N>
void ArraySize( std::array<int, N>& array )
{
std::cout << "Array size: "<< array.size( ) << '\n';
}
sizeof(a) returns the number of bytes in array,
sizeof(int) returns the number of bytes in an int,
ergo
sizeof(a)/sizeof(int) returns the array length
Easiest way to get the size of an array:
#include <iostream>
using namespace std;
int main(void) {
int ch[5], size;
size = sizeof(ch) / sizeof(ch[0]);
cout << size;
return 0;
}
Output: 5
simply divide sizeof(array1) by sizeof(int). it will give you total element in array. because sizeof(array1) will give total bytes in the array. for example sizeof(array1) = int * 8 because your array is int so int is 4 byte answer is 4*8 = 32.Now you have to divide it again by 4 cause its in byte.
cout << "Size of the Array is : " << sizeof(array1)/sizeof(int) << endl;
put above code in your main function to get result
(Disclaimer: Pointers in C++ is a VERY popular topic and so I'm compelled to believe that someone before me has already raised this point. However, I wasn't able to find another reference. Please correct me and feel free to close this thread if I'm wrong.)
I've come across lots of examples that distinguish between pointer to first element of array and pointer to the array itself. Here's one program and its output:
//pointers to arrays
#include <iostream>
using namespace std;
int main() {
int arr[10] = {};
int *p_start = arr;
int (*p_whole)[10] = &arr;
cout << "p_start is " << p_start <<endl;
cout << "P_whole is " << p_whole <<endl;
cout << "Adding 1 to both . . . " <<endl;
p_start += 1;
p_whole += 1;
cout << "p_start is " << p_start <<endl;
cout << "P_whole is " << p_whole <<endl;
return 0;
}
Output:
p_start is 0x7ffc5b5c5470
P_whole is 0x7ffc5b5c5470
Adding 1 to both . . .
p_start is 0x7ffc5b5c5474
P_whole is 0x7ffc5b5c5498
So, as expected, adding 1 to both gives different results. But I'm at a loss to see a practical use for something like p_whole. Once I have the address of the entire array-block, which can be obtained using arr as well, what can I do with such a pointer?
For single arrays, I don't think there's much point to it. Where it becomes useful is with multi-dimensional arrays, which are arrays of arrays. A pointer to one of the sub-arrays is a pointer to the row, and incrementing it gets you a pointer to the next row. In contrast, a pointer to the first element of the inner array is a pointer to a single element, and incrementing it gets you the next element.
int (*)[10] is a "stronger" type than int* as it keeps size of the array,
so you may pass it to function without passing additional size parameter:
void display(const int(*a)[10]) // const int (&a)[10] seems better here
{
for (int e : *a) {
std::cout << " " << e;
}
}
versus
void display(const int* a, std::size_t size) // or const int* end/last
{
for (std::size_t i = 0; i != size; ++i) {
std::cout << " " << a[i];
}
}