第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
© Copyright 2024 ExpyDoc