それが僕には楽しかったんです。

僕と MySQL と時々 MariaDB

セキュリティミニキャンプ北海道2016に参加してきた

初めてミニキャンに参加してきた

LOCAL学生部に加入して、しばらくしてからミニキャンのお知らせが回ってきたから何をやるんだという感じで詳細を見てみると…。Linuxでハードウェア制御、スマホアプリでサーバサイドへの攻撃と対策、クラウドセキュリティ基礎…。これほど興味を引く内容なのに申し込まないわけにはいかない!
というわけで、申し込んで無事行くことになって、この前の週末に参加してきた。

ミニキャンに参加してみて

セキュリティあんまり興味なかったけど、セキュリティキャンプはセキュリティ以外にも色々実習を行ったり、チームに分かれてディスカッションしたりと面白かった。

印象に残った講義の感想

初日に行われた、「スマホアプリでサーバサイドアプリケーションへの攻撃と対策を学ぶ」はミニキャンプが開催された二日間の中で特に面白かった。
BurpSuiteという脆弱性診断によく使用されるソフトウェアを使用して、実際にHTTP通信を覗いたり編集したりして脆弱性を探して行ったわけだけど、チーム別に行ったのでチームのみんなで「ああだこうだ」言いながら色々試していった。別のチームの事情はよくわからないけど、自分たちのチームはセキュリティとかネットワークに強いひとがいなくてすごく苦戦した。だけど、そういう分野に強い人が居なかったが故にみんなで意見出し合いながら実習を行えたのはすごくいい経験になったし、今までセキュリティの仕事ってどんなことするのか曖昧だったものが経験を通して「これがセキュリティの仕事だ」といったものを実感できたのも良かった。


それ以外で面白かったのは「クラウドセキュリティ基礎」。
これはいろんなパワーワードが飛び交ってすごく笑えた。特に「今日のサーバはペットではなく家畜」と「耐用年数間近のサーバなんて電気代バカ食いするだけのゴミ」が最高にキテる。それにこの講義の内容はwebサービスやサーバ関連の内容からクラウドに移っていったので、最近VPSを借りてwebサービスを構築しようとしていた自分にとってはすごくためになることばかりだった。それに今までサーバとかクラウドといった環境が用意できないからという理由でweb系の事を全くやってこなかったので、本当に基礎的な部分から始まった講義は全てが新鮮だった。


その次は、なんといっても「Linuxを用いたハードウェア制御」の講義がためになった。
実はミニキャン前はこれをすごく楽しみにしていた。実際はすごくハードウェア的なことを中心にやっていくものだったけど未経験だった電子工作的な部分とシステムコール的な処理を同時に学べたのは最高に面白かった。出来ることならハードウェア制御という名前らしく、自分でハードウェアを制御するプログラムを作ってみたかった。

全体を通して

ミニキャンが開催された、二日間は最高の時間だったと振り返ってみて思う。それもそうで、普段大学では、一年生ということもあるのかこういった内容はみんな勉強しないで、たとえやったとしても「授業でやるから」「テストがあるから」といったような理由で自分がわくわくするようなことがまず無い。それに一応存在するプログラミングサークル的なものではUnityとか他のライブラリ使ってゲームを作るだけなどと、もっといろんな事を勉強して吸収していきたい自分にとってはすごく生温い環境の中にいたからである。ただ、ミニキャンは違った。ミニキャンは、みんなが何かしら自分が得られるものを全部自分のものにしてしまえ。といったような気迫ややる気と言ったものが感じられ、チームディスカッション一つとっても今までの自分にはなかった発想がたくさん展開され、演習も「そうするのか!?」といった驚きばかりだった。生温い環境に居た自分にはこういった時間がすごく刺激的だった。その中で、自分のスキルの無さを多少なりとも実感し、このままでは数年後に社会に出て、今回出会った人たちと競っていくことになったら自分は確実に劣るといった根拠の無い確証も得た。

今回、ミニキャンに参加しそういった実感があったからこそ、それをそのままにせず、自分はもっともっと成長しなければいけない、成長し続けなければいけないと思う。ミニキャンは消えそうだった自分のエンジニア魂を燃えさせるいいきっかけとなった。参加して本当に良かった。

出来ることなら来年のセキュリティキャンプの全国大会に参加したい。きっとそこにはもっと成長できる刺激的な環境が待っているだろうから。

