配列,構造体と文字列

概要
このページ(章)ではより大きな記憶領域を変数として扱う方法について解説する.
目次

配列

「配列」とは同じ型のデータ型を集めたものである.配列を用いると,関連のある複数のデータをまとめて扱うことができる.例えば数学のベクトルを表現できる.

配列の定義

型と配列名(識別子),要素数を用いて配列を定義する.

length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1360.
length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1370.
  型 識別子[要素数];
  // 例:
  int n[5];

このとき,型が要素数の分だけ 連続で メモリが確保される(次図参照).識別子[要素番号]で表した変数は,他の変数と同じように扱うことができる (n[0] = 10; や n[0] = n[1] + n[2]; など).

配列の定義で確保されるメモリ
配列の定義で確保されるメモリ

備考

配列で注意しなければならないことは, [ ] の中(添え字)は0から始まっていることである. 今回の場合,図に示したように n[0] 0 n[4] が利用できる変数となる. つまり要素数は5だが, n[5] は存在しない.問題なのは n[5] を使用するプログラムを組んだとしてもコンパイラは注意してくれないことだ. しかも,実行時にもエラーにならないこともある.だから, プログラマが責任を持って管理する しかない.

配列の例

length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1360.
length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1370.
  #include <iostream>
  using namespace std;
  int main(int argc, char**argv)
  {
    int n[5];
    n[0]=10;
    n[1]=12;
    n[2]=25;
    n[3]=n[0]+n[1];
    n[4]=n[2]*n[3]%15;
    cout<<"n={";
    cout<<n[0];
    for (int i(1); i<5; ++i)
      cout<<", "<<n[i];
    cout<<"}"<<endl;
    return 0;
  }

結果

 n={10, 12, 25, 22, 10}

配列データの初期化

配列の定義 で紹介したサンプルプログラムでは配列の各値に一つ一つ代入したが,ここでは配列宣言時に同時に初期化する方法を紹介する.方法は簡単で,{ } と,(カンマ) を使って 初期化リスト を次のように書くだけでよい.

length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1360.
length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1370.
  int n[5]={11, 12, 13, 14, 15};
配列の初期化 = 初期値の代入
配列の初期化 = 初期値の代入

この初期化方法での注意点を2点書いておく.

  • 初期化子が要素数で指定した要素数より大きい場合はコンパイルエラーとなる.
length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1360.
length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1370.
  int no[5] = {11, 12, 13, 14, 15, 16};    // <-- コンパイルエラー
  • 初期化の足りない要素は 0 で初期化される.
    length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1360.
    length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1370.
      int no[5] = {1};    //  {1, 0, 0, 0, 0}で初期化される.

多次元配列

多次元配列は,数学の行列などのように,添え字(インデクス)を複数用いたい場合に使う.以下では2次元配列を例として考える.

2次元配列とは,1次元配列(前述した配列)を縦横に並べて,行列のように2次元としたものである.N次元にすると添え字の数がN個になる.

2次元配列の定義

型と配列名(識別子),要素数1,要素数2を使って定義を行う.1次元と違うところは添え字の数が2つになったところである.

length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1360.
length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1370.
  型 識別子[要素数1][要素数2];
  // 例:
  int n[3][4];

このとき次の図のようにメモリが確保される.

2次元配列の定義
2次元配列の定義

2次元配列データの初期化

1次元配列のときと同様,配列の宣言と同時に初期化する方法を紹介する. やはり { } を使って初期化リストを書く.

#codeh(cpp){{
int n[3][4]
={{1,2,3,4},
{5,6,7,8},
{9,10,11,12}}; }}

基本的な決まりごとは1次元配列と同じである.

構造体

