Reputation: 167
I have multiple arrays of various lenghts defined:
int arr1[] = {1, 2, 3, 4};
int arr2[] = {1, 3, 5, 7, 9};
int arr3[] = {6, 8, 11, 5, 2, 3, 6};
I'm passing these to a function that will do something with each element inside of the array:
void procesArr(int* array, int arrayLen) {
for (int i = 0; i < arrayLen; i++) {
// Do something, like print the value
cout << "array[" << i << "]: " << array[i] << endl;
}
}
Then I can do:
processArr(arr1);
Which results in:
array[0]: 1
array[1]: 2
array[2]: 3
array[3]: 4
But now I want to build a sequence of those individual arrays (the length of the sequence is not constant, can be from 2 to 5 individual arrays):
int seq1[] = {*arr1, *arr2, ..., *arrN};
... and be able to pass that to a function that would do the same. However, without each array's length, a for loop would have no idea what the upper bound of each array is.
The end result I'd like is a function that will take the sequence as argument, then separate and process each individual array, separately. Essentially something like this:
processSequence(seq1) { // I think I need to include sizeof(seq1) here
for (int s = 1; s < [length of seq1]; s++;) {
// process each individual array
for (int a = 1; a < [length of individual array]; a++) {
cout << "seq1[" << s << "][" << a << "]: " << seq[s][a] << endl;
}
}
}
And it would then produce something like:
// First array
seq1[0][0] = 1
seq1[0][1] = 2
seq1[0][2] = 3
seq1[0][3] = 4
// Second array
seq1[1][0] = 1
seq1[1][1] = 3
seq1[1][2] = 5
seq1[1][3] = 7
seq1[1][4] = 9
This is where my lack of programming knowledge shows because I can't figure out how to do this.
Upvotes: 1
Views: 3818
Reputation: 141145
(int* array, int arrayLen)
So we have three arrays of int
s:
int arr1[] = {1, 2, 3, 4};
int arr2[] = {1, 3, 5, 7, 9};
int arr3[] = {6, 8, 11, 5, 2, 3, 6};
Then we can:
// Create an array of pointers to these arrays
// "Array of type" is implicitly converted to "pointer to type"
// Type `int[X]` is implicitly converted to `int*`
int *arrs[] = { arr1, arr2, arr3, };
// Create an array of lengths of the arrays inside
size_t arrslenin[] = { 4, 5, 7 };
// And we have the array of pointers has the length itself
size_t arrslen = 3;
Then we can pass it all to our function:
void processSequences1(int **arrs, size_t *arrslenin, size_t arrslen) {
// iterate over elements in arrs
for (size_t i = 0; i < arrslen; ++i) {
// iterate over elements of the arrays inside arrs
for (size_t j = 0; j < arrslenin[i]; ++j) {
// print
std::cout << "seq1[" << i << "][" << j << "]: " << arrs[i][j] << std::endl;
}
}
}
// call
processSequences(arrs, arrslenin, arrslen)
We can do the same with different structure - ie store the pointer with length together, in an object. Then pass array of these objects to our function. Ex. we can declare a "span" object that represents a span, a region in memory:
// it begs to write template<typename T> here
struct span {
int *pnt;
size_t len;
// get size from type
template<size_t N>
span(int (&p)[N]) : pnt(p), len(N) {}
// accessors
size_t size() const { return len; }
int* data() { return pnt; }
int& operator[](size_t x) { return pnt[x]; }
};
Then create an array of spans:
span spans[3] = { span(arr1), span(arr2), span(arr3), };
size_t spanscnt = 3;
And pass it to our function:
void processSequences2(span *spans, size_t spanscnt) {
// iterate over elements in spans array
for (size_t i = 0; i < spanscnt; ++i) {
// iterate over elements in the array inside spans[i]
for (size_t j = 0; j < spans[i].size(); ++j) {
// print
std::cout << "seq1[" << i << "][" << j << "]: " << spans[i][j] << std::endl;
}
}
}
// call
processSequences(spans, spanscnt);
Or use STL and create ex. vector of vectors of ints (or use std::span from C++20, if available and use vector of spans). Below I use vector of vectors:
void processSequences3(std::vector<std::vector<int>> &v) {
for (size_t i = 0; i < v.size(); ++i) {
for (size_t j = 0; j < v[i].size(); ++j) {
std::cout << "seq1[" << i << "][" << j << "]: " << v[i][j] << std::endl;
}
}
}
void f() {
// note that values inside the arrays will be copied to vector
std::vector<std::vector<int>> v = {
std::vector<int>(arr1, arr1 + 4),
std::vector<int>(arr2, arr2 + 5),
std::vector<int>(arr3, arr3 + 7),
};
processSequences3(v);
}
Tested on tutorialspoint.
Upvotes: 2
Reputation: 880
In c and c++ you pass an array as a printer to the first element. The callee has no idea of the size. As you have noticed, you have to pass the size along the pointer. Another approach is to pass a special value at the last element of the array. This is how the zero-terminated strings work. Yet another approach is to reserve the first few elements to store the array size. Or embed the array in a structure which also started the size.
In c++ stl this is all solved by the vector class, which wraps the array, managers the size, growing and reducing the size of the array and other concerns.
Therefore, in c++ don't use the naked raw array but use vectors.
Upvotes: 1