配列とは
C言語における配列とは、同じ型のデータの集まりで、それらのデータへ変数名に添え字をつけることによりアクセス可能となるものです。関連のあるデータが複数ある時に、それらに対して一つ一つ変数を割り当てていては非効率的であるという場合に使用されます。添え字には任意の整数の式を使用することができるので、ループ処理を使って一括処理を行うのに便利です。
C言語の配列の添え字は0から始まります。他の言語では1から始まるものもありますので、混同しないように気をつけましょう。
また、C言語では多次元配列が可能です。しかし、比較的新しい言語でサポートされているような連想配列(添え字に文字列などのデータ型が使用可能な配列)、可変長配列(要素数により自動的にサイズが拡張する配列)、配列に異なった型のデータを格納できる機能などはサポートされていません。
配列の宣言例
int vernalEquinox[10] = {20, 20, 21, 21, 20, 20, 21, 21, 20, 20};
int vernalEquinox[] = {20, 20, 21, 21, 20, 20, 21, 21, 20, 20};
初期値の数が指定された要素数を超えた場合はコンパイルエラーとなります。逆に初期値の数が要素数に満たない場合、残りの要素は0で初期化されます。初期値の繰り返し指定や、要素をとばして一部の要素のみを初期化することなどはできません。
2次元配列
2次元配列とは行(縦)と列(横)の2次元で考える配列です。以下のように宣言します。
この配列は5行3列、すなわち縦方向に5、横方向に3のデータを持ちます。
<2次元配列のイメージ>
data[0][0] | data[0][1] | data[0][2] |
data[1][0] | data[1][1] | data[1][2] |
data[2][0] | data[2][1] | data[2][2] |
data[3][0] | data[3][1] | data[3][2] |
data[4][0] | data[4][1] | data[4][2] |
2次元配列のデータは、メモリ上には行毎に格納されます。したがって、メモリの順番で2次元配列にアクセスすると最初に列がインクリメントされていきます。
<メモリ上の2次元配列イメージ>
data[0][0] |
data[0][1] |
data[0][2] |
data[1][0] |
data[1][1] |
data[1][2] |
data[2][0] |
data[2][1] |
data[2][2] |
data[3][0] |
data[3][1] |
data[3][2] |
data[4][0] |
data[4][1] |
data[4][2] |
int equinox[][10] = {
{20, 20, 21, 21, 20, 20, 21, 21, 20, 20}
,{23, 23, 23, 23, 23, 23, 23, 23, 23, 23}
};
<equinox.c 春分日,秋分日を表示する>
/*
equinox.c
春分日,秋分日を表示するプログラム
*/
/* インクルードヘッダ */
#include <stdio.h>
/* プロトタイプ宣言 */
int vernalEquinox(int y);
int autumnalEquinox(int y);
void setVernalEquinoxTable(char table[2][25]);
void setAutumnalEquinoxTable(char table[][25]);
void printEquinoxTable(char (*table)[25]);
/*
メイン
*/
int main(int argc, char *argv[])
{
char equinox[2][25];
/* 春分日をテーブルにセット */
/* この場合配列名equinoxは配列の先頭アドレスを意味する */
/* それを引数として渡す */
setVernalEquinoxTable(equinox);
/* 秋分日をテーブルにセット */
setAutumnalEquinoxTable(equinox);
/* 春分日,秋分日を表示 */
printEquinoxTable(equinox);
return 0;
}
void setVernalEquinoxTable(char table[2][25])
/* 2次元配列へのポインタは上記のような宣言で受取可能 */
{
int i;
for (i=0;i<25;i++) {
table[0][i] = vernalEquinox(2000 + i);
}
}
void setAutumnalEquinoxTable(char table[][25])
/* 各行が25個のcharの配列である行の配列へのポインタなので */
/* 行の数は省略可能 */
{
int i;
for (i=0;i<25;i++) {
table[1][i] = autumnalEquinox(2000 + i);
}
}
void printEquinoxTable(char (*table)[25])
/* 25個のcharの配列へのポインタとしても受取可能 */
/* []の優先度は*よりも高いので()が必要*/
/* char *table[25]ならcharのポインタが25個ある配列になる */
{
int i;
printf("Vernal Equinox,Autumnal Equinox¥n");
for (i=0;i<25;i++) {
printf("%d/3/%d,%d/9/%d¥n", 2000 + i, table[0][i], 2000 + i, table[1][i]);
}
}
/*
春分日取得
vernalEquinox
<概要>
指定された西暦年の春分日を返す
<戻り値>
0:エラー
19〜22:春分日
<引数>
int y:(i)西暦年(1900〜2099)
<補足>
日のみを返す
・西暦年を4で割った余りが0の場合
1900〜1956なら3/21
1960〜2088なら3/20
2092〜2096なら3/19
・西暦年を4で割った余りが1の場合
1901〜1989なら3/21
1993〜2097なら3/20
・西暦年を4で割った余りが2の場合
1902〜2022なら3/21
2026〜2098なら3/20
・西暦年を4で割った余りが3の場合
1903〜1923なら3/22
1927〜2055なら3/21
2059〜2099なら3/20
*/
int vernalEquinox(int y)
{
int remainder = 0;
int day = 0;
/* 西暦年が範囲外ならエラーでリターン */
if ((y < 1900) && (y > 2099)){
return 0;
}
/* 西暦年を4で割った余りが */
remainder = y % 4;
switch (remainder) {
case 0:
/* 0で */
if (y <= 1956) {
/* 1900〜1956なら3/21 */
day = 21;
} else if (y <= 2088) {
/* 〜2088なら3/20 */
day = 20;
} else if (y <= 2096) {
/* 〜2096なら3/19 */
day = 19;
}
break;
case 1:
/* 1で */
if (y <= 1989) {
/* 1901〜1989なら3/21 */
day = 21;
} else if (y <= 2097) {
/* 〜2097なら3/20 */
day = 20;
}
break;
case 2:
/* 2で */
if (y <= 2022) {
/* 1902〜2022なら3/21 */
day = 21;
} else if (y <= 2098) {
/* 〜2098なら3/20 */
day = 20;
}
break;
case 3:
/* 3で */
if (y <= 1923) {
/* 1903〜1923なら3/22 */
day = 22;
} else if (y <= 2055) {
/* 〜2055なら3/21 */
day = 21;
} else if (y <= 2099) {
/* 〜2099なら3/20 */
day = 20;
}
break;
}
return day;
}
/*
秋分日取得
autumnalEquinox
<概要>
指定された西暦年の秋分日を返す
<戻り値>
0:エラー
22〜24:春分日
<引数>
int y:(i)西暦年(1900〜2099)
<補足>
日のみを返す
・西暦年を4で割った余りが0の場合
1900〜2008なら9/23
2012〜2096なら9/22
・西暦年を4で割ったりが1の場合
1901〜1917なら9/24
1921〜2041なら9/23
2045〜2097なら9/22
・西暦年を4で割った余りが2の場合
1902〜1946なら9/24
1950〜2074なら9/23
2078〜2098なら9/22
・西暦年を4で割った余りが3の場合
1903〜1979なら9/24
1983〜2099なら9/23
*/
int autumnalEquinox(int y)
{
int remainder = 0;
int day = 0;
/* 西暦年が範囲外ならエラーでリターン */
if ((y < 1900) && (y > 2099)){
return 0;
}
/* 西暦年を4で割った余りが */
remainder = y % 4;
switch (remainder) {
case 0:
/* 0で */
if (y <= 2008) {
/* 1900〜2008なら9/23 */
day = 23;
} else if (y <= 2096) {
/* 〜2096なら9/22 */
day = 22;
}
break;
case 1:
/* 1で */
if (y <= 1917) {
/* 1901〜1917なら9/24 */
day = 24;
} else if (y <= 2041) {
/* 〜2041なら9/23 */
day = 23;
} else if (y <= 2097) {
/* 〜2097なら9/22 */
day = 22;
}
break;
case 2:
/* 2で */
if (y <= 1946) {
/* 1902〜1946なら9/24 */
day = 24;
} else if (y <= 2074) {
/* 〜2074なら9/23 */
day = 23;
} else if (y <= 2098) {
/* 〜2098なら9/22 */
day = 22;
}
break;
case 3:
/* 3で */
if (y <= 1979) {
/* 1903〜1979なら9/24 */
day = 24;
} else if (y <= 2099) {
/* 〜2099なら9/23 */
day = 23;
}
break;
}
return day;
}