この文章はC#入門者が半ば自分のメモ書きのように書いたものです。おそらく間違いは多々あるとは思いますが、温かく見守ってください。本の内容を自分なりに解釈して、また実験を行っての「当時の理解」が記事に反映されています。
また、プログラム内部の変数名などに全大文字のローマ字書きが使われています、お気をつけください。逆に全大文字の部分は自由に変更しても大丈夫な部分です。
C#で扱うデータに関しての基礎のメモ書き
数字データに関して
・C#では、変数の型と変数の名前を宣言して定義する。
例えば下記のような形。
int HENSU = 10;
const int TEISU = 10;
ここで使用したconst
は宣言した変数を定数とする修飾子で、宣言時に代入した数値を保持し続けるように変えるものである。これ以後、const
で宣言された数値は定数となり、定数に再代入を行うプログラムはエラーを返すようになる。
また、定数を作る際には初期値を与える必要がある。変数のように枠だけ作っておく、という事は出来ない。
変数には様々な型があり、それぞれ使える範囲が決まっている。例えばbyte
であれば0~2 8-1までの正の整数、int
であれば±(231-1)までの整数、小数点以下を扱う際にはfloat
やdouble
、decimal
という型もある。
ここで、最大値に-1が付いている理由は数字の初めが0だからである。8ビットで表すことのできるパターンは256通りで、そのうち一つを0に割り当てる必要があるためにそうなっている。
sbyte
と書けばbyte
と同じデータサイズで符号をつけることができたり(つまり範囲は-27~27-1)、uint
と書けばint
と同じデータサイズで正の数のみのデータ(つまり範囲は0~232-1)になったりする。
これは整数を扱う型に限られ、sを付けるかuを付けるかは元の型に符号が付いているか否かで判別する。
以下に数字を扱う型の一覧を示す。
整数を扱う型
型の名前 | サイズ(bit) | 範囲 | 規定値 |
---|---|---|---|
byte | 8 | 0 ~ 255 | 0 |
short | 16 | -32768~32767 | 0 |
int | 32 | -2,147,483,648~2,147,483,647 | 0 |
long | 64 | -9,223,372,036,854,775,808~9,223,372,036,854,775,807 | 0L |
小数点以下も扱える型
型の名前 | サイズ(bit) | 規定値 |
---|---|---|
float | 32 | 0.0F |
double | 64 | 0.0D |
decimal | 128 | 0.0M |
*範囲は小数点の位置によって変動する。
*double
型よりもdecimal
型のほうが数値精度が高いが、数値範囲はfloat
型よりもdecimal
型のほうが小さい。また、CPUによってはdecimal
型そのものがサポートされていないことがあり、計算速度が圧倒的に遅くなることがあるようだ。
数字データの格納/代入に関して
作成したbyte
データをbyte
型よりデータサイズの大きいint
型に格納することは可能であるが、その逆は不可能である。ただし、とある宣言を行うことで強引に変換することもできる。
//代入元データ
byte MOTO_BYTE = 100;
int MOTO_INT = 200;
byte SAKI_A = MOTO_BYTE;//可能
byte SAKI_B = MOTO_INT;//不可能
byte SAKI_C = (byte)MOTO_INT;//可能
byte e = (byte)b;
の行で、(byte)
と代入する側に付記している。これによりint
型の数値をbyte
型に変換しているため、この式の内部ではbyte
型にbyte
型を代入していることになっていて、エラーとならない。ただし、この手法には問題もあり、例えば下のようなプログラムは正しい値を返すことはない。
int MOTO = 500;
byte SAKI_A = (byte)a;//bの値は244
byte SAKI_B = (byte)(a*-1);//cの値は12
byte CHOKUSETU = 500;//これはエラーとなる
これはビットで計算した際にint
型で格納されているデータの9ビット以上の値がbyte
型に変換される際に切り捨てられる(厳密に演算したとしても下8ビットに影響を及ぼさない)ことに原因がある。これによって256を表す9ビット目が切り捨てられ、244という値になっている。
cの値が244とならないのは二進数における負の数の表し方に原因があり、00000...000と32個0が連なったint
における規定値0のデータを負の方向にオーバーフローさせた11111...111を-1としていて、-2,-3と値が下がっていくごとに2進数を繰り下げていく方式であるために、負の数の下8ビットだけを参照した際に、8ビットすべてが1の値、つまり256から244を引いた値で12となっている。
500を直接byte
型に代入しようとするとエラーとなる。オーバーフロー/アンダーフローが起きるのはあくまでも変数から変数への代入を強引に(型変換を用いて)行った場合だけである。
ちなみに500をsbyte
型に代入した場合は-12となり、-500を代入した場合は12となる。なんとなく不思議な気分だ。
その他のデータに関して
C#で数字以外のデータを扱う型で簡単に触れられると私が思うのはbool
型、char
型、string
型の三種である。
以下でそれぞれの型についてまとめる。
*bool
型(論理型)
true
またはfalse
の二値を格納する型。比較演算子を用いた演算結果の格納にも用いることが出来る。よくフラグ管理に使う。
外部からの代入はtrue
またはfalse
を受け付ける。条件式が真か偽かという結果もここで保持することができる。
データサイズは8bit。
*char
型(文字型)
文字を一つだけ格納する型。手動で格納する際には`(シングルクォーテーション)で文字を囲んで格納する。個人的に使用したのはデータ転送で一文字づつ送られてくるものを保存するときのみ。もしかすると後述のstring
型で代用できるかもしれない。\u〇〇〇〇
という形で直接文字コードで生成することも出来る。(〇
には16進数が入る)
データサイズは16bit。
*string
型(文字列型)
文字列を格納する型。手動で格納する際には"(ダブルクォーテーション)で文字を囲んで格納する。シングルクォーテーション二回ではない。~~最初は騙された。~~数値を扱う方を含む、以上に示した型のどれとも違い、変数の中に直接格納するものではなくどこかにあるデータのアドレスを格納する型である。その二種に関してはいずれ触れるかもしれない。
データサイズは前後し、最大で2GBとのこと。
The maximum size of a String object in memory is 2GB, or about 1 billion characters.
String
オブジェクトの最大メモリは2GB、またはおよそ十億文字。https://docs.microsoft.com/ja-jp/dotnet/api/system.string :stringクラス解説の注釈欄より抜粋
ユーザーが中身を定義する型に関して
c#
には最初から用意されている前述の10(+α)種類のデータ形式だけでなく、ユーザーが形式を定義出来る型が用意されている。
その型とは列挙型、配列、構造体の三つである。
列挙型に関して
enum 名前:型名(整数型に限る){ 中身1,中身2, ... ,中身N };
のような形で宣言できる型。:型名
の部分は省略でき、省略した場合は自動的に中身はint
型になる。中身に対して何も代入しないと、中身1,中身2,...には0から順に番号が代入されていく。N番目の中身にはN-1番が代入される。途中の中身にも番号を代入することが出来る。代入した中身の後ろには、そのまま順番に番号が代入される。
また、中身に格納した数字を取り出すには型宣言が必要になる。
enum REKKYO:byte{
NAKAMI1,NAKAMI2 = 10,
NAKAMI3
}
System.Console.WriteLine(REKKYO.NAKAMI3);//出力:NAKAMI3
System.Console.WriteLine((byte)NAMAE.NAKAMI3);//出力:11
配列型に関して
//bool以外の型であればよい
int[] HAIRETU;
HAIRETU = new int[3];
/***/
int[] HAIRETU2 = new int[3];
/***/
int[] HAIRETU3 = new int[3] {0,1,2}
上記/***/で区切られた文章それぞれが別の配列型を宣言する方法である。上から順に私の思う使い道を述べていく。
- とりあえず配列の名前だけ作っておいて、分岐先で大きさを分けることが出来る。条件によって要素数が変わるときに使える。
- とりあえず空配列ができる。後から要素を埋めるが、その要素が決まっていない際に使える。
- 要素の決まった配列が作れる。暫定的、もしくは変動しない要素を作るときに使える。(ReadOnlyと併用するとよい?)
構造体に関して
public struct KOZOTAI{
public int SUUJI;
public string MOJI;
}
こいつに関してはよくわかってない。多分classを作るときのようなことをすると思われる。万が一これを目当てにしてきた人にはごめんなさい。ここまでの間違いまくりのどや顔解説も出来ないくらいわかってない。なんだこれは。
まず、Main()
の外で上記コードみたいな感じで関数を作る。そのあと、Main()
の中でKOZOTAI
型の変数?を宣言することで空のKOZOTAI
型を作ることが出来る。ここではKOZOTAI
型変数?の名称をSHISAKU
とする。
KOZOTAI SHISAKU; //これで空っぽのKOZOTAI型ができる。初期化は出来ない。初期化にはまた別の関数を作る必要があるらしい。
string TEST; //こちらは比較用。なんとなく似た形になっているのがわかる。
KOZOTAI
型の変数SHISAKU
はSHISAKU.SUUJI
とSHISAKU.MOJI
からなっていて、それぞれ多分既定値が入っている。ここから、SHISAKU.SUUJI
とSHISAKU.MOJI
を編集することが出来る。
SHISAKU.SUUJI = 100;
SHISAKU.MOJI = "文字";//ここではstring型やint型の編集ルールをそのまま用いる。
以上で、SHISAKU.SUUJI
とSHISAKU.MOJI
の二つの要素を持つ構造体のSHISAKU
が完成した。なんだこれは。
*追記
大体class
と似たようなことができるらしい。class
よりだいぶ軽いけどその分制約(初期化はダメ、継承不可等)が多いらしい。あとclass
は参照型だけど構造体、struct
は値型だとか。以下のサイトで長野 透様がわかりやすく解説してくださっていました。
https://www.sejuku.net/blog/59663 『【C#】構造体の使い方(クラスとの違い、初期化や配列の使用も解説)』