lC言語 配列/ストラクチャ/列挙型/共用体(1/2) '97. 1.10  
l.お知らせ 内容 LINK FILE   HTML Win PC Unix MS-DOS C C++ Mfc Java 
.C言語_ 3 フォ-マットコ-ド 6 演算子 9 FOR  集合デ-タ  目的別
1 表示してみる 4 変数と定数 7 条件判断 10 WHIILE  ポインタ     
2 エスケ-プ コ-ド 5 デ-タ入力 8 分岐   未使用  関数   ★ 
P1  配列  列挙型定数  共用体(ユニオン)  データのサイズを得る 
P2 ストラクチャ(構造体)  ストラクチャとポインタ  ストラクチャのネスト
 
C言語では、列挙型定数 と 共用体は必ずしも必要ではありません。 
ただし Cの関数には、共用体を使っているものがあります。

メモ : C言語では、使用するデータの宣言位置は決められています
グローバル変数は、使用するよりも前の位置の、関数の外側に 宣言を書きます。
自動変数は、関数の中の 一番最初の部分に宣言を書きます。

変数配列
配列は、データを順番に並べて 番号を付けたものです。
C言語では、型が同じ変数に 同じ名前を付け、番号で区別します。

宣言
  int x0, x1, x2, x3, x4;   この代りに配列を使用する場合は、
  int x[5];   のように宣言します。
x0  x1  x2  x3  x4 に相当するデータは、
x[0] x[1] x[2] x[3] x[4] の5個です。
配列の中の 一つ一つのデータは、要素と呼ばれます。

一般的な宣言の書式は、
 型 配列名[要素数]; 

宣言の働き
配列の宣言は、その配列を処理するプログラムの、作り方を決定します。
例えばデータを代入するとき、
char 型の配列なら、データを1バイト単位で代入するようにプログラムが作られます。
short 型の配列なら、データを2バイト単位 〃
このように宣言は、コンパイラが使用する部分です。
宣言しただけでは、プログラムの中に配列のデータは作られません。

一個でもデータを代入すると、プログラムの中に配列のデータが作られます。
このように 最初の代入には特別な働きがあるので、初期化と呼ばれて区別されます。
プログラムに変換された配列などのデータは、オブジェクトといいます。

初期化
宣言と同時に初期化する場合は、まとめて初期化できます。
  int x[5]={ 10, 20, 30, 40, 50 };  
  char s[5]={ 65,66,67,68,0 };  
  char s[5]={ 'A','B','C','D',0 };  
  char s[5]={ "ABCD\0" };  
宣言と同時に初期化した場合は、初期化しなかった要素は 0 の値に初期化されます。

宣言と同時でない場合は、要素のひとつずつに代入する必要があります。
  x[0]=10;  x[1]=20;  x[2]=30;  x[3]=40;  x[4]=50;  
自動変数は、宣言と同時に初期化しなかった場合、要素の値は不定です。

char 型の配列に文字コードを格納したものは、文字配列と呼ばれます。
文字配列のデータは、strcpy() などの関数を使って、まとめてコピーなどができます。
  #include<string.h>
  char y[10];
  char x[10]="ABC";
  strcpy( y, x );   /* y に、x をコピーします。*/
  printf( "%s \n", y ); /* コピーされていることを確かめられます。*/  

配列名はポインタ
x[10] などの配列の要素は、普通の変数と同じように扱うことができます。
ただし配列名(上の例では x ) は、配列の先頭を表わすポインタと等価です。
  char x[10]="ABC";
  char* p=x ;   /* 配列名は 同じデータ型のポインタと等価です。*/
  printf( "%s \n", p ); /* ポインタと配列名は同等に使用できます。*/  


多次元配列
一次元配列は、データを順番に並べて番号を付けたものです。
二次元配列は、一次元配列を順番に並べて番号を付けたものです。
C言語では、一つの配列には 同じ型のデータだけを格納できます。

宣言
  int x0[10], x1[10], x2[10], x2[10], x3[10], x4[10];   と宣言する代りに、
  int x[5][10];   のように宣言できます。

初期化
宣言と同時に初期化する場合は、まとめて初期化できます。
  int x[2][3] = { 11, 12, 13, 21, 22, 23 };  
  int x[2][3] = { {11, 12, 13}, {21, 22, 23} };  
  char s[2][3]={ 65,66,67,68,69,0 };  
  char s[2][3]={ 'A','B','C','D','E',0 };  
  char s[2][3]={ "ABC","DE\0" };  