構造体とは,複数の変数をひとつに押し込めた である. 複合型 の一種である. ある学校の生徒のデータについて考える.生徒Aについてのデータとしては,名前,年齢,住所,電話番号などいろいろなデータが考えられる.これらのデータをたとえば,nameA, ageA, addressA, telA, ... などという変数に入れていったとする.生徒Bや,生徒CについてもnameB, nameC, ... などと変数を作っていくと,変数ばかり増えて収拾がつかなくなってしまう.そこで,構造体と言うものを考える.

構造体の宣言

構造体の宣言は次のようにする:

length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1360.
length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1370.
  struct 構造体ダグ
  {
    int x;  // 構造体メンバー
    double y;
    char z;
  };

例として,上で説明した生徒A, B, Cを宣言する.

  • 構造体タグ → Student (生徒型)
  • 構造体メンバー → int age (年齢), char name[32] (名前)
  • 各生徒を記憶する変数 → Student a, b, c

この構造体の宣言は,次のようになる.

length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1360.
length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1370.
  struct Student
  {
    int age;
    char name[32];
  };
  Student a, b, c;

つまり,構造体 (struct) Student は age, name の2つのデータを持っているということを表している.そして, Student には a, b, c という3人がいる,という宣言を行っている.新しく生徒Dを宣言したい場合,以下のように宣言する.

length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1360.
length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1370.
  Student d;

これは構造体 (struct) Student の型を持つ変数 d を宣言している.

構造体変数の使い方

構造体の各メンバーは, 構造体変数名.メンバー名 のようにピリオド . を用いて指定する.また,構造体を構造体にコピーすることもできる.以下に例を示す.

length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1360.
length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1370.
  #include <iostream>
  using namespace std;
  // 構造体の定義
  struct  Point
  {
    int x;
    int y;
  };
  int main(int argc, char**argv)
  {
    Point a, b;
    a.x = 1;
    a.y = 2;
    b = a;  // 構造体の代入
    // 中身の出力
    cout<<"a=("<<a.x<<","<<a.y<<")"<<endl;
    cout<<"b=("<<b.x<<","<<b.y<<")"<<endl;
    return 0;
  }

結果

 a=(1,2)
 b=(1,2)

構造体の初期化

構造体の初期化は配列と同じようにすることができる.ただし,当然だが,与える初期値は各変数の型と同じ型でなければならない.

正しい例:

length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1360.
length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1370.
  struct Test
  {
    char c;
    int x;
  };
  Test test1={'b',2};

間違った例:

length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1360.
length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1370.
  struct Test
  {
    char c;
    int x;
  };
  Test test1={5.3,2};

構造体の配列の初期化の例

length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1360.
length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1370.
  #include <iostream>
  using namespace std;
  struct  Point  // 構造体の定義
  {
    int x;
    int y;
  };
  int main(int argc, char**argv)
  {
    Point p[3]
      = { {1,2}, {3,4}, {5,6} }; // 構造体の初期化
    for(int i=0; i<3; ++i)
      cout<<"p["<<i<<"]=("<<p[i].x<<","<<p[i].y<<")"<<endl;  // 中身の出力
    return 0;
  }

結果

 p[0]=(1,2)
 p[1]=(3,4)
 p[2]=(5,6)

メモリ

次の構造体を宣言したとき,メモリは以下のように確保される.

length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1360.
length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1370.
  struct Test
  {
    int x;
    char y[20];
    int z;
  };
メモリ空間
x(4バイト)
y[20](20バイト)
z(4バイト)

備考

 int は4バイト, char は1バイトの処理系の場合.

文字と文字列

C++には string クラスという文字列型が用意されており,文字列処理がとても簡単になっている.以下に示すサンプルを見れば, string クラスの基本的な使い方は容易にわかるだろう.

