C言語構造体

### 構造体とは
関連したいくつもの変数がある時、これをまとめて一つの名前だけで処理できるようにするもの

#include <stdio.h>
#include <string.h>

struct Person {
	char name[40];
	int height;
	int weight;
};

void dataout(struct Person ps){
	printf("name=%s height=%d weight=%d\n", ps.name, ps.height, ps.weight);
}

int main(void){
	struct Person dt, dt2;

	strcpy(dt.name, "tanaka kenichi");
	dt.height = 180;
	dt.weight = 70;

	dt2 = dt;
	dataout(dt2);

	return 0;
}

$ ./dev
name=tanaka kenichi height=180 weight=70

### 構造体の宣言
構造体はintやcharなどの基本データ型を好きなように組み合わせて新しいデータ型として扱うもの
struct 構造体名 {
必要な変数宣言の並び;
};
構造体は初期化することもできる
構造体の宣言はプログラムの先頭部分に記述する
構造体のメンバを指定する時は、2種類のメンバアクセス演算子を使う
-> 変数名で操作する時は”.”
-> ポインタで操作する時は”->”

#include <stdio.h>
#include <string.h>

struct Person {
	char name[40];
	int height;
	int weight;
};

int main(void){
	struct Person d1, d2;
	struct Person *p = &d2;

	strcpy(d1.name, "tanaka kenichi");
	d1.height = 180;
	d1.weight = 70;

	strcpy(p->name, "suzuki tomomi");
	p->height = 160;
	p->weight = 60;

	printf("%s %d %d\n", d1.name, d1.height, d1.weight);
	printf("%s %d %d\n", p->name, p->height, p->weight);

	return 0;
}

### 構造体の引数渡し

#include <stdio.h>

struct myst {
	int d1, d2;
};

struct myst add(struct myst x, struct myst y){
	struct myst wk;
	wk.d1 = x.d1 + y.d1;
	wk.d2 = x.d2 + y.d2;
	return wk;
}

int main(void){
	struct myst a, b = {10, 20}, c = {100, 200};
	
	a = add(b, c);
	printf("%d %d\n", a.d1, a.d2);

	return 0;
}

### 共用体
メモリ上の同じアドレスを複数の変数で共用すると言う機能
キーワードがstructではなくunionになる

union MyType {
	char ch;
	int n1;
	int n2;
};

int main(void){
	union MyType dt;

	dt.n1 = 0x41424344;
	printf("dt.ch=%X\n", dt.ch);
	printf("dt.n1=%X\n", dt.n1);
	printf("dt.n2=%X\n", dt.n2);

	return 0;
}

$ ./dev
dt.ch=44
dt.n1=41424344
dt.n2=41424344

### 列挙型
名前付き定数を使って、データの取り得る値を全て列挙したもの

enum RetType {YES, NO, CANCEL};

int main(void){
	enum RetType ret;

	ret = YES;
	if (ret == YES)
		printf("ret is yes\n");
	else if (ret == NO)
		printf("ret is no\n");
	else if (ret == CANCEL)
		printf("ret is cancel\n");
	printf("%d %d %d\n", YES, NO, CANCEL);
	
	return 0;
}

C言語ポインタ

### メモリ上のデータ配置
どのアドレスに確保するかはコンパイラとリンカとOSが決める
変数のアドレスは&を使う e.g. &mydt

int main(void){
	int mydt = 1234;
	printf("mydt=%d\n", mydt);
	printf("mydt address=%p\n", &mydt);
	return 0;
}

$ ./dev
mydt=1234
mydt address=0x7ffd3a448134

### ポインタ
アドレス値を格納できる
int *pt

int main(void){
	int *pt;
	int mydt = 1234, idt;

	pt = &mydt;
	idt = *pt;
	printf("mydt=%d\n", mydt);
	printf("*pt=%d\n", *pt);
	printf("idt=%d\n", idt);

	mydt = 555;
	printf("mydt=%d\n", mydt);
	printf("*pt=%d\n", *pt);

	*pt = 666;
	printf("mydt=%d\n", mydt);
	printf("*pt=%d\n", *pt);

	return 0;
}

