How can I pass an array by reference to a function in C++? - c++

I have the following program where two variables are to be passed by reference to a function where their values will be determined based on external factors before being returned to main() so that they can be used by other functions. The first variable I am trying to pass is an int, and that goes fine, but the other is an array of strings, which is causing me some problems.
I've done enough research into this to know that you can't have an array or references (though I've yet to figure out why) and I was wondering if anyone could help me figure out how to do this? The various methods I've tried have all resulted in segmentation faults.
NB: The code below has the array being passed by value since I just don't know what to write for it.
Update: I'm required to use an array for my coursework. Some other data structure, such as the vector that has been suggested, would be great, but I have to use specific structures.
void initialise_existing_devices(int& no_of_existing_devices, string existing_devices[100]);
int main()
{
int no_of_existing_devices = 0;
string existing_devices[100];
initialise_existing_devices(no_of_existing_devices, existing_devices[100]);
}
void initialise_existing_devices(int& no_of_existing_devices, string existing_devices[100])
{
string line;
ifstream DeviceList;
DeviceList.open("devices/device_list");
while (true)
{
getline(DeviceList, line, '\n');
if (DeviceList.eof())
{
break;
}
++ no_of_existing_devices;
}
DeviceList.close();
DeviceList.open("devices/device_list");
for (int i = 0; i < no_of_existing_devices; i ++)
{
getline(DeviceList, line, '\n');
existing_devices[i] = line;
}
}

A reference to an array looks like:
void f(std::string (&a)[N]) { }
where a is the name of the parameter and N is the number of elements in the array.
However, usually in C++ you don't pass an array by reference (you can; it's just not common). Other options include:
Pass a pointer to the initial element of the array; in this case, consider passing the size of the array as a second argument to the function.
Use a std::vector<std::string> or a std::array<std::string, N> instead and pass it by reference (you can also find the array psuedo-container in Boost; barring that, consider writing your own. If you take a look at the Boost source code, it's quite simple and straightforward).
Pass a pair of iterators (begin and end) to the function and use them to manipulate the range.
The last option is the most idiomatic C++ approach; it is also the most generic because you can use any type of container, including arrays, standard library containers, or containers that you've written yourself.
Since you are actually trying to use the parameter as an "out" parameter, it's probably better just to return a std::vector<string> or a std::array<string, 100> containing the results; this is much cleaner.

this line is not doing what you are expecting:
initialise_existing_devices(no_of_existing_devices, existing_devices[100])
hint: array index, 100 ...
I would suggest that you use a std::vector<std::string> rather than the array and pass that by reference.
EDIT: okay, given the update:
can you use a struct? If so, you can wrap the array in a struct:
struct string_array
{
string data[100];
};
and then define an instance of this in main, and pass that by reference? I'm sure you can fill in the details.. :)

You should use a std::vector<T> for heap-managed arrays or a boost::/std::array<T, N> for stack-based arrays. These objects will hold their own size.

This is one of those things C++ has in common with C. Arrays are not passed by value. They're demoted to pointers to their first elements. The array syntax in the function parameters is essentially just a comment. You can tell by doing a sizeof(existing_devices) inside your function call. So the answer to your question is that you're already doing it.

You can use templates, like so:
template <size_t size>
initialise_existing_devices(int& no_of_existing_devices, string (&existing_devices)[size])
{
}
or you can do:
typedef string hundred_strings[100];
initialise_existing_devices(int& no_of_existing_devices, hundred_strings &existing_devices)
{
}

For the actual argument, use just the array name, which represents the address of the array:
initialise_existing_devices(no_of_existing_devices, existing_devices);
For the parameter, use this for a constant pointer to the array:
void initialise_existing_devices(int& no_of_existing_devices, string existing_devices[])
That said, using a std::vector as the return type or a reference parameter would avoid the need to guess the number of devices before the call.

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);

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.

Arrays and length in C++

