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!