Reputation: 23
I'm trying to pass a user-defined array (defined here as matrix1) into a function (det) with the aim of calculating the determinant. Any help would be appreciated, I'm sure there's an easy way to do this, but my various attempts using pointers/vectors have been futile!
#include <iostream>
#include <math.h>
#include <vector>
using namespace std;
int c, d;
int matrix1(int nS)
{
cout << "Enter the elements of first matrix: ";
int matrix1[10][10];
for (c = 0 ; c < nS ; c++ )
for (d = 0 ; d < nS ; d++ )
cin >> matrix1[c][d];
for (c = 0 ; c < nS ; c++ )
{
for (d = 0 ; d < nS ; d++ )
cout << matrix1[c][d] << "\t";
cout << endl;
}
}
int det(int nS, int matrix)
{
int det;
int iii;
for (iii = 0; iii < nS; iii++)
{
double a;
double b;
int c;
for (c = 0; c<nS; c++)
{
// cout << (iii+c)%nS << endl;
// cout << (nS-1) - (iii+c)%nS << endl;
int z = (iii+c)%nS;
cout << c << ", " << z << endl;
a *= matrix[c][z];
b *= matrix[c][(nS-1) - (iii+c)%nS];
}
det+= a-b;
}
cout << det << endl;
}
int main()
{
cout << "Enter the number of rows and columns of matrix: ";
int nS;
cin >> nS;
matrix1(nS);
det(nS, matrix1);
return 0;
}
Upvotes: 2
Views: 1503
Reputation:
There are generally two ways of passing arrays in C++. One that does use a template and is C++-specific and another one that does not use templates and can be used in both C and C++ programs. Here is an example of the template version:
#include <cstddef> // for std::size_t
#include <iostream> // for std::cout
#include <algorithm> // for std::copy
#include <iterator> // for std::ostream_iterator
template <std::size_t length>
static void accept_array(const int (&array)[length])
{
std::cout << "Got array of " << length << " elements:\t";
std::copy(array, array+length, std::ostream_iterator<int>(std::cout, ", "));
std::cout << " and that's all.\n";
}
int main()
{
int arr[10] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
accept_array(arr);
}
And here is an example of a non-template way:
#include <cstddef> // for std::size_t
#include <iostream> // for std::cout
#include <algorithm> // for std::copy
#include <iterator> // for std::ostream_iterator
static void accept_array(const int *array, std::size_t length)
{
std::cout << "Got array of " << length << " elements:\t";
std::copy(array, array+length, std::ostream_iterator<int>(std::cout, ", "));
std::cout << " and that's all.\n";
}
int main()
{
int arr[10] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
accept_array(arr, 10);
}
Please note that in both cases, an array itself is decayed to a pointer. In other words, it is being passed to accept_array()
function as const int *array
in both cases. The only difference is that in a template version, compiler helps you to automatically determine the size of array.
Note, however, that compiler does not always know about the length of array (array subscripts). For example, the code might be more complicated and involve a dynamic allocation, in which case the only thing that compiler knows is that it is a pointer to one or more elements, but it doesn't know how many elements are there (if any :-)). Here is an example where it would not be convenient to use a template version (even though an insistent programmer still could use it through potentially unsafe type casting):
#include <cstddef> // for std::size_t
#include <iostream> // for std::cout
#include <algorithm> // for std::copy
#include <iterator> // for std::ostream_iterator
static void accept_array(const int *array, std::size_t length)
{
std::cout << "Got array of " << length << " elements:\t";
std::copy(array, array+length, std::ostream_iterator<int>(std::cout, ", "));
std::cout << " and that's all.\n";
}
int main()
{
int *a1 = new int[5];
for (int i = 0; i < 5; ++i)
a1[i] = i+1;
accept_array(a1, 5); // In here, we know we have just allocated 5 elements.
// But compiler doesn't really know it. So calling a
// template version just like that won't work. We must
// know how the length of the array...
delete [] a1; // Never forget to free what you have allocated :)
}
So for dynamic arrays you always must know the length. However, sometimes when programmers do not want to carry array's length around, they can introduce a convention that is used to determine the end of array (to avoid accessing invalid memory/elements). For example, a programmer may say that no matter how long the array is, the last element will always be 0. And the code is built with that in mind (which is a bit dangerous and requires extra care and may not allow for storing certain values in array — say you cannot have 0 value in array without other code thinking it is an end of array indicator rather than a normal value). Most often this approach is used for arrays of pointers and programmers agree that a nil pointer is an indicator of the end. But strings are a very good example of that approach where \0
is an end of string indicator. For example:
#include <iostream>
static unsigned int my_strlen(const char *value)
{
// How long is our string? We don't really know unless we
// go through its characters and count them until we see '\0'.
// WARNING: Please do not use this function in your code as it is
// extremely inefficient and serves an example purpose:
unsigned int result = 0;
while (value[result] != '\0')
++result;
return result;
}
int main()
{
const char str[] = "Hello, world!";
std::cout << "The length of '" << str << "' is " << my_strlen(str)
<< " bytes.\nThe size of the array where the data is stored is "
<< sizeof(str)/sizeof(str[0]) << " bytes.\n";
}
Also, a template version might be very useful in certain cases. For example, you can use compile-time assertions to make sure that array length is sufficient or the array is not too large. You can also mix two approaches together. Here is a complete example for your reference:
#include <cstddef>
#include <iostream>
#include <algorithm>
#include <iterator>
static void accept_array(const int *array, std::size_t length)
{
std::cout << "Got array of " << length << " elements:\t";
std::copy(array, array+length, std::ostream_iterator<int>(std::cout, ", "));
std::cout << " and that's all.\n";
}
template <std::size_t length>
static void accept_array(const int (&array)[length])
{
// Generally, we can just call a non-template version.
// However, in this case "length" is a compile-time expression
// and we can benefit from that. For example, by not letting users
// compile if array length is more than 10 elements:
static_assert(length <= 10, "Array is way too large"); // Beware: C++11 feature.
accept_array(array, length);
}
int main()
{
int *a1 = new int[5];
for (int i = 0; i < 5; ++i)
a1[i] = i+1;
accept_array(a1, 5);
delete [] a1;
int a2[10] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
accept_array(a2);
accept_array(a2, sizeof(a2)/sizeof(a2[0]));
// The below code would fail to compile:
// int a3[11] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
// accept_array(a3);
}
Oh, and I almost forgot to show you an example with matrices. It works exactly the same. For the same to keep it short, I won't do a template version since your program does not know the length of a matrix in compile-time and works with a run-time user's input instead. Here is how I would write your code:
#include <cstdlib>
#include <iostream>
#include <cmath>
static void grab_matrix(int **matrix, int nS)
{
std::cout << "Enter the elements of first matrix ("
<< nS << " by " << nS << "): " << std::flush;
for (int c = 0; c < nS; ++c)
for (int d = 0 ; d < nS; ++d)
std::cin >> matrix[c][d];
std::cout << "Thank you! You have entered the following:\n";
for (int c = 0; c < nS; ++c) {
for (int d = 0 ; d < nS ; d++ )
std::cout << matrix[c][d] << "\t";
std::cout << '\n';
}
std::cout << std::flush;
}
static void det(int **matrix, int nS)
{
std::cout << "Calculations:\n" << std::flush;
double d = 0;
for (int i = 0; i < nS; ++i) {
double a = 0;
double b = 0;
for (int c = 0; c < nS; ++c) {
int z = (i + c) % nS;
a *= matrix[c][z];
b *= matrix[c][(nS - 1) - (i + c) % nS];
std::cout << c << ", " << z << '\n';
}
d += a - b;
}
std::cout << d << std::endl;
}
int main()
{
std::cout << "Enter the number of rows and columns of matrix: "
<< std::flush;
int nS = 0;
std::cin >> nS;
if (nS <= 0) {
std::cerr << "Sorry, that's not a good number. Try again later!\n";
return EXIT_FAILURE;
}
int **matrix = new int*[nS];
for (int i = 0; i < nS; ++i)
matrix[i] = new int[nS];
grab_matrix(matrix, nS);
det(matrix, nS);
for (int i = 0; i < nS; ++i)
delete [] matrix[i];
delete [] matrix;
}
Hope it helps. Good Luck!
Upvotes: 1
Reputation: 3346
You have to declare the array inside your main function for other functions to access it as well. An array declared inside a function other than main has a local scope on the stack and it gets destroyed as soon the function body gets executed.
That being said, you have two entities with the same name, a matrix array and a function. This wont compiler so make their names unique. Declare your matrix array in main like this.
int matrix[10][10] ;
Now pass it to your input function matrix1
like this.
matrix1(matrix, nS) ;
And your matrix function would be like this.
int matrix1(int matrix[][10], int nS)
{
//code runs here
}
You can pass it to the det
function as well in a similar fashion. And it is better if you make the row and column numbers as const
so that you can change them later in your program easily.
const int ROWS = 10 ;
const int COLS = 10 ;
You can learn more on why the column number is passed and how a 2D array gets passed to a function in a similar answer here.
2D-array as argument to function
Upvotes: 3