I'm trying to get the length of an array passed as a parameter on some function.
The code is look like this :
double getAverage(int numbers[])
{
int length = sizeof(numbers)/sizeof(numbers[0]);
// here the result of the length is 1.
int sum = 0;
for (int i = 0 ; i < length ; i++)
{
sum += numbers[i];
}
return (double)sum / length;
}
int main()
{
int numbers[8] = {1,2,3,4,5,6,7,8};
//if I call here sizeof(numbers)/sizeof(numbers[0] the result will be 8 as it
//should be.
cout << getAverage(numbers) << endl;
return 0;
}
My question is how to get the array length which is passed as argument of a function by reference(although I know that every array is passed by reference)?
I know that there is a lot of questions about finding the array length in C/C++ but no one of them give me the answer which I'm looking for.
Thanks in advance.
You will have to explicitly pass the length of the array as an parameter to the function.
What you pass to the function is just an pointer to the array, not the array itself, so there is no way to determine the length of the array inside the function unless you explicitly pass the length as an function parameter.
You can probably use std::vector, which provides member functions to get no of elements in the vector, using std::vector::size(), that is the best you can do there is no way to do so using c-style arrays.
Arrays decay to pointers when passing them as parameters. You can't retrieve size information inside the function.
Why aren't you using std::vector? It's the c++ way.
At run-time, there is no information associated with an array that tells you its length. The array pretty much "decays" into just the address of the first element.
At compile-time, the length is part of the type, so if you declare your function to take e.g. int numbers[8] you can get the length using the sizeof expression you mention.
Of course, this means you can only validly call the function with arrays of length 8, which kind of makes it a bit useless.
Thus, the only way around this is to explicitly add information at run-time about the array's length, by adding a second size_t length argument to the function.
In C++, you could also use templates to have the compiler create specialized versions of the function for each array length, but that is kind of wasteful.
As pointed out by others, you can also "level up" your abstraction and use e.g. std::vector<int> to get a size() method. That is of course pretty much the same thing, the vector container adds run-time information about the number of elements.
This might not be "the answer which you're looking for", I'm sorry about that.
If you must use an array, you could 'templatize' your function:
template <size_t length> double getAverage(int (&numbers)[length]) {
int sum = 0;
for (int i = 0 ; i < length ; i++)
{
sum += numbers[i];
}
return (double)sum / length;
}
You have to pass in the length as a parameter, or use std::vector which "contains" the length. You can access it with the size() method.
Or use std::vector (instead of int[]) which provides a size() function
You can use std::vector, or std::list as all have give. But if you are adamant that you want to use an int[] without a second argument, then you can insert a code number as the last element of the array. that way you can know the end.... Or u can save the length of the array in its first element and use the rest normally.
You can pass an array by reference in which case the areay size has to be specified. However, the size of a statically sized array can be deduced for a template argument:
template <int Size>
double getAverage(int (&numbers)[Size]) { ... }
The only problem with this approach is that it creates a new instantiation for each array size. Of course, the fix to this is to actually pass begin and end iterators to the function doing the actual work. The iterators can easily be determined using begin() and end() functions using the trick above. The code would look something like this:
double average
= std::accumulate(begin(numbers), end(numbers), 0.0)
/ std::distance(begin(numbers), end(numbers));
You can use templates:
template<std::size_t Length>
double getAverage(int (&numbers)[Length])
{
...
}
but this may lead to code bloat as the compiler will create this for every new array size you pass in. You might be better off combining a template with a parameter
template<typename T, std::size_t Length>
std::size_t GetCount(T (&numbers)[Length])
{
return Length;
}
[main]
getAverage(numbers, GetCount(numbers));

Handling multi-dimensional array lengths in 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.

Best Replacement for a Character Array