後日談

キャンパーはその後紀伊国屋に集結してしまった。やはり似てるものはある。
あと、これからOS、カーネルの人になろうと思う。
「普段は何の人ですか?」と聞かれて答えれないのはあれだから。

さくっとアセンブリ入門 hello,world編

さくっとアセンブリ入門

なんとなくアセンブリをはじめてみる
レジスタがーとかメモリがーっていうお話は割愛

とりあえず「Hello,World」

まずはお決まりの「Hello,World」から

.globl main
main:
movl $4,%eax
movl $1,%ebx
movl $msg,%ecx
movl $13,%edx
int $0x80
movl $1,%eax
movl $0,%ebx
int $0x80
.data
msg: .asciz "Hello,World\n"

今まで色々なプログラミング言語に触れてきたけど、これほど初見で難解なhello,worldを見たことがない

わからないながら解説

まず一行目の「.globl」のように.から始まる命令をディレクティブといいアセンブラに対する命令を表している
その中でも「.globl」はエントリーポイントを指定するものである。またGASを使用するのでmainを指定しておく

二行目の「:」これがつくとC言語と同様にラベルになる
またラベルはプログラム実行中のメモリアドレスの代わりとして定数のように使用可能(最終行で使用)

三行目から六行目までは代入処理で「mov命令」と呼ばれるもの
この命令は以下の形式を取る

mov [代入元],[代入先]

詳しくは後述
$から始まるものは数値で%から始まるものはレジスタ

そしてこのmov命令を今回のコードの中では「mov」ではなく「movl」となっている
これは「long word」のlである。
アセンブリはただ数値としてすべてを扱うので何ビットずつ数値を扱っているかということを示す必要がある
これをオペレーションサフィックスといい以下のようなものが使える

サフィックス サイズ
b バイト、8ビット
s ショートで16ビット整数かシングルの32ビット浮動小数
w ワード、16ビット
l ロングで32ビット整数か64ビット浮動小数
q クワッド、64ビット
t 10バイト、80ビット浮動小数

これらから、Byte値を代入するなら「movb」となりWord値を代入するなら「movw」となる
今回はLongWordなので「movl」となる


七行目の謎の処理は「割り込み命令」といい、CPUが処理をしている時に現行作業を復帰可能な状態にして割り込みする処理を実行するといったもの
またここでは16進数で0x80を指定しているが、これは割り込み番号0x80番でシステムコールを実行してくださいということ

11行目でのdataディレクティブでは実行用のコードがおいてあるのではなく、初期化済みのデータを置くと宣言している

最後はascizディレクティブは文字列を置くと宣言するもので最後にnull文字を付与する

メディアンフィルタ

メディアンフィルタ

移動平均法ではn*nの局所領域における濃度の平均値を領域中央の画素が保有する濃度として扱ったが
別の画質改善法にメディアンフィルタというものがある
これは局所領域中の濃度値の中央値を領域中央の画素が保有する濃度として扱う方法である

例えば以下のような画素の一次元配列が存在すると仮定する
1,4,5,6,7,3,2,9,5
これを移動平均方では平均値を領域中央として扱ったが
メディアンフィルタでは
1,2,3,4,5,5,6,7,9
と並べ替えて中央値を領域中央の値とする

詳しい仕組み

メディアンフィルタでは、局所領域における画素の中央値を扱うため
その領域内の画素に対して非線形な演算を必要とするが、領域内の要素数を奇数にする
つまりnを奇数としてn*nの領域に対して処理を行うことで中央値を一意に求めることが可能になる

メディアンフィルタの使いところ

メディアンフィルタは雑音、つまりノイズが画像の内容と無関係でランダムな白色雑音の時に有効な手段としてつかえる
これはメディアンフィルタによる処理を行うことでスパイク状の雑音が取り除かれることとエッジがボケることが少ないためである

平均値を取る移動平均法のような手段では処理を重ねていくたびに周辺画素への影響が大きくなるが
メディアンフィルタのように中央値を選ぶことで極端な値の影響を非線形な演算が吸収しているためである

OpenCVPythonで実装してみる


いつもどおりPythonOpenCVメディアンフィルタをかけてみる

#coding:utf-8

import numpy as np
import cv2