普通は、二番目の例のように、次元毎に { } でくくって記述します。
宣言と同時に初期化した場合は、初期化しなかった要素は 0 の値に初期化されます。

宣言と同時でない場合は、要素のひとつづつに代入する必要があります。
  x[0][0]=11;  x[0][1]=12;  x[0][2]=13;  x[1][0]=21;  x[1][1]=22;   x[1][2]=23;  
宣言と同時でない初期化の場合は、初期化しなかった要素の値は 不定です。

多次元配列のデータ構造

参考 : 多次元配列
データを 縦, 横, 高さ方向 のように、異なる方向に順番に並べたものです。
並べられた個々のデータは要素、並べた順番は要素番号といいます。
並べた方向は次元といい、一次元, 二次元, 三次元 のように番号で表わします。
一つのデータ(の位置) は、各次元の要素番号を 順番に並べて表わします。
このとき、要素番号は 0 から始めることになっています。
また、高い次元(後に並べた方向) から順番に書くことに決められています。

次の例は、縦方向を一次元 横方向を二次元とした、二次元配列です。
  名前     身長 Cm    体重 Kg
  一郎(0,0)  150(1,0)   50(2,0)  ()内は要素番号です。
  二郎(0,1)  160(1,1)   60(2,1)
  三郎(0,2)  170(1,2)   70(2,2)
  四郎(0,3)  180(1,3)   80(2,3)
  五郎(0,4)  190(1,4)   90(2,4)
次元には、抽象的な方向(例えば 大きさ、番号、行数、ページ数、四次元方向など) を使用することができます。

コンピュータでは、データはメモリに格納されます。
配列のデータは、格納するデータの型(のサイズ) に合わせてメモリを区切り、番号(要素番号) を付けて順番に格納します。
要素番号とデータの位置(アドレス) の関係を簡単に計算できるように、 配列には同じ型のデータだけを格納します。

※ 異なる型のデータを 配列と同じように番号で扱いたい場合には、 データとは別にポインタ配列を用意して、ポインタ配列に個々のデータのポインタを代入します。
C++ では、コレクションという名前で このようなデータ構造が用意されています。


二次元配列は、複数の一次元配列を 順番に並べて番号を付けたものです。
 1.一次元配列と同じサイズでメモリを区切り、二次元要素番号を付けます。
 2.一次元配列を、二次元配列の要素として順番に格納します。
データそのものは、一次元配列の場合と同様に配置されます。
次の二つの配列のデータは、全く同じ構造になります。
  int x[6] = { 11, 12, 13, 21, 22, 23 };  
  int y[2][3] = { {11, 12, 13}, {21, 22, 23} };  
次のように確かめることができます。
  char s[6] = { "ABCDE\0" };  
  char t[2][3] = { "ABC","DE\0" };  
  printf("%s ",s);      /* ABCDE と表示されます。*/
  printf("%s",t[0] );  /* 同じく、ABCDE と表示されます。*/

int x[2][3]; のように宣言すると、
int 型(2バイト) のサイズにメモリが区切られます。
そのサイズを一次元要素数[3] だけ並べたサイズに区切られます。
それを二次元要素数[2] だけ並べた領域が、配列として使用されます。

配列名は、配列のポインタ(配列の先頭のアドレス) と等価です。
int x[3]; このように宣言したとき
先頭の要素は *x のように表わします。
二番目の要素は *(x+1) のように表わします。
三番目の要素は *(x+2) のように表わします。

要素番号とアドレス
[一次元配列の場合]
int 型の場合、要素のデータサイズが2バイトですから、各要素のアドレスは2バイト間隔になっています。
従って、二番目の要素のアドレスは x+2、三番目の要素のアドレスは x+4 です。

配列 x を int 型で宣言した場合、*(x+1) のように書くと、コンパイラは型に応じて 正しいアドレスを計算してプログラムを作ってくれます。 *(x+1) のような、アドレスの変移部分(+1) は、メモリを区切ったときのサイズ(int 型=2バイト) を掛けてプログラムを作ってくれます。