$ ./dev
mydt=1234
*pt=1234
idt=1234
mydt=555
*pt=555
mydt=666
*pt=666

### ポインタの演算
&: アドレスを取り出す(アンド)
*: アドレスにある値を参照する(アスタリスク)

– ポインタを宣言するとき、型指定が必要

### ポインタの配列

int main(void){
	int ary[3] = {100, 110, 120};
	int *pt;

	pt = ary;
	printf("adress=%p value=%d\n", pt, *pt);

	pt = &ary[0];
	printf("adress=%p value=%d\n", pt, *pt);

	pt = &ary[1];
	printf("adress=%p value=%d\n", pt, *pt);

	return 0;
}

$ ./dev
adress=0x7fff517b4eec value=100
adress=0x7fff517b4eec value=100
adress=0x7fff517b4ef0 value=110

### ポインタの加減算
+ – ++ —

int main(void){
	int ary[3] = {100, 110, 120};
	int *pt;

	pt = ary;
	while(1){
		printf("%d\n", *pt);
		if (*pt == 120) break;
		++pt;
	}

	pt = ary;
	printf("%d\n", *pt);
	printf("%d\n", *(pt+1));
	printf("%d\n", *(pt+2));

	return 0;
}

### ポインタと文字列

int main(void){
	char s[10] = "ABCD";
	char *p;

	p = s;

	printf("s=%s\n", s);
	printf("p=%s\n", p);

	while(*p != '\0') {
		*p = tolower(*p);
		++p;
	}

	p = s;
	printf("s=%s\n", s);
	printf("p=%s\n", p);

	return 0;
}

./dev
s=ABCD
p=ABCD
s=abcd
p=abcd
ポインタは文字列アドレスだけでなく、文字列リテラルのアドレスも持つことができる。

### ポインタを引数にする

void func(int *dt){
	printf("value=%d\n", *dt);
}

int main(void){
	int nn = 1234;
	func(&nn);

	return 0;
}

### ポインタによる配列渡し
関数への文字列渡しはポインタを使うのが一般的

void strout(char s[]){
	int i;
	printf("%s\n", s);
	for(i=0; s[i] != '\0'; i++)
		printf("%X ", s[i]);
	printf("\n");
}

void strout(char *p){
	printf("%s\n", p);
	while(*p){
		printf("%X ", *p);
		++p;
	}
	printf("\n");
}

int main(void){
	char st[] = "ABCD";

	strout(st);
	strout_p(st);

	return 0;
}

ポインタを戻り値にする関数を書くこともある

ポインタも、メモリのアドレスにアドレスを格納するという概念さえ理解できれば言うほど難しくはありませんね。

C言語の関数

### 関数基本形
何らかの仕事をするのを「サブルーチン」、計算を「関数」と読んでいる言語もある
int foo(double a) // int型を返す関数, double aを引数という
double foo(double a) // double型を返す関数
void foo(double a) // データを返さない関数
関数から値を返す時はreturn文を使う
関数を呼び出す場合、関数の書式が先に判明している必要がある(関係書式だけ記述したものを関数プロトタイプという)

#include <stdio.h>

double ave(double x, double y){
	double wk;
	wk = (x + y) / 2.0;
	return wk;
}

int main(void){
	double a, b, c;

	a = 11.11;
	b = 33.33;
	c = ave(a, b);
	printf("a=%f b=%f ave=%f\n", a, b, c);

	return 0;
}

$ ./dev
a=11.110000 b=33.330000 ave=22.220000

数値を渡す場合は、Call by value(値呼び出し)という
配列を渡す場合は、アドレスによる呼び出し

void disp_ary(int n[]){
	printf("n[0]=%d\n", n[0]);
	printf("n[4]=%d\n", n[4]);
}

int main(void){
	int dt[5] = {10, 20, 30, 40, 50};
	disp_ary(dt);

	return 0;
}

$ ./dev
n[0]=10
n[4]=50
※配列名を指定すると、配列の先頭アドレスとして評価される
Cでは配列の長さはプログラマーが上手くやってくださいとなっている

