• 検索結果がありません。

理学部数学科・木村巌

N/A
N/A
Protected

Academic year: 2021

シェア "理学部数学科・木村巌"

Copied!
29
0
0

読み込み中.... (全文を見る)

全文

(1)

プログラミング演習

プログラミング演習 II II

2004 2004 年 年 11 11 月 月 16 16 日(第 日(第 5 5 回) 回)

理学部数学科・木村巌

理学部数学科・木村巌

(2)

前回までの復習 前回までの復習

配列とポインタの関係 配列とポインタの関係

引数と配列 引数と配列

(3)

今日学ぶこと 今日学ぶこと

文字列とポインタ 文字列とポインタ

文字列の操作 文字列の操作

動的なメモリの確保動的なメモリの確保

関数ポインタ 関数ポインタ

教科書 教科書 10.3 10.3 から( から( p. 317 p. 317 ~) ~)

(4)

文字列をポインタで扱う 文字列をポインタで扱う

7 7 章で見たように、 章で見たように、 C C 言語には「文字列 言語には「文字列 型」というものは存在せず、

型」というものは存在せず、 char char 型の配 型の配 列(で、最後の要素が’

列(で、最後の要素が’ \0’ \0’ になっている になっている もの)で代用しているのだった

もの)で代用しているのだった char str[] = “Hello”;

char str[] = “Hello”;

これは、次と同じ これは、次と同じ

char str[] = {‘H’, ‘e’, ‘l’, ‘l’, ‘o’, ‘\0’};

char str[] = {‘H’, ‘e’, ‘l’, ‘l’, ‘o’, ‘\0’};

(5)

文字列をポインタで扱う(続)

文字列をポインタで扱う(続)

char char 型のポインタで扱うことも出来る: 型のポインタで扱うことも出来る:

char *str = “Hello”;

char *str = “Hello”;

ポインタで扱う場合は、どこかに、” ポインタで扱う場合は、どこかに、” Hel Hel lo” lo” を保存するのに必要なだけのメモリが を保存するのに必要なだけのメモリが

確保され、その先頭のアドレスが

確保され、その先頭のアドレスが str str とい とい う う char char 型のポインタ変数 型のポインタ変数 str str に保存される に保存される

教科書の図 教科書の図 10-7 10-7 ( ( 318 318 頁参照) 頁参照)

Sample8.c Sample8.c を打ち込んで、コンパイル・実 を打ち込んで、コンパイル・実 行してみよう

行してみよう

(6)

配列とポインタとの違い 配列とポインタとの違い

配列には、一度初期化した後で、再び代 配列には、一度初期化した後で、再び代 入することは出来ない

入することは出来ない

char str[] = “Hello”;

char str[] = “Hello”;

str = “Goodbye”; /*

str = “Goodbye”; /*

これは出来ない これは出来ない

*/ */

実際に試してみて、どのようなエラー 実際に試してみて、どのようなエラー メッセージが表示されるか確認しよう!

メッセージが表示されるか確認しよう!

しかし、ポインタを使うばあいは、再代 しかし、ポインタを使うばあいは、再代 入することが出来る(図

入することが出来る(図 10-8 10-8 、 、 320 320 頁) 頁)

(7)

文字列を入力する場合 文字列を入力する場合

配列を宣言して、文字列を格納する領域 配列を宣言して、文字列を格納する領域 を確保しておく:

を確保しておく:

char str[100]; /*

char str[100]; /* 文字列を格納する配列 文字列を格納する配列 */ */

