2.2.1. 固定サイズの1次元配列をグローバル変数として定義する例
この例ではグローバル変数 data1, data2 として配列を2つ割り当てています。
少しずつソースを見ていきます。
1//
2// s001 : fixed size array on static data area
3//
4
5#include <iostream>
6
7const int N_SIZE = 10;
8
9// グローバル変数として定義された固定長の(コンパイル時点で値が確定する)配列
10double data1[N_SIZE];
11double data2[N_SIZE];
data1,data2はそれぞれ double の配列 になります。
data1[i]
などと添え字をつけて普通は使いますが、C++では配列名の data1
単体で
も意味(値)を持ちます。 data1
とだけ書くと配列の先頭アドレスを示す定数にな
ります。配列の先頭アドレスが欲しかったら、 data1
と書けばいいわけです。
定数ですので data1
単体では、代入の左辺に来ることはできません。
この値は doubleのポインタ変数に代入できます。
12// 配列にダミーデータを設定する
13void set_dummy_data(double *d, int n)
14{
15 for (int i = 0; i < n; i++) {
16 d[i] = static_cast<double>(i) / static_cast<double>(n);
17 }
18 // static_cast<double>(x) について
19 // i や n は整数型で、C++では整数型同士の除算では計算結果も整数型になり
20 // 切り捨てられてしまう。
21 // 結果を少数で得るには double型(またはfloat型)に変換してから計算する必要がある。
22 // 古い文法では d[i] = ((double)i) / ((double) n); と書いたが現行の文法では上記の
23 // static_cast<型名>(値) を使う。
24}
最初の関数 set_dummy_data
は、配列にダミーのデータを格納する関数です。
引数dの型は、doubleのポインタ型です。 ここには配列の先頭アドレスを渡すことができます。
27void copy_data(double *dest, const double *src, int n)
28{
29 // 引数の dest (destination) と src (source) では srcにだけ、const指定がついている
30 // constをつけた変数には代入はエラーになる。関数の中で、代入する必要性のない引数は const
31 // 指定をつけることで、誤って変更してしまうことを防止できる。また、関数を使う人は、
32 // const指定を見ることで、その引数は改変されないことを確信できる。
33 for (int i = 0; i < n; i++) {
34 dest[i] = src[i]; // 左辺と右辺を入れ替えるとエラーになる。
35 }
36}
次の関数 copy_data
は、配列から配列へ中身をコピーする関数です。
第二引数は const double *d
として宣言されています。
こう書くと、ポインタdが指しているメモリの中身 *d
が定数として扱われ、そこへの
代入が禁止され、エラーになります。d 単体には const がついていないので、 d
は
変数であり、dへの代入は可能です。
もし const double * const d
と書けば、*d
にも d
にも代入禁止になります。
38void print_data(const double *d, int n)
39{
40 std::cout << "[";
41 for (int i = 0; i < n; i++) {
42 std::cout << d[i];
43 if (i < n - 1) {
44 std::cout << ", ";
45 }
46 }
47 std::cout << "]\n";
48}
次の関数では配列の中身を印字しています。
49int main(int argc, const char *argv[])
50{
51 std::cout << "s001\n";
52
53 // 静的領域のメモリの初期値は 0
54 // ただし自分で初期値を入れることが推奨される。
55 std::cout << "Before initialization\n";
56 print_data(data1, N_SIZE);
57
58 // 配列の名前のデータ型は配列要素のアドレス。
59 // 受ける側のdoubleのポインタに代入できる。
60 set_dummy_data(data1, N_SIZE);
61 std::cout << "After initialization\n";
62 print_data(data1, N_SIZE);
63
64 copy_data(data2, data1, N_SIZE);
65 std::cout << "After array copy\n";
66 print_data(data2, N_SIZE);
67
68 return EXIT_SUCCESS; // exit status code 0
69}
最後に main 関数が書いてあります。
59行目を見ると、double のポインタを受け取る引数に、配列変数 data1
を渡してい
ます。配列変数はこのようにポインタ変数に代入ができます。
全体のソースを以下に示します:
1//
2// s001 : fixed size array on static data area
3//
4
5#include <iostream>
6
7const int N_SIZE = 10;
8
9// グローバル変数として定義された固定長の(コンパイル時点で値が確定する)配列
10double data1[N_SIZE];
11double data2[N_SIZE];
12
13// 配列にダミーデータを設定する
14void set_dummy_data(double *d, int n)
15{
16 for (int i = 0; i < n; i++) {
17 d[i] = static_cast<double>(i) / static_cast<double>(n);
18 }
19 // static_cast<double>(x) について
20 // i や n は整数型で、C++では整数型同士の除算では計算結果も整数型になり
21 // 切り捨てられてしまう。
22 // 結果を少数で得るには double型(またはfloat型)に変換してから計算する必要がある。
23 // 古い文法では d[i] = ((double)i) / ((double) n); と書いたが現行の文法では上記の
24 // static_cast<型名>(値) を使う。
25}
26
27void copy_data(double *dest, const double *src, int n)
28{
29 // 引数の dest (destination) と src (source) では srcにだけ、const指定がついている
30 // constをつけた変数には代入はエラーになる。関数の中で、代入する必要性のない引数は const
31 // 指定をつけることで、誤って変更してしまうことを防止できる。また、関数を使う人は、
32 // const指定を見ることで、その引数は改変されないことを確信できる。
33 for (int i = 0; i < n; i++) {
34 dest[i] = src[i]; // 左辺と右辺を入れ替えるとエラーになる。
35 }
36}
37
38void print_data(const double *d, int n)
39{
40 std::cout << "[";
41 for (int i = 0; i < n; i++) {
42 std::cout << d[i];
43 if (i < n - 1) {
44 std::cout << ", ";
45 }
46 }
47 std::cout << "]\n";
48}
49
50int main(int argc, const char *argv[])
51{
52 std::cout << "s001\n";
53
54 // 静的領域のメモリの初期値は 0
55 // ただし自分で初期値を入れることが推奨される。
56 std::cout << "Before initialization\n";
57 print_data(data1, N_SIZE);
58
59 // 配列の名前のデータ型は配列要素のアドレス。
60 // 受ける側のdoubleのポインタに代入できる。
61 set_dummy_data(data1, N_SIZE);
62 std::cout << "After initialization\n";
63 print_data(data1, N_SIZE);
64
65 copy_data(data2, data1, N_SIZE);
66 std::cout << "After array copy\n";
67 print_data(data2, N_SIZE);
68
69 return EXIT_SUCCESS; // exit status code 0
70}
実行例を示します:
% ./s001
s001
Before initialization
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
After initialization
[0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
After array copy
[0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]