I have been tasked with creating a function template that will add all elements of any 2-dimensional integer array as part of an exercise for a programming theory language course.
I have tried several methods and keep getting compiler errors that I don't understand.
1)
template<typename T>
T addArraysOne(T rows, T cols, T arr[][cols])
{
T output;
for(int i = 0; i < rows; i )
{
for(int j = 0; j < cols; j )
{
output = arr[i][j];
}
}
return output;
}
This one errors as the parameter for the number of columns is "not a constant".
2)
int addArraysTwo(int rows, int cols, int** arr)
{
int output;
for(int i = 0; i < rows; i )
{
for(int j = 0; j < cols; j )
{
output = *arr[i*rows j];
}
}
return output;
}
This one errors when I try and call it with addArraysTwo(5, 5, arr);
because it "does not match the function call", when "arr" is a 2 dimensional int array. I haven't found any problems particularly similar to this online. Any suggestions on how to modify these so that I do not piss off the compiler would be much appreciated. Thanks!
CodePudding user response:
You can use the following program that uses template nontype parameters.
Version 1: For integer arrays
#include <iostream>
//a function template that takes a 2D int array by reference
template< std::size_t N, std::size_t M>
int calculateSum(const int (&arr)[N][M])
{
int sum = 0;
//iterate through rows and colums of the passed 2D int array
for(std::size_t row = 0; row < N; row)
{
for(std::size_t col = 0 ; col < M; col)
{
sum = arr[row][col];
}
}
return sum;
}
int main()
{
int arr[2][3] = {{1,2,3},{3,4,5}};
std::cout<<"Sum is: "<<calculateSum(arr)<<std::endl;
return 0;
}
Version 2: For array of arbitrary type
#include <iostream>
//a function template that takes a 2D array(with elements of type T) by reference
template< typename T, std::size_t N, std::size_t M>
T calculateSum(const T (&arr)[N][M])
{
T sum{0};
//iterate through rows and colums of the passed 2D T array
for(std::size_t row = 0; row < N; row)
{
for(std::size_t col = 0 ; col < M; col)
{
sum = arr[row][col];
}
}
return sum;
}
int main()
{
double arr[2][3] = {{1.4,2,3},{3.6,4,5.45}};
std::cout<<"Sum is: "<<calculateSum(arr)<<std::endl;
return 0;
}
CodePudding user response:
Your first method, variable-lengthed-array only supported by c99 (and not adopted by c I believe?). otherwise, the length of the array must be known at compile time. And at least with c 17 and below, any parameter of array type is adjusted to the corresponding pointer type by the compiler, so it is no difference between int f(int a[5])
and int f(int a[])
and int f(int* a)
。But for 2d arrays, the size of the second dimension must be known at compile time. int f(int a[][2])
(which is equavalent to int f(int(*a)[2])
) is OK, but int f(int a[][])
is not.
Your second method, 2d arrays are not implicitly convertable to pointer of pointers, but pointer to 1d arrays:
int arr[2][3];
int **p = arr; // Error
int(*p)[3] = arr; // OK
so one of the solutions is just:
template<typename T>
T addArraysOne(T rows, T cols, T* arr)
{
T output = 0; // NOTE: initialize to 0
for(int i = 0; i < rows; i )
{
for(int j = 0; j < cols; j )
{
output = arr[i*cols j]; // NOTE: not i*rows j
}
}
return output;
}
and called it with:
int arr[2][3];
addArraysOne(2, 3, &arr[0][0]);