length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1360.
length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1370.
  #include <iostream>
  #include <string>  // 文字列クラスを読み込む
  using namespace std;
  // 文字列変数を表示するためのマクロ
  #define PRINT(str) cout<<#str "= \""<<str<<"\""<<endl
  int main(int argc, char**argv)
  {
    string word="other";  // 文字列クラスの定義
    PRINT(word);
    word="m"+word;  // 文字列を連結して代入
    PRINT(word);
    word[0]='f';  // 文字要素に代入
    word[1]='a';
    PRINT(word);

 char c name[10]; // 旧来の文字列
 strcpy(c_name,word.c_str()); // 文字列のコピー
 // word.c_str() によってこれまでの文字列型のデータを取得できる
 PRINT(c_name);
    return 0;
  }

string クラスは便利だが,このクラスは旧来の文字列型 char str[length] をクラス化することによって作られているため,場合によっては処理速度が旧来の文字列型に比べて遅くなることがある.また, *ライブラリをCとC++の両方で利用できるようにするために,文字列を旧来の文字列型で実装するライブラリが多い* のも事実だ.そこで,以下では旧来の文字列型を学ぶ.

なお, string クラスの詳細な使い方は

あたりを参照するとよい.

文字

人間は「A」という文字データを表すのに 'A' と記述する.コンピュータは 'A' という記述を 65 というコードで扱う.

この 'A' に対応する 65 という代表的なコードに「ASCIIコード」がある.ASCIIコードを表にしたものを「ASCIIコード表」と言う.ASCIIコードは128個の文字を1バイトに割り当てている(ページ末にASCIIコード表を乗せている).以下に 'z' を文字として出力,コードとして出力した結果を載せておく.

length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1360.
length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1370.
  #include <iostream>
  using namespace std;
  int main(int argc, char**argv)
  {
    char c = 'z';  // 1文字はシングルクォーテーションで囲む
    int x;
    x = c;  // c をint型に代入
    cout<<"文字:\t"<<c<<endl;
    cout<<"文字コード(10進数):\t"<<(int)c<<endl;  // c をint型に変換 (キャスト)
    cout<<"文字コード(16進数):\t"<<hex<<(int)c<<dec<<endl;
    cout<<"x:\t"<<x<<endl;
    return 0;
  }

結果

 文字:   z
 文字コード(10進数):     122
 文字コード(16進数):     7a
 x:      122

数字と文字としての数字

各文字には文字コードというものが割り当てられているということが分かってもらえたと思う.次に注意したいのは,数字の1と文字の'1'が違うと言うことだ.下に載せているASCIIコード表の'1'のところを見て頂きたい.10進コードで49になっている.つまり,文字'1'を上記の方法で数字に変換すると,49になる. 文字としての'1'を数字の1にうまく変換したい場合は,上記のプログラムの x = c; の部分を x = c ? '0'; に書き換えて, c に1桁の数字を入れて実行すればよい.1が正しく数字の1としてxに入るはずである.どうしてこのようになるかASCIIコード表を見て考えてみよう.

文字列

文字列,つまり,文字の集まりは,文字の配列で表す.先に例を書いてみよう.

length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1360.
length() used on @lines (did you mean "scalar(@lines)"?) at /usr/bin/code2html line 1370.
  char ch = 'A' ; // 1文字
  char str[4] = "ABC"; // 文字列

配列 str はメモリ上に,次のように記憶されている.

メモリ空間
str[0]=65('A'の文字コード)
str[1]=66('B'の文字コード)
str[2]=67('C'の文字コード)
str[3]=NULL(ナル文字)

文字列入力したときのメモリ上の最後の NULL は,ナル文字という特殊な文字で, 文字列の最後を表す記号 である.これを忘れると,バグが発生する.

文字列の代入は,文字列を " (ダブルコーテーション) で囲む. str[4]="ABC" のように書くと,ABCのあとにコンパイラが自動的に NULL を入れてくれる. 自分で領域を確保するときは,NULL が最後に入れられることを考慮して入力する文字列 +1 バイトで容量を確保する必要がある.

付録: ASCII文字コード表

ASCII文字コード表
ASCII文字コード表

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2018-08-30 (木) 07:17:05 (75d)