scanf (“%s”, str); /*

scanf (“%s”, str); /* 配列に文字列を格納 配列に文字列を格納 * * / /

ポインタを使う場合は、文字列を格納す ポインタを使う場合は、文字列を格納す る領域を、動的に確保する(

る領域を、動的に確保する( malloc() malloc() を使 を使 う、後述)

う、後述)

(8)

文字列への再代入 文字列への再代入

標準ライブラリ関数に、文字列の再代入 標準ライブラリ関数に、文字列の再代入 を行う関数がある

を行う関数がある

実際は、文字列をメモリ上のどこかにコ 実際は、文字列をメモリ上のどこかにコ ピーしてくれる関数

ピーしてくれる関数 strcpy() strcpy()

後述 後述

(9)

文字列の配列 文字列の配列

複数の文字列を、文字列の配列 複数の文字列を、文字列の配列 1 1 つにま つにま とめることが出来る

とめることが出来る

Sample9.c Sample9.c を打ち込んで、コンパイル・実 を打ち込んで、コンパイル・実 行してみよう

行してみよう

char str[3][20] = {“Hello”, “Goodbye”, “Than char str[3][20] = {“Hello”, “Goodbye”, “Than

kyou”};

kyou”};

19 19 文字までの文字列が 文字までの文字列が 3 3 つからなる、文 つからなる、文 字列の配列

字列の配列

図 図 10-9 10-9 を参照 を参照

(10)

文字列ポインタの配列 文字列ポインタの配列

文字列はポインタとしても扱える 文字列はポインタとしても扱える

文字列のポインタの配列として、複数の 文字列のポインタの配列として、複数の 文字列をまとめて扱うことも出来る

文字列をまとめて扱うことも出来る

char *str[3] = {“Hello”, “Goodbye”, “Thankyo char *str[3] = {“Hello”, “Goodbye”, “Thankyo u”}; u”};

ポインタの配列として実現されている. ポインタの配列として実現されている.

図 図 10-10, 325 10-10, 325 頁を参照 頁を参照

(11)

文字列の操作 文字列の操作

標準ライブラリ関数には、文字列を操作 標準ライブラリ関数には、文字列を操作 するための関数が多数用意されている するための関数が多数用意されている

string.h string.h というヘッダーファイルをインク というヘッダーファイルをインク ルードする

ルードする

#include <string.h>

#include <string.h>

(12)

文字列操作用の関数(例)

文字列操作用の関数(例)

size_t strlen (const char *str); size_t strlen (const char *str);

文字列文字列

str str

の長さ(最後のの長さ(最後の

NULL NULL

を除く)を除く)

char *strcpy (char *str1, const char *str2); char *strcpy (char *str1, const char *str2);

文字列文字列

str2 str2

str1 str1

にコピーし、にコピーし、

str1 str1

を返すを返す

char *strcat (char *str1, const char *str2); char *strcat (char *str1, const char *str2);

文字列文字列

str2 str2

str1 str1

の末尾に追加しての末尾に追加して

str1 str1

を返すを返す

int strcmp (const char *str1, const char *str2); int strcmp (const char *str1, const char *str2);

文字列文字列

str1, str2 str1, str2

を辞書式順序で比較し、を辞書式順序で比較し、

str1 str1

str2 str2

より小さい、等しい、大きいに応じて、負より小さい、等しい、大きいに応じて、負

0 0

、正の値を返す、正の値を返す

(13)

文字列の長さを調べる 文字列の長さを調べる

入力された文字列の長さを返すプログラ 入力された文字列の長さを返すプログラ ム ム Sample11.c Sample11.c

入力して、コンパイル・実行してみよう 入力して、コンパイル・実行してみよう

文字列の長さを知るには、 文字列の長さを知るには、 strlen() strlen() を使う を使う

( ( string length string length ) )

strlen() strlen() を自分で書いてみよ を自分で書いてみよ

(14)

文字列をコピーする 文字列をコピーする

文字列を配列に代入した場合、再代入が出来ない文字列を配列に代入した場合、再代入が出来ない のだったのだった

配列の各要素に、一文字ずつ代入することはでき配列の各要素に、一文字ずつ代入することはでき

簡単な関数で実現できる(書いてみよ)が、これ簡単な関数で実現できる(書いてみよ)が、これ も標準ライブラリ関数

も標準ライブラリ関数

strcpy() strcpy()

として用意されていとして用意されてい

Sample12.c Sample12.c

を打ち込んで、コンパイル・実行してを打ち込んで、コンパイル・実行して みようみよう

コピー先に、コピー元が収まるだけのメモリがあコピー先に、コピー元が収まるだけのメモリがあ ることを保証するのは、プログラマの責任

ることを保証するのは、プログラマの責任

(15)

文字列を連結する 文字列を連結する

char *strcat (char *str1, const char *str2); char *strcat (char *str1, const char *str2);

一つの文字列 一つの文字列 str str の末尾に、もう一つの文 の末尾に、もう一つの文 字列 字列 str2 str2 を連結するという処理を行うの を連結するという処理を行うの が、 が、 strcat() strcat() 関数( 関数( string conCATenate string conCATenate ) )

str1 str1 が指しているメモリに、連結した後の が指しているメモリに、連結した後の 文字列が収まるだけのメモリがあること 文字列が収まるだけのメモリがあること

を保証するのは、プログラマの責任 を保証するのは、プログラマの責任

Sample12.c Sample12.c を入力し、コンパイル・実行 を入力し、コンパイル・実行 してみよう

してみよう

(16)

配列の大きさに注意 配列の大きさに注意

上でも述べたように、上でも述べたように、

strcpy() strcpy()

のコピー先、のコピー先、

またまた

strcat() strcat()

の連結先に、十分なメモリがあの連結先に、十分なメモリがあ ることを保証するのは、プログラマの責任 ることを保証するのは、プログラマの責任

そうでない場合、配列の最後の要素を超えてそうでない場合、配列の最後の要素を超えて 書き込まれる

書き込まれる

何が起こるか分かりません何が起こるか分かりません

また、また、

strcpy() strcpy()

で、コピー元とコピー先が重で、コピー元とコピー先が重 なっている場合の挙動も未定義

なっている場合の挙動も未定義

(17)

文字列を比較する 文字列を比較する

strcmp() strcmp() 関数( 関数( string compare string compare )は、引数 )は、引数 を比較し、一致していた場合は

を比較し、一致していた場合は 0 0 を返す を返す

Sample14.c Sample14.c を入力し、コンパイル・実行 を入力し、コンパイル・実行 してみよう

してみよう

必ずしも同じ長さの配列でなくても良い必ずしも同じ長さの配列でなくても良い

(18)

文字列の長さを実行時に決める 文字列の長さを実行時に決める

これまでのプログラムでは、文字列の長さこれまでのプログラムでは、文字列の長さ は(配列の長さとして)、コンパイル時に は(配列の長さとして)、コンパイル時に

(つまり、プログラムの実行が始まる前

(つまり、プログラムの実行が始まる前 に)決まっていた

に)決まっていた

プログラムの実行中に、文字列の長さを決プログラムの実行中に、文字列の長さを決 めることが出来ると便利である

めることが出来ると便利である

文字列に限らず、任意の大きさのメモリを文字列に限らず、任意の大きさのメモリを

、実行中に確保・開放できる:

、実行中に確保・開放できる:

malloc() malloc()

とと

fr fr

ee() ee()

(19)

void *malloc(size_t n)

void *malloc(size_t n) 関数 関数

#include <stdlib.h> #include <stdlib.h> を忘れないこと を忘れないこと

プログラムの実行時に、必要なサイズ( プログラムの実行時に、必要なサイズ( n n bytes

bytes )のメモリを確保して、そのメモリ )のメモリを確保して、そのメモリ のアドレスを返す

のアドレスを返す

任意の型にキャストできるように、返値 任意の型にキャストできるように、返値 の型は の型は void * void *  (  ( void void 型へのポインタ) 型へのポインタ)

メモリの確保に失敗した場合は、 メモリの確保に失敗した場合は、 NULL NULL ポインタが返る

ポインタが返る

(20)

void *free(void *p)

void *free(void *p) 関数 関数

p p

が指すメモリ領域を開放し、後のが指すメモリ領域を開放し、後の

malloc() malloc()

などに使えるようにする

などに使えるようにする

ほとんどのほとんどの

OS OS

(たとえば(たとえば

Microsoft Windo Microsoft Windo ws, FreeBSD, Linux

ws, FreeBSD, Linux

など)では、プログラムなど)では、プログラム が正常に終了すれば、そのプログラムが

が正常に終了すれば、そのプログラムが 使ったメモリは自動的に開放される

使ったメモリは自動的に開放される

長時間実行され続けるプログラムでは、長時間実行され続けるプログラムでは、

ma ma lloc()

lloc()

して不要になったメモリを正しく開放して不要になったメモリを正しく開放 するのは重要。そうでないと、使用可能な するのは重要。そうでないと、使用可能な

メモリが減少していく(

メモリが減少していく(

memory leak memory leak

といとい う)う)

(21)

動的なメモリ確保の例 動的なメモリ確保の例

Sample15.c Sample15.c を入力し、コンパイル・実行 を入力し、コンパイル・実行 してみよう

してみよう

型 型 T T の要素 の要素 n n 個を保持するメモリは、 個を保持するメモリは、 size size of (T) * n bytes

of (T) * n bytes

たとえば、たとえば、

T = char T = char

なら、なら、

n n

文字からなる文文字からなる文 字列を保持するのに必要なのは 

字列を保持するのに必要なのは 

sizeof (char) sizeof (char)

* (n+1) bytes.

* (n+1) bytes.

最後の’最後の’

\0’ \0’

用に用に

1 1

足している足している

(22)

関数ポインタ 関数ポインタ

ポインタ変数とは、さまざまなオブジェク ポインタ変数とは、さまざまなオブジェク ト( ト( int, char, double int, char, double 型の値や、それらの配 型の値や、それらの配 列など)のアドレスを格納する変数だった 列など)のアドレスを格納する変数だった

アドレスとは、メモリ上の場所(通し番 アドレスとは、メモリ上の場所(通し番

号)だった

号)だった

関数も、メモリ上に一定の場所を占める 関数も、メモリ上に一定の場所を占める

関数のアドレスもある 関数のアドレスもある

関数ポインタ 関数ポインタ

(23)

関数ポインタの宣言 関数ポインタの宣言

関数ポインタの宣言 関数ポインタの宣言

戻り値の型  戻り値の型  

(* (*

関数ポインタ関数ポインタ

) ( ) (

引数リス引数リス

); );

たとえば たとえば

int (*pM) (int x, int y); int (*pM) (int x, int y);

pM pM は、 は、 int int 型を二つ取り、 型を二つ取り、 int int 型を返す関 型を返す関 数へのポインタ

数へのポインタ

(24)

関数ポインタにアドレスを代入 関数ポインタにアドレスを代入

関数ポインタに、関数のアドレスを代入する関数ポインタに、関数のアドレスを代入する

関数ポインタ 関数ポインタ

= =

関数名関数名

; ;

& &

はいらない(関数名は関数のアドレスそのもはいらない(関数名は関数のアドレスそのも の)の)

たとえばたとえば

pM = max; pM = max;

pM pM

は関数は関数

max() max()

を指すを指す

関数ポインタに代入された関数の呼び出し関数ポインタに代入された関数の呼び出し

(*pM)(5, 10) /* max(5, 10) (*pM)(5, 10) /* max(5, 10)

と同じ と同じ

*/ */

