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進数をプログラム処理場で使うイメージがわかないな。

C言語基礎3

1972年にベル研究所のDennis M. Ritchieが設計
UnixもC言語で書かれている
C++、JavaなどはC言語をモデルに設計されている
ANSI(American National Standards Institute)が標準化してANSI/ISO 9899という規格を作った
日本では、JIS X 3010-1993に翻訳した(JIS C)

コンパイラで機械語に変換する。これをオブジェクトモジュールと言う
複数のオブジェクトモジュールを一つにまとめることをlinkと言う linkを行うのはリンカと言うソフトウェア
プログラムを実行させるには、コンパイルしてリンク処理を実行する必要がある。

test1.c -> test1.obj ↓
test1.c -> test2.obj -> link -> test1.exe

### Unixでの操作
gcc smp1.c // a.outが作成される
gcc -o smp1 smp1.c // -oスイッチでファイル名を指定

unixでは、パス設定がされていない場合、カレントディレクトリのファイルをそのまま実行することはできないが、”./”を付与すれば実行することができる。
カレントディレクトリのパスは以下のようにする
$ PATH=$PATH:$HOME/cwork

品質を高めるためには、errorだけでなく、warningも修正した方が望ましい

### 最初のC

#include <stdio.h>
/*
第一歩
*/
int main(void){
	printf("Helicopter money\n");
	return 0;
}

*.hのファイルをヘッダファイルと呼ぶ
stdio.hは入出力時に必要
int main()は、main関数が返す値が整数値であることを指定 main(void)のvoidは、main()に渡されるデータがないことを指定している
文にはセミコロン(;)を付ける
printf()は標準ライブラリ関数
return 0は、正常終了の時はOSに0を、異常終了の時は1異常を返すのが慣例になっている

#include 
/*
インデント
*/
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);
	return 0;
}

$ ./dev
sum=15 mul=120

### データ出力

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

	a = 100;
	b = 12.34567;

	printf("a=%d\n", a);
	printf("a=%f\n", b);
	return 0;
}

### コメント
/* コメント */

### 識別子
- 英文字または_で始まらなければならない
- 長さに制限はないが、31文字(C99は63文字)が識別対象になる
- 予約語を識別子に使うことはできない。例: for
- 大文字と小文字は区別される

### 予約語
auto, double, int, struct, break, else, long, switch, case, enum, register, typedef, char, extern, return, union, const, float, short, unsigned, continue, for, signed, void, default, goto, sizeof, volatile, do, if, static, while

※C99追加
inline, restrict, _Bool, _Complex, _Imaginary

スクリプト言語と比べて、変数代入時の型指定のところがまだとっつきにくいです。

C言語のポインタとメモリ空間2

### メモリの節約
long型は8つのアドレス空間を取るが、ポインタは4つ分のアドレス空間しか取らないため、アドレス空間の節約になる
アドレス(&a)を渡すことを参照渡しという

void f(long *pa){
	*pa += 100;
	printf("%ld\n", *pa);
}


int main(void){

	long a = 1000;
	f(&a);
	return 0;
}

配列でアドレス空間が巨大な場合などは有効

void swap(int *pa, int *pb){
	int tmp;
	tmp = *pa;
	*pa = *pb;
	*pb = tmp; 
}

int main(void){

	int a = 5;
	int b = 10;
	swap(&a, &b);
	printf("a:%d, b:%d\n", a, b);
	return 0;
}

C言語のポインタとメモリ空間1

ポインタとはメモリのアドレスを使って操作をすること
&: アドレス演算子
*: アドレスを示す(間接演算子)
宣言時も*を使う

int main(void){
	int a;
	a = 10;

	int *pa; // *でポインタの宣言
	pa = &a; // &aでaのアドレスを入れる
	printf("%d\n", *pa); //paに入っているアドレスの値を呼び出す

	return 0;
}

$ ./dev
10

なんだこれは? 要は「*」でポインタを宣言した後に、「&」でアドレスを入れて、「*」でアドレスを呼び出してるってことか。
char型でも同じようchar型のポインタを割り当ててできるが、どう活用するかようわからん。

int main(void){
	char s[] = "hello";

	char *ps;
	ps = &s[3];
	printf("%c\n", *ps);

	return 0;
}