### 文字列の引き渡し
最後の”\n”を利用することで長さを知ることができる

#include <stdio.h>

void strout(char s[]){
	int i;
	printf("s=%s\n", s);
	for(i=0; s[i] != '\0'; i++)
		printf("%X ", s[i]);
	printf("\n");
}

int main(void){
	char st[] = "ABCD";
	strout(st);
	strout("abcde");
	return 0;
}

### ローカル変数とグローバル変数
グローバル変数はmain()の中の値でも使える
ローカル変数は衝突しない。グローバルよりローカルが優先される

#include <stdio.h>

int g;

void func(void){
	int b;
	b = 99;
	printf("func b=%d g=%d\n", b, g);
}

int main(void){
	int a;
	a = 10;
	g = 20;
	printf("func a=%d g=%d\n", a, g);
	func();

	return 0;
}

$ ./dev
func a=10 g=20
func b=99 g=20

staticの静的変数は値を保持する

#include

int g;

void func(int n){
int a = 0;
static int s = 0;

a = a + n;
s = s + n;
printf(“a=%d s=%d\n”, a, s);
}

int main(void){
int i;
for(i=1; i<=5; i++){ func(i); } return 0; } [/code] $ ./dev a=1 s=1 a=2 s=3 a=3 s=6 a=4 s=10 a=5 s=15

C言語printf, scanf

### printfの機能
文字列や変数値を出力する機能
他にもputchar(), puts()などがあるが、printf()でも記述できる。
putchar(ch);
puts(ss);
printf(“%c”, ch);

### printfの変換指定
%o: 8進数出力
%d: 10進数出力
%x: 16進数出力
%X: 16進数出力
%ld: long型数値を10進数で出力
%f: 不動小数点として出力
%e: 指数形式で出力
%E: 指数形式で出力
%c: 文字として出力
%s: 文字列として出力
%p: アドレスを表示

int main(void){
	char c;
	int n;
	long l;
	float f;
	double d;
	char s[20] = "abcde";

	c = 65;
	printf("c: %c\n", c); //文字列
	printf("10: %d\n", c); //10進数
	n = 66;
	printf("c: %c\n", n); //文字列
	printf("10: %d\n", n); //10進数
	n = 1000;
	printf("8: %o\n", n); //8進数
	printf("10: %d\n", n); //10進数
	printf("16x: %x\n", n); //16進数
	printf("16X: %X\n", n); //16進数 英大文字
	l = 1234567890;
	printf("ld: %ld\n", n); //long
	f = 12.34F;
	printf("f: %f\n", n); //浮動小数点数
	printf("e: %e\n", n); //指数形式
	printf("E: %E\n", n); //指数形式 英大文字
	d = 56789.12;
	printf("f: %f\n", d); //浮動小数点数
	printf("e: %e\n", d); //指数形式
	printf("E: %E\n", d); //指数形式 英大文字
	printf("s: %s\n", s); // 文字列
	printf("c=%d n=%d s=%s", c, n, s);

	return 0;
}

### printfのオプション
%d: 必要な幅で出力
%8d: 8文字で出力
%-8d: 左寄せ8文字幅で出力
%2d: 指定値の方が小さくても必要幅は確保
%8X: 先行スペース文字を入れて8文字
%08X: 先行0を入れて8文字出力 ※16進数に便利
%12f: 小数点を入れて12桁
%9.2f:小数点を入れて9桁、小数点以下2桁
%9.f: 整数部のみ9桁

### scanfの機能
scanf()は書式付き入力を行う関数
scanf(書式指定文字列, 変数アドレスの並び);
格納先は変数名ではなく変数のアドレス
※単純変数の場合は&を付け、配列変数の場合は&は不要

### scanfの変数指定
%o: 8進数
%d: 10進数
%ld: long型変数に10進数読み込み
%x: 16進数
%f: float型
%lf: double型変数
%c: 1文字
%s: 文字列

