[時間割:C言語]『はじめてのC言語完全入門』その15
2009/01/18 21:13 posted by kunkichi
火曜日は仕事だったのでしょうがないとして、金曜日は帰宅早々寝ちゃったので、その分を取り返しておきます。ということで『C言語』です。引き続き文字列とポインタです。関数の引数として文字列を渡す、その関数を呼び出す、というのをやります。
塚越 一雄
技術評論社
売り上げランキング: 420963
- 引数の書式は2パターン。配列で渡すか、ポインタで渡すか。
- 配列の場合
void kansu(char str[])
{
printf("渡された引数は%sです。¥n", str);
}配列の場合はサイズ指定できないのは通常の配列と同じ。また、この時strは配列名であり定数である点に注意。
- ポインタの場合
void kansu(char *p)
{
printf("渡された引数は%sです。¥n", p);
}この時strはポインタであり変数である点が配列で渡す場合と異なる。
- 配列形式、ポインタ形式のそれぞれで渡された配列の引数は意味としては異なるけど、関数内では文法上同じ扱いになる。従って、
- 配列で渡されたものを関数内でポインタとして使っても良い。
- ポインタで渡されたものを関数内で配列として使っても良い。
以前にやった配列とポインタのところと全く同じ。
- 呼び出す時は、文字列の先頭アドレスを渡してあげる。つまり、
- 文字配列で渡す場合は配列名(配列名は配列の先頭アドレスを示す)
kansu(str);
- ポインタで渡す場合はポインタ(ポインタはそもそも先頭アドレス、サイズはポインタの型が決める)
kansu(p);
- さらにもう一つ、文字列を直接指定してあげることもできる。
kansu("abcdef");というのは式の中で文字列リテラルが渡されると先頭アドレスとして評価されるから。
- ということでサンプル。書籍にもある、エラーメッセージとリターンコードを渡して、exitしちゃうプログラム。配列指定の場合とポインタ指定それぞれの場合の関数を用意してます。mainの中で呼び出す関数を変更すればそれぞれを呼び出します。まあ結果は同じなんだけど。
#include <stdio.h>
#include <stdlib.h> /* include exit() */
void fatal_p(char *errmsg, int errcode);
void fatal_a(char *errmsg, int errcode);
int main()
{
fatal_a("異常終了!!!",255);
fprintf(stdout,"%s\n", "正常終了");
return 0;
}
void fatal_p(char *errmsg_p, int errcode)
{
fprintf(stderr, "%s\n", errmsg_p);
exit(errcode);
}
void fatal_a(char errmsg_a[], int errcode)
{
fprintf(stderr, "%s\n", errmsg_a);
exit(errcode);
}
- さっきの例では、サンプルの関数はvoidだったので何も返さないのだけど、関数で文字列を返す場合は、関数の型を文字へのポインタとして定義する必要がある。そして呼び出す際は、返された文字列を一時的に入れておく文字列用バッファを用意しておいてそこに代入する。
char *kansu(〜){
・・・
}
int main(){
char str[256];
char = kansu(〜);
}とあるのだけど、んー、うまく動かない、、、最後に書いてある、文字列を渡したら最後の1文字を除いた文字列を返すサンプルスクリプトをちょっといじってみた。本の中ではループで順に1文字づつ消しているのだけど、単に1文字だけ返すように書き換えてみたのだけど、バッファに返そうとするところでコンパイラがエラーを吐いちゃう。#include <stdio.h>
#include <string.h>
char *remove_last_char(char str[])
{
int last = strlen(str);
if( last > 0 )
str[last-1] = '\0';
return str;
}
int main()
{
char s[] = "1234567890";
char ret[256];
ret = remove_last_char(s);
printf("%s\n",p);
}ビルドするとこんな感じ。$ gcc -o str_ary2 str_ary2.c
str_ary2.c: In function ‘main’:
str_ary2.c:19: error: incompatible types in assignment
本のサンプルと同様に関数の結果をそのままprintfに渡してやるとちゃんと動く。#include <stdio.h>
#include <string.h>
char *remove_last_char(char str[])
{
int last = strlen(str);
if( last > 0 )
str[last-1] = '\0';
return str;
}
int main()
{
char s[] = "1234567890";
printf("%s\n",remove_last_char(s));
}なんでかなぁ〜、、、文字へのポインタにする意味がまったくわからない。
うーん、やっぱりポインタ、配列、文字配列とまだまだ整理できてないので、理解できてない。以前にやった、ポインタと配列のところ読み返してみたんだけどね〜、それでもだめか。一度整理しておく必要があるかな。ただまあそれは課題として置いておいて、どんどん進んで一通り終わらせることを優先とします。
次回は文字列の応用編。
Category: C, Programming | コメント&トラックバック(0)
[時間割:Perl]『ミニマルPerl』その15
2009/01/16 01:00 posted by kunkichi
木曜日は「Perl」です。今回からfindコマンドです。これまでやってきた grep、sed、awk については、Perlで置き換えれるように見てきたのだけど、find の場合は「Perl との組み合わせ」でいろいろやっていきます。
Tim Maher
オライリージャパン
売り上げランキング: 96883
- ファイルのテスト機能。シェルやtestコマンドで使うようなやつです。
例:sample.txt が通常のファイルだったら。 -f sample.txt and print;例:sample.binが通常のファイルじゃなかったら。! -f sample.bin and print;ファイル名を省略して$_にすることもできます。
例:$_ が 通常のファイルだったら。-f and print $_;例:$_が通常のファイルじゃなかったら。! -f and print $_;
- これ以外にもテスト機能の指定はできます。findじゃできないような、テキストとバイナリのテスト、実行ユーザの権限に準じたアクセス権でのテスト、などなど。
- find と Perl を組み合わせでは、find で一連のパスを作っておいて、フィルタをかけるのにPerlを使います。
$ find . -type -name '*.dat' |
> find /var/log -mtime -3これにPerlでフィルタをかけます。> | perl -wnl -e '/-f and -T/ and print;'上記の例では、findでカレントディレクトリ配下の”*.dat”というファイル名で、かつ、最終更新日が3日以内のファイル名をリストアップして、最後にPerlで、通常ファイル、かつ、テキストファイルのものだけを抽出しています。
- 名前のマッチングとかはPerlの強力な正規表現をつかったほうがらくちんです。
$ find . -type -f | perl -wnl -e '/.+¥.dat$/ and print;'ちなみにfindの場合は以下。$ find . -type f -name "*.dat"ファイル名のマッチングが一つだけしかないなら、それほどでもないけど、以下のように複数のファイル名のマッチとかの場合は、括弧で囲んだ上、エスケープして、複数のファイル名の条件は、-oでつなぐ、そして、ファイル名のマッチにはワイルドカードレベルのものしか使えない、となり結構面倒。$ find . -type f \( -name '*.dat' -o -name '1¥.*' -o '*34*' \)
- フルパスでファイルのリストがあって、この中から、特定の「ファイル名だけ」でマッチをしたい場合、以下のように-aオプションでパスを分解して使うと良い。
$ find . -type f | perl -wnla'/' -e '$F[-1] =~ /abc$|*cde*|^123/ and print;'
- 逆に特定の「ディレクトリ配下」という指定もできる。
$ find . -type f | perl -wnl -e '-T and m:data/\w+\.dat:i and print;'-Tでテキストファイル限定、mを使って正規表現中にパスを表すスラッシュをいちいちエスケープしないように、iで大文字小文字無視。こういうのはfindだけではちょっと難しいのでかなり便利。
とりあえず今日はここまで。
Category: Programming, Perl | コメント&トラックバック(0)
お休み
2009/01/13 20:47 posted by kunkichi
今夜は徹夜で仕事があるので、おべんきょはお休みです、、、
まあ、仕事やけん、しょうがなか。
Category: Diary | コメント&トラックバック(0)
[時間割:Perl]『ミニマルPerl』その14
2009/01/12 23:53 posted by kunkichi
祝日ですががんばります。月曜日は「Perl」。AWKをPerlでやってみようの最後です。演算子とか組み込み関数とか。
Tim Maher
オライリージャパン
売り上げランキング: 96883
これでAWKのところも終わりました。次はfindコマンドの機能をPerlでやっていきます。
Category: Programming, Perl | コメント&トラックバック(0)
[時間割:C言語]『はじめてのC言語完全入門』その14
2009/01/10 03:37 posted by kunkichi
金曜日は「C言語」。文字列とポインタです。難しそーだなー。
塚越 一雄
技術評論社
売り上げランキング: 420963
- 文字へのポインタ宣言。
char *p;
- ただしこの時文字列のためのメモリ確保は行われていないため、以下の方法でメモリを確保する。
- 動的メモリの確保。これは後日。
- 配列を確保して先頭アドレスをポインタに代入。
char *p;
char str[]= "Hello, World";
p = str;これでpが文字列を表す変数として使えるので、printfで出力してみる。printf("%s¥n",p);結果:Hello,Worldさらにポインタをインクリメントして、文字列の操作もできる。p++;
printf("%s¥n",p);結果:ello,World
- 文字列リテラル
char *p = "Hello, World";シンプルでわかりやすい。ただし、確保した文字列の変更はできない。printf("%s\n",p);
*p = 'h';
printf("%s\n",p);結果:Hello,World
Bus error逆に、配列を確保してポインタに代入した場合は変更できる。char *p;
char s[] = "Hello,World";
p = s;
printf("%s\n",p);
*p = 'h';
*(p+6) = 'w';
printf("%s\n",p);
return 0;結果:Hello,World
hello,world
うーん、なんかピンとこないなー。配列、ポインタ、文字列とややこしいのがミックスした感じですっきりしない。
もう一度、前のところ見直してみようかな。
ちょっと短いけど今日はここまで。
Category: C, Programming | コメント&トラックバック(0)
[時間割:Perl]『ミニマルPerl』その13
2009/01/09 01:44 posted by kunkichi
木曜日は「Perl」です。引き続きAWK編。今回は「パターン範囲」で特定のレコード「群」を抜き出すのをやってみたいと思います。
Tim Maher
オライリージャパン
売り上げランキング: 96883
複数行を範囲で抽出するシチュエーションで本当に多いので、これはかなり使えるかも。
Category: Programming, Perl | コメント&トラックバック(0)
[時間割:読書] [お知らせ] メディアマーカーに移行
2009/01/08 23:26 posted by kunkichi
READING HACKS!読書ハック!―超アウトプット生産のための「読む」技術と習慣に書いてあった、「自分の読書の傾向を管理する」ためにお試しで使っていたメディアマーカーですが、書評やレビューはもう完全にあっちに移行することにしました。

