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

Slides:



Advertisements
Similar presentations
プロセスの生成とコマンドの実行 プロセスの生成とコマンドの実行 プロセス生成のシステムコール プロセス生成のシステムコール プロセス生成のプログラム例 プロセス生成のプログラム例 プログラム実行のシステムコール プログラム実行のシステムコール 子プロセスの終了を待つシステムコール 子プロセスの終了を待つシステムコール.
Advertisements

オブジェクト指向言語・ オブジェクト指向言語演習 中間試験回答例. Jan. 12, 2005 情報処理技術基礎演習 II 2 オブジェクト指向言語 中間試験解説 1  (1) 円柱の体積(円柱の体積 = 底面の円の面積 x 高さ) を求めるプログラムを作成しなさい。ただし、出力結果は、入 力した底面の円の半径.
15.1 文字列処理の基本 15.2 文字列処理用ライブラリ関数
情報処理演習C2 ファイル操作について (2).
情報基礎演習B 後半第5回 担当 岩村 TA 谷本君.
数理情報工学演習第一C プログラミング演習 (第3回 ) 2014/04/21
プログラミング入門2 第10回 構造体 情報工学科 篠埜 功.
プログラミング入門2 第10回 構造体 情報工学科 篠埜 功.
システムプログラミング 第5回 情報工学科 篠埜 功 ヒアドキュメント レポート課題 main関数の引数 usageメッセージ
基礎プログラミングおよび演習 第9回
プログラミング演習Ⅱ 第12回 文字列とポインタ(1)
文字配列の課題1 解説 /* a */ #include <stdio.h> main( ) { int i;
12: コマンドライン引数 C プログラミング入門 総機1 (月1) Linux にログインし、以下の講義ページ を開いておくこと
情報処理Ⅱ 2005年12月9日(金).
12: コマンドライン引数 C プログラミング入門 基幹7 (水5) Linux にログインし、以下の講義ページ を開いておくこと
第8回 プログラミングⅡ 第8回
第4回放送授業.
プログラミング演習Ⅰ 課題2 10進数と2進数 2回目.
関数 関数とスタック.
第3回 配列,構造体,ポインタ ~ データ構造について学ぶための基礎~
プログラミング論 関数ポインタ と 応用(qsort)
プログラミング2 関数
モバイルプログラミング第4回 Cプログラミングの基礎( 3 )
プログラミング論 ファイル入出力
関数の定義.
プログラミング論 II 2008年10月30日 文字列
プログラミング 4 記憶の割り付け.
プログラミング演習I 2003年6月25日(第10回) 木村巌.
第10章 これはかなり大変な事項!! ~ポインタ~
プログラミング入門2 第8回 ポインタ 情報工学科 篠埜 功.
プログラミング入門2 第11回 情報工学科 篠埜 功.
演習1の解答例の解説 2004年10月21日 海谷 治彦.
第7回 プログラミングⅡ 第7回
復習 前回の関数のまとめ(1) 関数はmain()関数または他の関数から呼び出されて実行される.
アルゴリズムとデータ構造 補足資料5-1 「メモリとポインタ」
プログラミング論 ファイル入出力
第11回 プログラミングⅡ 第11回
演習1の解答例の解説 2006年11月8日 海谷 治彦.
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.
09: ポインタ・文字列 C プログラミング入門 総機1 (月1) Linux にログインし、以下の講義ページ を開いておくこと
プログラミング基礎B 文字列の扱い.
岩村雅一 知能情報工学演習I 第12回(C言語第6回) 岩村雅一
メモリとメモリアドレス, ポインタ変数,関数へのポインタ渡し
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
プログラミング言語論 第六回 理工学部 情報システム工学科 新田直也.
15.1 文字列処理の基本 15.2 文字列処理用ライブラリ関数
プログラミング入門2 第9回 ポインタ 情報工学科 篠埜 功.
プログラミング 3 2 次元配列.
文字列へのポインタの配列 static char *lines[MAXLINES]; lines[0] NULL
ポインタとポインタを用いた関数定義.
情報基礎演習B 後半第2回 担当 岩村 TA 谷本君.
プログラミング論 ポインタ
09: ポインタ・文字列 C プログラミング入門 基幹7 (水5) Linux にログインし、以下の講義ページを開いておく こと
ネットワーク・プログラミング Cプログラミングの基礎.
第5回 プログラミングⅡ 第5回
プログラミング論 文字列
プログラミング 4 文字列.
岩村雅一 知能情報工学演習I 第12回(後半第6回) 岩村雅一
情報処理Ⅱ 2005年11月25日(金).
プログラミング演習II 2004年11月 16日(第5回) 理学部数学科・木村巌.
15.1 文字列処理の基本 15.2 文字列処理用ライブラリ関数
プログラミング演習II 2004年11月 2日(第3回) 理学部数学科・木村巌.
プログラミング入門2 第5回 配列 変数宣言、初期化について
情報処理Ⅱ 小テスト 2005年2月1日(火).
分岐(If-Else, Else if, Switch) ループ(While, For, Do-while)
プログラミング演習I 補講用課題
岩村雅一 知能情報工学演習I 第7回(後半第1回) 岩村雅一
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
プログラミング 3 ポインタ(1).
12: コマンドライン引数 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと
Presentation transcript:

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

