This question already has answers here:
Why doesn't C++ support functions returning arrays?
(10 answers)
Closed 10 years ago.
I've got a syntax question in C++ about returning an array. When we pass in an array, when can do like this:
void merge_sort(int input_array[], int size);//notice the first parameter
I know this works:
int* merge_sort(int input_array[], int size){
//do something with input_array
return new int[2]; //dummy array
}
Question:
int[] merge_sort(int input_array[], int size){ //Question is on return type, wont compile
//do something with input_array
return new int[2]; //dummy array
}
return int* succeed. Why returning int [] fail?
In both C and C++, you cannot either pass an array as an argument to a function, or return an array as a function result.
Yes, the syntax can make it look like you're passing an array argument:
void func(int param[]) {
// ...
}
...
int arr[10];
func(arr);
but in fact that's just passing a pointer to the array's first element. The parameter definition int param[] is adjusted; it's exactly equivalent to int *param. And an expression of array type, in most contexts, is implicitly converted to a pointer its first element.
That's why you need to pass the size as a separate argument.
Using only C features, there are several ways to do something like returning an array:
A function can return a pointer to the first element of a static array. This has some disadvantages: the size has to be fixed, and multiple callers get pointers to the same object.
A function can receive a pointer to the first element of an array, passed in by the caller. This places the burden of allocating and deallocating the array on the caller.
A function can return a pointer to the first element of a dynamically allocated (malloc() in C, new in C++) array. This requires the caller to deallocate the array.
C++ provides a rich set of library classes that can take care of all this for you.
Recommended reading: Section 6 of the comp.lang.c FAQ.
You can pass structs as arguments, and return them as function results, and structs can contain arrays as members. But that's not as useful as you might think. An array that's a member of a struct must have a fixed size; most useful code that operates on arrays can handle dynamic sizes.
Why would you want to return anything in the first place?
Array is not really "passed" to the function (no copy of the elements is made), only the pointer to it's beginning is. When the function rearranges the array elements, it is doing so in the original array. After the function exits, the calling code can simply continue to use the old (now-sorted) array.
In other words, the function produces a side-effect.
I know this works:
int* merge_sort(int input_array[], int size){
//do something with input_array
return new int[2]; //dummy array
}
(Assuming you actually need to return...)
Well it "works", but is very dangerous. The caller needs to be aware it needs to free the returned array (otherwise a memory leak ensues), and it needs to be aware it must use delete[] and not just delete (otherwise an undefined behavior ensues), which is distinctly non-obvious based only on the return type (which is just a pointer). The caller might also be in doubt whether the input_array is freed inside the function or not.
Even if you have documented all that, it's extremely easy for the caller to make a mistake. It's much better to use the facilities provided by modern C++ instead: for example, you could return an std::vector.
you should be using a vector in this approach, in your project include and then use a vector almost as u would with an array.
u can have a look at vectors here: http://msdn.microsoft.com/en-us/library/vstudio/9xd04bzs.aspx
the great thing about vectors is that they are dynamically scaling for your projects and would not create any memory leaks or such due to buffer overflow's, its much like an ArrayList
Related
#include <iostream>
using namespace std;
int func(int ar[5]){
//the code is written here with returning whatever the requirement is
}
int main(){
int ar[5];
func(ar);
return 0;
}
In this kind of situation where we are passing array through a function why the address of the array is used in actual parameter whereas the array in formal parameter?
This is because C handled arrays weirdly.
In C, arrays convert to a pointer to their first element at the drop of a hat, cannot be passed as arguments to a function, cannot be returned from functions, and cannot be copied by assignment.
C++, originally based off C, carries these screwed up design decisions as a legacy issue. Fixing them would break insane amounts of code.
If you want an array that behaves more reasonable, use std::array.
void foo(int[5]);
this is actually taking an int* argument.
int arr[7];
foo(arr);
this converts the 7 element arr to a pointer and passes it to foo. Which seems to take int[5] but that 5 does nothing.
Yes this is utterly crazy.
Now,
void bar(int(&)[5])
because C does not have references, the above is an actual reference to an array if 5 elements, so
bar(arr)
won't compile.
There is nothing weird, nor screwed up about how arrays are passed in C. C is expressed pretty simply, really. C /does/ have references; they are explicit, so, easy to see when they're in use. We call them pointers.
One simply needs to understand that there is not dedicated storage for array types, that arrays are not first-class types, so, won't behave like first-class types. Can't be assigned into (directly), nor passed into and out of functions directly.
In C/C++ we use pointers to refer to a chunk of memory where the contents of the array are stored.
So, all that's left is that we understand that when we declare an array, the name of the array is really a pointer to the beginning of the array.
int a[12] ;
/* a's type is this: */
int *a ;
So, when we "pass an array" to a function, we are copying the pointer into the function. The semantics are straightforward, and entirely consistent (unlike Java).
The array, itself, is never passed directly.
Finally, realise that there is no difference between a pointer to a single integer, and a pointer to a contiguous chunk of integers in memory.
Remember, a[i] is equivalent to *(a+i). So, in this example:
int i = 12 ;
int *p = &i ;
, *p is the same as *(p+0); the p can be thought of as an array of length 1.
With a slight change in perspective you should be able to see the simplicity, the elegance, that is C.
I have just begun using C++, with a base in C. Having learned about Call by reference, I need to know,if in the following function I found online:
int insertSorted(int arr[], int n, int key, int capacity)
{
if (n >= capacity)
return n;
arr[n] = key;
return (n+1);
}
,which is used for insertion in an unsorted array, will the array in the main function get affected/changed? Since the arr[] argument in the function is not a reference variable, so how do any changes in this called function, reflect in the calling function? Is this correct code, if at all? I am basing my question upon the fact that call by value, creates copy variables and changes them, while call by reference changes the actual variables themselves. I'm sorry if this question is a bit silly.
Any help in clearing up this concept would be great.
Thanks.
arr is effectively a pointer to the array. Thus, in your case it acts like a reference and the function changes the array arr points to.
If you want to do it more the C++ way you should use a std::vector<int> instead of a int[] for your array. std::vector has all features of a C-style array but takes care of memory management and the actual number of elements.
In case of a std::vector you really have to pass a reference (std::vector &), otherwise the function will receive a copy of the entire array.
In the following code, im trying to build 2 arrays. The first one is an array given by the user, the second one is an array which has been sorted among other things, although kept short since the actual implementation is not nescessary :
int main()
{
int size = 0;
cout << "Please enter size: ";
cin >> size;
int array[size];
int newArray[size] = doSomething(array,&size);
return 0;
}
int* doSomething(int array[],int *size)
{
*size+=1;
int newArray[size];
//do something with the array and store it in the newArray
return newArray;
}
So my question is this:
My teacher told me that most compilers work differently, and the order of some operations might differ among them.
At the line int newArray[size] = doSomething(array,&size); I am expecting the size variable to be changed inside doSomething before it is used to initialize newArray. Once the doSomething method is finished running, it should return an array (WHICH I ASSUME It IS JUST RETURNING THE ADRESS OF THE FIRST ELEMENT OF THE ARRAY, PLEASE CORRECT ME IF THIS IS WRONG). Once it returns I want to store that address into my newly array, where the variable size is used to initalize the array's size. This variable should be according to my logic, equal to the original size entered by the user +1. So if the user enters a size of 4, the size of newArray should be 5. Is this a good way of going about it, or would it produce unreliable results for different compilers?
For the purpose of this exercise, I can only use built in array and pointers. So I cannot use vectors. Furthermore, in this example, the newArray is one element larger, but the actual code has a size which is dynamic, and therefore might be different each time. I can therefore not hard code the +1 inside the declaration.
If this is wrong, can someone point me in the right direction and help me to find a way where I can pass a built in array (no vectors or array<>), modify the contents and size of it and then return that array and store it in a variable in the caller method?
Thank you very much
First, standard C++ does not allow so-called variable-length arrays (VLAs); the size of the array in the declaration must be a compile-time constant. Standard C does allow them and both gcc and clang implement them as an extension. So technically, your code is ill-formed C++.
Let's accept the extension, for argument's sake. Now we have another problem, which is that arrays cannot be used as initializers for arrays. (An array could be used to initialize a pointer because the array will decay to a pointer in that context, but the pointer doesn't have a size at all. If you did tgat, though, you would introduce a different problem: the returned array has automatic storage duration which means that it is destructed and deallocated immediately. It is, therefore, a "dangling pointer" and using it is undefined behaviour.) You could work around that restriction a bit awkwardly by wrapping the array in a struct.
None of that touches the order of evaluation issue you are curious about. The answer is that the order is unspecified; the compiler might evaluate the function call before or after allocating space for the array. So even if your compiler allows VLAs, the size of this one is unspecified.
You have a problem here:
cin >> size;
int array[size];
Unless you use new you can't do that. The compiler creates the array container before the program runs, so you can't give it a custom size once it is running.
You must allocate your array as a new object on the heap:
cin >> size;
int* array = new int[size];
Maybe this will point you in the right direction, but I have no idea exactly what classes you are trying to call as you haven't included all of your source code.
I edited my previous answer, because I believe you are trying to simply call an array of ints, not a class called "array". If you just want a C-style array of integers, the above example is how you do it properly.
Keep in mind once you are done using the data you should call
delete[] array;
I have a class that has a large 2 dimensional array in it. It used to be a dynamic array allocated on the heap and now it is statically sized which I prefer.
private:
int fontTextureCoords_[100][7];
I had to add the type casting to the the accessor in order to return the array for access outside the class which is currently working okay, but I'm not sure it is safe or the correct way to handle this.
public:
inline int **getFontTextureCoords()
{
return (int**)fontTextureCoords_;
}
Is this safe / the correct way to do this or is there a more preferred method for returning a pointer to a multi-dimensional array?
That's not the correct way to do that and shouldn't compile. A 2d array is not convertible to a pointer to pointer. You'd have to return a pointer to an array, which is easiest to write using a typedef:
using T = int[7];
inline T* getFontTextureCoords() { return fontTextureCoords_; }
Although it'd be much better to just return a reference the full array:
using T = int[100][7];
inline T& getFontTextureCoords() { return fontTextureCoords_; }
You could also just std::array<std::array<int, 7>, 100>.
Maybe this diagram shows you the difference between the two types of multi-dimensional array declarations. (Sometime people don't understand this.)
The first one says a is a single block of 100 consecutive 7-int chunks, or 700 ints total, all together in one piece.
The second says a is an array of pointers, where each pointer points to a different chunk of ints, scattered all over memory.
The compiler needs to know this, because if you write a[i][j] it has to generate totally different code.
Casting an array such as int fontTextureCoords_[100][7]; to an int** is not right. It leads to undefined behavior.
If it is not too much, change getFontTextureCoords to:
inline int (*getFontTextureCoords()) [7]
{
return fontTextureCoords_;
}
and use it as:
int (*ptr)[7] = getFontTextureCoords();
If you have the option of using std::vector or std::array, it will be better to use them.
There are no multi-dimensional arrays in C/C++. There are only single dimenstional arrays. You can have a single-dimensional array, with every element of it being another single dimensional array. While there seem to be no difference, it is there and is very important.
This is exactly way transitive logic doesn not work. Everybody has gone through it. 'If single-dimensional arrays are passed as a pointer to the first elelement, 2-D arrays should be passed as a pointer to pointer to first element, etc'. But since it is not a two-dimensional array, but array of arrays, the logic can not be applied.
You can reason about it in the following way. Let's say, you have an array of types X.
X x[10];
How do you access element number 5? Easy -
x[5] = 42;
But what compiler does when it sees it? It does approximately this:
*(&x[0] + 5) = 42;
So it takes the address of the first element, and adds 5 to it to get to the address of your 5th element. But what adding 5 means? In bytes, how many bytes should be skipped from address of beginning of the array to arrive at requested memory location? Of course, 5 * sizeof(X). Now, if you have '2-D' array, declared like this:
X x[2][3];
And you try to work with it through the pointer to pointer:
px = (X**)x;
px[3][4] = 42;
Remember, to genereate the code for [][], compiler needs to express in the way of *(px + ). And something has to be the size of the array (as elements of your array are arrays). But you need to know array size for this, and as you can see, your px does not have any array size encoded in it. The only size it know is size of X, which is not enough.
Hope it makes sense, and explains why you can't use int** instead of x[][].
I have one quick question about the passing of arrays in C++ which I don't understand.
Basically when you want to pass a array of type integer to another function you have to pass an address to that array instead of directly passing the whole block of contiguous memory. Exactly why is the case?
Also, why is that char arrays can directly be passed to another function in C++ without the need to pass an address instead??
I have tried looking for learning materials for this online (such as cplusplus.com) but I haven't managed to find and explanation for this.
Thanks for your time, Dan.
As long as C++ is concerned, passing char arrays and int arrays are same.
There are 2 ways to pass arrays in c++.
Address is passed
int fn(int *arrays, int len);
int fn(int arrays[], int len); // Similar to above, still staying as sytax hangover from anci c
Array reference is passed
int fn(int (&array)[SIZE]); // Actual array passed as reference
You can templatized above function as
template<size_t SIZE>
int fn(int (&array)[SIZE]);
Above method allows you to pass array of anysize to this function. But beware, a different function is created from template for each size. If your function's side effect changes a local state (static variable for ex), this should be used with care.
If you don't want to change contents, use const with arguments.
If you want a copy of array in function argument, consider using stl container like std::array or std::vector or embed array in your class.
It isn't entirely clear from your question exactly what you're trying and what problems you've had, but I'll try to give you useful answers anyway.
Firstly, what you're talking about is probably int[] or int* (or some other type), which isn't an array itself... its a pointer to a chunk of memory, which can be accessed as if it were an array. Because all you have is a pointer, the array has to be passed around by reference.
Secondly, passing around an array as a "whole block of contiguous memory" is rather inefficient... passing the point around might only involve moving a 32 or 64 bit value. Passing by reference is often a sensible thing with memory buffers, and you can explicitly use functions like memcpy to copy data if you needed to.
Thirdly, I don't understand what you mean about char arrays being "directly" passable, but other types of arrays cannot be. There's nothing magic about char arrays when it comes to passing or storing them... they're just arrays like any other. The principle difference is that compilers allow you to use string literals to create char arrays.
Lastly, if you're using C++11, you might want to consider the new std::array<T> class. It provides various handy facilities, including automatic memory management and keeping track of its own size. You can pass these by value, template<class T> void foo(std::array<T> bar) or by reference template<class T> void foo(std::array<T>& bar), as you like.
You can't pass any array by value. You can pass by value either a struct containing array or std::array from C++11.