(25)

関数ポインタの利用と応用 関数ポインタの利用と応用

Sample16.c Sample16.c を入力して、コンパイル・実 を入力して、コンパイル・実 行してみよう

行してみよう

関数ポインタの応用 関数ポインタの応用

たとえば、関数ポインタを配列に格納し、必たとえば、関数ポインタを配列に格納し、必 要に応じて異なる関数を呼び出すことができ 要に応じて異なる関数を呼び出すことができ

Sample17.c Sample17.c を入力して、コンパイル・実 を入力して、コンパイル・実 行してみよう

行してみよう

(26)

今日学んだこと 今日学んだこと

文字列とポインタ 文字列とポインタ

文字列の操作 文字列の操作

動的なメモリの確保動的なメモリの確保

関数ポインタ 関数ポインタ

教科書 教科書 10.3 10.3 から から 10.5 10.5 まで( まで( p. 317 p. 317 ~ ~ 34 34

8 8 ) )

(27)

レポート課題 レポート課題

(1) (1) 13 13 番目のスライドにあるように、 番目のスライドにあるように、 str str len()

len() と同じ動作をする関数、 と同じ動作をする関数、 mystrlen() mystrlen() を書いてみよ。

を書いてみよ。 Sample11.c Sample11.c を、 を、 mystrlen mystrlen () () を使うものに書き換えよ。 を使うものに書き換えよ。

