「配列」とは「変数」と同様にプログラム実行中に使用するデータを格納しておくためのものです。
「変数」はデータを入れておく箱のようなものと紹介しましたが、「配列」も同じようにデータを入れておく箱のようなものです。
「変数」との違いは「変数」が「1つのデータを入れておく箱」なのに対して「配列」は複数のデータを入れておく「仕切りの付いた箱」です。
「配列」は複数のデータを連続的に扱う時に便利です。今回は「配列」の使い方について紹介します。
「変数」については以下のリンクで詳しく紹介しています。
1.「配列」の宣言と初期化
・基本的な初期化方法
・要素数を省略した初期化方法
・要素数を確認する方法
・「2次元配列」の宣言と初期化
2.「配列」の使い方
・データを取り出す方法
・データを変更する方法
・データを連続的に処理する方法
3.「LEDテープライト」で「配列」の使い方を確認してみよう(ATOM LITE使用)
・フルカラーLEDの赤、緑、青の値を「配列」で指定
・フルカラーLEDの赤、緑、青の値を「2次元配列」で指定
・「2次元配列」の1次要素(色番号)を演算で指定して赤、緑、青を交互に点灯
・応用編:流れる光のサンプルプログラム
4.「配列」の「型」について
5.ブラウザ上で動作確認するなら
6.まとめ
7.独学に限界を感じたら
1.「配列」の宣言と初期化
「配列」も「変数」と同様に、使用する前にあらかじめ宣言しておく必要があります。
「初期化」は「変数」と同様に宣言時に行うことができます。
「配列」の宣言と初期化は以下のように行ないます。
型名:扱うデータの「型」を指定します。主に使用される「型」の種類は以下のようになります。
・文字型:char
・整数型:int
・単精度浮動小数点型:float
・倍精度浮動小数点型:double
配列名:「配列名」は自由に決めることができますが、「変数」と同様に以下の①~⑤のような制限があります。
①下線( _ )、英大文字小文字、数字で構成する。
②先頭の1文字目は数字以外。
③大文字小文字は区別されますが、一般的に配列名には小文字が使われます。
④「プログラム言語」の文法で使用されているコマンド(if や for等)は使用できません。
⑤文字数に制限はありません。
要素数(サイズ):「配列」に格納するデータの数です。
初期値n:「配列」に格納するデータです「初期値」は{ }で囲って「 , 」で区切って「要素数」分記入します。
・基本的な初期化方法
「int型」で配列名を「data」として「要素数」が[3]の場合の初期化方法は以下のようになります。
「型名」と「配列名」は「変数」と同じように設定します。
「要素数」は[ ]で囲って「初期値」の数だけを記入します。
今回は「初期値」が3個なので{ }内に「 , 」で区切って「1,2,3」3個の値を「初期値」として設定しています。
以下のように「初期値」を設定せずに宣言することもできます。
この場合は「要素数」が[3]の配列が準備され、この時点では「初期値」は全て「0」になります。
・要素数を省略した初期化方法
「要素数」は宣言時には以下のように省略することができます。
・要素数を確認する方法
「要素数」を指定せずに宣言した配列等の「要素数(サイズ)」は以下のようなプログラムで知ることができます。
「要素数」を省略して宣言した「data」という配列を例に紹介します。
int datasize = sizeof(data) / sizeof(int);
datasize:「要素数」を格納するために「変数」を使用します。
sizeof:データのバイト数を確認するコマンドです。
sizeof(data):「配列」全体のバイト数を表します。
ここでは「int型」のデータが10個あるので「4バイト × 10個 = 40バイト」
sizeof(int):「int型」のバイト数(4バイト)を表します。
まず、「配列」全体のバイト数(40バイト)を確認し、使用している「型」(ここでは「int型」4バイト)のバイト数で割ることで要素数を知ることができます。
「datasize」の要素数は 40/4 = 10 となります。
・「2次元配列」の宣言と初期化
「2次元配列」とは「配列」の中に「配列」を持たせたものです。
「配列」内のデータを関連する項目ごとにまとめて表のように扱えるので複雑なデータを処理する時にに便利です。
「int型」で配列名を「data」として「1次要素数」と「2次要素数」が[3]の場合の初期化方法は以下のようになります。
「1次要素数」と「2次要素数」はそれぞれ[ ]で囲って「初期値」の数だけ記入します。
「2次元配列」のデータは下表のように格納されます。
2.「配列」の使い方
以下の「配列」を例に使い方を紹介します。
・データを取り出す方法
「配列」の値を取り出して使用する時は以下のように指定します。
2を取り出す時 data[1]
3を取り出す時 data[2]
・データを変更する方法
配列の値を変更する時は以下のように行います。
と指定すると配列内の値は{1, 2, 3} が {4, 2, 3} となります。
・データを連続的に処理する方法
データを連続的に処理する時は以下のように「for文」を使用します。
int sum = 0;
for (int i = 0; i < 3; i++) {
sum = sum + data[i];
}
「配列data」の3つの要素を合計して「変数sum」に格納しています。
「for文」の繰り返し回数を「要素数」に設定して連続的に「配列data」の値を取り出して処理しています。
3.「LEDテープライト」で「配列」の使い方を確認してみよう(ATOM LITE)
「ATOM LITE」と「LEDテープライト」を使用して「配列」の使用方法を確認してみましょう。
「LEDテープライト」は「フルカラーLED」がたくさん並んでつながったものです。
使用したのは60個のLEDが連なった1mのものですが、このうち10個を配列に見立ててLEDの点灯色を指定します。
LEDの点灯色は「赤、緑、青」の明るさを変えることで指定できます。このLED一つ一つを「配列」と考えると理解がしやすいと思います。
「ATOM LITE」と「LEDテープライト」については以下のリンクで詳しく紹介しています。
下のコードを「コピペ」して書き込んで動作確認してみましょう。
※コピーは下コード(黒枠)内の右上角にある小さなアイコンのクリックでもできます
・フルカラーLEDの赤、緑、青の値を「配列」で指定
フルカラーLEDの色は「赤、緑、青」の色の3原色の組み合わせ(明るさの値を0~255で指定)で点灯色を指定します。
以下のプログラムは3つの色の組み合わせを、「要素数」3個の配列(10~13行目)として指定することで10個のLEDを1秒ごとに赤、緑、青に変えるプログラムです。
#include <M5Atom.h>
#include <Adafruit_NeoPixel.h> //NeoPixel SK6812制御用ライブラリ
#define PIN 26 // LEDテープ信号端子
#define NUMPIXELS 10 // LEDの数
// NeoPixel初期設定
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
// 配列宣言 LED色(明るさ)指定 0~255 (赤, 緑, 青)
int red[3] = {10, 0, 0}; //LED色赤
int green[3] = {0, 10, 0}; //LED色緑
int blue[3] = {0, 0, 10}; //LED色青
// 初期設定 **********************************************************************
void setup() {
M5.begin(true, false, false); //Serial,POWER,LED
pixels.begin(); //LED色初期化
pixels.clear(); //LED色指定クリア
}
// メイン ***********************************************************************
void loop() {
for(int i = 0; i < NUMPIXELS; i++) { //LED番号0~NUMPIXELまで繰り返し
pixels.setPixelColor(i, pixels.Color(red[0], red[1], red[2])); //全LED赤
}
pixels.show(); //LED色出力
delay(1000); //遅延時間(1秒)
for(int i = 0; i < NUMPIXELS; i++) { //LED番号0~NUMPIXELまで繰り返し
pixels.setPixelColor(i, pixels.Color(green[0], green[1], green[2])); //全LED緑
}
pixels.show(); //LED色出力
delay(1000); //遅延時間(1秒)
for(int i = 0; i < NUMPIXELS; i++) { //LED番号0~NUMPIXELまで繰り返し
pixels.setPixelColor(i, pixels.Color(blue[0], blue[1], blue[2])); //全LED青
}
pixels.show(); //LED色出力
delay(1000); //遅延時間(1秒)
}
・フルカラーLEDの赤、緑、青の値を「2次元配列」で指定
上のコードと同じ動作をするプログラムを「2次元配列」を使うともっとシンプルに指定することができますし、複数の色を扱う時にも便利です。
以下のプログラムの11行目のように「2次元配列」を指定します。
「1次要素」を色番号として、「2次要素」にその色の「赤、緑、青」の数値を指定しておきます。
#include <M5Atom.h>
#include <Adafruit_NeoPixel.h> //NeoPixel SK6812制御用ライブラリ
#define PIN 26 // LEDテープ信号端子
#define NUMPIXELS 10 // LEDの数
// NeoPixel初期設定
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
// 配列宣言 LED色(明るさ)指定 0~255 (赤, 緑, 青)
int red[3][3] = {{10, 0, 0}, {0, 10, 0}, {0, 0, 10}}; //赤、緑、青を2次元配列で指定
// 変数宣言
int change = 0; //色切換カウント用
// 初期設定 **********************************************************************
void setup() {
M5.begin(true, false, false); //Serial,POWER,LED
pixels.begin(); //LED色初期化
pixels.clear(); //LED色指定クリア
}
// メイン ***********************************************************************
void loop() {
for(int i = 0; i < NUMPIXELS; i++) { //LED番号0~NUMPIXELまで繰り返し
pixels.setPixelColor(i, pixels.Color(red[change][0], red[change][1], red[change][2])); //全LED色指定
}
pixels.show(); //LED色出力
// 色変更
change++; //色切換カウント+1
if (change == 3) { //色切換カウントが3なら
change = 0; //色切換カウント0リセット
}
delay(1000); //遅延時間(1秒)
}
・「2次元配列」の1次要素(色番号)を演算で指定して赤、緑、青を交互に点灯
下コードの25行目のように「for文」の中で繰り返しカウント「i」を3で割った余り(0~2繰り返し)を「2次元配列」の「1次要素」の色番号に指定することで「赤、緑、青」を交互に連続的に指定することも簡単にできます。
#include <M5Atom.h>
#include <Adafruit_NeoPixel.h> //NeoPixel SK6812制御用ライブラリ450
#define PIN 26 // LEDテープ信号端子
#define NUMPIXELS 10 // LEDの数
// NeoPixel初期設定
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
// 配列宣言 LED色(明るさ)指定 0~255 (赤, 緑, 青)
int red[3][3] = {{10, 0, 0}, {0, 10, 0}, {0, 0, 10}}; //赤、緑、青を2次元配列で指定
// 変数宣言
int change = 0; //色切換カウント用
// 初期設定 **********************************************************************
void setup() {
M5.begin(true, false, false); //Serial,POWER,LED
pixels.begin(); //LED色初期化
pixels.clear(); //LED色指定クリア
}
// メイン ***********************************************************************
void loop() {
for(int i = 0; i < NUMPIXELS; i++) { //LED番号0~NUMPIXELまで繰り返し
change = i % 3; //iを3で割った余りを色番号(change)に指定。0~2を繰り返す
pixels.setPixelColor(i, pixels.Color(red[change][0], red[change][1], red[change][2])); //全LED色指定
}
pixels.show(); //LED色出力
delay(1000); //遅延時間(1秒)
}
・応用編:流れる光のサンプルプログラム
配列の要素を隣へ順番にずらしていくことで流れる光も表現できます。
下のプログラムを実行すると、電源ONで全LEDが点灯し白い光(2個)が流れ続けます。
全LEDの色は「ATOM LITE」本体のボタンを押すごとに4色の切換えができます。
#include <M5Atom.h>
#include <Adafruit_NeoPixel.h> //NeoPixel SK6812制御用ライブラリ
#define PIN 26 // LEDテープ信号端子
#define NUMPIXELS 60 // LEDの数
// NeoPixel初期設定
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
// 配列宣言
int array[NUMPIXELS+2][3] = {}; //LED色指定用配列(先頭と最終要素に色保持するため+2)
// 流れる光(白)と残光の配列snow(白をだんだん暗く、残光数の分準備)
int snow[][3] = {{60, 60, 60}, {40, 40, 40}, {30, 30, 30}, {20, 20, 20}, {10, 10, 10}};
// ベース色指定用配列color
int color[][3] = {{10, 5, 1}, {12, 0, 2}, {0, 10, 1}, {2, 0, 12}};
int cnt = 0; //流れる光出力タイミング用
int afterglow = 0; //流れる光と残光回数用
int snow_size = sizeof(snow) / (sizeof(int)*3); //配列snowの要素数(1次要素数)
int color_size = sizeof(color) / (sizeof(int)*3); //配列colorの要素数(1次要素数)
int change = 0; //ベース色切替えカウント用
// 初期設定 **********************************************************************
void setup() {
M5.begin(true, false, false); //Serial,POWER,LED
Serial.begin(9600);
pixels.begin(); //LED色初期化
pixels.clear(); //LED色指定クリア
// 配列colorの最終要素の(赤, 緑, 青)を初期値として配列arrayにコピー
for(int i = 0; i < NUMPIXELS+1; i++) { //LED番号0~NUMPIXELまで繰り返し
for (int j = 0; j < 3; j++) { //LED(赤, 緑, 青)の3個分繰り返し
array[i][j] = color[color_size-1][j]; //ベース色をLED指定用配列にコピー
}
}
}
// メイン ***********************************************************************
void loop() {
M5.update(); //本体ボタン状態更新
// ボタンが押されるごとにベース色変更
if(M5.Btn.wasPressed()) { //本体ボタンが押されていれば
cnt = 30; //流れる光出力タイミング
for(int i = 0; i < NUMPIXELS+2; i++) { //LED番号0~NUMPIXEL+2まで繰り返し
for (int j = 0; j < 3; j++) { //LED(赤、緑、青)の3個分繰り返し
array[i][j] = color[change][j]; //ベース色をLED指定用配列にコピー
}
}
change++; //ベース色切替えカウント+1
if (change == color_size) { //changeがcolor_sizeなら
change = 0; //0リセット
}
}
// ベース色セット
for (int i = 0; i < 3; i++) { //LED(赤、緑、青)の3個分繰り返し
array[NUMPIXELS+1][i] = array[0][i]; //LED指定用配列の0番目をベース色に指定
}
// 流れる光と残光設定
if (afterglow < snow_size) { //流れる光数カウント(afterglow)がsnow配列の要素数以下なら
for (int i = 0; i < 3; i++){ //LED(赤、緑、青)の3個分繰り返し
//残光用LED色指定(残光とベース色を加算して1/2することで残光を表現)
array[NUMPIXELS+1][i] = (snow[afterglow][i] + array[0][i]) / 2;
}
afterglow++; //流れる光と残光回数+1
}
// 流れる光タイミングと残光カウントリセット
if (cnt == NUMPIXELS/2) { //NUMPIXELS(LED数)の1/2で流れる光2個、1/3なら3個
cnt = 0; //流れる光出力タイミング0リセット
afterglow = 0; //流れる光と残光回数0リセット
}
cnt++; //流れる光出力タイミング+1
for(int i = 1; i < NUMPIXELS+1; i++) { //LED番号1~NUMPIXEL+1まで繰り返し
// 全LED色指定
pixels.setPixelColor(i-1, pixels.Color(array[i][0], array[i][1], array[i][2]));
}
for(int i = 1; i < NUMPIXELS+1; i++) { //array配列の2つ目からLED数+1まで繰り返し
for (int j = 0; j < 3; j++) { //LED(赤、緑、青)の3個分繰り返し
array[i][j] = array[i+1][j]; //array配列を左へシフト
}
}
pixels.show(); //LED色出力
delay(100); //遅延時間(ms)
}
4.「配列」の「型」について
「変数」の時にも紹介しましたが、「配列」も同様に「型名」には扱えるデータサイズ(データ範囲)によってたくさんの種類があります。
今全てを覚える必要はありませんので紹介程度に一覧表にまとめました。
今後必要に応じて確認してみてください。
型 | 型の説明 | データサイズ | 扱えるデータ範囲 |
---|---|---|---|
unsigned char | 文字型 | 1byte | 0~255 |
char | 文字型 | 1byte | -128~127 |
unsigned short | 符号なし単整数型 | 2byte | 0~65,535 |
short | 単整数型 | 2byte | -32,768~32,677 |
unsigned int | 符号なし整数型 | 4byte | 0~4,294,967,295 |
int | 整数型 | 4byte | -2,147,483,648~ 2,147,483,647 |
unsigned long | 符号なし長整数 | 4byte (8byte) | 0~4,294,967,295 |
long | 長整数 | 4byte (8byte) | -2,147,483,648~ 2,147,483,647 |
float | 単精度浮動小数点 | 4byte | 最小の正の数:3.4e-38 最大値:3.4e+38 |
double | 倍精度浮動小数点 | 8byte | 最小の正の数:1.7e-308 最大値:1.7e+308 |
5.ブラウザ上で動作確認するなら
ちょっとした動作確認をしたい時は、ブラウザ上でプログラムを作成して実行できる「paiza.IO」が便利なので以下にリンクを貼っておきます。
無料で使用できて「C言語」だけでなく「python」や「JavaScript」「PHP」等たくさんの言語にも対応しています。
プログラミングの上達には学ぶことも大切ですが、自分で書いて実行して、どんな動きになるか、間違っててもいいのでこれをひたすら繰り返すことが一番の近道と思います。たくさん書いて実行してみましょう。
6.まとめ
「配列」は「変数」と同様にデータを格納しておくことができますが「変数」が一つのデータを格納するのに対して、「配列」は複数のデータを格納しておくことができます。
格納するデータ数は「要素数(サイズ)」と呼ばれます。
格納されている1番目のデータを示す要素番号は[1]ではなく[0]からになります。
「配列」を使用するには「変数」と同様にあらかじめ宣言しておく必要があり、宣言時に「要素数」と「要素数」分の「初期値」を指定します。
「要素数」は省略することができ、省略した場合は指定した「初期値」の数が「要素数」となります。
「要素数」は「sizeof」コマンドで確認することができ、これを「for文」の繰り返し回数に指定することで、後から「初期値」の数(要素数)を変更した時にプログラム内の繰り返し回数を変更する手間が無く、自動で変更されるため変更忘れや間違いを無くすことができます。
このように、関連するデータをまとめて格納しておける「配列」を使うことで「for文」等を使って連続的に処理を行うことができるため、効率的で理解しやすいプログラムにすることができます。
動かして学ぶ「C言語」については、他にも以下のリンクで基礎からサンプルプログラムを使って詳しく紹介しています。
7.独学に限界を感じたら
最後に、独学に限界を感じている方へ、私のように無駄な時間を過ごさないように「C言語」や「Python」を基礎から学べるオンラインスクール(教室での受講も可)の紹介です。
私は学生の頃、独学で「C言語」を始めましたが、かなり時間をかけて結局一度挫折しました(汗)
仕事で少しプログラミングに触れる機会もあり、今となっては小規模なプログラムなら組めますが、どれだけ時間をかけたでしょう・・・
短期間で基礎から学べて質問もできる、そんな環境が当時あったらと思うと・・・
今はとても羨ましい時代になりました。
いろいろなプログラミングスクールのサイトを見て回りましたが「C言語」と「Python」の両方を扱っている所は少ないです。その中でも以下のスクールは他の言語も含めて、たくさんの講座から目的やスキルに合ったものを組合わせて、オンラインでも対面でも受講が可能です。
ほとんどの受講生が未経験で、全国に教室があるため現地で直接指導してくれますが多くの講座がオンライン対応です。
オンラインでは「個人レッスン(講師一人につき3名程)」と「集合レッスン」の選択も可能です。
オンラインレッスンの方には授業で使用するノートPC(ソフトインストール済み)も追加料金なしで貸りられて、質問掲示板を使って授業時間外でも質問できます。
無料体験もあり、説明会やカウンセリング等も行っています。
以下のリンクから内容だけでも確認してみてください。
コメント