第13講 ベクタの学習
第2話 1次元ベクタ

配列に似たものとして、ベクタがあります。
配列、ポインタ、ベクタは要素へのアクセス(代入と値取得)の方法に次のような違いがあります。

配列
@添え字Aアドレス(ポインタを利用)
ポインタ
@添え字Aアドレス
ベクタ
@添え字Aアドレス(ポインタを利用)B反復子

具体例で説明しましょう。

第11講第1話第11講2話に従いまして、新しいコンソールアプリケーションを作り、
次のようにコーティングしましょう。
#include<vector>
using namespace std;
using namespace System;

int main(){
  int a[3];
  int* b=(int* )malloc(3*sizeof(int));
  vector<int> c(3);

  //配列の要素への添え字による代入
  a[0]=1;
  a[1]=2;
  a[2]=3;
  //配列各要素の値の表示
  Console::WriteLine("配列各要素の値の表示");
  Console::WriteLine("{0} {1} {2}",a[0],a[1],a[2]);
  //ポインタを利用したアドレスによる配列各要素への代入
  b=a;
  *b=4;
  *(b+1)=5;
  *(b+2)=6;

  //配列各要素の値の表示
  Console::WriteLine("配列各要素の値の表示");
  Console::WriteLine("{0} {1} {2}\n",a[0],a[1],a[2]);

  //ポインタの場合の添え字による代入
  b[0]=1;
  b[1]=2;
  b[2]=3;
  //ポインタの場合の添え字による値の表示
  Console::WriteLine("ポインタの場合の添え字による値の表示");
  Console::WriteLine("{0} {1} {2}",b[0],b[1],b[2]);
  //ポインタの場合のアドレスによる代入
  *b=3;
  *(b+1)=4;
  *(b+2)=3;
  //ポインタの場合のアドレスによる値の表示
  Console::WriteLine("ポインタの場合のアドレスによる値の表示");
  Console::WriteLine("{0} {1} {2}\n",*b,*(b+1),*(b+2));

  //ベクタの添え字による値の代入  
  c[0]=1;
  c[1]=2;
  c[2]=3;

  //ベクタの添え字による値の表示
  Console::WriteLine("ベクタの添え字による値の表示");
  Console::WriteLine("{0} {1} {2}",c[0],c[1],c[2]);
  //ポインタを利用したアドレスによるベクタ各要素への代入
  b=&c[0];
  *b=4;
  *(b+1)=5;
  *(b+2)=6;
  //ベクタ各要素の値の表示
  Console::WriteLine("ベクタ各要素の値の表示");
  Console::WriteLine("{0} {1} {2}",c[0],c[1],c[2]);
  //ベクタの反復子による代入
  vector<int>::iterator i;
  i=c.begin();
  *i=7;
  *(i+1)=8;
  *(i+2)=9;

  //ベクタ各要素の値の表示
  Console::WriteLine("ベクタ各要素の値の表示");
  Console::WriteLine("{0} {1} {2}",c[0],c[1],c[2]);
}


