モバイルプログラミング第4回 Cプログラミングの基礎( 3 )

Slides:



Advertisements
Similar presentations
プログラミング演習 II 2005 年 1 月 19 日(第 9 回) 理学部数学科・木村巌. 前回までの復習 共用体( union type ) 共用体( union type ) 列挙 (enumerated type ) 列挙 (enumerated type ) 構造体、構造体のポインタ、
Advertisements

オブジェクト指向言語・ オブジェクト指向言語演習 中間試験回答例. Jan. 12, 2005 情報処理技術基礎演習 II 2 オブジェクト指向言語 中間試験解説 1  (1) 円柱の体積(円柱の体積 = 底面の円の面積 x 高さ) を求めるプログラムを作成しなさい。ただし、出力結果は、入 力した底面の円の半径.
システムプログラミング 第7回、8回 ファイルシステム関連の システムコール
15.1 文字列処理の基本 15.2 文字列処理用ライブラリ関数
情報処理演習C2 ファイル操作について (2).
情報基礎演習B 後半第5回 担当 岩村 TA 谷本君.
数理情報工学演習第一C プログラミング演習 (第3回 ) 2014/04/21
プログラミング入門2 第10回 構造体 情報工学科 篠埜 功.
プログラミング入門2 第10回 構造体 情報工学科 篠埜 功.
リダイレクト パイプ 標準入出力プログラム コマンド行引数 関数 system()
システムプログラミング 第5回 情報工学科 篠埜 功 ヒアドキュメント レポート課題 main関数の引数 usageメッセージ
プログラミング演習(2組) 第12回
OSとコマンド OS:コンピュータを使うための基本プログラム コマンド:OS上で使用できる命令 OS本体であるカーネルの内部コマンド
12: コマンドライン引数 C プログラミング入門 総機1 (月1) Linux にログインし、以下の講義ページ を開いておくこと
記憶クラス 変数をどのような記憶領域に割り当てるかを指定するのが記憶クラス 記憶クラスには、自動変数、静的変数、外部変数などがある。
12: コマンドライン引数 C プログラミング入門 基幹7 (水5) Linux にログインし、以下の講義ページ を開いておくこと
第8回 プログラミングⅡ 第8回
担当:青木義満 情報工学科 3年生対象 専門科目 システムプログラミング システムプログラミング プロセス間通信(パイプ) 担当:青木義満
構造体.
プログラミング演習Ⅰ 課題2 10進数と2進数 2回目.
精密工学科プログラミング基礎 第9回資料 (12/11 実施)
ファイル操作と文字列の利用.
精密工学科プログラミング基礎Ⅱ 第3回資料 今回の授業で習得してほしいこと: 2次元配列の使い方 (前回の1次元配列の復習もします.)
第10回 プログラミングⅡ 第10回
10: ファイル入出力 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと
C言語講座 第3回 ポインタ、配列.
プログラミング論 関数ポインタ と 応用(qsort)
プログラミング論 ファイル入出力
プログラミング論 II 2008年10月30日 文字列
情報・知能工学系 山本一公 プログラミング演習Ⅱ 第2回 ファイル処理 情報・知能工学系 山本一公
リダイレクト パイプ 標準入出力プログラム コマンド行引数 関数 system()
プログラミング演習I 2003年6月25日(第10回) 木村巌.
第10章 これはかなり大変な事項!! ~ポインタ~
プログラミング入門2 第11回 情報工学科 篠埜 功.
プログラミング入門2 第11回 情報工学科 篠埜 功.
第7回 プログラミングⅡ 第7回
復習 前回の関数のまとめ(1) 関数はmain()関数または他の関数から呼び出されて実行される.
アルゴリズムとデータ構造 補足資料5-1 「メモリとポインタ」
地域情報学 C言語プログラミング 第5回 ポインタ、関数、ファイル入出力 2017年11月17日
プログラミング論 ファイル入出力
第11回 プログラミングⅡ 第11回
P n ポインタの基礎 5 q m 5 7 int* p; int 型の変数を指すポインタ int* q; int 型の変数を指すポインタ int n=5, m=7; int 型の変数 int array[3]; int* pArray[3]; p = &n; ポインタにアドレスを代入しているのでOK.
プログラミング基礎B 文字列の扱い.
システムプログラミング 第7回、8回 ファイルシステム関連の システムコール
精密工学科プログラミング基礎Ⅱ 第4回資料 今回の授業で習得してほしいこと: 文字列の扱い ファイル入出力の方法 コマンドライン引数の使い方
岩村雅一 知能情報工学演習I 第12回(C言語第6回) 岩村雅一
システムプログラミング 第7回、8回 ファイルシステム関連の システムコール
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
プログラミング言語論 第六回 理工学部 情報システム工学科 新田直也.
15.1 文字列処理の基本 15.2 文字列処理用ライブラリ関数
文字列へのポインタの配列 static char *lines[MAXLINES]; lines[0] NULL
プログラミング演習I 2003年7月2日(第11回) 木村巌.
プログラミング論 ポインタ
12: コマンドライン引数 C プログラミング入門 基幹7 (水5) Linux にログインし、以下の講義ページを開いておく こと
ネットワーク・プログラミング Cプログラミングの基礎.
プログラミング論 文字列
岩村雅一 知能情報工学演習I 第12回(後半第6回) 岩村雅一
プログラミング言語論 第九回 理工学部 情報システム工学科 新田直也.
オブジェクト指向言語論 第七回 知能情報学部 新田直也.
プログラミング言語論 第九回 理工学部 情報システム工学科 新田直也.
オブジェクト指向言語論 第七回 知能情報学部 新田直也.
情報処理Ⅱ 2005年11月25日(金).
プログラミング演習II 2004年11月 16日(第5回) 理学部数学科・木村巌.
15.1 文字列処理の基本 15.2 文字列処理用ライブラリ関数
プログラミング演習II 2004年11月 2日(第3回) 理学部数学科・木村巌.
プログラミング入門2 第5回 配列 変数宣言、初期化について
モバイルプログラミング第3回 Cプログラミングの基礎( 2 )
分岐(If-Else, Else if, Switch) ループ(While, For, Do-while)
岩村雅一 知能情報工学演習I 第7回(後半第1回) 岩村雅一
12: コマンドライン引数 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと
Presentation transcript:

モバイルプログラミング第4回 Cプログラミングの基礎( 3 )

前回の復習 ポインタ 配列 文字列

変数が入っているメモリ番地(アドレス)を表す変数 ポインタ 変数が入っているメモリ番地(アドレス)を表す変数 値 ptr 2 0番地 6 1番地 ptr 6 2番地 printf(“ptr: %x”, ptr); ptr: 2 3番地 …

ポインタの使い方 void func(int *a); main(){ int *a_ptr; a_ptr = &a; 宣言内の*は変数が ポインタであることを表す ポインタは型を持っていて その型の中身を持つ void func(int *a); main(){ int *a_ptr; a_ptr = &a;  *a_ptr = 6; } &でアドレスを取得 *はポインタが 指している中身を表す

main() { int num = 3; int *num_ptr; num_ptr = # *num_ptr = 6; 記述例 main() { int num = 3; int *num_ptr; num_ptr = # *num_ptr = 6; printf("%d\n", num); } ポインタとして宣言 numのアドレスをnum_ptrに代入 num_ptrの中身に値を代入 出力結果 $./a.exe 6

関数とポインタ 値渡し call-by-value ポインタ(アドレス)渡し ① ② 値 ポインタ 値 値 関数 関数 func(int a){…} ② func(int *a){…} 複製 値 ポインタ 値 値 文字列や配列を関数に渡すために必要 関数 関数

配列 a[0] x a[1] y 複数の要素を持つ変数 a[2] z … char a[80]; int num[20]; // 配列の配列(二次元配列) char *argv[10]; // ポインタの配列 …

配列とポインタ ptr ptr++ ptr+1 ptr+3 buf buf char buf[4]; 配列の名前はポインタ char *ptr = buf; 配列の名前はポインタ ポインタに加算すると次の要素、減算すると前の要素を指すようになる ptr ptr++ ptr+1 buf buf ptr+3

文字列 連続した文字の並び ヌル文字(\0)で終わる 例 a b c \0

文字列の宣言 char *buf = “abc”; a b c \0 “buf”はこの要素へのポインタ

前回の課題 課題1. 文字列を空白で分割する関数をつくろう。 ただし、ポインタと文字列(終端記号)の性質を利用すること。 課題2. microshellにヒストリー機能をつけよう。 実行したコマンドを配列に保存し、特定のキーを押したらコマンドリストを表示、実行できるようにする。 http://www.ht.sfc.keio.ac.jp/mobile2004/lecture4.htm にサンプルコード

課題1 解答例 int split(); main() { … if(fork() == 0){ split(input, argv); // 入力を空白で分割し、argvに格納する if(execvp(argv[0], argv)<0) perror(argv[0]); } int split(char *input, char *argv[]){ int i; argv[0] = input; // 最初にinputの先頭をargv[0]に入れておく while(*(input++)) // inputの今の文字が終端(\0、つまり偽)で無い限り if(*input==' '){ // inputの今の文字が空白なら *input = '\0'; // 代わりに終端文字を入れる argv[++i] = input+1; // iを増やして、argv[i]にinputの次の文字列を入れる return i; 課題1 解答例

空白に\0を入れてポインタで次の文字を指す int split(char *input, char *argv[]){ int i; argv[0] = input; // 最初にinputの先頭をargv[0]に入れておく while(*(input++)) // inputの今の文字が終端(\0、つまり偽)で無い限り if(*input==' '){ // inputの今の文字が空白なら *input = '\0'; // 代わりに終端文字を入れる argv[++i] = input+1; // argvの次のポインタにinputの次の文字列を入れる } return i; splitの内容 argv[0] argv[1] l s - l \0 \0 空白に\0を入れてポインタで次の文字を指す 文字列を見ていって

課題2 解答例 char history[20][80]; int history_num = 0; void process_history(char *input); main() { … while(fgets(input, sizeof(input), stdin)){ if(input[0] == 'h'){ process_history(input); } else{ if(history_num < 20) strcpy(history[history_num++], input);  if(fork() == 0) ... void process_history(char *input){ int i, j; char buf[80]; for(i=0; i<history_num; i++) printf("%d) %s \n", i, history[i]); printf("input: "); fgets(buf, sizeof(input), stdin); j = atoi(buf); strcpy(input, history[j]); 課題2 解答例

process_historyの内容 呼び出し側 char history[20][80]; if(!strcmp(input, “h”)){ process_history(input);    // 入力がhなら、ヒストリーから選択させ、inputにコマンドを代入 } else{  if(history_num < 20) strcpy(history[history_num++], input); // そうでなければhistoryに追加 … inputの実行 関数 void process_history(char *input){ int i, j; char buf[80]; for(i=0; i<history_num; i++) printf(“%d) %s \n”, i, history[i]); // historyを表示 printf(“input: ”); fgets(buf, sizeof(input), stdin); //ユーザの入力を取る j = atoi(buf); // それを数字に直して strcpy(input, history[j]); // historyに代入 process_historyの内容

今日やること 講義 mainへの引数 ファイル 構造体 プリプロセッサ 演習 リダイレクション機能

main(int argc, char *argv[])と宣言することで int i=argc; char *cmd=argv[0] } main(){ fgets(…); }

argc, argv main(int argc, char *argv[]) $./a hello world argv[0]はプログラム名、argv[1]は 第一引数… どちらも自動的に計算されてmainに渡される

記述例 #include <stdio.h> 実行結果 int i; $gcc sample.c main(int argc, char *argv[]) { printf("argc = %d\n", argc); for(i=0; i<argc; i++) printf("argv[%d] = %d\n", i, argv[i]); } 実行結果 $gcc sample.c $./a.exe hello world argc = 3 argv[0] = ./a argv[1] = hello argv[2] = world $

練習問題 コマンドラインから引数として二つ文字列を取って それらをつなげるプログラムを作ろう 引数の数が異なったらエラーメッセージを出そう int strncmp(const char *s1, const char *s2, size_t n); 二つの文字列を比べる char *strncpy(char *dest, const char *src, size_t n); 文字列をコピーする char *strncat(char *dest, const char *src, size_t n); 二つの文字列を連結する nにはstrlenを使うと良い

nmコマンド nmを使ってa.exeを見る T テキスト D データ BSS 未初期化データ addr低 addr高 $nm a.exe 00000000 A __dll__ 00401050 T _function 00401055 T _main 00402000 D __data_start__ 00402000 D _a 00402004 D _b 00402010 d _dw2_object_mutex.0 00402014 d _sjl_once.2 00402020 D __data_end__ 00403000 b .bss 00403000 B __bss_start__ 00403010 b _sjl_fc_key.1 00403020 B _environ 00403024 B __impure_ptr 00403028 B __fmode 00404114 i .idata$6 nmを使ってa.exeを見る  T テキスト  D データ  BSS 未初期化データ addr低 addr高

プログラムの中身を見る アセンブラコード $ gcc –S ファイル.c $ less ファイル.s gdb $ gdb a.exe … (gdb) disassemble main

ディスク上のデータ、端末などをファイルとして扱う バイトの羅列 ディスク上のデータ、端末などをファイルとして扱う ファイル型変数 FILE *(ファイルポインター)で扱える ファイルを扱うプログラムはstdio.hをincludeする必要がある ファイル

ファイル関連の関数 オープン・クローズ FILE *fopen(const char *path, const char *mode); int fclose(FILE *stream); 読み書き char *fgets(char *s, int size, FILE *stream); int fputs(const char *s, FILE *stream);

fopenのモード FILE *fopen(char *ファイル名, const char *モード); モード(これらを組み合わせて指定する) r 読み込み r+ 書き込みもできる w 書き込み、ファイルの内容を初期化 w+ 読み込みもできる a 追加書き込み a+ 読み込みもできる b バイナリファイルとしてオープンする 詳しくはjmanのfopenを参照

記述例 main() { FILE *file; char buf[80]; file = fopen(“sample2.c", "r"); fgets(buf, sizeof(buf), file); fputs(buf, file); printf("%s", buf); fclose(file); } 読み込み専用で開いている 書き込みは行われない

定義済みの名前 stdin 標準入力(キーボード) stdout 標準出力(スクリーン) stderr 標準エラー出力(スクリーン) それぞれFILE *型変数 プログラムを実行すると自動的に開かれる

ファイル記述子 ファイルポインターやアドレスの代わりにやり取りされる整数値 オープンされているファイルのテーブルに対するインデックス ファイルディスクリプターとも呼ぶ FILE *型の中にも含まれる stdin 0, stdout 1, stderr 2 int open(const char *pathname, int flags); int creat(const char *pathname, mode_t mode); int close(int fd);

dup関数 ファイル記述子の複製を作る int dup(int oldfd);  使用されていない最小の値のディスクリプタを新しいディスクリプタとして使用する int dup2(int oldfd, int newfd);  oldfd の複製として newfd を作成する。必要ならば最初に newfd をクローズ (close) する

#include <stdio.h> char buf[80]; main(int argc, char *argv[]) { FILE *file = fopen("tmp", "w"); dup2(file->_file, 1); if(argc==3){ strncpy(buf, argv[1], strlen(argv[1])); strncat(buf, argv[2], strlen(argv[2])); printf("%s",buf); } else printf("usage: a string1 string2"); fclose(file); 記述例 標準出力の1を閉じて tmpのfdに割り当てる printfの内容は tmpに書き込まれる

pipe関数 パイプ用のファイル記述子の組を作る パイプ: 一つのプロセスの出力をもう一方の入力にする (例) ls | less int pipe(int filedes[2]);   filedes[0] には読み出し用、 filedes[1] には書き込み用のファイル・ディスクリプターが格納される

構造体 複数の異なる要素を持った変数 配列は各要素が同じデータ型だったが、構造体は各要素のデータ型が異なる

構造体の宣言 構造体自体 struct NAME{ int one; char two; struct hoge three; } [変数名]; 変数 struct NAME a, b, c[10];

FILEの構造体 /usr/include/sys/reent.hに定義されている struct __sFILE { unsigned char *_p; /* バッファ内の現在のポジション */ int _r; /* getc()用に残っているスペース */ int _w; /* putc()用に残っているスペース */ short _flags; /* フラグ、0ならフリー*/ short _file; /* ファイル記述子 */ struct __sbuf _bf; /* バッファ */ … } /usr/include/sys/reent.hに定義されている

要素の参照 . 要素の実体を参照する -> 要素のポインタを参照する 例) a.one = 3; b.two = ‘x’; . 要素の実体を参照する -> 要素のポインタを参照する 例) a.one = 3; b.two = ‘x’; c->one = &(a.one) dup(file->_file, 1);

typedef データ型に別の名前を付ける typedef int suuji; typedef struct{ int a; char b; … } hoge; typedef __FILE FILE;

プリプロセッサ - ヘッダーファイルを読むために - プリプロセッサ - ヘッダーファイルを読むために  - プログラムがコンパイルされる前に行われる前処理 #include<stdio.h> #define HOGE 100 など ヘッダーファイルを読み込んだり、変数やマクロが展開されたりする 単純な置き換え

プリプロセッサコマンドの書き方 # で始める ¥ で複数行に渡って書く ; は要らない 例) # で始める ¥ で複数行に渡って書く ; は要らない 例) #include<string.h> #define SIZE 100 for(i=0; i<SIZE; i++); ←SIZEが100に置き換わる

マクロ #define kakeru(a, b) ((a)*(b)) int x = kakeru(2, 3); と書くと、コンパイルする前に int x = ((2)*(3)); と置き換えられる

#ifdef 変数が#defineされていたらコードを有効にする 例) #define DEBUG 1 ←0ならDEBUGしない … #ifdef DEBUG printf(“input = %s”, input); #endif

ヘッダーファイルの定義もコンパイル前に展開される 通常 名前.h 関数プロトタイプやマクロ定義が含まれている ヘッダーファイルの定義もコンパイル前に展開される

今日の演習 コマンドラインから引数として複数のファイル名を取り、その内容をつなげるプログラムを作ろう Microshellを拡張し、リダイレクションを使えるようにしよう リダイレクション:コマンドの後ろに>をつけることで、コマンドの実行結果をstdoutではなく、ファイルに書き込む