なんといっても便利なのが、
- 月に書籍購入費がどれだけかかっているか?を把握できる。
- 月に何冊読了しているか?を把握できる。
- この二つがグラフで表示される。
- 本のカテゴリーをタグづけできるのでどの分野に偏っているか?が把握できる。
- 同じ本を読んだ人の一覧やコメントが「はてブ」チックに見れる。
というところ。似たようなサイトは他にもあるのだけど、基本的にはこれらの点だけ把握できれば個人的には十分なので、満足しています。欲を言うと、
- 書評ではなく自分用まとめをメインで書きたいのでエディタ機能をもう少し充実してほしい。特に箇条書きができないのが痛い。
というところだけがアレなのですが、まあそのうち改善されることを期待。ちなみに会社の同僚もこれを使っていることがわかったので、互いの本棚をのぞいてる感じがとても楽しかったりします(笑)。
他のITエンジニアの方の本棚ものぞいてみたいです。よかったらトラックバックで教えてください。
メディアマーカー - kunkichiのバインダー
Category: Book | コメント&トラックバック(0)
[時間割:C言語]『はじめてのC言語完全入門』その13
2009/01/06 22:56 posted by kunkichi
火曜日は「C言語」。前回、ファイルからの入出をやったので、今度はファイルへの出力です。
塚越 一雄
技術評論社
売り上げランキング: 420963
- 書き込み時は、オープンモードを”w”にする。
FILE *ofp;
ofp = fopen("output.txt","w")
- ファイルへの出力にはfputcを使う。
fput(c, ofp);
- 書き込みの場合はエラー処理が重要。fputcは、EOFに達した場合も書き込みエラーの場合も両方-1を返すので、終了とエラーの区別ができない。よって、エラーが発生していたら真を返すferror関数を使って、「書き込みエラー」を取得する。
fputc(c,ofp);
if(ferror(ofp)){
printf("書き込みに失敗しました。¥n");
fclose(ofp);
return XXX;
}エラーが発生した場合に処理を終了する場合は、ファイルのクローズを忘れないように。
- 前回のサンプルスクリプトに出力処理を追加。sample.txtを読み込んで、その内容をそのままresult.txtに出力する、いわばcpコマンドのような感じで。
#include <stdio.h>
#define INFILE "./sample.txt"
#define OUTFILE "./result.txt"
int main()
{
FILE *ifp;
FILE *ofp;
if( !(ifp = fopen( INFILE, "r" )) ){
printf("cannot open input file.\n");
return 255;
}
if( !(ofp = fopen( OUTFILE, "w" )) ){
printf("cannot open output file.\n");
return 255;
}
int c;
while( (c = fgetc(ifp)) != EOF ){
fputc(c,ofp);
}
if(ferror(ofp)){
printf("書き込みに失敗しました。\n");
fclose(ofp);
fclose(ifp);
remove(OUTFILE);
return 1;
}
if( fclose(ofp) ){
printf("cannot close output file.\n");
return 255;
}
if( fclose(ifp) ){
printf("cannot close input file.\n");
return 255;
}
return 0;
}
- getcharを使うと、標準入力から1文字読み込むことができる。fgetcと同じように返り値はintで受ける。引数はなし。
- ferrorってイメージとしてはエラーフラグが立つという感じかな。whileのループの中でなく、ループが終了した後にチェックしているのはそういう意味かと。
- 上記はferrorで書き込みエラーを拾ったら、出力ファイルポインタをクローズすると共にファイルを削除している。削除にはremove(ファイル名)を使用する。Perlのunlinkみたいなもんかな。
- fputcは1文字単位なので、ちょっと使いにくい。だけど、fprintfを使えば、printfのように、文字列を特定の書式に当てはめる形で出力することができる。
fprintf(ofp,"今日は%d月%d日です。¥n", month, day);引数にファイルポインタを追加する以外はprintfと全く同じ使い方。
- fprintfを使ったファイル出力のサンプル
$ cat fprintf.c
#include <stdio.h>
#define OUTFILE "result.txt"
int main()
{
FILE *ofp;
if(!(ofp = fopen(OUTFILE,"w"))){
printf("cannot open outfile.\n");
return 255;
}
int num=0;
printf("数字を入力してください。 ");
scanf("%d",&num);
fprintf(ofp,"入力された数字は、%d です。\n",num);
fclose(ofp);
return 0;
}
ビルドして実行してみる。$ ./fprintf
数字を入力してください。 356
$ cat result.txt
入力された数字は、356 です。
- 標準出力、標準エラー出力にも出力できる。それぞれ組み込みのファイルポインタである、stdout、stderr を fprintfの引数にすれば良い。エラーメッセージ等はstderrに出すと良いね。
ということでファイルの出力もできるようになりました。
次は文字列とポインタです。
Category: C, Programming | コメント&トラックバック(0)
[時間割:Perl]『ミニマルPerl』その12
2009/01/06 02:44 posted by kunkichi
三日坊主にならないようにがんばりますw
月曜日は「Perl」です。引き続き、AWKの処理をPerlで実現していきます。今日はAWKの得意なパターンとアクションを組み合わせた処理です。
- AWKの「パターン&アクション」の例
$ awk -F":" '/^root/{ print NR ":" $1 }' /etc/passwd
1:rootAWKのいいところは、
- アクションを指定していないパターンの場合は、レコードをそのまま自動的に出力する。
$ awk -F":" '/^root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
- パターンを指定していない場合はアクションを全てのレコードに対してそのまま実行する。
$ awk -F":" '{ print NR ":" $1 }' /etc/passwd
1:root
2:bin
3:daemon
4:adm
5:lp
・・・
- 上記のそれぞれをPerlで実装する。
- パターンとアクション
$ perl -wnlaF":" -e '/^root/ and print "$.:$F[0]";' /etc/passwd
1:root
- パターンのみ
$ perl -wnlaF":" -e '/^root/ and print;' /etc/passwd
root:x:0:0:root:/root:/bin/bashこの場合は明示的にprintをつけないといけない。
- アクションのみ
$ perl -wnlaF":" -e 'print "$.:$F[0]";' /etc/passwd
1:root
2:bin
3:daemon
4:adm
5:lp
・・・
- AWKのBEGINとENDもそのままPerlで使える。apacheログのファイルサイズの合計と平均を出すサンプルスクリプト。サイズは10番目のフィールド($F[9])に出力されているものとする。
# perl -wnla -e '
> BEGIN{
> $total=0;
> $cnt=0;
> $average=0;
> }
> $total=$total+$F[9];
> $cnt++;
> END{
> $average=$total/$cnt;
> print "TOTAL:$total AVERAGE:$average";
> }' access_log.1
TOTAL:1100250219 AVERAGE:1559BEGINのブロックで変数を初期化しておいて(初期化していない場合は初期化されていないという警告が出る場合があるのと、最終的にデータがなかった場合にENDで出力する際に警告が出て、かつ、NULLになってしまうため。)、ENDでまとめて出力。
- フィールド処理に対してマッチングするとより細かい条件を設定できる。/etc/passwdの中からUIDが一桁のものを抽出してUIDとユーザ名を出力する。
# perl -wnlaF':' -e '($username, undef, $uid) = @F;$uid =~ /^\d$/ and print "$uid:$username";' /etc/passwd
0:root
1:bin
2:daemon
3:adm
4:lp
5:sync
6:shutdown
7:halt
8:mail
9:news
- AWKのNF(最後のフィールド)は、Perlだと$F[-1]。
- 段落モードの場合(-00)は、行単位でフィールド処理を行うのではなく、段落内の全ての文字列に対してフィールド処理が行われる。わかりにくいので以下の例で説明。
例)sarコマンドでCPU使用率を定期的に取得した場合の出力結果は以下。# sar -P ALL -u 1 10
1: Linux 2.6.X-X.X.X (www.example.com) 2009年01月06日
2:
3: 02時08分43秒 CPU %user %nice %system %iowait %steal %idle
4: 02時08分44秒 all 0.00 0.00 0.00 0.00 0.00 100.00
5: 02時08分44秒 0 0.00 0.00 0.00 0.00 0.00 100.00
6: 02時08分44秒 1 0.00 0.00 0.00 0.00 0.00 100.00
7:
8: 02時08分44秒 CPU %user %nice %system %iowait %steal %idle
9: 02時08分45秒 all 0.00 0.00 0.00 0.00 0.00 100.00
10: 02時08分45秒 0 0.00 0.00 0.00 0.00 0.00 100.00
11: 02時08分45秒 1 0.00 0.00 0.00 0.00 0.00 100.00
12:
・・・
47:
48: 02時08分52秒 CPU %user %nice %system %iowait %steal %idle
49: 02時08分53秒 all 0.00 0.00 0.00 0.00 0.00 100.00
50: 02時08分53秒 0 0.00 0.00 0.00 0.00 0.00 100.00
51: 02時08分53秒 1 0.00 0.00 0.00 0.00 0.00 100.00
52:
53: 平均値: CPU %user %nice %system %iowait %steal %idle
54: 平均値: all 0.00 0.00 0.00 0.10 0.00 99.90
55: 平均値: 0 0.00 0.00 0.00 0.30 0.00 99.70
56: 平均値: 1 0.00 0.00 0.00 0.00 0.00 100.00※わかりやすいように行番号を入れてますが実際には出力されていません。
このうち、個々のCPU使用率のidle値の推移を取得する。
$ perl -00 -wnla -e '/^¥d/ and print "$F[23] $F[-1]";'
100.00 100.00
100.00 100.00
100.00 100.00
100.00 100.00
97.06 100.00
100.00 100.00
100.00 100.00
100.00 100.00
100.00 100.00
100.00 100.00
ポイントは以下。
- 欲しいのは推移データだけなので、1行目のunameの出力と最後のサマリーの段落を出力しないように、段落の最初が数字(sarの個々の出力データは日付が最初に出力されている)の箇所にマッチした段落のみを抽出
- さらに、個々の段落全体の文字列を最初から見ていくと、CPU0のidle値は24番目、CPU1のidle値は32番目なので、それぞれを@Fのインデックス指定で取得。インデックスは0オリジンなので、CPU0のidle値は$F[23]、CPU1のidle値は$F[31]、ただしCPU1のidle値はその段落全体で最後のフィールド最後になるので$F[-1]、として出力。
といった感じで、表データの任意の値だけ取得というのもかんたんにできる。
まあ、こういうデータ抽出をするかどうかは別にして、自分なりの例を作ってやってみると理解しやすい気がしました。次回に続きます。
Category: Programming, Perl | コメント&トラックバック(0)
Touch Diamond向けのページを作るには、、、
2009/01/03 23:01 posted by kunkichi
Touch Diamond の Opera のブックマークが使いにくいので、よく使うサイト一覧のHTMLを作ってサーバにアップしたのだけど、どうやっても横幅が小さくなる。折り返すほど長い文字列はないのだけどなぁ、、、
Category: Diary | コメント&トラックバック(0)
Page 5 of 32« First...«34567»...Last »
2009/10/21/ 14:08
2009/10/04/ 12:39
2009/09/23/ 13:31
2009/09/23/ 13:30
2009/08/24/ 18:34