前回まで:microshell #include <stdio.h> char command[80]; char *prompt="% "; main() { printf("%s", prompt); while(scanf("%s", command) != EOF){ if(fork() == 0){ execl(command, command,0); }else{ wait(0); }

前回の課題 課題1. lsコマンドを呼び出して実行できるようにしよう。 Hint. %/bin/ls と実行すれば実行できますが、 %ls だけでは実行できません。 パスをサーチするには? execl ⇒ execlp 課題2. 知らないコマンドがでたらエラーを返すようにしよう。 Hint.大抵のシステムコール・関数は正常に実行できたかどうか確認するため返り値という値を返します。 if( ( execlp(command, command, 0) ) <0 ) printf(“error\n”);等 課題3. ls -lやcatコマンドのように、第2引数を処理するようにしよう。 第2引数をchar *argv[]等に入れて execvp(argv[0], argv)のようにする

解答例 #include <stdio.h> char *prompt="% "; char *argv[20], input[80]; main() { printf("%s", prompt); while( fgets(input, sizeof(input), stdin) != NULL ){ if(fork() == 0){ /* inputを空白で分割し “ls -l” ⇒ “ls” “-l” argvに格納する */ if( execvp(argv[0], argv)<0 ) perror(argv[0]); }else{ wait(0); }

傾向 第3課題でつまるケースが多かった char *argv[]を整える方法 応用ではcdやパイプを実装するケースが多かった

今日やること 関数 ポインタ 配列 文字列 演習はこれらを応用した文字列分割と ヒストリー機能

関数とは 頻繁に使うコードをまとめたもの int func(int a, char b){ … } 返り値(戻り値)の型 出力 関数名 引数の型と名前   入力 int func(int a, char b){ … }

関数の定義 int add(int a, int b){ int num; num = a+b; return num; } 返り値を返さないといけない 呼び出し側が得られる 唯一の結果

関数の宣言と呼び出し void func(int a, char b); main(){ func(x, y); } 宣言が無いとimplicit(暗黙に)intを返すと解釈する 定義は別の場所でできる

返り値 int型の返り値は定義で省略しても良い 返り値は呼び出し側が無視してもOK main(){ … } 等 単にexecvp(…); 等と呼び出して良い (intが返ってるけど)

引数 関数への入力 main(){ func(x, y); } x, y 実引数(呼び出し側) int func(int a, int b){ … }    a, b 仮引数 (呼び出され側) どんな値が渡されるか分からないから 「仮」

関数への引数の渡し方 値渡し call-by-value ポインタ(アドレス)渡し ① ② 値 ポインタ 値 値 関数 関数 func(int a){…} ② func(int *a){…} 複製 値 ポインタ 値 値 関数 関数

これまでに利用した関数 ポインタ From jman page int execlp(const char *file, const char *arg, ...); int execvp(const char *file, char *const argv[]); int scanf(const char *format, ...); char *strcpy(char *dest, const char *src); …(ピリオド三つ)は可変個の引数を表す constはその変数の値が変更されないことを 保証する ポインタ

ポインタ 2 6 変数が入っているメモリ番地を表す変数 値 ポインタ 6 a int a; int *a_ptr; … メモリ 値 変数 0番地 1番地 6 a 2番地 int a; int *a_ptr; 3番地 …

*と& int *a_ptr; a_ptr = &a; *a_ptr = 6; &でアドレスを取得 宣言 宣言内の*は変数が 使い方 a_ptr = &a;  *a_ptr = 6; 宣言内の*は変数が ポインタであることを表す &でアドレスを取得 *はポインタが 指している中身を表す

ポインタと中身の関係 int a; int *b; 代入不可 b a &a b 代入できる *b 代入できる a *b 代入不可 &a

ポインタと引数 値渡し call-by-value ポインタ(アドレス)渡し ② ① 実際にaは渡さない 実際にaを処理できる  ポインタ(アドレス)渡し ② ① func1(int a){ return a++; } func2(int *a){ a = “abc”; } 実際にaは渡さない 実際にaを処理できる

具体例 main(){ int a, b; int *a_ptr; b = func1(a); func2(a_ptr) }