int main(void){
	int i;
	float f;
	double d;
	long l;
	char s[80];

	printf("1文字入力:");
	scanf("%c", &i);
	printf("1文字出力=%c\n", i);

	printf("文字列入力:");
	scanf("%s", s);
	printf("文字列出力=%s\n", s);

	printf("8進入力:");
	scanf("%o", &i);
	printf("10進出力=%d\n", i);

	printf("10進入力:");
	scanf("%d", &i);
	printf("10進出力=%d\n", i);

	printf("16進入力:");
	scanf("%x", &i);
	printf("10進出力=%d\n", i);

	printf("long入力:");
	scanf("%ld", &l);
	printf("long出力=%ld\n", l);

	printf("float入力:");
	scanf("%f", &f);
	printf("float出力=%f\n", f);

	printf("double入力:");
	scanf("%lf", &d);
	printf("double出力=%16f\n", d);

	return 0;
}

$ ./dev
1文字入力:A
1文字出力=A
文字列入力:abc
文字列出力=abc
8進入力:11
10進出力=9
10進入力:9
10進出力=9
16進入力:11
10進出力=17
long入力:1234567890
long出力=1234567890
float入力:12.3456
float出力=12.345600
double入力:123456.78901
double出力= 123456.789010

gets()は空白を含む文字列を読み込むが、scanf()は空白類文字列に出会うと終了

### 標準入力と標準出力
リダイレクトを指示すると、ファイルから入力し、ファイルから出力するようになる
bb.txt // 出力先をbb.txtにする

int main(void){
	char ss[256];

	gets(ss);
	puts(ss);

	return 0;
}

$ ./dev
abcd
abcd
$ ./dev >aa.txt
hogehoge
$ ./dev bb.txt
$ ls
aa.txt bb.txt dev hello.c
$ cat bb.txt
hogehoge

標準出力の意味がここでやっとはっきりしました。

C言語のコンソール入出力基本パターン1

### 基本用法
– getchar(), gets(), scanf()は「標準入力」(キーボード)から入力
– putchar(), puts(), printf()は「標準出力」(ディスプレイ)に出力

int main(void){
	int ch; // 変数確保

	ch = getchar();
	putchar(ch); // 入力文字を画面に出力

	return 0;
}

$ ./dev
hello
h
※getchar()関数はキーボードから1文字を入力する

### 連続文字入力

#include <stdio.h>
#include <ctype.h> /* for toupper() */

int main(void){
	int ch; // 変数確保

	ch = getchar();
	while (ch != EOF){
		ch = toupper(ch);
		putchar(ch);
		ch = getchar();
	}

	return 0;
}

$ ./dev
hello
HELLO
※EOFはend of fileで、[ctl]+[z]で終了。
※バッファリング処理で、内部バッファで1行単位で読み込み、内部的に1文字ずつ処理している。

### 1行入出力

int main(void){
	char s[80];

	gets(s);
	puts(s);

	return 0;
}

$ ./dev
abc def
abc def

gets()はキーボードから文字列を1行入力する為の関数
puts()はディスプレイに文字列を出力する為の関数
– 文字列だけしか出力できない
– 文字列を出力した後、自動的に改行を行う