[二次元配列の場合]
*(y+1) のように書くとコンパイラは、アドレスの変移部分(+1) に一次元配列のサイズを掛けて、 二番目の要素(=一次元配列) のアドレスに変換してプログラムを作ってくれます。
*(y+1)+1 のように書くとコンパイラは、二番目の一次元配列の 二番目の要素 のアドレスに変換してプログラムを作ってくれます。
  int y[2][3] = { {11,12,13},{21,22,23} };  
  printf("%p %p \n",*(y+0),*(y+1) );   /* 6バイト間隔のアドレスが表示されます。*/
  printf("%p %p %p \n", *(y+0)+0, *(y+0)+1, *(y+0)+2 );   /* 2バイト間隔の 〃 */
*(y+1) の +1 の部分は、配列を宣言したときの型に合わせて6倍されます。
*(y+0)+1 の +1 の部分は、配列を宣言したときの型に合わせて2倍されます。



列挙型定数 enumeration
int型の変数を複数 宣言して、連続的な値で初期化します。
enum データ名{変数名0,変数名1,変数名2,...変数名n };
この場合のデータ名は、プログラムを見易くするだけの働きなので省略可能です。
これは次のように宣言/初期化した場合と等価です。
int 変数名0=0 ,変数名1=1 ,変数名2=2 , ...変数名n=n ;

初期化する値を指定することもできます。
enum sample{xa, xb=5 , xc, xd, xe };
これは次のように宣言/初期化した場合と等価です。
int xa=0 , xb=5 ,xc=6 ,xd=7 ,xe=8 ;

列挙型定数の用途
定数値に別名を付けて使うには、定数変数 const を付けて変数を宣言しました。
列挙型定数は、定数変数を 複数まとめて宣言します。

例えば 時刻関数を使えば曜日や月を得ることができます。
しかし、得られるのは 0 1 2 3 . . . のような long 型の数値です。
これらを処理するときに、
enum week{ Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };
enum month{ January, February, March, April, May, June, July,
      August, September, October, November, December, };
のように定義して、
0 1 2 3 . . . の代りに sunday や January を使います。
※ 私は英語が苦手なので、数字をそのまま使った方がわかり易いです。



共用体 (ユニオン) union
ひとつの変数の格納場所を、複数の変数に共同で使用させます。
union 見出し名 {型 変数名; 型 変数名; 型 変数名; } データ名;
データが一組だけの場合は、見出し名(タグ名)は省略可能です。

個々の変数は データ名.変数名 のように、データ名と共に指定します。
ひとつの共用体の中に宣言された変数は、一度にひとつだけ使うことができます。
以下は共用体の働きを示す例です。
#include <stdio.h>
void main()
{
union {int x; int y; }aa; /* 共用体を宣言します。*/
aa.x=5; /* x に 5 を代入します。*/
aa.y=7; /* y に 7 を代入します。同じ場所の x の値に上書きされます。*/
printf("%d %d",aa.x, aa.y); /* 7 7 と表示されます。*/
}
いちどにひとつの変数しか使えないこと以外は、普通の変数と全く同じです。

共用体を使う目的
プログラムが使用するメモリを、節約するために使用します。



データのサイズを得る sizeof

データの大きさ(バイト数)を得るには、
sizeof 変数名  のように書きます。
得られる値は int 型の数値です。

以下は構造体のデータサイズを表示する例です。
#include <stdio.h>
main()
{
int n ;
struct {int x;char s[5];} ST[2]={1,"ABC",2,"DEFG"};

printf("%d \n",sizeof ST ); /* 構造体全体のサイズ =(2+5)*2 =14 */
printf("%d \n",sizeof (ST[0]) ); /* 1個の配列のサイズ =2+5 =7 */
printf("%d \n",sizeof (ST[0].s) ); /* 文字配列 s のサイズ =5 */
printf("%d \n",sizeof (ST[0].s[0]) ); /* 文字1個のサイズ =1 */
n=sizeof (ST[0].x) /* 変数 x のサイズ =2 */
printf("%d \n",n );
}

型のサイズを確認することもできます。
int n1 = sizeof (char)
int n2 = sizeof (int)
int n3 = sizeof (long int)

変数の内容をファイルとして保存するときに、保存すべきサイズを求められます。
プログラム本体とは別にメモリを確保してデータを格納するときに、 必要なサイズを計算するために使用できます。


T

C言語 10 WHIILE  集合デ-タ  ポインタ
 
  mtoga@sannet.ne.jp   登録日 '96. 6.15
URL : http://www.page.sannet.ne.jp/mtoga/index.html