I know this question has been asked, but I haven't really seen an answer that makes sense to me.
I'm writing a function to calculate determinants in C++. To do this, I need to pass a matrix.
My code looks like the following:
#include <stdlib.h>
#include <stdio.h>
double determinant(int N, double M[N][N]);
int main(){
double myMatrix[3][3] = {{1,2,3}, {4,5,6}, {3,6,1}};
double okay = determinant(4, myMatrix);
printf("determinant = %f\n", okay);
}
double determinant(int N, double M[N][N]){
double det=0.0;
//if N=2 matrix, use the easy formula
if(N==2){
det = M[0][0]*M[1][1] - M[0][1]*M[1][0];
}
//otherwise, find minor matrices, multiply by top row
else {
double Mminor[N-1][N-1];
double sign = 1.0;
for(int i=0; i<N; i++){
//get the minor matrix
for(int a=1;a<N;a++){
int m=0;
for(int b=0;b<N;b++){
if(b!=i){
Mminor[a-1][m] = M[a][b];
m++;
}
}
}
//add top row element times determinant of its minor
det += sign*M[0][i]*determinant(N-1, Mminor);
//swap the sign
sign *= -1.0;
}
}
return det;
}
If I compile this as C and use the C99 compiler, it runs fine and with no issues, giving the correct values for several different test matrices.
But I don't need this to compile as C, I need it to compile as C++. And it will not compile as C++. The GNU compiler gives the following errors:
determinant.c:25:24: error: no matching function for call to 'determinant'
det += sign*M[0][i]*determinant(N-1, Mminor);
^~~~~~~~~~~
determinant.c:5:8: note: candidate function not viable: no known conversion from 'double [N - 1][N - 1]' to
'double (*)[N]' for 2nd argument
double determinant(int N, double M[N][N]){
^
determinant.c:36:16: error: no matching function for call to 'determinant'
double okay = determinant(4, myMatrix);
^~~~~~~~~~~
determinant.c:5:8: note: candidate function not viable: no known conversion from 'double [4][4]' to 'double (*)[N]'
for 2nd argument
double determinant(int N, double M[N][N]){
I know that C and C++ have a deep prejudice against 2D arrays and don't like them and refuse to work with them, but everything I've read has suggested that by specifying the size N as an argument that it should work. And it does. In C99. But not with the g++ compiler (neither C++99 nor C++11).
Is there some specific compiler flag I have to use? Or some other way to do this?
To be clear: I need the size of the matrix to be flexible, because it's going to be different every time I call the function.
I'd like to avoid using 1D arrays to make 2D arrays, if at all possible. I know how to do this with 1D arrays, I'd just rather do this in a more natural and elegant way.
Thank you.
Edit: And I know you're going to suggest I use vector<> instead. Using vector<> isn't optimal because this all is supposed to go into a much larger program at around 20,000 lines that only uses arrays.
Edit 2: The GNU compiler documentation says that it implements VLAs in C++ as an extension of the language. Several other past posters have posted their surprise that VLAs work and asking how to turn the functionality off. But how does one turn it on?
In C++, you might use template:
#include <iostream>
double determinant(const double (&M)[2][2]){
return M[0][0] * M[1][1] - M[0][1] * M[1][0];
}
template <std::size_t N>
double determinant(const double (&M)[N][N]){
double det=0.0;
double Mminor[N - 1][N - 1];
double sign = 1.0;
for (int i = 0; i < N; i++) {
//get the minor matrix
for (int a = 1; a < N; a++) {
int m=0;
for (int b = 0; b < N; b++) {
if (b != i) {
Mminor[a - 1][m] = M[a][b];
m++;
}
}
}
//add top row element times determinant of its minor
det += sign * M[0][i] * determinant(Mminor);
//swap the sign
sign *= -1.0;
}
return det;
}
int main(){
const double myMatrix[3][3] = {{1,2,3}, {4,5,6}, {3,6,1}};
double okay = determinant(myMatrix);
std::cout << "determinant = " << okay << std::endl;
}