人気ブログランキング | 話題のタグを見る

新規ドキュメント


忘れていく脳のための備忘録
by w_l_s

fgetsでgetsを再現する

gets。
バッファ・オーバーフローが起きるから使うなと言われる。
代わりにfgetsを使えと。
取得するサイズを決められるから、バッファ・オーバーフローが起きにくい。

でも動作がちょっと違う。
改行を含むのがfgets、含まないのがgets。
取得し切れなかった文字列がストリームに残るのがfgets、残らないのがgets。

株式会社きじねこさんのページを見て、簡単に置き換えられるものじゃないことを知った。
改行云々については前に悩まされたことがあったけど、ストリームに残ることについては
気にしたことなかったな。

きじねこさんのページには、getsをfgetsで再現するコードが載っている。
関数にすれば便利かも知れないので、まとめてみることにした。
初心者にはちょうどいい練習になりました。

/**********************************************************************/
/*
_getsヘッダ
*/

#ifndef _GETS
#define _GETS

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

extern char *_gets(char *s, size_t bytes);

#endif

/*
_getsソースコード
*/

#include "_gets.h"

#define ERROR 1
#define CORRECT 0

static int clear_buffer(void);

// getsをfgetsで再現
char *_gets(char *s, size_t bytes)
{
size_t length = 0;

fgets(s, bytes, stdin);
length = strlen(s);

if(s[length - 1] == '\n') {
s[length - 1] = '\0';
} else {
clear_buffer();
}
return s;
}

// バッファに残った文字列を消す
static int clear_buffer()
{
int letter;
int state = ERROR;

do {
letter = getchar();
if(letter == EOF) {
if(feof(stdin)) {
state = CORRECT;
break;
} else {
/*エラー処理を入れる*/
break;
}
}
} while(letter != '\n');

return state;
}

/**********************************************************************/

clear_buffer()のエラー処理は、単純にエラーコードを返すだけにした。
バッファに入りきらずにストリームに残った入力はすべて捨てている。
feof()なんて使ったことないな…。本によっては、この関数も絶対使うなと書いてあるけど、今回の例ではどうなんだろうか。
# by w_l_s | 2009-01-12 01:37 | c言語

PythonでQueueを作ってみた

今、アルゴリズムの勉強をしている。
学生のころ、ほとんどやってこなかったせいで、今かなり苦しんでる。
やっぱり時間があるときやっとくべきだったなぁ…。

そんなわけで本を買ってきて勉強してるんだけど、中身はCで書かれている。
最近はPythonにあまり触ってこなかったし、せっかくなのでPythonでも書いてみることにした。

ちなみに本は「定本 Cプログラマのためのアルゴリズムとデータ構造」(著者: 近藤 嘉雪)です。

そのまんま書き写しただけだとつまらないので、ちょっと関数を追加してたりする。

/*************************************************************************/

# -*- coding: utf-8 -*-

class Queue:
def __init__(self, MAXQUEUESIZE = 100):
self.queue = []
self.MAXQUEUESIZE = MAXQUEUESIZE

# queueが空?
def isEmpty(self):
return (self.total() == 0)

# queueがいっぱい?
def isFull(self):
return (self.total() == self.MAXQUEUESIZE)

# 残りのqueue数
def remain(self):
return self.MAXQUEUESIZE - self.total()

# 今のqueue数
def total(self):
return len(self.queue)

# queueの初期化
def init(self, MAXQUEUESIZE = 100):
self.__init__(MAXQUEUESIZE)

# queueの中身を取得
def peekAll(self):
return self.queue[:]

# 次のpush()の値を取得
def peek(self):
stat = None
if not self.isEmpty():
stat = self.queue[0]
return stat

# queueに値を入れる
def enqueue(self, element):
state = False
if not self.isFull():
self.queue.append(element)
state = True
return state

# queueから値を取り出す
def dequeue(self):
state = None
if not self.isEmpty():
state = self.queue.pop(0)
return state


/*************************************************************************/

最初は本のとおりにリングバッファを使おうとしていた。
でも途中でpop()は削除して以降の要素を詰めることに気づく。
本のままじゃうまくいかなくなるわけだ。
Cの配列とは違うなぁ。

いまさら変数名が気に入らなくなってきた。
pointerよりcurrentIndexとかのほうがいい気がする。

2009/1/9修正
pointerなんていらなかったので消去。
peek()は今のリストのコピーを取れるように変更。
ほかいくつか関数を追加

2009/1/11修正
enqueue, dequeueだよね
# by w_l_s | 2009-01-09 01:52 | Python

人の記事にけちをつけてみる

メモ帳のところにリンクを張ってあるbokujuの日記さん。
そこで気になる日記を見つけた。

pythonでの文字の連結は、文字列よりリストを使おう!

なるほど、結果を見ると早い。
ただ、ひとつ気になることが。。。

リストにくっつけるだけじゃ連結してないんじゃないか?

気になったので調べてみたら、join関数でくっつけられるらしい。
>>> s = "こんばんわ" + "ひとふくろうです"
>>> print s
こんばんわひとふくろうです