#画像を読み込み
img = cv2.imread("lenna256.png")
#グレースケール化
gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
#これは奇数にしておく必要がある
k = 3

res_img = cv2.medianBlur(gray,k)

cv2.imshow("median filter",res_img)
cv2.waitKey(0)
cv2.destroyAllWindows()


ここで使った画像はいつものlenna256.png
これをグレースケール化してlenna256_median.pngを生成する

lenna256.png
f:id:RabbitFoot141:20160403113730p:plain

そしてこれがメディアンフィルタを適用させた画像
lenna256_median.png
f:id:RabbitFoot141:20160403113807p:plain

他の画質改善手法に比べてスパイク雑音を取り除き、エッジに与える作用が小さいので
移動平均法などに比べて、連続した部分は滑らかになり
輪郭線もある程度はっきりしている

サイトをリニューアルしたから今回使ったものをまとめてみた

はじめに

今回自分のサイトをリニューアルしたので
kentsu-141.github.io
これに使ったものをざっくりまとめてみる

基本的なデザイン

まず基本的なデザインはこのホームページを見て思いついた
sard.website
ただ画像なんかを用意するのがめんどくさかったのと
なるべく最初の状態でスクロールする状況を作りたくなかったので

折りたたみ(後述)といつもどおりのカラーだけでゴリ押しのスタイルで作ると
今回のようなサイトになった

折りたためるあれ

今回使ったもので、表示部分を折りたためるあれは「アコーディオン」というもので
htmlタグのdl,dt,ddタグとjqueryを使って作った

参考にしたサイトはこれ
liginc.co.jp

これで表示部分を折りたためるようになった
しかしデフォルトでは折りたたまれず展開された状態になってしまうので

dd{
    display:none;
}

スタイルシートに追加しておいた
これでページ読み込み時で折りたたまれた状態になる

フォント

今回は今まで使ってこなかった方法でフォントを持ってきてみた

