Handling multi-dimensional array lengths in C++ - c++

I would like to build a function that takes a multidimensional array and prints it like a grid. I'm having trouble with it because c++ doesn't allow a function to have a multidimensional array argument unless you specify its length. There is a question about it on here, that was answered using vectors. I haven't learned how to use vectors yet, so please don't use them in an answer, or at least provide a good tutorial on them if you do.
Anyway, I was wondering if it's possible to return an array in c++... I started programming with javascript, so the first solution I thought of was to do something like
int gen(int len){
return int arr(int a[][len]){
cout << a[0][0];
};
}
I knew it wouldn't work, tried it, and wasn't surprised when it didn't. Is there a way to do something like this though?

In C++ you can pass array by reference. With making an array a template, it's possible to receive any length in the function. For example,
template<size_t SIZE1>
void print (int (&arr)[SIZE1])
{ ... }
template<size_t SIZE1, size_t SIZE2>
void print (int (&arr)[SIZE1][SIZE2])
{ ... }
template<size_t SIZE1, size_t SIZE2, size_t SIZE3>
void print (int (&arr)[SIZE1][SIZE2][SIZE3])
{ ... }
This pattern will internally create a unique function for every different size of array. It offers ease of use, but may increase the code size.

You have to know the size of the array, there's no way around it. std::vector is the correct way to solve this, and you can find a good reference here. That allows passing only the vector, as it knows its own length and the function can ask it, making it similar to what you're used to from Javascript.
Otherwise, you must pass the size of the array to the function one way or another.
One way is using templates, but that would not work on dynamic arrays (and is a bit wasteful, as it creates a copy of the function per each array size used). The other is just adding an additional parameter to the function, with the size.

Related

Trying to pass 3d array to function c++ [duplicate]

So I have several questions. First how do I pass a 3D array into a function. I need to pass the whole array as the function is to run a loop to output the contents of the array to a file. This is what I currently have
int array[5][3][3]
void function(int a[5][3][3])
{
//...
}
void function(array); //or void function(array[5][3][3]);
I have found a way to make it work using pointers to the array, however I have asked my teacher and he does not want us to use pointers.
My second question is if I plan to modify a global variable inside a function, I do not need to pass it to the function? I can just use it inside the function as I would inside main?
Yet another problem I am having now is passing a single value from an array into a function.
In a loop I need to pull a value from an array[i][j][2] (i and j being indexes of an outer and inner loop) and pass it to a function to evaluate whether or not it is greater than 90. This is for a school assignment, so understand there are certain specifications I have to meet. (Like not using pointers, and passing a whole array, and passing one value from an array, because as a class we have not yet learned how to use pointers)
Your code is correct, but actually there no such thing as an array parameter in C++ (or in C). Silently the compiler will convert your code to the equivalent pointer type, which is
int array[5][3][3];
void function(int (*a)[3][3])
{
...
}
So although your professor told you not to use pointers, actually you cannot avoid them, because there's really no such thing as an array type parameter in C++.
Second question, the only point of globals is that you can refer to them anywhere, so no need to pass them as parameters.
For passing complex arrays I prefer to wrap them in a structure:
struct array {
int a[5][3][3];
};
void function(struct array *a) ...
This avoids a lot of pitfalls with trying to pass arrays as function arguments.
you might use a pointer instead int ***a
int array[5][3][3]
void dummy(int d[][3][3])
{
d[1][1][1] = 0;
}
you may also pass it as a void * then make
int array[5][3][2]
void function(int* b)
{
int i=0;
int j=1;
int k=2;
l[ k*(3*2)+j*(2)+i ] = 9;
}
function((int*) array);

Reference to a subarray within an array

I was trying to figure out how can I create sub arrays from within a larger array and got a piece of code here and started using it.
I created an array of ints
int arr[10];
for(int h=0;h<10;h++)
{
arr[h]=20+h;
}
Now say I want a sub-array (of 4 ints) within the same larger array
int (&arrOnly4Elements)[4]=(int (&)[4])(*arr);
It works well and does what I want.
While I understand references and that they point to actual objects, What I am not able to understand how the above code works.
why do we need the braces to surround &arrOnly4Elements
Also, can anyone explain me the RHS (int (&)[4])(*arr); in detail step by step manner.
cdecl.org translates it for you:
int (&arrrOnly4Elements)[4]: declare arrrOnly4Elements as reference to array 4 of int
int &arrrOnly4Elements[4]: declare arrrOnly4Elements as array 4 of reference to int
As NathanOliver pointed out, C++20 introduces std::span. You should take a look at it (also compare this SO question). A std::span is a templated view into an array/contiguous sequence of objects. It consists of a pointer and a size. It makes accessing arrays and sub arrays convenient (allows range based for) and safe (keeps track of the size).
int arr[10];
std::span<int> arr_span = arr;
std::span<int,4> arr_subspan1 = arr_span.first<4>();
std::span<int> arr_subspan2 = arr_span.first(4);
If you cannot yet switch to C++20 you might consider checking GSL which provides a gsl::span which was lately aligned to match std::span.

