計算機言語 I 第 15 回 : 文字列
この資料: http://www.math.u-ryukyu.ac.jp/~suga/gengo/2022/15.pdf
この講義の最終回ですが,感染状況の問題もあり,今回は対面ではなく,この資料の提供で講義を実施したこ とにします. レポート課題も今回はありません.
文字列 ( 教科書 11 章 )
CはUnixというOSの開発に利用するために作られました. そのため, (Ascii)文字列の扱いは, 割と便利 なようになっています. なぜなら, OSにおいては,例えば(Cのような)プログラム言語処理系,ファイルシス テムの維持,管理などでは, 文字列の扱いが必要な処理になるからです. 多くの Cの参考書でも,「文字列の扱 い方」に多くのページが割かれています. これは, Cという処理系がそのようなものを便利にしたいという要 求から出たものであるからです. (さらに,他の予備知識をあまり必要としないという理由もあります. 例えば, 数値計算を題材にしようとすると,数学的な予備知識が必要となり, それを持っている人はかなり少なくなり ます.)
私の能力の都合で,この資料では「Ascii文字列」の扱いについてのみ解説します. アメリカ語以外の言語の 扱いは面倒で,文字コードに対する理解が必要です. ただし,現在,ネットの世界で標準的に利用されている文
字コードUTF-8では,文字列の長さ(文字数)に注意をすれば,原理的には Asciiとほぼ同じようにプログラ
ムできるようです(確証はない). 問題は, 文字数のカウントが言語や文字によって様々になり,面倒なところ です.
Cの素朴な文字列はchar 型の配列で,文字列の終端を示す文字(終端文字, NULL文字,エスケープシーケ ンスで\0と記述する)が必ず最後についているものです. 文字列の扱う際には,このNULL文字を目印に文 字列の終了を判定してプログラムします. C で利用される「配列とポインタの対応」を利用したプログラムが, 文字列を扱う処理では多く書かれます.
ただし,配列なので, 代入によるコピー,関数の引数や返り値にすることはできません.
Cでは,ダブルクォート"で囲まれた文字の集まりは, 文字列定数(文字列リテラル)として,コンパイラは 認識します. (シングルクォート’で囲めるのは, Ascii の1文字で,その意味はAsciiの文字コードの値にな る. プログラム記述文字の集合がAscii以外処理系では,どういう扱いになるかは,知らない.)
すなわち, プログラムソース内で, "abcd" は char型の配列で, ’a’, ’b’, ’c’, ’d’, ’\0’と最後に NULL文字をつけた大きさ5 の配列です.
教科書11.6節「文字列と関数」までを読んで理解おけば,他の本を読むときの参考になります.
1
教科書に対するコメント
プログラム11.2
教科書, プログラム11.2 はわかりづらいソースの典型例で, このようなプログラムを書いてはいけません し,現在では, 実際上書くこともありません(プログラム 11.4のようなものを利用する.). なにが分かりづら いかというと,プログラムのfor文の中のif文
if ((str2[i]=str1[i]) == ’\0’) break;
の部分で, 代入と条件判定を一度にしているからです. 上の場合,「式の値は左辺値」を理解していれば,意味 が理解できます. ただし,今では, 2つの動作を1度にする文は書かないことが推奨されています. どの順で 2 つのことが起こるかの判定が面倒になるからです.
文字列入力(11.2節)
これまでのプログラムでは,文字列を標準入力から読み込むには,scanf("%s", ...)を利用してきました. しかし,scanf()は改行文字の扱いや,入力エラーが起きた時の処理が,実は面倒なことが知られています.
標準入力からの文字列の読み込み用のライブラリ関数として,gets()があるのですが,これもセキュリティ 上問題があることは,教科書に書かれている通りです.
文字列の読み込みは,教科書にあるように,ライブラリ関数fgets() を利用するのが通常の方法です. 注意 するのは,読み込む先には十分なメモリ(char型の配列)を必ず準備する必要があるところです.
文字列操作のライブラリ関数(11.3 節)
(Ascii)文字列を扱うライブラリ関数が多く準備されており,
#include <string.h>
で利用できます. どのような関数があるかは,次でわかります. Bash-4.4$ man string.h
Ascii文字列だけを扱う限りでは,ここにあるライブラリ関数で,多くの文字列処理をすることができます.
このライブラリ関数の扱いで難しいのは, メモリ管理の部分です. 例えば,「5文字分しかないchar配列に 10文字代入する」のような事が起こりがちで,コンパイルエラーにならず,実行時エラーになります.
2
文字列とポインタ, main() の引数(11.3節, 11.4節)
文字列とポインタの部分は,配列とポインタの関係をchar型配列に適用しただけです. 計算機概論Iで, CUIでのコマンドは次の形になると述べました.
Bash-4.4$ コマンド名 オプション1, ... , ファイル名またはディレクトリ名, ...
上で, コマンド名に続く「オプション1, ... ,ファイル名またはディレクトリ名, ...」はコマンドライン引数 と呼ばれます.
Cのプログラミングでは,main()の引数として,コマンドライン引数を受け取ることができます. 具体的に
は,教科書p. 180 の解説にある通りで,前回の講義で述べたポインタの配列が用いられています.
文字列と関数(11.6節)
この部分も,文字列はchar型配列である. 配列名は先頭部分を指すポインタであるということの応用です. これまでに述べたことですが,配列のコピーは時間がかかります. そこで, 文字列を扱う関数の多くは,ポイ ンタを利用した参照渡しをすることにより,配列のコピーはできる限りしないようなプログラムを書くのが, C でのプログラムの流儀です.
ファイルから文字列を読み込む,日本語(11.7節, 11.8節) 時間があれば,この部分も一通り実行してみてください.
ファイルからの読み込みの部分も,基本的これまでのことの応用です.
上で述べたように,fgets()の方が改行文字の扱いがしやすいので,こちらを利用するのが普通です. 日本語については,文字コードの問題があり, 解説をするのは私の手に余ります.
3
Epilogue
この講義では,プログラミング言語Cの文法を中心とした講義をしました. Cの文法は概ね講義で述べてい ます. 改めて Cの特徴を述べておきます.
1. 構造化プログラミングのための手続き型言語である.
2. 言語仕様は,ライブラリ仕様とともに国際的な規格が存在し, ほとんどの処理系はそれに準拠する. (た だし,文法上曖昧な部分があり,その部分は,処理系依存となっている.)
3. 言語仕様は比較的小さく,多くの処理をライブラリが受け持つようにしている.
4. OS開発用言語として作られたため,ハードウェア制御の記述もでき,比較的,低水準言語である.
5. プログラムでのメモリ管理は,プログラマが面倒を見る必要があり,プログラマに高い能力を要求する.
6. CPUの特性をうまく利用して,実行速度の速いプログラムを書く事ができるようになっている.
7. Open Sourceと呼ばれる, ソースコードを公開して開発されるプログラム(例えばLinux)で多数利用
されており, Cのサンプルソースは,ネットに沢山ある.
講義では文法が中心で,それ以上に重要な, データ構造やアルゴリズムをほとんど述べる事ができませんで した. それらについては,後期の授業で少し講義されると思います.
なお, 「わざわざプログラムはしないで今あるものを上手く利用する.」というのは, コンピュータを利用す る上での基本的な態度です.
しかし, 今あるものでは必要な処理を行ってもらえないという事も, 時に起こります. その時には, なんらか のプログラミング言語を用いてプログラムを組むという事も考える柔軟さは,持って下さい. その際には, C のような面倒な言語より,より使いやすい言語を利用する事も考えて下さい.
Cで勉強するメリットは,次の部分だと思います.
• 素朴なプログラミング環境なので,簡単なプログラムを書くには, 勉強する事柄が少ない.
• システムプログラムではCが使われる.
• どのような処理をコンピュータは苦手とするかという事が,感覚的にわかる.
• 沢山のサンプルソースがネットにある.
計算機言語II
後期の計算機言語IIでは,次を参考書に,数値計算を中心としたプログラミングを三柴先生が講義されると 思います.
• C言語による数値計算入門,皆本晃弥著,サイエンス社
• C言語によるアルゴリズム辞典,奥村晴彦著,技術評論社
特に,奥村さんの本は,様々なアルゴリズムの解説とサンプルソースがあり,良い本です.
授業評価アンケート
教務情報システムにある授業評価アンケートを実行していただけるとありがたいです. 今回はレポート課題はありません.
4