第3回授業資料

第3回ネットワークプ
ログラミング
中村 修
今日のお題

ディスクリプタ
 file
I/O
 練習問題1:cat –n を作ってみよう

ポインタ
 ポインタと文字列
 練習問題2:ファイルの中身をひっくり返してみよう

引数
 argc,argv
 練習問題3:
引数を出力しよう
--------(休憩)-----------------

実習
 cat
–n –r file1 file2 file3 …… を作ろう
ファイルディスクリプタ

プロセスが外の世界と通信するためのデータ
の入り口
 全ての通信は、必ずファイルディスクリプタを通じ
て行われる
(予約済)
0: 標準入力(キーボード)
1: 標準出力(モニタ)
2: 標準エラー出力(モニタ)
入出力関数:システムコール
open
 read
 write
 close

次のページから例あり
open()システムコール

int open(char *path, int flags, …);
 返り値がファイルディスクリプタ
 引数は基本的に3つ
 char *path


int flags


開くファイルのパス名が保存されている文字配列(へのポイン
タ)
ファイルを開くときにどのような状態で開くかを決める
 読み込みだけ(O_RDONLY)
 書き込みだけ(O_WRONLY)
 読み書き両方(O_RDWR)
 追加(append) (O_APPEND)
 新規作成(O_CREAT)
 ブロックしない(O_NONBLOCK)
3番目は便宜的に 0
read()システムコール

int read(int d, void *buf, size t nbytes)
 引数
 int d: ファイルディスクリプタ
 void *buf: 読み込んだデータを保存するための配列(バッファ)
 size_t nbytes: 1回のread()で読める最大バイト数(バッファの
大きさ)
 返り値
 int: 実際に読み込んだバイト数



0より大きい: 読み込み成功
0: ファイルの最後(EOF)に到達
0より小さい: エラー
write()システムコール

int write(int d, void *buf,size t nbytes)
 引数



int d: ファイルディスクリプタ
void *buf: 書き込むデータを保存している配列・ポインタ(バッファ)
size_t nbytes: 1回のwrite()で書き込むバイト数(書き込むデータ
の大きさ)
 返り値

int: 実際に書き込んだバイト数


0より大きい: 書き込み成功
0より小さい: エラー
close()システムコール

int close(int fd);
 引数

int fd: ファイルディスクリプタ
 返り値
0: 成功
 0より小さい: エラー
 通常はあまりチェックしない

open()/read()/write()/close()の例
#include <fcntl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#define BUFSIZE 1024
int main()
{
char buf[BUFSIZE];
int fd;
int nbyte;
fd = open(“test.txt”, O_RDONLY, 0);
while((nbyte = read(fd, buf, BUFSIZE)) > 0) {
write(1, buf, nbyte);
}
close(fd);
exit(0);
}
ファイルを扱う関数

fopen(char *filename, char *mode)
 r,w,a,r+,w+,a+
fgets(cahr *s,int length,FILE *fd)
 fgetc(FILE *fd)
 fclose(FILE *fd)

次のページに練習問題あり
これらの関数を使うと
#include <stdio.h>
int main()
{
FILE *fp;
char buf[1024];
int c;
fp = fopen(“sample.txt”,"r");
while((fgets(buf, sizeof(buf),fp)) != NULL){
fputs(buf,stdout);
}
fclose(fp);
exit(0);
}
練習問題1

-nオプションを指定したcatコマンドのように、
左端に行番号を出力するようなプログラム
catn.cを作成する
 sample.txtを読み込んで

行番号を付けて出力。
sample.txt
 /home/kaizaki/osamuNP/3/sample.txt
次のページから「ポインタ」解説
ポインタ
アドレス
100
101
102
103
104
105
106
107
108
109
110
111
112
113
200
201
メモリ空間
"T"
"h"
"i"
"s"
""
"i"
"s"
""
"t"
"e"
"s"
"t"
"."
NULL
100
….
string[]
char string[] = "This is test.";
"で括った文字列は
どこかに格納されている
ポインタ変数: メモリアドレスを格納している
変数
型: ポインタが示すメモリにどの型で格納さ
れているかを示す
cf char *s; 文字(列)が入っている変数
のアドレスが入る変数
char *s = string;
文字列とポインタ

文字列は配列で管理されている
char mystr[8] = “hello”;
h
e
l
l
o
\0
char *mystr = “hello”;
h
e
l
l
o
\0
mystr
mystr
mystr
mystr
mystr
+
+
+
+
= “hello”
1 = “ello”
2 = “llo”
3 = “lo”
4 = “o”
*mystr *(mystr+1) *(mystr+2) *(mystr+3) *(mystr+4)
mystr[3]
mystr[4]
mystr[2]
mystr[0] mystr[1]
文字配列と文字定数とポインタ
文字列定数 宣言時にどこかに存在する(無名配列)
“hello”
文字配列
h
e
l
l
o
\0
どこかに存在する
l
l
char str1[8] = “hello”;
str1
8つの文字変数からなる
str1という配列を用意
配列に対して「どこかに
存在している」”hello”の
内容をコピー(初期化)
ポインタ
str1
h
e
char *ptr = “hello”;
文字変数を指すポインタ型
変数ptrを用意
ptr
ptr
ポインタ変数に対して
「どこかに存在している」
”hello”のアドレスをコピー(初期化)
0xff0120
o
\0
ポインタが役に立つ時は?

ポインタの利用例
 動的に割り当てた配列(malloc()など)
 複数ある類似の変数への汎用なアクセス
 関数引数の(擬似的な)参照渡し(call
by reference)
 あらゆる種類のデータ構造を動的に割り付ける

cf ツリー構造、リンクリスト
 配列や効率のよい参照渡しのコピー

関数引数の場合
次のページに練習問題あり
練習問題2

sample.txtファイルの内容をひっくり返して、
anagram.txt という名前のファイルを作成す
る。
abcdef
ghijkl
:
:
fedcba
lkjihg
:
:
コマンドライン引数:argc,argv

コマンドの引数を用いるには?
–n file
 cat file1 file2 file3
 cat
コマンドライン引数の利用法
main( int argc, char **argv)
 main( int argc, char *argv[])

argc には引数の数
 argv[0] にはコマンド名
 argv[1] には1番目の引数
 argv[2] には2番目の引数

練習問題3
argc,argvを用いて引数を全て出力する。
 実行例/出力例

%./a.out 123 456 789
arg[0]: ./a.out
arg[1]: 123
arg[2]: 456
arg[3]: 789
練習問題3の回答
#include<stdio.h>
int main(int argc, char *argv[]){
int i;
for(i = 0; i < argc; i++){
printf("arg[%d]: %s\n", i, argv[i]);
}
}
実習

今日作成した、





cat –n
cat –r (中身をひっくり返す)
引数を出力する関数
を参考に、以下の書式を満たすcatを作成する
cat –r
cat –n
cat file1 file2 file3
複数のオプションを同時に満たす機能を実現できたらボーナ
ス得点。
実習ヒント

-r –nなどは 2通りでチェックできる
 if(*argv[i]
== ‘-’ && *(argv[i]+1) == ‘r’ )
 if(argv[i][0] == ‘-’ && argv[i][1] == ‘r’)

fopenでファイルを開いたら、かならずfclose