Why do we specify arrays size as a parameter when passing to function in C++?

I searched this question, most of them says the same thing. Since we only pass the arrays address in a function, compiler can not know the arrays size by looking at the address, they say. I tried to test this by using this code, and both functions gave the same results. So, how does specifying the arrays size as a function parameter help me in a practical way?. In which conditions does specifying the size help us?.
class ArrayTest
{
public:
void say(int ar[])
{
cout<<ar[1]<<endl;
cout<<ar[7]<<endl;
}
void say(int ar[],int sizeAn)
{
cout<<ar[1]<<endl;
cout<<ar[7]<<endl;
}
};
int main()
{
ArrayTest test;
int anAr[5] = {1,2,3,4,5};
test.say(anAr);
test.say(anAr,5);
return 0;
}
This is about you as a programmer having the chance to boundary check, not whether the compiler can do it.
Just try to print out all the elements in the array, with the size:
void say(int ar[],int sizeAn)
{
for(int i=0; i< sizeAn; ++i)
cout<<ar[i]<<endl;
}
now without the size:
void say(int ar[])
{
for(int i=0; i< /*HOW DO I KNOW NOW?*/; ++i)
cout<<ar[i]<<endl;
}
Passing array size as a function parameter is a bad idea, because if you need an array as an array in function passing its size won't have any effect. The array you passed will be decayed to a pointer. So you need to maintain array as is.
Templates provide a simple and effective way to prevent array decay while passing them as function arguments.
template<std::size_t N>
void foo(int (&your_array)[N])
{
for(int i = 0; i < N; i++)
//process array, N will be your array size.
}
//simply pass array when calling the function. N be taken automatically.
//somewhere else
int main()
{
int arr[10];
foo(arr);
}
hope this helps.
Note that your code is invoking undefined behavior because you're accessing element 7 of an array that is only 5 elements big. Using the size parameter, you could for instance check if the index is past its size and not do that call instead.
In your example, you get the same results becaue you aren't actually using the parameter:
void say(int ar[],int sizeAn)
{
cout<<ar[1]<<endl;
cout<<ar[7]<<endl;
}
sizeAn is unused, so it's not making any difference. But consider for instance the following code:
void say(int ar[],int sizeAn)
{
for (int i = 0; i < sizeAn; i++){
cout<<ar[i]<<endl;
}
}
Here, it's printing all the items in the array, so it needs to know how big the array is. If you used an std::vector, for instance, you wouldn't need to pass the size as you can just call the size function, but you can't do that with C style arrays, so you need to pass that size as a parameter if you want to write a function that behaves differently depending on the size).
Or here's a more practical example of your code where the size parameter is used to avoid the undefined behavior:
void say(int ar[],int sizeAn)
{
cout<<ar[1]<<endl;
if (sizeAn >= 8){
cout<<ar[7]<<endl;
}
}
Now it's the same as your code with the change that it's only printing the element 7 if it actually exists.
As you say, compilers can't tell how big an array is if passed to a function. Your first say function tries to reference past the end of the array (ar[7] is beyond the size of 5). Your second say function means you can length check to make sure you don't make this error.
void say(int ar[], int sizeAn)
{
if(sizeAn>1)
cout<<ar[1];endl;
if(sizeAn>7)
cout<<ar[7];endl;
}
This way, YOU know the length and the function can check it before accessing invalid memory locations.
Why do we specify arrays size as a parameter when passing to function in C++?
Do we?
Well, sometimes. The canonical way to pass a range in C++ is using an iterator-pair though, even if I can see it evolve to using ranges when the Range-TS is finally used everywhere.
Anyway, there are other ways to convey what (sub-)range we want to work with. So, let's take a look:
In-band-signalling, like NUL-terminator for c-strings.
An implicit part of the functions contract, like "it will always be exactly 12 elements".
Passing a view of the part we want. Unfortunately, until the ranges-TS is fully incorporated, standard-library-support for that is severely anemic, being restricted to std::string_view in C++17 and extended with std::span for contiguous ranges (like arrays) in C++20 (look at the guideline-support-library for now).
Using an iterator-pair. The full flexibility of iterators, though calculating the length might be costly, or impossible without consuming the range. This is the preferred way in the standard-library.
Using start-iterator and length. Also quite common, but not to the same degree, and does not allow iterators determining the length as you iterate, not that that is an issue here.
Using a (constant where appropriate) reference to the whole container or range, probably templated for generality. This might be combined with point 3, but need not.
Of those, if you know the element-type, and restrict to contiguous arrays, pointer+length is the most comfortable and flexible to use for now, which does not need different code for different lengths, so that's that.