@import url(http://fonts.googleapis.com/css?family=Economica:400,700);

普段はダウンロードしたrobotoとかtahoma,impactあたりを使うんだけどこれもこれで良かった
こうして持ってきたフォントは以下のように使う(今回は全ページで統一なのでbodyタグに)

body{
    font-family:'Economica',sans-serif;
}

アニメーション

これが一番気になるだろうけど、特に独自実装したわけでなく
外部からwow.jsとanimate.cssを持ってきただけという

animate.cssは以下のサイトからいろいろ選べる
https://daneden.github.io/animate.css/

wow.jsはanimate.cssと併用するため必要
以下のレポジトリからダウンロードした
github.com

ただ注意すべきは、wow.jsをググればわかるが
ページがスクロールされ表示範囲に入った時にアニメーションに入ることや
サイズの大きい要素や、いくつも要素を同時に動かすと特にスマホなどで見た時にラグがでてかくかくになるので注意

最後に

割といつもフラットデザインになるようにしているが今回もなかなか微妙な出来になってしまった

C言語 構造体

6章 構造体

構造体とは、操作しやすいように一つの名前でまとめられた
1つ以上の異なった型の集まりである

この構造体と呼ばれるものは大きなプログラムで特に複雑なデータを組織化するのに役立つ
それは関連したデータを実体としてでなく一つの単位として扱えるという性質から来ている

6.1 構造体の基本事項

まずは構造体を使って二次元平面上の点を構造体を使って表してみる

int x,y;

普通はこう表すかもしれないけど、構造体でひとつの単位としてまとめるとこうなる

struct point{
    int x;
    int y;
};

これでpointという平面上での座標を表す一つの単位が出来た
前者に比べて後者のほうが何を示しているかわかりやすくなる

ここで少し説明するとstructという予約語の後に続いている名前は構造体タグと言われるものである
この構造体タグなるものは宣言以後、カッコ内の宣言部分の略称としてしようすることができる

構造体の中で命名された変数はメンバーと言われる
そして構造体タグとメンバー名は同名であってもぶつかることはない

構造体を使いたいときは以下のような記述をする

struct point pt;

これによりptはstruct point型であると宣言される

また以下のように各メンバーに対する定数式による初期化式の並びを定義の後につけることで構造体を初期化することができる

struct point max_pt = {100,100};

さらに宣言だけしておいて以下のように別々に初期化することも出来る

struct point min_pt;
min_pt.x = -100;
min_pt.y = -100;

上の例でわかるように

構造体型の変数名.メンバー名
>||
でその構造体のメンバにアクセスできるため、値を代入するときだけじゃなくて
値を呼び出したいときにも使用することが出来る


構造体は入れ子にすることも出来て
以下のようなメンバーを持つ構造体を宣言することも出来る
>|c|
struct rect{
     struct point pt1;
     struct point pt2;
};

この構造体は2つのpoint構造体をメンバとして含んでいる
ここでscreenを以下のように宣言しすると

struct rect screen

これでxが呼び出せる

screen.pt1.x

ここで紹介した以外にも構造体は以下のようにも宣言できる

struct{}x,y;

実は構造体タグは省略可能

6.2 構造体と関数

構造体に対して許される唯一の演算はコピーすること
&でそのアドレスを求めること

コピーと代入には関数に渡して関数から値を返すことも含まれている
しかし構造体の比較はできない

ここでは関数の値として構造体を返すことを例にあげてみる

struct point makePoint(int x,int y){
    struct point tmp;
    tmp.x = x;
    tmp.y = y;
    return tmp;
}

この関数はstruct point型の構造体を返すもので、前に書いたようにメンバー名と引数名が衝突していないことにも注目したい
ここで作成したmakePoint関数は任意の構造体を動的に初期化することができる

次に示すのは関数の引数と戻り値が構造体の場合のとき

struct point addPoint(struct point pt1,struct point pt2){
    pt1.x += pt2.x;
    pt1.y += pt2.y;
    return pt1;
}

ここは明示的な一時変数を使わないでpt1のメンバに加算しているが
これは構造体のパラメータが他のものと同じように値によって渡されることを強調するためである

これまでは構造体をそのまま渡してきたが関数に対して大きな構造体を渡す場合は構造体全体をコピーするより
ポインタを渡すほうが一般に能率的である
構造体ポインタは普通の変数へのポインタと変わらず以下のように宣言できる

struct point *pp;

これは変数ppがstruct point型へのポインタであることを示す
この時構造体ポインタのメンバにアクセスする場合は以下のようにする

(*pp).x;
(*pp).y;

この時注意すべきことは*は.より優先順位が低いため()が必要になる

これを用いて以下のようなコードが書ける

struct point base;
struct point *pointer;

pointer = &base;
printf("%d,%d",(*pointer).x,(*pointer).y);

また構造体のポインタへの参照はこれ以外にも別の方法がある
上の例に続いて、pointerが構造体へのポインタだとすると

pointer -> メンバー

のようにすることでメンバーを参照出来る

そこで2つ上の例は以下のように出力処理を書き直せる

printf("%d %d",pointer->x,pointer->y);

6.3 構造体配列

構造体自体は配列にすることができる
ここまでのまとめに準ずるなら

#define NUM 10
struct point pt[NUM];

もしくは

#define NUM 10
struct point{
     int x;
     int y;
}pt[NUM];

更にいうのであれば

struct point{
    int x;
    int y;
}pt[] = {
    1,1,
    2,1,...
};

のようにも定義出来る

この時構造体は配列になっているので、構造体のメンバーにアクセスしたい場合は

//iを0以上の任意の整数として
point[i].x
point[i].y

見たいな風にすれば、その構造体のインデックスに対応したメンバーを参照することが出来る

6.4 typedef

ここで少し話は逸れるがtypedefという新しいデータ型を宣言するための機能を紹介する
ただこの説明ではわからないと思うので実際に例を上げる

typedef int Length;

これでLengthをint型と同意義のものとして定義する

なので以下のような構文が書ける

Length len = 10;
Length maxLen = 20;

ということは文字列関連でいつもめんどくさいなと思っていたことを解消できる
それは文字列である。文字列はC言語においてポインタや配列で実現するのが通例になっているが
JavaC++,C#といった言語を先に経験した人にとってはこれは煩わしいものであったと思う
それをtypedefを使って以下のようにすれば

typedef char *String;

他の言語と同じように文字列を宣言できる

String str = "hello,world!!";

ちなみに同意義のものとして新しい型を既存の型と結びつけるので
typedefで宣言した新しい型でキャストすることもできる

例えば

String str;
str = (String)malloc(100);

のように

6.5 共用体

共用体(union)と言われるものは構造体とすごく似ているが、異なる型を同一のメモリで扱うことが出来る
というのも共用体のすべてのメンバにおいてオフセットが0である構造体のようなものだからである
共用体のメンバは構造体と同じように参照できる
ただ共用体自体の宣言が少し違う

union SampleUnion{
};

これでひと通りの構造体、それに類似するもののまとめは終わり

C言語 ポインタと配列

5章 ポインタと配列

ポインタは、他の変数のアドレスを格納する変数でありC言語では頻繁に利用される

理由は大きく分けて2つある
一つ目としてポインタを使うことが処理を行う唯一の方法である場合があるから
二つ目はポインタを用いて記述したほうが、それを使用しないで記述されたコードよりコンパクトで効率的になる場合があるから

そしてポインタと配列には密接な関係がある

しかしポインタは理解不能なプログラムをつくってしまうものとしてgotoとどっこいの扱いを受けてきた
確かに不用意にポインタを使うと理解不能なプログラムになってしまうが十分に注意することでポインタを活用し
よりよいコードを書くことも出来る。これはさっき述べた理由の二番目に合致する

ANSI Cではポインタの扱いが明確に定義され型void *(voidへのポインタ)をchar *の代わりに一般化されたポインタとして利用出来るようになった

5.1 ポインタとアドレス

これはポインタを扱う上で基礎的な知識になる

まずメモリ構成について、普通コンピュータでは個々にあるいは連続したグループとして扱うことの出来る
連続番号付きのつまりはアドレス付きのメモリセルという形の配列を持つ、これは配列とポインタの関係を説明する上で重要な点になる

そして、ポインタとはアドレスを格納することができるので
以下のように書ける

int *p;
int n = 1;

p = &n;

まず一行目でint型のポインタを宣言し四行目でint型変数のアドレスを代入している
ここで使用した&演算子はオブジェクトのアドレスを示すものであり、変数か配列の要素にのみ使用できる
逆に式や定数、レジスタ変数には適用できない

次にポインタを示す*演算子は間接演算子、逆参照演算子と言われる
これをポインタに適用にするとそのポインタが示すオブジェクトにアクセスできる

具体的には以下のように使える

int *p;
int x = 1, y = 2;

p = &x;//変数xのアドレスを代入
y = *p;//アドレスが示すオブジェクトつまり1を代入

printf("%d\n",y);//print -> 1

また以下のような文があったとしよう

double *dp,atof(char *);

この場合*dpとatof(char *)がdouble型をもちatofの引数charへのポインタであることを示すと同時に
ポインタがある特定の種類のオブジェクト指すように制約されている
そのため各ポインタは特定のデータ型を指す

ただし例外がありvoidへのポインタは任意の型のポインタを保持できるがそれ自身を逆参照することは出来ない

それではさっきの例に戻って*pがxを表すなら*pはxの代わりにどの文脈でも使用できる
つまり

//*p,x=1,p=&xを仮定
*p+=2;//これでxとpは3を表す

*p = *p + 2;
++*ip;

//これだけ演算子の関係でかっこが必要
(*p)++;

このように自由に計算できるが*pはxのアドレス、つまりxが存在する場所を参照できるので演算結果がxにも影響する
さらに最後の場合で単行演算子は右から左へ評価されるためipだけがインクリメントされてしまうなど注意が必要

さらに*qを同じくintへのポインタだとすると

q = p;

とすることでpがqにコピーされqはpを示すものとなる

5.2 ポインタと関数引数

以下のような関数を考える

void swap(int x,int y){
    int tmp = 0;
    tmp = x;
    x = y;
    y = tmp;
}

これは何ら問題なくコンパイルできるし一見正しく動作するように思えるが
関数内部の処理をどう変更してもこのままでは外部に全く影響しないのでswapしてるようでswapしてない
一種のバグを生み出している

それもそのはず、関数の引数はポインタやアドレスが関係しない限り渡した値のコピーでしかないからだ

ただポインタを使えば、アドレスを参照することができるので変更が外部にも適用される
なので以下のように変更すると想定どおりの動作をするだろう

void swap(int *x,int *y){
    int tmp = 0;
    tmp = *x;
    *x = *y;
    *y = tmp;
}

このようにポインタを使うと簡単に実装できたりポインタがなければ実装できない処理もある
またわかりやすい例を上げるならscanf関数である、scanf関数は入力を格納したい変数のアドレスを渡しているため
scanf関数外にある変数に値を代入できる

5.3 ポインタと配列

ポインタと配列には強い関係がある

というのも配列でインデックスを指定して実行出来る操作がポインタでも出来るためである
ポインタを使った操作のほうが一般に高速だとされているが初心者には理解しにくい

まず例を上げる

int a[10];

という宣言があるとき、配列はa[0],a[1],a[2]...と連続するオブジェクトからなるブロックである
a[i]といった記法は先頭からi番目の要素を参照する

また以下のintへのポインタ

int *p;

が宣言されているとすると、以下の代入によって

p = &a[0];

aの0番目の要素のアドレスがpにセットされる

さらにintへのポインタpに対して配列aの特定の要素が定義されている場合
p+1で次の要素を指す
一般にp+iはi番目の要素を指す

したがって、pがa[0]を指しているなら

*(p+1)

はa[1]の要素を参照する
またp+iはa[i]のアドレスであり*(p+i)はその要素を指す

ここまでで説明したものは配列aの変数の型やサイズに関わらず当てはまる


インデックシングとポインタ演算の間の対応は非常に良く、定義により配列型の変数あるいは式の値は配列の先頭の要素のアドレスであるから

p = &a[0];

のあとでpとaは同じ値を持つ。つまり配列の名前はその先頭の要素の位置と同義であるから
以下のようにも書ける

p = a;

この前にもさらっと書いたがa[i]への参照は*(a+i)とかけることからそれもまた同等であると言える
またその等式に&演算子を適用すると&a[i]とa+iは同じということになる

ただしここで一つだけ注意しないといけないことがある

p = a;

でおこなわれた定義に対して

p++;

は意味のある演算であるが

a = p;
a++;

のような演算は正しくない
配列名が関数などに渡されるとき渡されるのは配列の先頭のアドレスであって
呼び出された関数内では局所的な変数として扱われる
したがって配列名のパラメータはポインタはである

これらを使って文字列の長さを求めるstrlen関数を新しく作ってみる

int strlen(char *str){
	int lencount;
	for(lencount = 0; *str != '\0'; str++,lencount++);
	return lencount;
}

このコードにおいてstr++というのはstrがポインタなので許される
それらは関数内の文字列に何ら影響しない
これはポインタの単にstrlen内でのプライベートなコピーを演算しているだけに過ぎない

ここまでまとめたことにより

char str[]

char *str

は関数の仮引数として同一であると言える

そして以下のように配列をポインタに渡した場合

//int *p;int a[n];を仮定
p = a;

以下のような操作も出来る

p[i]

5.4 アドレス演算

今pが配列のどれかの要素へのポインタだと仮定すると、p++でインクリメントされると次の要素を指すようになる
同様にp+=iならi要素分だけ先を指すようになる

このような形はポインタ、アドレス演算の典型的な形である

Cではアドレス演算のアプローチが首尾一貫してて規則的になっている
ポインタ、配列、アドレス計算を統合したのはこの言語の主な強力さの一部になっている

まずmallocなどの関数を使ってメモリをメモリを確保し
使い終わったらfree関数などを使って確保したメモリを解放する2つのルーチンがある

これらはいままとめた順序で行う必要があり
順番が違っても、どちらかが抜けてもエラーやバグの原因となるので注意

そして特に配列が絡む場合ポインタは+,-などの演算子を使って計算することができる
というのも結果的にどの要素を指しているかということなので==,<=,!=,<,>,>=といったものも使える

特に2つの配列のポインタp,qを仮定したとき

p < q

などとするとpとqの場所が比較される

また演算子で計算できることから
さっき書いたstrlen関数を以下のように書きなおすこともできる

int strlen(char *str){
    char *p = str;
    while(*p != '\n')
        p++;
    return p - s;
}

5.5 文字ポインタと関数

以下のように記述された文字列定数は文字の配列である

"hello,world"

別の章でも言ったように実際はこれの末尾にnull文字があるので文字列のサイズは
ダブルクォートの中身の文字の数より1多い数値になる

おそらく最も文字列定数が現れるのは以下のような関数への引数として現れるときだろう

printf("hello,world");

このようなものが実際にコードの中にあるとき、それへのアクセスは文字ポインタを通して行われる
ただし実際にprintf関数が受け取るのは文字列定数の初めのアドレスである

話は変わって、ここで文字列定数が以下ように

char *pmsg = "hello,world";

char amsg[] = "hello,world";

と宣言、定義された場合
pmsgとamsgでは明確な違いがある

この単元の最初でも言ったように文字列定数は配列である
それを配列に代入した場合、文字数とnull文字を含めたサイズ分だけの大きさを持つ
この配列の中身の文字は変わるかもしれないが、amsgは常に同じアドレスをさす

一方pmsgのようにポインタを使った場合、pmsgには文字列のポインタのみが代入される
したがってこのポインタをあとで別の場所を参照するように変更することもできる
しかし文字列の内容を変えようとするとその結果は不定となるので注意が必要

5.6 ポインタのポインタ

ポインタとはそれ自身がアドレスを格納する特殊な変数なので
それ自身も変数のアドレスをメモリのどこかに確保していることになる
なのでポインタ自身もアドレスをもつということがわかる

C言語ではポインタのアドレスを更にポインタに格納することが可能である
例えばintへのポインタのポインタを作るなら

int **p;

のように宣言できる

ポインタの連鎖自体は何個でも作ることができるが自分が管理できる範囲にしておくのがいい

またこの考えはポインタ配列というものにも適用できて以下のような関数が書ける
複数個の文字列の配列に対して

void swap(char *str[],int i,int j){
     char *tmp;
     
     tmp = str[i];
     str[i] = str[j];
     str[j] = tmp;
}

このようなことも出来る

Javaオブジェクトのライフサイクル管理

はじめに

javaではnewを使うことで簡単にオブジェクトを生成できるが
プログラムの規模が大きくなると、オブジェクトの生成から消滅までの管理が複雑化してしまう

オブジェクトのライフサイクルを適切に管理するには以下のようなやり方がある

・変数のスコープに注意して不要に長い寿命のオブジェクトを減らす
・寿命の長いオブジェクトと短いオブジェクトを分離する
・ファクトリパターンなどを駆使する
・いっそフレームワークなどに隠す

このなかで一番簡単なファクトリパターンと
クラス自体を利用する方法についてまとめていく

ファクトリパターンとは

ファクトリパターンとはオブジェクト生成を一つの役割とみなしてそれを分離してしまうこと
またこれにはいくつかの技法があるが今回はファクトリメソッドに隠してしまいます

このときファクトリメソッドはstaticである必要があります

またファクトリメソッドを使うとするなら、コンストラクタは外部から参照出来ないようにprivateにしておくとよい
これはファクトリメソッドを使用する以外の方法でオブジェクトが生成されるのを防ぐため

実際のコード

これらを踏まえてファクトリパターンを使ったコードを実際に書いてみる

public class Test{

	//コンストラクタを外部から参照できないようにする
	private Test(){
	}

	//ファクトリメソッド
	static Test getInstance(){
		/*
		* Test test = new Test();
		* return test;でもいい
		*/
		return new Test();
	}
}

ファクトリパターンの利点

大きく3つの利点がファクトリパターンには存在する

・自由にメソッド名を付けられるので可読性を上げることができる
・ファクトリメソッドが必ず新規オブジェクトを返す実装にする必要がない
・戻り値の型を抽象型にできる

二番目はよくわからないと思いますが
オブジェクト生成にコストがかかる場合生成済みのオブジェクトをキャッシュして
ファクトリメソッドがプール内のオブジェクトを返すオブジェクトプーリングという技法の事です
これはオブジェクトを一種類に制限して必ず同一のオブジェクトを返すことで実現できる

クラス自体を利用

例えばStringクラスに対して

"hello".length()

のような使い方をするもので、クラスフィールドやクラスメソッドを直接参照する方法

これを実現させるのは簡単なのでわざわざ例を上げる必要はないと思いますが
注意点がいくつかあります

・finalクラスにして継承を禁止する
コンストラクタをprivateにする
・すべてのメソッドとフィールドにstaticをつける

利点は
・クラス利用者が必要なメソッドを探すときクラス名で絞り込めるようになる
メソッド呼び出し箇所を見た時に意味がわかりやすい



これらを適切に使うことでオブジェクトのライフサイクル管理がしやすくなります