リストだとこうなる。
>>> ls = ["こんばんわ"]
>>> ls.append("ひとふくろうです")
>>> print "".join(ls)
こんばんわひとふくろうです

おお、これで早い文字列連結が可能だ!

...ここでやめときゃよかったんだ。
なんで"じゃあ、リストの要素にリストやタプルがあったらどうなるんだろう"なんて考えるんだ。

結果は、例外が発生して終了する。
さらに、str型とunicode型が混在すると、今度はUnicodeDecodeErrorが発生。これは+を使った連結でも起きる。

どんな状況でも連結させたい。
リストの要素にリストやタプルがあっても一直線に連結させたい。
...需要があるかどうかは知らないけど。

そんなわけで、リストの中身を文字列にして返す関数を書いてみた。

##########################################################
def ListToStr(obj, encoding = 'utf-8'):
target = []
for item in obj:
if isinstance(item, unicode):
item.encode(encoding)
elif not isinstance(item, str):
if isinstance(item, int) or isinstance(item, float):
item = str(item)
else:
item = ListToStr(item)

target.append(item)

s = ''.join(target)
return s

##########################################################

要素にリストがあるとこけるなら、リストがなくなるまで要素をばらしてしまえばいい。
乱暴だけど、再帰で書けるので少し楽かも。

数値があってもstr型に変換するので連結できる。
虚数?そんなの知らんわ。
…虚数を入れると例外が起きます。
辞書を要素に入っていると、キーだけを連結します。
正直使いづらいです。

早さはどうなんだろ…。
いまさらだけど、文字列の連結にリスト使おうとする人が、要素にリスト突っ込んだりするもんなんだろうか…。
なんか午前中を無駄にした気になってきたぞ。
# by w_l_s | 2008-12-21 20:16 | Python

突然Linuxからはじき出されて困る

VMware Server2 を使って仮想マシン上でlinuxを動かしている。
いつもsshでログインしてるんだけども、たまにターミナルが固まって動かなくなることがある。
それだけならまだしも、再度接続しようとすると接続できない。

なぜなのか。接続できない状態でifconfigコマンドを打ってみると、なんとeth0にIPアドレスが割り当てられてない。ネットワークに接続できていない状態になっていた。

ネットワークの再起動を行うと、再度eth0にアドレスが割り当てられて接続できるようにはなる。
そんな状況はわかったけど、原因まではわからず。

しょうがないので、シェルスクリプトでネットワークの接続状況を監視することにした。
eth0にアドレスが割り振られていなかったら、ネットワークの再起動を行う。


#! /bin/bash

line=`ifconfig eth0 | grep Bcast`

# ネットワークに接続されていないと、$lineはからっぽ
if [ "$line" = "" ]; then
/etc/init.d/network stop >/dev/null 2>&1
/etc/init.d/network start >/dev/null 2>&1
fi


cronにこいつが1分毎に動くよう設定する。

場当たり的な対応だけど、これで少なくても接続できなくなってあわてることはない。
1分後にはネットワークが再起動されて、また接続できるようになるはず。

ほんとは、ちゃんと原因を調べて対処したいけど、今の知識ではさっぱり…
シェルスクリプトのお勉強にはなったからいいか。
# by w_l_s | 2008-11-09 00:20 | シェルスクリプト

[作って遊ぼう] エニグマ暗号を作ってみた

2次大戦中にドイツ軍が使ったという、エニグマ暗号と同じ方法で暗号化するものをC言語で書いてみた。エニグマ暗号についてはここが詳しい。
とある演習の課題用に書いてみたけど、お蔵入りしそうなので載せてみる。採用されるとうれしいな。

…こんな課題、出されるほうはたまったもんじゃないと思うけど。

CentOS5.2 + gcc4.3.2でコンパイルの確認はとってますが、コピペ中になにか起きてるかもしれないので、まんまコピペでほかでも動くか心配。

まだまだ不完全な部分もあるけれど、ちゃんと暗号化、復号化を行える。
実行例 --
 暗号化する
./a.out
I am a cat. // 平文(元の文章)入力
22 // 暗号化に使う3つの数字を入力
14
32
I et q pbx. // 暗号化された文

 元の文章に戻す
./a.out
I et q pbx. // 暗号化された文を入力
22 // 同じ順番で、同じ数字を入力
14
32
I am a cat. // 元に戻る
----------

大文字や記号、数字まで対応させれば、人じゃ解読できなくなりそう。

<---------------------------- ここから ---------------------------->

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

#define ALPHABET 26
#define CORRECT 0
#define ERROR 1
#define UNCHECK CORRECT
#define CHECKED ERROR
#define REF_OFF CORRECT
#define REF_ON ERROR

void rand_alphabet(char alphabetTable[ALPHABET], int seed);
void mirror_alphabet(char alphabetTable[ALPHABET],
char mirrorTable[ALPHABET]);

char reflector(char input);
char rotor(char input, int seed, int reflect_flag);

void encryption();
char convert(char input, int Fseed, int Sseed, int Mseed);
void seedcontrol(int *Fseed, int *Mseed, int *Sseed);

int main()
{
encryption();
return 0;
}