それぞれの違い 値渡し ポインタ渡し 長所: 渡した値に何されても平気 短所: 適切な値をreturnし、処理しないといけない 長所: 渡した値に何されても平気 短所: 適切な値をreturnし、処理しないといけない ポインタ渡し 長所: 関数内で全て処理が行われるから便利    配列を渡す場合は必然 短所: 変数の中身が変更される可能性がある

ポインタの型 a_ptrは特定の型の変数を指し *a_ptrはその型の中身を持つ ポインタは型を持つ Int, char, long…それぞれのポインタは異なる

ポインタの出力 printf(“%x”, ptr); 16進数(Hexadecimal) 例:22f064 printf(“%p”, ptr); アドレスを出力 出力例:0x22f064

ポインタの例 ポインタとして宣言 numのアドレスをnum_ptrに代入 出力結果 num_ptrが指す値(=num) $./a.exe 6 main() { int num = 3; int *num_ptr; num_ptr = &num; *num_ptr = 6; printf("%d\n", num); printf(“%d\n”, *num_ptr); printf("%x\n", num_ptr); } numのアドレスをnum_ptrに代入 出力結果 $./a.exe 6 22f06c $ num_ptrが指す値(=num)

ポインタの初期化 int *a_ptr = &a; // アドレスの取得 int a[10]; 初期化していないポインタを使うと多くの場合エラーになる

配列 … a[0] x a[1] y 複数の要素を持つ変数 a[2] z char a[3]; int num[20]; a = { x, y, z }; num = { {1, 2, 3, …, 10} , {1,2, 3, …, 10} } …

配列の名前とポインタ 配列の名前の実体はポインタ a[0] a 実際は最初の要素を指すポインタ int *a[10] なら a == &a[0] a[0] a

関数への受け渡し 配列として受け渡せない 配列名(ポインタ)を渡す Int buf[20]; func(buf); int func(int *num){ } char a[3]; char b[3]; strcat(a, b); 要素数などを渡す手段が必要 文字列の場合終端記号\0で終わりを判別

execlでの例 char command[80]; main() { … execl(command, command,0); int execl(const char *path, const char *arg, ...); char command[80]; main() { … execl(command, command,0); 配列の名前なので渡せている

多次元配列とポインタの配列 配列 多次元 配列 配列 多次元配列: num[2][3] ポインタの配列: char *argv[6] 全ての要素がポインタ 配列

それぞれ関数への受け渡し execvp(argv[o], argv); sum(num[1]); int sum(int *num){ ポインタが渡るように注意する execvpなどはポインタの配列を引数に取る int execvp(const char *file, char *const argv[]); execvp(argv[o], argv); sum(num[1]); int sum(int *num){ for(;;) total += num[i]; return total; }

配列とポインタへの演算 ポインタには加算と減算ができる a_ptr-1 a_ptr a_ptr+1 値を出すときは*(a_ptr+1)

加算の例 文字列の中から特定の文字を探す char buf[80]; char *ptr = buf; while(*(ptr++)!=‘文字’) ; ptrが文字を指した状態でループを抜ける ポインタの初期化 値を取り出し比較

加算の例2 a[0] char a[6]; char *ptr = a a[1] a[2] a[3] a[4] a+4 a[5] 配列のx番目の要素は名前+x a[0] char a[6]; char *ptr = a a[1] a[2] a[3] a[4] a+4 a[5]

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

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

‘ ’ と “ ” の違い “a”は 01100001 00000000に自動変換される ‘a’は 01100001 ‘ ’ と “ ” の違い “a”は 01100001 00000000に自動変換される ‘a’は 01100001 終端記号 ‘\0’ は8つの0

文字列の検査 ‘\0’は偽なので、文字列の終端で自動的にwhileを抜ける char *buf = “abc\0xyz”; char *ptr = buf, *ptr2; While(*(ptr++) ) ; ptr2 = ptr; printf(“%s”, ptr2); 出力結果はxyzになる ‘\0’は偽なので、文字列の終端で自動的にwhileを抜ける

strlenとsizeof strlen: 最初の\0までの長さ sizeof:オブジェクトの大きさを求めるのに使う char *buf a x y z \0 strlen(buf) == 3 sizeof(buf) == 8

文字列の取得 buf a b c \n \0 char *fgets(char *s, int size, FILE *stream); char buf[80]; … fgets(buf, sizeof(buf), stdin); buf[strlen(buf) -1] = '\0'; 改行文字も読んでしまうのでその前で終端させる buf a b c \n \0

今日の演習 課題1 一行の入力を空白で分割し、char *argv[n]に格納する関数split(名前はなんでも良い)をつくろう。 ただし、ポインタと文字列(終端記号)の性質を利用すること。 課題2 実行したコマンドを配列に保存し、特定のキーを押したら過去のコマンドのリストを表示、 実行できる機能(ヒストリー)をmicroshellに付加しよう。 % h 0) ls 1) ls -l 2) gcc mshell.c % 0 a.exe mshell.c %