C言語基礎2

### 関数
関数: 複数の処理
返り値の型 関数名(引数){
処理;
return
}
C言語は、最初にmain()関数を実行する
main内で使用する関数は、mainよりも上部に書く
プロトタイプ宣言を最上部に記述する

float getMax(float a, float b){
	if(a >= b){
		return a;
	} else {
		return b;
	}
}
void sayHi(void){
	printf("Hi\n");
}
int main(void){
	float result;
	result = getMax(2.3, 5.2);
	printf("%f\n", result);

	sayHi();
	return 0;
}

引数がない場合はvoidをつける

### 三項演算子
返り値 = (条件) ? A : B;

float getMax(float a, float b){
	return (a >= b) ? a : b;
}

### ローカル変数とグローバル変数
※グローバル変数は非推奨

int a = 0;

void f(void){
	a++;
	printf("a:%d\n", a);
}


int main(void){
	f();
	printf("[main]a:%d\n", a);
	return 0;
}

### static
型指定の前に、staticとすると、静的変数となり、値を保持する

void f(void){
	static int a = 0;
	a++;
	printf("a:%d\n", a);
}


int main(void){
	f();
	f();
	f();
	return 0;
}

$ ./dev
a:1
a:2
a:3

### 変数
領域を確保する
なお、variables[]={a,b,c} と書くことができる

int main(void){
        // int sales[] = {200, 405, 302};
	int sales[3];
	sales[0] = 200;
	sales[1] = 400;
	sales[2] = 300;

	printf("%d\n", sales[1]);

	return 0;
}

### 文字列
char型の配列、終端は「\0」
char s[] = {‘a’,’b’,’c’,’\0′};
char s[] = “abc”;

int main(void){
	char s[] = "abc";

	printf("%c\n", s[1]);

	return 0;
}

配列の書き方が原始的というか、他の言語でも仕組み上は同じと考えると、面白いです。

C言語基礎1 

### 変数
変数の指定は、intは%d, floatは%f, charは%cと決まっている。

#include <stdio.h>

/*
int -> %d, 
float -> %f, 
char -> %c
*/

int main(void){

	int x = 10;
	float y = 5.2;
	char c = 'A';

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

$ ./dev
x = 10, y = 5.200000, c = A

### 演算
x++ は+1、x–は-1のこと

int main(void){

	int x = 10 % 3;
	x += 5;
	x++;

	printf("x = %d\n", x);
	return 0;
}

$ ./dev
x = 7

### if
一致の場合は”==”、不一致は”!=”

int main(void){

	int score = 50;
	if(score >= 60){
		printf("nice score\n");
	} else {
		printf("come on\n");
	}
	return 0;
}

$ ./dev
come on

### switch

int main(void){

	int rank = 2;

	switch(rank){
		case 1:
			printf("Gold!\n");
			break;
		case 2:
			printf("Silver!\n");
			break;
		case 3:
			printf("Bronze!\n");
			break;
		default:
			printf("no medal!\n");
			break;
	}
	return 0;
}

### while

int main(void){

	int m = 0;
	while(m < 10){
		printf("m: %d\n", m);
		m++;
	}
	
	return 0;
}

### for

int main(void){

	int m;
	for(m = 0; m < 10; m++){
		if (m == 3){
			continue;
		}
		if (m == 8){
			break;
		}
		printf("m: %d\n", m);
	}

	return 0;
}

$ ./dev
m: 0
m: 1
m: 2
m: 4
m: 5
m: 6
m: 7

改めてC言語を勉強するとなると、C言語が偉大なので、慣れるまで構えてしまいます。

ubuntuでcを実行する

$ cat /etc/os-release
NAME=”Ubuntu”
VERSION=”18.04.4 LTS (Bionic Beaver)”

gccはc言語用のコンパイラ
GNU Compiler Collectionの略

$ gcc –version
gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ sudo apt-get install build-essential

#include <stdio.h>

int main(void){
	printf("hello world!\n");
	return 0;
}

// コンパイル時に-oオプションを使うことで、実行形式ファイルの名前を指定
$ gcc -o hello hello.c
$ ls
hello hello.c
// ./実行形式ファイルパスで実行
$ ./hello
hello world!