(コピーペースト用

#include<vector>
using namespace std;
using namespace System;

int main(){
int a[3];
int* b=(int* )malloc(3*sizeof(int));
vector<int> c(3);

//配列の要素への添え字による代入
a[0]=1;
a[1]=2;
a[2]=3;
//配列各要素の値の表示
Console::WriteLine("配列各要素の値の表示");
Console::WriteLine("{0} {1} {2}",a[0],a[1],a[2]);
//ポインタを利用したアドレスによる配列各要素への代入
b=a;
*b=4;
*(b+1)=5;
*(b+2)=6;
//配列各要素の値の表示
Console::WriteLine("配列各要素の値の表示");
Console::WriteLine("{0} {1} {2}\n",a[0],a[1],a[2]);

//ポインタの場合の添え字による代入
b[0]=1;
b[1]=2;
b[2]=3;
//ポインタの場合の添え字による値の表示
Console::WriteLine("ポインタの場合の添え字による値の表示");
Console::WriteLine("{0} {1} {2}",b[0],b[1],b[2]);
//ポインタの場合のアドレスによる代入
*b=3;
*(b+1)=4;
*(b+2)=3;
//ポインタの場合のアドレスによる値の表示
Console::WriteLine("ポインタの場合のアドレスによる値の表示");
Console::WriteLine("{0} {1} {2}\n",*b,*(b+1),*(b+2));

//ベクタの添え字による値の代入
c[0]=1;
c[1]=2;
c[2]=3;
//ベクタの添え字による値の表示
Console::WriteLine("ベクタの添え字による値の表示");
Console::WriteLine("{0} {1} {2}",c[0],c[1],c[2]);
//ポインタを利用したアドレスによるベクタ各要素への代入
b=&c[0];
*b=4;
*(b+1)=5;
*(b+2)=6;
//ベクタ各要素の値の表示
Console::WriteLine("ベクタ各要素の値の表示");
Console::WriteLine("{0} {1} {2}",c[0],c[1],c[2]);
//ベクタの反復子による代入
vector<int>::iterator i;
i=c.begin();
*i=7;
*(i+1)=8;
*(i+2)=9;
//ベクタ各要素の値の表示
Console::WriteLine("ベクタ各要素の値の表示");
Console::WriteLine("{0} {1} {2}",c[0],c[1],c[2]);
}




順に解説していきます。
#include<vector>using namespace std;はベクタを使うために必要なものです。
ベクタを使う場合には、この2つを冒頭に入れておかなければならないのです。
using namespace System;はConsole::WriteLineを使うために必要なものです。
vector<int> c(3);はベクタの宣言です。
ベクタの宣言は、
vector<変数の型> 変数名(0を含めた添え字数=配列のサイズ)
とします。
これは1次元ベクタの宣言ですが、
後に2次元ベクタ、3次元ベクタの宣言についても学びます。
尚、配列のサイズを指定せず、
vector<int> c;
と宣言することもできます。
これも配列とポインタとの違いの1つです。
配列ではint a[3];とサイズを指定しないとエラーになります。
ポインタでも同じでint* b=(int* )malloc(3*sizeof(int));とピンクの部分でサイズ数を指定します。
ということは配列とポインタではサイズが決まったいるので、サイズを超えたアクセスは行えません。
int a[3];と宣言したとき、a[3]=5;等とするとエラーします。
a[3]の場合許されるのはa[0],a[1],a[2]のみだからです。
int* b=(int* )malloc(3*sizeof(int));の場合も同様で、
*(b+3)=9;とするとエラーします。許されるのは、*b,*(b+1),*(b+2)のみだからです。
ベクタの場合はサイズの指定しなくてもよく、次の方法
c.push_back(3)(ベクタcに3を代入している。もしこれが最初の代入ならc[0]=3に相当する。)
で代入すれば、サイズは自動的に拡張していくからです。
詳しくは第11話で解説します。

//配列の要素への添え字による代入の//は、本講義ではじめて登場したものです。
//のついている文は、注釈文と言われ、コンピュータはこの文を無視します。
つまり、//のついている文はプログラムに何の影響も与えないのです。
では、何のためについているかと言いますと、それは人間のためのものです。
今までこの注釈文を入れてこなかったのは、私の悪癖の1つです。
プログラミングを始めた頃タイピングの腕がなく、入力が面倒であったがその理由です。
本来は、この注釈文はまめに入れなければなりません。
プログラムをわかりやすくするために。
尚、複数行単位で注釈文にするためには、
/*と*/で挟みます。例を挙げると、
/*
これは注釈文です。
この文をコンピュータは無視します
つまり読み飛ばします。
何のために注釈文があるかというと、
それはプログラムを作った本人やプログラムを読む人のためのものです。
なんのプログラムなのかを説明するためのものです。
*/

です。
また、//や/*と*/は、プログラムがうまく作動しないときに、
その原因を探るために活用できます。
エラーの疑われる文を注釈文に変えて、つまりコンピュータに無視をさせて、
その影響を探るのです。
Windows版マルチスレッド対応数独問題作成ソフトが意図したとおり作動しないとき、
何度もこの手法を利用して、原因を探査しました。
もちろん、ビルドエラーを探るときにも有効な方法です。
尚、プログラムが意図したとおりに動かない場合やビルドエラーの対策については、
講を設けて、後ほど説明する予定です。

  b=a;
  *b=4;
  *(b+1)=5;
  *(b+2)=6;

については既習済みです。1行目b=a;で配列の最初のアドレスをポインタ変数bに代入しています。
そして、2行目*b=4;で最初のアドレスが指すメモリー(値を入れる箱)に値を入れています。
3行目*(b+1)=5;では2番目のアドレスが指すメモリーに値を入れています。
4行目は、3番目のアドレスが指すメモリーに値を入れています。

  c[0]=1;
  c[1]=2;
  c[2]=3;

このようにベクタは、配列と同様に扱えます。
後に説明する2次元ベクタなら、c[1][2]のように添え字を扱えます。
つまり、添え字による使用方法は配列とまったく同じです。
したがって、表示のさせ方についても配列とまったく同じで、
Console::WriteLine("{0} {1} {2}",c[0],c[1],c[2]);
でよいことになります。
vector<int>::iterator i;は反復子の宣言です。
反復子の宣言は、vector<変数の型>::iterator 変数名
と行います。
反復子は、ポインタ変数に似た変数ですが、
アドレスの取得方法が、
i=c.begin();
i=c.end();
と2つ用意されています。
初めのアドレスについては、b=a;やb=&c[0];のようにポインタでも計算しないで、扱えますが、
最後のアドレスについては、ポインタの場合計算しないとなりません。
ポインタ変数の場合、bがアドレスを入れるポインタ変数、*bがそのアドレスが指すメモリー(変数=値を入れる箱)だったように、
iがアドレスを扱う変数、*iがそのアドレスが指すメモリー(変数=値を入れる箱)です。
  i=c.begin();
  *i=7;
  *(i+1)=8;
  *(i+2)=9;

したがって、*i=7;で最初のアドレスが示すメモリーに7が代入されます。



第11講第6話へ
 第12講第1話へ 第13講第1話へ 第13第3話へ

vc++講義第1部へ
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座へ