C++: Return multiple NEW arrays

I think this is an easy issue, but it's driving me crazy: I want to return multiple arrays from one method, for which the calling method does not know their size in advance. So I have to create those Arrays inside the method (in contrast to just filling them) and I am not able to return them using return.
So what I would want is a method signature like this:
void giveMeArray(int[] *anArray)
Method signature has only one parameter to simplify the examples, please assume I could also have a signature like
void giveMeArrays(int[] *anArray, float[] *anotherArray)
Inside that method giveMeArray I would construct the array with
*anArray = new int[5];
and I would call that method using
int[] result;
giveMeArray(&result);
However, all this (starting with the method signature) is at least syntactically wrong. Please excuse that I don't have the compiler errors at hand by now, I'm pretty sure some of you will know what's wrong.
EDIT I know that std::vector would be the best (meaning cleanest) approach. However, folks, that wasn't the question.
Return a single vector (this is C++ afterall)
void giveMeArray(std::vector<int>& anArray)
{
anArray = std::vecotr<int>(5);
}
Return a vector of vectors:
void giveMeArray(std::vector<std::vector<int> >& anArray)
void giveMeArray(int **anArray);
int *result;
giveMeArray(&result);
std::vector<int> giveMeArray() {
std::vector<int> ret;
ret.resize(5);
return ret;
}
Nice resource cleanup, bounds checking in debug modes, etc. Good for all the family.
Consider wrapping the arrays in a class or struct.
struct Arrays {
int *ints;
int intCount;
double *doubles;
int doubleCount;
};
Arrays giveMeArrays() {
Arrays arrays;
arrays.ints = new int[10];
arrays.intCount = 10;
arrays.doubles = new double[20];
arrays.doubleCount = 20;
return arrays;
}
An alternative is to use a std::pair<> or a std::tuple<>, but in my experience any use of those eventually becomes a named type. The fact that they are all part of the result of your function suggests they may have enough coherence to be an object. Having a user-defined type makes it easier to pass the data around, and so to refactor code. You may even find that giveMeArrays() becomes a member function of this object.
Replacing ints/intCount with std::vector<int> would be better, if possible. If not, you may want to give Arrays more responsibility for memory management, disable copying while allowing moving, and so forth.

Need help with returning a 2D array C++, please

I'm trying to create an array and pass it to functions, which then return it, but I don't know the correct way of returning.
I've been looking around tutorials and trying stuff out, but haven't managed to solve this.
I'm new to C++ and thought it would be similar to Java, but apparently it isn't.
This is where I've gotten:
class MainClass {
public:
static int countLetterCombinations(string array[], int numberOfWords) {
// Code
return totalCombos;
}
// This is the function I'm having trouble with.
static string** sortCombos(string combinations[][3]) {
// Do something
return combinations; // This gives converting error.
}
};
int main() {
// Code
int numberOfCombinations = MainClass::countLetterCombinations(words, numberOfWords);
string combinations[numberOfCombinations][3];
combinations = MainClass::sortCombos(combinations);
// Further code
}
Anyone know how to fix this?
You need to use a vector. C++ stack-based arrays cannot be dynamically sized- oh, and you can't convert [][] to **, the conversion only works for the first dimension. Oh, and you can't assign to arrays, either.
The simple rule is, in C++, never use primitive arrays- they're just a headache. They're inherited from C, which actually defined a lot of it's array behaviour for source compatibility with B, which is insanely old. Use classes that manage dynamic memory for you, like std::vector, for dynamically sizable arrays.
std::vector<std::array<std::string, 3>> combinations(numberOfCombinations);
static void sortCombos(std::vector<std::array<std::string, 3>>& combinations) {
// Do something
} // This function modifies combinations in-place and doesn't require a return.
Oh, and you really don't have to make functions static class members- they can just go in the global namespace.
Your sortCombos method can modify the array parameter in-place, and the caller will see those changes directly. Because you doesn't need to return anything, you should change the return type to void.
Even if you could return input array, you can't assign to combinations.