// 変換用アルファベット
void rand_alphabet(char alphabetTable[ALPHABET], int seed)
{
int code_num;
int count = 0;
char checkTable[ALPHABET] = "";

srand(seed);

while(count < ALPHABET)
{
code_num = rand() % 123;
if(code_num >= 97 && checkTable[code_num - 97] == UNCHECK)
{
alphabetTable[count] = code_num;
checkTable[code_num - 97] = CHECKED;
count++;
}
}
}

// リフレクタ通過後の変換用アルファベット
void mirror_alphabet(char alphabetTable[ALPHABET],
char mirrorTable[ALPHABET])
{
int idx = 0;

for(idx = 0; idx < ALPHABET; idx++)
{
mirrorTable[alphabetTable[idx] - 97] = 97 + idx;
}
}

// リフレクタ部分
char reflector(char input)
{
char output = ' ';

if(input == 'a'){
output = 'm';
} else if(input == 'b') {
output = 'e';
} else if(input == 'c') {
output = 'j';
} else if(input == 'd') {
output = 'u';
} else if(input == 'e') {
output = 'b';
} else if(input == 'f') {
output = 'z';
} else if(input == 'g') {
output = 'q';
} else if(input == 'h') {
output = 'k';
} else if(input == 'i') {
output = 't';
} else if(input == 'j') {
output = 'c';
} else if(input == 'k') {
output = 'h';
} else if(input == 'l') {
output = 'o';
} else if(input == 'm') {
output = 'a';
} else if(input == 'n') {
output = 'y';
} else if(input == 'o') {
output = 'l';
} else if(input == 'p') {
output = 'w';
} else if(input == 'q') {
output = 'g';
} else if(input == 'r') {
output = 'v';
} else if(input == 's') {
output = 'x';
} else if(input == 't') {
output = 'i';
} else if(input == 'u') {
output = 'd';
} else if(input == 'v') {
output = 'r';
} else if(input == 'w') {
output = 'p';
} else if(input == 'x') {
output = 's';
} else if(input == 'y') {
output = 'n';
} else if(input == 'z') {
output = 'f';
} else {
printf("input %d\n", input);
}

return output;
}

// ロータ
char rotor(char input, int seed, int reflect_flag)
{
char alphabetTable[ALPHABET] = "";
char mirrorTable[ALPHABET] = "";
char output;

rand_alphabet(alphabetTable, seed);
if(reflect_flag)
{
mirror_alphabet(alphabetTable, mirrorTable);
output = mirrorTable[input -97];
} else {
output = alphabetTable[input - 97];
}

return output;
}

// 暗号部
void encryption()
{
char input[100] = "";
char output[100] = "";
char tmp;
int strlength = 0;
int count = 0;
int Fseed, Sseed, Mseed;

Fseed = Sseed = Mseed = 0;
fgets(input, sizeof(input), stdin); // 平文入力
scanf("%d %d %d", &Fseed, &Mseed, &Sseed); // ロータ番号入力
Fseed = Fseed % 26;
Mseed = Mseed % 26 + 26;
Sseed = Sseed % 26 + (26 * 2);
strlength = strlen(input); // 平文の長さを調べる

for(count = 0; count < strlength; count++)
{
tmp = input[count];
if(tmp >= 97 && tmp <= 122) {
tmp = convert(tmp, Fseed, Mseed, Sseed);
seedcontrol(&Fseed, &Mseed, &Sseed);
}
output[count] = tmp;
}

printf("%s\n", output);
}

void seedcontrol(int *Fseed, int *Mseed, int *Sseed)
{
*Fseed += 1;
if(*Fseed > 26)
{
*Fseed = 0;
*Mseed += 1;
}
if(*Mseed > 52)
{
*Mseed = 26;
*Sseed += 1;
}
if(*Sseed > 78)
{
*Fseed = 0;
*Mseed = 26;
*Sseed = 52;
}
}

char convert(char input, int Fseed, int Mseed, int Sseed)
{
int reflect_flag = REF_OFF;
char tmp;
char output;

tmp = rotor(input, Fseed, reflect_flag);
tmp = rotor(tmp, Mseed, reflect_flag);
tmp = rotor(tmp, Sseed, reflect_flag);
tmp = reflector(tmp);
reflect_flag = REF_ON;
tmp = rotor(tmp, Sseed, reflect_flag);
tmp = rotor(tmp, Mseed, reflect_flag);
output = rotor(tmp, Fseed, reflect_flag);

return output;
}

<---------------------------- ここまで ---------------------------->

それににしても長い。
ブログにそのまま貼り付けるのは間違いだったかも。
全体をいくつかの関数の集まりに分割してメモを書いておくことにしよう。

TODO:
コマンドライン引数を使ってみる。
文字列や数字の入力に何も説明がないなんて、無愛想にも程がある。
数字の入力チェックを行う。ここに文字列を入力されると困る。
アルファベットのテーブルなんて持ちたくないなぁ。

######
081105 loter -> rotorに修正 恥ずかしい…
# by w_l_s | 2008-11-05 00:18 | 作って遊ぼう