C ++で配列を渡すには、一般に2つの方法があります。1つはテンプレートを使用し、C ++固有であり、もう1つはテンプレートを使用せず、CプログラムとC++プログラムの両方で使用できます。テンプレートバージョンの例を次に示します。
#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);
}
そして、これは非テンプレートの方法の例です:
#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);
}
どちらの場合も、配列自体がポインタに減衰することに注意してください。つまり、両方の場合accept_array()
と同じように機能するように渡されます。const int *array
唯一の違いは、テンプレートバージョンでは、コンパイラが配列のサイズを自動的に決定するのに役立つことです。
ただし、コンパイラは配列(配列の添え字)の長さを常に認識しているわけではないことに注意してください。たとえば、コードはより複雑で動的な割り当てを伴う場合があります。この場合、コンパイラが認識しているのは、1つ以上の要素へのポインタであるということだけですが、要素がいくつあるかはわかりません(存在する場合)。 :-))。これは、テンプレートバージョンを使用するのが不便な例です(ただし、執拗なプログラマーは、潜在的に危険な型キャストを通じてそれを使用する可能性があります)。
#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 :)
}
したがって、動的配列の場合、常に長さを知っている必要があります。ただし、プログラマーが配列の長さを持ち歩きたくない場合は、配列の終わりを決定するために使用される規則を導入できます(無効なメモリ/要素へのアクセスを回避するため)。たとえば、プログラマーは、配列の長さに関係なく、最後の要素は常に0になると言うかもしれません。そして、コードはそれを念頭に置いて構築されています(これは少し危険で、特別な注意が必要で、特定の要素を格納できない場合があります)配列内の値—他のコードが通常の値ではなく配列の終わりインジケーターであると見なさずに配列内に0の値を持つことはできないと言います)。ほとんどの場合、このアプローチはポインターの配列に使用され、プログラマーはnilポインターが終了のインジケーターであることに同意します。しかし、文字列はそのアプローチの非常に良い例です。\0
文字列の終わりのインジケータです。例えば:
#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";
}
また、テンプレートバージョンは特定の場合に非常に役立つ場合があります。たとえば、コンパイル時のアサーションを使用して、配列の長さが十分であること、または配列が大きすぎないことを確認できます。2つのアプローチを組み合わせることもできます。参考までに、完全な例を次に示します。
#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);
}
ああ、そして私はあなたに行列の例を示すのをほとんど忘れていました。まったく同じように機能します。同じように短くするために、プログラムはコンパイル時にマトリックスの長さを認識せず、代わりにランタイムユーザーの入力で動作するため、テンプレートバージョンは実行しません。これが私があなたのコードを書く方法です:
#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;
}
それが役に立てば幸い。幸運を!