Arrays are passed to C ++ functions, giving different lengths
I want to say first - I am interested in what is going on "behind the scenes" to cause this issue, since I am in a blind fix for the code. Perhaps the C ++ standard or something I don't know dictates what is causing it :-)
Anyway...
I am trying to pass 3 arrays A, B, C
to a function that will concatenate A
and B
store the result in C
.
Function declaration: void merge(int* a, int* b, int* c)
Transferred from main()
by:
int A[] = {1,2,3,4};
int B[] = {6,7,8,9};
int* C; //this could be wrong, btw!
merge(A, B, C);
Problem 1.
What's strange in main()
, if I print the result sizeof(A)/sizeof(A[0])
, it gives me the correct result for the "length" of the array - 4
- and the same for B. But when I pass the arrays to the function, I try to calculate the size again, by the same method, but i am getting the result 2
for both arrays. First lines merge()
:
void merge(int* a, int* b, int* c)
{
int sizeA = sizeof(a)/sizeof(a[0]);
int sizeB = sizeof(b)/sizeof(b[0]);
int totalsize = sizeA + sizeB;
std::cout << "size A = " << sizeA << std::endl; //prints 2
std::cout << "size B = " << sizeB << std::endl; //prints 2
std::cout << "total = " << totalsize << std::endl;
...
Problem 2.
Just for fun, I tried looping through A
and B
passed to merge()
(inside the merge function):
for (int i = 0; i < 4; ++i)
std::cout << a[i]; //prints "1234" as expected
Everything is awesome. But when I increase the index limit to 8 ...
for (int i = 0; i < 8; ++i)
std::cout << a[i]; //prints "12346789" - A and B concatenated!
Increasing the max index a couple more times, because why not:
for (int i = 0; i < 10; ++i)
std::cout << a[i]; //prints "1234678900"
...
for (int i = 0; i < 11; ++i)
std::cout << a[i]; //prints "1234678900-444896443"
Undefined behavior due to the limits of indexing and accessing other memory I guess.
Printing is B
similarly similar:
- looping to
i = 4
prints the array -6789
- to
6
adds two zeros -678900
- to
8
adds another material -678900-126926969126613
Printing C does nothing, of course.
Are these oddities the result
- the fact that I am using C ++ Shell (with options
-std=c++14 -Wpedantic -O2
)? - incorrect transfer of arrays to
merge()
? - incorrect initializations in
main()
? - arrays requiring a terminator like char arrays?
- all of the above?
source to share
- In the first case, you have an array that is not the same as a pointer . Thus, it
sizeof
is calculated correctly. Whereas itint*
is a pointer, and the array passed to the function always decays to a pointer (except when it is passed by reference). Also,sizeof(int*)/sizeof(int)
is the size of the pointer on your computer divided by the sizeint
, so if your system is 64-bit (8 bytes) andint
is typical size4
, you get8/4=2
. - Typical behavior is undefined by indexing out of bounds.
Tip: use std::vector<int>
instead and you will avoid allocating memory for C
and using sizeof
. You can just use a member function std::vector::size()
to get the size of the vector.
source to share
When you pass an array in void merge(int* a, int* b, int* c)
a and b
here are no longer arrays but pointers. So when you calculate its size using
int sizeA = sizeof(a)/sizeof(a[0]);
here sizeof(a)
will give you the size of the pointer and sizeof(a[0]
will give you the size int
. Hence the result.
And for your second problem, when you increment the indices and connect both arrays, it only happens because a contiguous block of memory is allocated in both arrays, but not necessarily that they will always be assigned contiguous blocks of memory, and other exits due to the behavior of Undefined ...
source to share
You cannot calculate the size of an array with a simple pointer passed to a function.
sizeof(integers) / sizeof(integers[0])
will simply be replaced with
sizeof(pointer on integer) / sizeof(integer)
.
But you can calculate it earlier and then pass the size to the function as shown below.
#include <iostream>
using namespace std;
void doSomeWork(int* integers, const size_t size)
{
for (size_t i = 0; i < size; ++i)
{
std::cout << integers[i] << std::endl;
}
}
int main()
{
int integers[] { 0, 1, 2, 3 };
const size_t size = sizeof(integers) / sizeof(integers[0]);
doSomeWork(integers, size);
return 0;
}
std::vector<int>
Much better than playing with C arrays, as stated below .
source to share
-
you need to remember that sizeof is a keyword that expands at compile time to the appropriate size.
sizeof(T)
will expand to byte size (T). inside the main function sizeof (a) will give you the number of bytesint[4]
, inside another function the array decays to a pointer.sizeof(T*)
notsizeof(T[4])
! you are calculating the size of the pointer (after decay), not the size of the real array. now let's say my object weighs 1 MB, doessizeof(OBJ) == sizeof(OBJ*)
? of course not. -
you have Undefined beaviour. in this particular example
A
andB
sit just after another on the stack. so in this super specific case, when you iterate over the stack, you are actually printing both arrays because they sit one after the other. but again, this is the Undefined beaviour. different compilers may padd the area between the array, or another OS may even kill your program.
source to share
There are many good answers here already. In short, C ++ arrays are of a fixed size. If you want to change it, you must use pointers and dynamic allocation. It can be tiresome. the reason for most people is here to advise you to use vectors.
Vectors are built for dynamic and variable size. You can use them almost like arrays. Here's your code adapted:
void merge(vector<int> &a, vector<int>& b, vector<int> &c) // pass by reference
{
int sizeA = a.size();
int sizeB = b.size();
int totalsize = sizeA + sizeB;
c.resize(totalsize); // easy !
// ...
}
int main() {
vector<int> A{1,2,3,4};
vector<int> B {6,7,8,9};
vector<int> C;
cout <<A[2]<<endl; // access elements exacly like arrays
merge(A, B, C);
}
source to share