Reputation: 21
Because you cannot return int[]
(or any array type for that matter) in c++, I have a function or two which instead return int*
, which has made my existence rather difficult.
A function of my program requires that an array that I've been passing about between functions be copied and incremented around in various ways, and then the copy returned. The only way I've found to copy the data such that the original array is unaffected by changes in the copy, is copying each "member" at a time, e.g.
int* foo(int* a) {
int b[2] = {a[0], a[1]};
/* do unspeakable things to b */
return b;
}
Which is fine enough for this very specific case, but I'm sure isn't the most effective method, especially for large arrays.
Is there some type-casting wizardry or other method I can use to do this more efficiently?
NOTE: I'm not asking if this is good practice, useful, in line with the Geneva convention, or safe very intentionally. I don't particularly care about that information at this moment, and if you absolutely must say it I'd rather it not be the body or opening of your answer.
Also, is the kerning around the T in NOTE super weird for anyone else?
EDIT: After actually using my "solution" I determined that I'm an idiot and should test things before spouting off about them.
Upvotes: 0
Views: 271
Reputation: 141145
int b[2];
int * c = b;
From cppreference implicit conversion:
Array to pointer conversion
An lvalue or rvalue of type "array of N T" or "array of unknown bound of T" can be implicitly converted to a prvalue of type "pointer to T".
That means that any array of type is implicitly converted to a pointer to type. The pointer points to the first member of the array, so c == &b[0]
. Interestingly, the pointer to array is also equal to the pointer of the first element of the array &b == &b[0]
, but has a different type, ie:
int b[2];
int * c = b; // implicit conversion from array to pointer
int (*d)[2] = &b; // &b is a pointer to an array of 2 ints
int * e = &b[0]; // pointer to the first element
The function:
int* foo(int* a) {
int b[2] = {a[0], a[1]};
/* do unspeakable things to b */
return b;
}
Is very invalid, wrong, confusing and bad. The memory behind b
is invalid after }
function returns, so the pointer returned by the function is invalid and cannot be used.
Because you cannot return int[]
int[]
is an array of unspecified size, you cannot do anything with it. Note that inside function parameter list int[]
is implicitly converted into int*
. So the following are exactly equivalent:
void f(int a[]);
void f(int *a);
or any array type for that matter) in c++
You can return std::array<int , 2>
std::array<int, 2> f() {
std::array<int, 2> ret;
return ret;
}
Note that this is highly inefficient. It needs to return 2 * sizeof(int)
of data, which will get bigger with greater size. Returning a pointer to the first member of the array is only returning the pointer value, needs less space. Also note that std::array<int, 2> var = f();
will copy
all array elements between f()
returned value and var
(without copy elision), so it's very inefficient.
I'm sure isn't the most effective method
In terms of speed, initializing each array member explicitly and returning a pointer to the first element of an array is the most efficient method. A proper compiler will generate fast instruction for that. But you say and then the copy returned
- you have to create a copy in your function of the array, so you have to copy all array members between the original and the copy. There's no other way around.
Is there some type-casting wizardry or other method I can use to do this more efficiently?
Toss raw C array to the trash bin, and move to containers. Move to std::array<int, 2>
if you know the size at compile time, and std::vector<int>
if the size is unknown at compile time.
std::vector<int> foo(std::vector<int> a) {
std::vector<int> b{a};
return b;
}
Note that return b
is ok here, as the std::vector<int>
in itself stores a pointer to dynamically allocated memory. Memory allocated with new
does not cease to exist after }
, so you can return a pointer to it. If your compiler supports copy elision, the function should work fast. A faster version would be to use references.
void f(std::vector<int>& ret, std::vector<int> a) {
ret = a;
}
Upvotes: 1
Reputation: 11
You can input both int array into a function and let the function do the copy for you like this:
bool CopyIntArray(int* pA, int cA, int* pB, int cB)
{
if (pA == NULL || cA == 0 || pB == NULL || cB == 0)
{
return false;
}
for (int i = 0; i < cA && i < cB; i++)
{
pB[i] = pA[i];
}
return true;
}
int main()
{
int x[10] = { 0,1,2,3,4,5,6,7,8,9 };
int y[10] = { 0 };
CopyIntArray(x, 10, y, 10);
return 0;
}
by the way
int* foo(int* a) {
int b[2] = {a[0], a[1]};
/* do unspeakable things to b */
return b;
}
b is destroyed when step out of the function scope, so your app would be dangerous when use a destroyed variable as the function output.
Upvotes: 0