計算機言語
II
第2
回http://www.math.u-ryukyu.ac.jp/~suga/gengo/2018-2/02.pdf
1
文字列C
には文字列という型がありません.
他の言語(
例えばJava)
では,
文字列という型(Java
の場合はクラス)
が定義されているものも多くあります.
最初に
C
が開発された際には, Unix
のシステム記述言語として開発され,
当時はAscii
文字の操作ができ ることが重要でした. Unix
の開発動機が(
米語の文章の)
文書処理でしたので, Ascii
文字に対する処理を効率 よくするシステムが要求されました.
そのためのライブラリ関数が,
標準ライブラリに多く実装されています.
Ascii
文字の処理だけなら,
これらのライブラリ関数を利用することにより,
効率よくプログラムを書くことができます
.
現実の処理系の実装では,
特別なバイト列に対するデータの操作が実装されています.
教科書, 9
章,
11
章では,
このAscii
文字に対する処理法だけが書かれています.
現在では
, Ascii
文字以外の多くの文字があることを,
ほとんどのプログラマは理解しています.
それらの文字列を操作する仕組みも
C
言語にいくらか取り入れられていますが,
文字コードの規格の変遷があったため,
Ascii
コードほど充実していませんしこれからも変更される可能性もあります.
ここでも
, Ascii
コードの処理を中心に解説します.
日本語文字列を操作するのなら, Java
やPython
のような
,
より近代的なプログラミング環境を利用するべき時代だと思います.
1.1
文字列リテラルC
で,
ダブルクォート(2
重引用符) "
で囲まれる文字列は,
「文字列リテラル」あるいは「文字列定数」と 呼ばれます.
この値は, ’\0’
で終わるchar
型の配列としてプログラム内に置かれます. ’\0’
はAscii
コード の数値0
に対応する文字コードで, null character,
ヌル文字(
ドイツ語風発音),
あるいはナル文字(
英語風発 音)
と呼ばれるものです.
すなわち,
文字列の終了記号として, ’\0’
を用いています.
文字列操作をするライ ブラリ関数も,
上の文字列の決め方を利用してプログラムが書かれています.
従って,
文字列リテラルでは,
本 来の文字が消費するメモリ量に終端記号’\0’
の1
バイトが加わった値です.
上のことを確かめるのが
, p. 240, List 9–1
です.
このリストに文字列"
あいう"
のデータ量を表示する部分 を付け加えて,
コンパイル,
実行して見てください.
文字列は
,
大きさが実行時に確定できないことが多くあります. C
では,
大きさを最初に確定するのではな く,
「実行時に必要なメモリを取ってきて文字列操作をすれば良い(
メモリの動的確保)
」という考え方で,
言 語仕様を決めました.
ただし,
データの範囲(
大きさ)
が確定できないと,
プログラムを書くことができません.
そこで,
終端記号を定義して,
それを利用して大きさなどを測ることにしたのです.
1
1.2
文字列変数上に述べたように
,
文字列は,
最後が’\0’
であるchar
型の配列として扱うことができます(
というか,
むし ろchar
型の配列としてしか扱えない).
文字列を変数として,
すなわち文字列の値を変化させるには,
文字列 変数として, char
型の配列変数を宣言します.
配列型変数としての素朴な初期化
(
代入)
が,
教科書p. 242, List 9–2
で,
文字列の初期化に用意された,
特 別な初期化方法が, p. 243, List 9–3
です. List 9–2
の形の代入による初期化では, Ascii
文字しか文字列に入 力できません. List 9–3
のやり方だと, UTF-8
の漢字なども初期値として入力可能です.
教科書
p. 243
の下の方にあるように,
配列変数の代入はできません.
文字列のList 9–3
の初期化は,
ある種の例外となっています
.
List 9–2, List 9–3
をコンパイル実行してください.
1.3
文字列の読み込みprintf, scanf
で, %s
が文字列指定であることは,
計算機概論でのawk
と同じです. scanf
では, UTF-8
の漢 字もきちんと文字列として読むことができます. scanf
で,
整数を読み込んだ時のような&
が不要な理由は,
ポインタ
(pointer)
を解説するときに述べます.
List 9–4
をコンパイル,
実行してください.
これらの実行がうまくいくのは
, UTF-8
の設計がわりにうまくできていることと,
皆さんが利用している端 末エミュレータがUTF-8
をきちんと扱えるようにプログラムされているからです.
1.4
文字列の操作文字列の配列等は
,
ポインタを扱うときに集中して扱う方が理解しやすいので,
ここでは飛ばします 最初に述べましたが, (Ascii)
文字列を操作するライブラリ関数が,
沢山の用意されています. Linux
の環境 では,
それらは次のman
コマンドでわかります.
残念ながら英語で表示されますが,
この程度の英文は読める ようになってください.
man string.h man ctype.h
この結果を読むと
,
どのような関数が定義されているかがわかります*1.
あとは,
その関数の元となった英語 が何かが問題なのです.
例えば
,
教科書p. 248
の(Ascii)
文字列の長さを求める関数は, strlen
として標準ライブラリにあります.
従って
,
通常はをれを計算する関数を書くのではなく, strlen
を利用します. strlen
の使い方を知るには, man 3 strlen
で
,
マニュアルを読むことができます.
なお
,
ライブラリ関数strlen
は, List 9–4
とほぼ同じソースです.
*1全て, Ascii文字列に対する操作です
2
List 9–8
は次のようにするのが正しいC
でのプログラミングです(
コメントは略).
#include <stdio.h>
#include <string.h>
int main() {
char str[128];
printf("
文字列を入力してください:");
scanf("%s", str);
printf("
文字列\"%s\"
の長さは%d
です.\n", str, (int) strlen(str));
return 0;
}
このプログラムも
,
漢字を入力するとUTF-8
が占めるバイト数が出力されます.
1.5 toupper, tolower
教科書
p. 252
にアルファベットの大文字,
小文字を交換するというプログラムが書かれています.
ライブラリ関数を利用していますが
,
実装によっては,
実は引数付きマクロ(
講義では,
解説が面倒なので省略した)
と 呼ばれるものだったりします. /usr/indluce/ctype.h
にこれは書かれています.
これを実装するのはそれほど面倒なものではないので
,
ここでは,
レポート問題にします(
もちろん,
普通 のプログラミングでは,
わざわざ実装せずに,
ライブラリ関数を使います).
文字は, Ascii
コードであるとし,
Ascii
コードの決め方をうまく利用して書いて見てください.
教科書
List 9–11
での関数, str_toupper
とstr_tolower
の動作では,
引数として受け取った値の中身を 変更しています.
このような仕組みは,
ポインタのところでもう一度取り上げます.
教科書
List 9–11
は実際にコンパイル実行して見てください.
漢字を入力しても問題ありませんが,
全角の英文字を入れても期待通りの動作はしません
.
「同じ文字に2
つのコードを割り当てる」が邪悪であることを 実感してください.
レポート問題
(
締め切り: 10
月18
日(
木))
•
文字列"
あいう"
のデータ量はいくつか?
件名:
あいう.
•
教科書p. 243,
演習9–1.
件名: Enshu 9–1.
•
関数char toupper(char c)
を作成せよ.
入力文字はAscii
コードであるとし,
英小文字を英大文字に変換する