we have a data structure
struct MyData
{
int length ;
char package[MAX_SIZE];
};
where MAX_SIZE is a fixed value . Now we want to change it so as to support
"unlimited" package length greater than MAX_SIZE . one of the proposed solution
is to replace the static array with a pointer and then dynamically allocating
the size as we require For EX
struct MyData
{
int length ;
char* package;
};
and then
package = (char*)malloc(SOME_RUNTIME_SIZE) ;
Now my question is that is this the most efficient way to cater to the requirement OR is there any other method .. maybe using STL data structures like growable arrays etc etc .
we want a solution where most of the code that works for the static char array should work for the new structure too ..
Much, much better/safer:
struct my_struct
{
std::vector<char>package;
};
To resize it:
my_struct s;
s.package.resize(100);
To look at how big it is:
my_struct s;
int size = s.package.size();
You can even put the functions in the struct to make it nicer:
struct my_struct
{
std::vector<char>package;
void resize(int n) {
package.resize(n);
}
int size() const {
return package.size();
}
};
my_struct s;
s.resize(100);
int z = s.size();
And before you know it, you're writing good code...
using STL data structures like growable arrays
The STL provides you with a host of containers. Unfortunately, the choice depends on your requirements. How often do you add to the container? How many times do you delete? Where do you delete from/add to? Do you need random access? What performance gurantees do you need? Once you have a sufficiently clear idea about such things look up vector, deque, list, set etc.
If you can provide some more detail, we can surely help pick a proper one.
I would also wrap a vector:
// wraps a vector. provides convenience conversion constructors
// and assign functions.
struct bytebuf {
explicit bytebuf(size_t size):c(size) { }
template<size_t size>
bytebuf(char const(&v)[size]) { assign(v); }
template<size_t size>
void assign(char const(&v)[size]) {
c.assign(v, v+size);
}
// provide access to wrapped vector
std::vector<char> & buf() {
return c;
}
private:
std::vector<char> c;
};
int main() {
bytebuf b("data");
process(&b.buf()[0], b.buf().size()); // process 5 byte
std::string str(&b.buf()[0]);
std::cout << str; // outputs "data"
bytebuf c(100);
read(&c.buf()[0], c.buf().size()); // read 100 byte
// ...
}
There is no need to add many more functions to it, i think. You can always get the vector using buf() and operate on it directly. Since a vectors' storage is contiguous, you can use it like a C array, but it is still resizable:
c.buf().resize(42)
The template conversion constructor and assign function allows you to initialize or assign from a C array directly. If you like, you can add more constructors that can initialize from a set of two iterators or a pointer and a length. But i would try keeping the amount of added functionality low, so it keeps being a tight, transparent vector wrapping struct.
If this is C:
Don't cast the return value of malloc().
Use size_t to represent the size of the allocated "package", not int.
If you're using the character array as an array of characters, use a std::vector<char> as that's what vectors are for. If you're using the character array as a string, use a std::string which will store its data in pretty much the same way as a std::vector<char>, but will communicate its purpose more clearly.
Yep, I would use an STL vector for this:
struct
{
std::vector<char> package;
// not sure if you have anything else in here ?
};
but your struct length member just becomes package.size ().
You can index characters in the vector as you would in your original char array (package[index]).
use a deque. sure a vector will work and be fine, but a deque will use fragmented memory and be almost as fast.
How are you using your structure?
Is it like an array or like a string?
I would just typedef one of the C++ containers:
typedef std::string MyData; // or std::vector<char> if that is more appropriate
What you have written can work and is probably the best thing to do if you do not need to resize on the fly. If you find that you need to expand your array, you can run
package = (char*)realloc((void*)package, SOME_RUNTIME_SIZE) ;
You can use an STL vector
include <vector>
std::vector<char> myVec(); //optionally myVec(SOME_RUNTIME_SIZE)
that you can then resize using myVec.resize(newSize) or by using functions such as push_back that add to the vector and automatically resize. The good thing about the vector solution is that it takes away many memory management issues -- if the vector is stack-allocated, its destructor will be called when it goes out of scope and the dynamically-allocated array underlying it will be deleted. However, if you pass the vector around, the data will get copied that can be slow, so you may need to pass pointers to vectors instead.