(2・やや難)文字列

(2・やや難)文字列 str1 str1 と と str2 str2 とを連結 とを連結 した文字列を新たに作り、それを返す関 した文字列を新たに作り、それを返す関 数 数

char *strappend (const char *str1, const char *str2);

char *strappend (const char *str1, const char *str2);

を書け。 を書け。

(28)

レポート課題(続)

レポート課題(続)

(2)のヒント:(2)のヒント:

char *char *

strappend (const char *str1, const char *str2)strappend (const char *str1, const char *str2)

{{

char *str = (char *) malloc (/*str1char *str = (char *) malloc (/*str1 str2str2 が入るだけのメモが入るだけのメモ リを確保する

リを確保する */);*/);

if (!str)if (!str)

{{

perror ("malloc failed in mystrappend()");perror ("malloc failed in mystrappend()");

exit (EXIT_FAILURE);exit (EXIT_FAILURE);

}}

strcpy (/* strstrcpy (/* str str1str1 をコピーする をコピーする */);*/);

strcat (/* strstrcat (/* str str2str2 を連結する を連結する */);*/);

return str;return str;

}}

(29)

レポート課題(続)

レポート課題(続)

締め切り: 締め切り: 2004 2004 年 年 11 11 月 月 22 22 日一杯(日本 日一杯(日本 時間で) 時間で)

提出:メールで木村( 提出:メールで木村(

[email protected]

[email protected] )まで. )まで.

感想などあると木村が喜びます 感想などあると木村が喜びます

図 図 10-10, 325 10-10, 325 頁を参照 頁を参照

参照

関連したドキュメント

プログラムに参加したどの生徒も週末になると大

長尾氏は『通俗三国志』の訳文について、俗語をどのように訳しているか

長尾氏は『通俗三国志』の訳文について、俗語をどのように訳しているか

噸狂歌の本質に基く視点としては小それが短歌形式をとる韻文であることが第一であるP三十一文字(原則として音節と対応する)を基本としへ内部が五七・五七七という文字(音節)数を持つ定形詩である。そ

日頃から製造室内で行っていることを一般衛生管理計画 ①~⑩と重点 管理計画

管理画面へのログイン ID について 管理画面のログイン ID について、 希望の ID がある場合は備考欄にご記載下さい。アルファベット小文字、 数字お よび記号 「_ (アンダーライン)

本文のように推測することの根拠の一つとして、 Eickmann, a.a.O..

“〇~□までの数字を表示する”というプログラムを組み、micro:bit