hello.c:(.text+0x24): warning: the `gets’ function is dangerous and should not be used.
gets()関数の配列オーバーに対する危険性は広く認識されている。C11では安全なgets_s()関数が使えるようになっている。

### 連続文字列入力

int main(void){
	char s[80];

	while (gets(s) != NULL){
		puts(s); puts(s);
	}

	return 0;
}

$ ./dev
abcde
abcde
abcde
XYZ
XYZ
XYZ

[ctl]+[z]でNULLを返す。NULLの値はstdio.hの中で定義されている

int main(void){
	char s[80];

	while(1) {
		gets(s);
		if (strcmp(s, ".") == 0) break;
		printf("input char is %s.\n", s);
	}

	return 0;
}

strcmp()は文字列を比較する関数

### 整数値の入出力

int main(void){
	int n;

	scanf("%d", &n);
	printf("%d\n", n);

	return 0;
}

scanf()関数はキーボードから色々なデータを入力する機能をもつ。
scanf(“%d”, &n)は、変数のアドレスを記述する

double ddt;
scanf(“%lf”, %ddt);
printf(“%f\n”, ddt);

scanf()は数値入力のみ受け付ける

int main(void){
	int n = 9999;

	scanf("%d", &n);
	printf("number is %d\n", n);

	return 0;
}

gets()関数で文字列として受け取って、atoi()関数で整数に変換という方法もある
不動小数点の場合はatof()

int main(void){
	int n;
	char s[80];

	gets(s);
	n = atoi(s);
	printf("number is %d.\n", n);

	return 0;
}

scanf や fgetsは、格納先に入力できる最大長を指定することでバッファオーバーランを回避することができる
getsは入力される文字列の長さを制限する機能が存在しない
C言語の設計者は、配列格納とは異なる意図でgets()を作ったのだろうか
プログラムの脆弱性をつくプログラマーも相当ロジカルでないと務まらんな

C言語の制御文

### 制御文の記述
– if, for, whileなどの制御式を使う
– 制御式が条件を満たしていることをture, 満たしていないことをfalse
– 何もしない空文は ; と書く

### if文

int main(void){
	int a = 10, b = 20, c;

	if (a == 10)
		printf("a is 10. \n");
	if (a == b){
		printf("a is equal to b. \n");
	} else {
		printf("a is not equal to b. \n");
	}

	if (b > 100) c = 1;
	else if (b > 50) c = 2;
	else if (b > 10) c = 3;
	else c = 9;
	printf("b=%d c=%d\n", b, c);
	return 0;
}

$ ./dev
a is 10.
a is not equal to b.
b=20 c=3

### for

int main(void){
	int i, sum, mul;

	sum = 0; mul = 1;
	for(i=1; i<=5; i++){
		sum = sum + i;
		mul = mul * i;
	}
	printf("sum=%d mul=%d\n", sum, mul);

	for(i=40; i>=20; i=i-2){
		printf("%d ", i);
	}
	printf("\n");
	return 0;
}

$ ./dev
sum=15 mul=120
40 38 36 34 32 30 28 26 24 22 20

### while
while(1)と書くと、breakを使わないと無限ループになる

int main(void){
int i=1;
while(i < 1000){ printf("%d ", i); i = i * 2; } printf("\n"); return 0; } [/code] $ ./dev 1 2 4 8 16 32 64 128 256 512 ### do-while do-whileは使用頻度が然程高くない [code] int main(void){ int n; char a[80], b[] = "ABCD"; n = -1; do { ++n; a[n] = b[n]; } while(b[n] != '\0'); printf("a=%s b=%s\n", a, b); return 0; } [/code] $ ./dev a=ABCD b=ABCD ### switch [code] int main(void){ int a; for(a=1; a<=5; a++){ printf("-------%d\n", a); switch(a){ case 1: printf("a=1\n"); break; case 3: printf("a=3\n"); break; case 5: printf("a=5\n"); break; default: printf("others\n"); } } return 0; } [/code] $ ./dev -------1 a=1 -------2 others -------3 a=3 -------4 others -------5 a=5 ### break & continue [code] int main(void){ int n; printf("----- break test\n"); for (n=1; n<=3; n++){ printf("%d start\n", n); if (n == 2) break; printf("%d end\n", n); } printf("----- continue test\n"); for (n=1; n<=3; n++){ printf("%d start\n", n); if (n == 2) continue; printf("%d end\n", n); } return 0; } [/code] $ ./dev ----- break test 1 start 1 end 2 start ----- continue test 1 start 1 end 2 start 3 start 3 end 意図的に無限ループを指定できるってのは面白いです。

C言語の演算子

### 算術演算子
+: 加算
-: 減算
*: 乗算
/: 除算
%: 余り

int main(void){
	int a, b, n;
	double d1, d2, dd;

	a = 100; b = 30;

	n = a + b; printf("%d\n", n);
	n = a - b; printf("%d\n", n);
	n = a * b; printf("%d\n", n);
	n = a / b; printf("%d\n", n);
	n = a % b; printf("%d\n", n);

	d1 = 90.0; d2 = 40.0;
	dd = d1 / d2; printf("%f\n", dd);
	return 0;
}

$ ./dev
130
70
3000
3
10
2.250000
intとdoubleなど混合計算も可能。その場合、表現能力の高いデータ型(double)に合わせて計算される。

### 関係演算子と等価演算子
<: 小さい <=: 小さいか等しい >: 大きい
>=: 大きいか等しい

等価演算子
==: 等しい
!=: 等しくない
※[C = 10]は代入、[C == 10]は等しいなので、注意が必要

### 論理演算子
!: NOT
&&: AND
||: OR

### インクレメント・デクレメント演算子
++: ++a(先加算) or a++(後加算);
–: –a(先加算) or a–(後加算);

先加算とは、先に1を足してから代入
e.g.
a = ++b  ↓
b = b+1; a = b

後加算とは、先に代入してから加算処理
e.g.
a = b++;
a = b; b=b++;

### 代入演算子
単純代入演算子: =
複合代入演算子: +=, -=, *=, /=, %=, &=, ^=, |=, <<=, >>=
a = b = 20
a *= b + c; ↓
a = a *(b + c); と解釈される

### キャスト演算子

int idt;
double ddt = 123.456;

idt = ddt;
printf("idt=%d ddt=%f\n", idt, ddt);

doubleからintへの変換で小数点以下のデータが失われる為、warningが出ることがある。
キャスト演算子では、 idt = (int)ddt; と言うように書く
warningを消す目的だけでなく、整数部分のみ取得したい場合にも使われる

### 条件演算子(三項演算子?)
条件式 ? 式1 : 式2
e.g.
b = (a < 10) ? 200: 300; ### ビット演算子 ビット単位のデータ操作をする &: ビット毎のAND a = b & 0x7FFF |: ビット毎のOR a = b | 0x8000 ^: ビット毎のXOR a = b ^ 0x000F ~: ビットの反転 a = ~a; <<: 左シフト a = a << 2; >>: 右シフト a = a >> 2;

int main(void){
	int a = 0x00005555;
	int b = 0x000000FF;
	int c;

	printf("a=%08X\n", a);
	printf("b=%08X\n", b);
	c = a & b; printf("&=%08X\n", c);
	c = a | b; printf("|=%08X\n", c);
	c = a ^ b; printf("^=%08X\n", c);
	c = ~a; printf("~=%08X\n", c);
	return 0;
}

$ ./dev
a=00005555
b=000000FF
&=00000055
|=000055FF
^=000055AA
~=FFFFAAAA
※[%08X]は、先行0埋め、8文字幅の16進数
※負の数の右シフトはC処理系によって動作が異なることがある

### sizeof演算子
引数のサイズをバイト数で返す。

int main(void){
	int a, b[10];

	printf("%d\n", sizeof a);
	printf("%d\n", sizeof b);
	printf("%d\n", sizeof(char));
	printf("%d\n", sizeof(short int));
	printf("%d\n", sizeof(int));
	printf("%d\n", sizeof(long int));
	printf("%d\n", sizeof(float));
	printf("%d\n", sizeof(double));
	return 0;
}

$ ./dev
4
40
1
2
4
8
4
8

### 演算子の優先順位
優先順位の高い演算子が先に計算される
* / % は + – より優先処理される
()を使うと、括弧の内部を先に計算する
同じ優先順位の演算子が連続した時は、左から(あるいは右)処理を行う
a = b = 10; // この場合は、右から処理
結合規則で右からは前置(++, –)、キャスト(型名)、条件(?:)、代入(=など)。それ以外は左から処理

ビット演算子は状態管理やサブネットマスクなど多種多様に使われているとのこと。実際にビット演算子を使って作らないと、いまいち頭に入ってきませんな。

C言語の文字列と配列

### char型配列で文字列を表現
char ss[80]; char型の変数80個
strcpy(s, “abcde”); // 文字列を設定

#include <stdio.h>
#include <string.h>
int main(void){
	char s[80];

	strcpy(s, "abcde");
	printf("%s\n", s);
	return 0;
}

$ ./dev
abcde

C言語では文字列は文字コードの最後に0を付加すると言うルールで配列に格納される。
‘A’,’B’,’C’,0
-> コードが0になるまで何かの処理をする。null characterと言う。その為、0を含めて十分な長さのchar[]配列を確保する必要がある。10文字の場合は、char s[10]ではなく、char s[11]でないと、異常動作の原因になる。

int main(void){
	char s[10];

	s[0] = 'A';
	s[1] = 'B';
	s[2] = 'C';
	s[3] = 0;
	printf("%s\n", s);
	printf("%d %d %d %d\n", s[0], s[1], s[2], s[3]);
	return 0;
}

$ ./dev
ABC
65 66 67 0

s[3] = ‘0’; とすると、以下のような出力になる。
ABC0?B?
65 66 67 48

char型配列の性格を利用すると、以下のような書き方もできる。

int main(void){
	char s[10];

	strcpy(s, "abcdef");
	printf("%s\n", s);
	s[3] = 0;
	printf("%s\n", s);
	return 0;
}

$ ./dev
abcdef
abc

※文字をクリアする時は strcpy(s, “”);に加えて、s[0] = 0も。
s[0] = 0 は、s[0] = ‘¥0’;でも表現できる。
意味合いは同じだが、s[0] = 0 は、0を代入しているみたいなので、s[0] = ‘¥0’の方がよく使われる。

int main(void){
	char s[10];

	strcpy(s, "abcdef");
	printf("%s\n", s);
	s[3] = '\0';
	printf("%s\n", s);
	s[3] = 'X';
	printf("%s\n", s);
	s[0] = '\0';
	printf("%s\n", s);
	return 0;
}

$ ./dev
abcdef
abc
abcXef

### 変数の初期化

int main(void){
	char c = 'A';
	int i = 1234;
	double d = 3.45;

	printf("c=%c\n", c);
	printf("i=%d\n", i);
	printf("d=%f\n", d);
	return 0;
}

$ ./dev
c=A
i=1234
d=3.450000

– 配列の初期化
int a[5] = {11, 12, 13, 14, 15};
double b[5] = {10.1, 10.2, 10.3, 10.4, 10.5};

int a[] = {10, 20, 30};  // 初期化する際に省略できる
int a[3] = {10, 20, 30}; // 上と同じ

int a[2][3] = {{10, 20, 30}, {40, 50, 60}};

– 文字配列の初期化
char s[5] = {65, 66, 67, 68, 0}; // 直接数値を書く
char s[5] = {‘A’, ‘B’, ‘C’, ‘D’, ‘\0’}; // 文字定数をかく
char s[5] = “ABCD”; // 文字列で初期化

char e[] = “abcd”; // 省略可
char e[5] = “abcd”;

char s[80] = “aaaa”;
s = “bbbb”; // !エラー
strcpy(s, “bbbb”) // 初期化以外の文字列設定にはstrcpyを使う

### 初期化をしなかった場合
グローバル変数は0系の値に、ローカル変数は不定値になるとされている。

int gdt;
int main(void){
	int ldt;

	printf("%d\n", gdt);
	printf("%d\n", ldt);
	return 0;
}

$ ./dev
0
0

文字列の配列で、’0’を終端とする思想は面白い。確かに、nullや空白だと、英語を始め、あらゆる言語でセンテンスが成り立たなくなる。
それと、プログラミング学習はC言語から学ぶと良いというが、スクリプト言語->C言語の順番が必ずしも駄目って訳ではなさそうに感じる。

C言語の変数とデータ型

### 変数の宣言
int a, b;
a = 10;
a = 20 + 30; // a=50
b = a; // b=50
b = a + 100; // b=150
b = b + 200; // b=350;
※const変数は値を参照できるが変更はできない

### データ型
char(1byte): -128〜127
unsigned char(1byte): 0〜255
int(4byte): -2147483648〜2147483648
unsigned int(4byte): 0〜4294967295
short int(2byte): -32768〜32767
unsigned short int(2byte): 0〜65535
long int(4byte): -214783648〜214783647
unsigned long int(4byte): 0〜4294967295
float(4byte): 10^-37〜10^38
double(8byte): 10^-307〜10^308
long double: doubleと同じかそれより大きい
※バイトはメモリ内に確保されるメモリサイズ
※unsignedはマイナスの符号なしのデータ表現
※signed, unsigned, short, longが先行する場合はintを省略できる
※初級ではint, char, doubleがよく使用される

int main(void){
	printf("%d\n", sizeof(char));
	printf("%d\n", sizeof(int));
	return 0;
}

$ ./dev
1
4

### データ型の性格
– char型は1byteだが、int型は4byte, char型の配列を文字列型と称することがある
– double, floatなどの浮動小数点の値をint型に入れようとすると、小数点以下が切り離される ※四捨五入はなし

### 整数値のオーバーフロー
2147483647に、1をプラスすると、オーバーフローして、-2147483648になる。

int main(void){
	int a;
	a = 2147483647;
	a = a + 3;
	printf("%d\n", a);
	return 0;
}

### floatとdoubleの使い分け
浮動小数点数は通常double型が使われる。sin, cos, tanなどは全てdouble型を返す
floatは、大量のfloat型データを使用する際など、メモリ領域を節約したい時に有効

### 配列
int dt[10];
dt[10] = 100; // 不正、dt[10]はdt[0]〜dt[9]

### 多次元配列
int a[2][3]; // 二次元配列、配列長3の配列を2組用意した構成
int b[5][6][7]; // 三次元配列
※二次元配列以外を使うのは稀

int main(void){
	int dt[3][5];

	dt[0][0] = 11;
	dt[1][3] = 55;
	dt[2][4] = 66;

	printf("%d\n", dt[0][0]);
	printf("%d\n", dt[1][3]);
	printf("%d\n", dt[2][4]);
	return 0;
}

多次元配列や行列には慣れないといけませんね。

C言語基礎4

### 整数定数
数値や文字列を直接表現したものを定数(リテラル)と言う。
– 整数定数
 L 8進定数 0~8
 L 10進定数 0~9
 L 16進定数 0〜9, A~F ex.0x1a, 0XAB03
 L unsigned型定数 uまたはU ex.12800U
 L long型定数 lまたはL ex.0L

### 浮動小数点型定数
小数点形式と指数形式がある。デフォルトはdoubleで、接尾語を付けることでfloat型やlong double型になる。
– 整数定数
 L 小数点形式 double型 12.345
 L 指数形式 eまたはE 3.456E2(=345.6), 6.78e-3(=0.00678)
 L float型 fまたはFを末尾に付ける 12.34F
 L long, double型 lまたはLを付ける 100.23L 5.67e-21

int main(void){
	int n8, n10, n16;
	double f1, f2;

	n8 = 0100;
	n10 = 100;
	n16 = 0x100;
	f1 = 1.234;
	f2 = 5.678e2;

	printf("n8=%d\n", n8);
	printf("n10=%d\n", n10);
	printf("n16=%d\n", n16);
	printf("f1=%f\n", f1);
	printf("f2=%f\n", f2);
	return 0;
}

### 文字定数と文字列リテラル
文字定数はそれぞれの文字が持っている文字コードを表現するもの
int c;
c = ‘A’;
c = 65 ….Aに対応する文字コード

二重引用符合で囲ったものを文字列リテラルと言う
“ABCDEF”
“C language”

### その他の定数機能
¥a : alert
¥b : back space
¥f : form feed(改ページ)
¥n : new line
¥r : carriage return(復帰)
¥t : horizontal tab(水平タブ)
¥v : vertical tab(垂直タブ)
¥’ : 文字定数対策
¥” : 文字列定数対策
¥? : 三連文字対策
¥ooo : 8進数 octal
¥xhh : 16進数 hexadecimal

単一文字コードで用いる時は’¥n’と囲むが、文字列リテラルに埋め込む時は、”AAAA¥tBBBB¥n”とそのまま書く
”’ … エラー
‘¥” … 正常

### 記号定数
任意のデータを意味ある名前で扱うようにするための記号定数
e.g.
#define MAXDATA 3715

### const付定数
宣言の時に値を設定し、それ以降は値の変更ができない
e.g.
const int a = 10;

8進数が2進数の3乗で、電子回路の処理上、都合がいいのはわかるが、8進数をプログラム処理場で使うイメージがわかないな。