...

配列その2:文字列

by user

on
Category: Documents
16

views

Report

Comments

Transcript

配列その2:文字列
情報処理演習
配列 その2: 文字列
システム科学科 生物工学コース 佐々木耕太
http://www7.bpe.es.osaka-u.ac.jp/~kota/classes/jse.html
[email protected]
問題
両手に指が10本ある。それぞれの指は曲げ
る、伸ばすのふたつの状態をとることがで
きる。このとき、両手でいくつまで数えられ
るか?
データの単位ビットとバイト
• ビット:0か1かの2状態をとる
n
• nビットあれば、2の異なる状態を記述できる
一般的に
01101001(2)
=105
• 1バイト=8ビット
8
• 1バイト(2=256状態)あれば、0から9の数字、
大文字、小文字のアルファベットを表現するのに十分
足りる(例えば、105という数には‘i’という文字が
対応し、106という数には‘j’という文字が対応する
と解釈する)
• 日本語や多言語をあつかうときは、(256状態ではと
ても足りないので)2バイト以上で1文字を表現する
• 日本語の表現方法(文字コード)はひとつではないの
で、違う文字コードで解釈すると文字化けが起こる
同じものの異なる表現
‘i’ vs 105
テキスト表現
(105という数は‘i’と
いう文字だと解釈する)
バイナリ表現
ナニカチガウノ?
#include <stdio.h>
23696E636C756465203C73
7464696F2E683E0A0A696E
©Beeworks/SUCCESS
int main(void)
742061696E28766F696429
{
0A7B0A097072696E746628
printf(“Hello, world!\n”);
2248656C6F2C20776F726C
64215C6E22293B0A0A0972
return 0;
657475726E203B0A7D0A
16進数で示してある
}
0x69 = 105
= 01101001 (2)
od -tx1 ファイル名 または、
od -tx1c ファイル名 で
ファイルの内容を16進ダンプしてみよ
コンピュータにとっては、テキストファイル
であろうとバイナリデータの羅列でしかない
代表的な日本語文字コード
あ
ぃ
い
ShiftJIS
0x82A0
EUC-JP
0xA4A2
UTF-8
0xE38182
ShiftJIS
0x82A1
EUC-JP
0xA4A3
UTF-8
0xE38183
ShiftJIS
0x82A2
EUC-JP
0xA4A4
UTF-8
0xE38184
ソースコード中に全角スペースが
あると出るこのエラーは…
和字間隔
全角スペース
ShiftJIS
0x8140
EUC-JP
0xA1A1
UTF-8
0xE38080
エラーメッセージノ
数ハ8進数表記デス
©Beeworks/SUCCESS
0xE3 = 227 = 343 (8)
0x80 = 128 = 200 (8)
Cの基本型(整数)
型
char
short
long
long long
規格で定められた 授業で使っている
大きさ
ときの大きさ
8ビット以上
8ビット
2chars以上
16ビット
4chars以上
32ビット
8chars以上
64ビット
• short型の大きさ≤long型の大きさ≤longlong型の大きさ
• 大きさがnビットのとき、整数型は
n-1
n-1
n-1
符号つきの場合、-2(または-2+1)∼2-1の整数を表す
n
符号なしの場合、0∼2-1の整数を表す
• int型は、環境に応じて、short型かlong型かのいずれかになる
• char型が符号つきかなしかは環境によるが、その他の整数型は
(unsignedで修飾しない限り)符号つきとなる
Cの基本型(浮動小数点数)
型
規格で定められた 授業で使っている
大きさ
ときの大きさ
float
double
32ビット
32ビット
64ビット
64ビット
long double
80ビット以上
128ビット
8ビット符号なし整数
最大値(28-1=255)
16ビット符号なし整数
16
最大値(2
-1=65535)
http://www2.ucatv.ne.jp/~pen.snow/dq/dq2-7.html
2038年問題
• UNIXでは、1970年1月1日0時0分0秒から何秒
経ったかで時刻を表現している(UNIX時間)
• C言語もこれに準じている
• 標準関数time(NULL)は、UNIX時間をtime_t型で返す
• 伝統的に、time_t型は符号つき32ビット整数で実装されてきた
31
• したがって、この型は2-1よりも大きな整数は表現できな
い。経過秒数が(2038年1月19日3時14分7秒に)これを超
えると、オーバーフローを起こし、負の数として扱われ(最上
位ビットが立っている符号つき整数は負の数)、気をつけて書
かれなかったすべてのプログラムは誤作動する。
文字列
文字列: ‘\0’(NULL文字、終端文字)で終わる、文字の配列
•
文字列の宣言と初期化
例: char str1[128];
要素数を省略すると(普通
の配列と同じように)必要
char str2[] = “Hi”;
な要素数だけ確保される
char str3[128] = “Hi”;
char str4[128] = {‘H’, ‘i’, ‘\0’};
char str5[128] = {0x48, 0x69, 0x00};
•
“”でくくると、文字の配列に‘\0’が付け加えられ
て文字列となる。例えば、“Hi”を格納するために
は、少なくとも3要素ないといけない。
•
•
‘’でくくると、文字としてあつかわれる。
NULLは/nʌl/と読む。
文字列
文字列: ‘\0’(NULL文字、終端文字)で終わる、文字の配列
• 文字列を代入しても、配列の要素数(文字列を格納するため
のバイト数)は使い切らないことがよくある(違う言い方を
すると、長い文字列を(後で)代入するために、配列の要素
数はあらかじめ十分に確保しておく必要がある)
• したがって、文字列の終わりと配列の最後の要素は必ずしも
一致しないので、どこで文字列が終わるのか明示しなくては
ならず、そのために‘\0’(NULL文字、終端文字)を用いる
‘H’
•
‘i’ ‘\0’
‘\0’以降の要素は無視される
また、配列の要素数(文字列を格納するためのバイ
ト数)を超えて文字(列)にアクセスすると、
Segmentation faultのエラーが起こる
ASCIIコード
American Standard Code for Information Interchange
00
01
02
03
04
05
06
07
08
09
0A
0B
0C
0D
0E
0F
00
NUL
SOH
STX
ETX
EOT
ENQ
ACK
BEL
BS
HT
LF
VT
FF
CR
SO
S1
10
DEL
DC1
DC2
DC3
DC4
NAC
SYN
ETB
CAN
EM
SUB
ESC
FS
GS
RS
US
20
SP
!
“
#
$
%
&
‘
(
)
*
+
,
.
/
30
0
1
2
3
4
5
6
7
8
9
:
;
<
=
>
?
40
@
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
50
P
Q
R
S
T
U
V
W
X
Y
Z
[
\
]
^
_
60
`
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
70
p
q
r
s
t
u
v
w
x
y
z
{
|
}
~
DEL
制御文字
空白
図形文字
7 ビットしか使っていない
エスケープ・シーケンス
特殊文字。\をつけて入力できる。
\a
BEL bell
\v
VT vertical tab
\b
BS backspace
\\
backslash
\f
FF form feed
\’
’
\n
LF line feed
\”
”
\r CR carriage return \0
NUL NULL code
\t HT horizontal tab
改行コードは環境による
Unix、今のMac
LF
\n
Windows
CR LF
\r\n
昔のMac
CR
\r
‘\0’は0だが、‘0’や“0”とは違う
#include <stdio.h>
int main(void)
{
char null = ‘\0’, n0 = 0, c0 = ‘0’;
char s0[2] = “0”;
int n;
そっくりでも違う
printf(“[%c] -> %3d (0x%02X)\n”, null, (int) null, (int) null);
printf(“[%c] -> %3d (0x%02X)\n”, n0, (int) n0, (int) n0);
printf(“[%c] -> %3d (0x%02X)\n”, c0, (int) c0, (int) c0);
%c:1文字の出力
%s:文字列の出力
printf(“文字列s0: %s\n”, s0);
n = -1;
do {
n++;
printf(“s0[%d]: [%c] -> %3d (0x%02X)\n”, n, s0[n], (int) s0[n], (int) s0[n]);
} while (s0[n] != ‘\0’);
(int)はint型への型変換(キャスト)
n = 105;
printf(“[%c] -> %3d (0x%02X)\n”, (char) n, n, n);
}
return 0;
(char)はchar型への型変換(キャスト)
/* 入力された文字列の小文字を大文字に変換する */
#include <stdio.h>
int mygetline(char str[], int n);
int capitalize(char str[]);
#define N 128
int main(void)
{
char str[N];
printf(“入力された文字列の小文字を大文字に変換します\n”);
printf(“文字列を入力してください:”);
if (mygetline(str, N) != -1) {
capitalize(str);
printf(“変換の結果:%s\n”, str);
}
}
return 0;
/* 次のページへ続く */
• mygetline(str,N)を実行
し、戻り値が–1でなかったら
• 文字列を引数として関数に渡す
ときは、(配列のときと同じ
ように)[]はいらない
/* 前のページからの続き */
int mygetline(char str[], int n)
/* リターンキーかControl+Dが押されるまでキーボード入力を受け付け、入力された文字(最大n-1文字)を
strに代入し、入力された文字数を返す。ただし、1文字も入力されなかった場合は-1を返す。 */
{
int c, i; /* getchar関数はint型の戻り値を返す */
for (i = 0; (c = getchar()) != EOF && c != ‘\n’ && i < n - 1; i++) {
str[i] = c;
}
str[i] = ‘\0’; /* 終端文字 */
if (c == EOF && i == 0) {
i = -1;
}
}
まずgetchar()を実行し、戻り値をcに代
入する。cがEOFでも‘\n’でもなく、かつ
i<n-1の間、forの繰り返しを行う。
return i;
int capitalize(char str[])
/* 小文字を大文字に変換し、変換した文字の数を返す */
{
int i, changed = 0;
for (i = 0; str[i] != ‘\0’; i++) /* str[i]が終端文字に至るまで繰り返す */ {
if (str[i] >= ‘a’ && str[i] <= ‘z’) /* str[i]が小文字のときは */ {
str[i] += ‘A’ - ‘a’;
changed++;
}
}
‘a’や‘z’、‘A’を数で置き換えるな
ら、どうしたらいい?
}
return changed;
ifの条件式を、標準Cライブラリの
関数を使って書くなら?
以下のAとBは違う
strはchar型配列、
iはint型変数とする
A)str[i++] = ‘A’;
B)str[++i] = ‘A’;
演算子の計算の順序
インクリメント演算子(++)とデクリメント演算子(--)は、後置す
るか前置するかで計算の順序が異なるので、文の中で他の式と組み
合わせて用いると、後置するか前置するかで異なる結果を生じうる
計算の順序
例1
例2
後置
前置
これを含む式の
処理が終わった後
これを含む式を
処理する前
n = m;
m = m + 1;
n = m++;
n = ++m;
m = m + 1;
n = m;
i = 1;
i = 1;
printf(“%d->”, i++); printf(“%d->”, ++i);
printf(“%d\n”, i);
printf(“%d\n”, i);
出力: 1->2
出力: 2->2
文字列操作に関わる、代表的な
標準Cライブラリ関数
いずれも、使うためには #include <string.h> が要る
strcat
strcmp
strcpy
strlen
文字列を連結する(concatenate)
文字列を比較する(compare)
文字列をコピーする(copy)
文字列の長さを取得する
文字列の長さに制限があり、より安全な関数
strncat 文字列を連結する
strncmp 文字列を比較する
strncpy 文字列をコピーする
引数や戻り値を含め、それぞれの関数の使い方を調べる。わから
ないことを自分で調べて、他のこととつじつまがあったり、あわ
なかったりすることまで理解(納得)する経験や訓練を積む。
str*関数の危険なところ
#include <stdio.h>
#include <string.h>
int main(void)
{
char str1[] = “I\’m ”;
char str2[] = “studying C.”;
strcat(str1, str2);
return 0;
str2を連結できるだけの要素数(バ
イト数)がstr1に確保されていない
}
• 安全に連結するためには、str1に何バイト確保されていて、
str2を何バイト連結してもよいか確認しなくてはいけない
• str2を何バイト連結するか、strncatの第3引数で指定で
きる(‘\0’も終端に付け加えなくてはいけないので、str2
からnバイト連結させためには、n+1バイト必要となる)
文字操作に関わる、代表的な
標準Cライブラリ関数
いずれも、使うためには #include <ctype.h> が要る
isalnum
isalpha
isspace
isdigit
islower
isupper
toupper
tolower
アルファベットまたは数字であるか調べる
アルファベットかどうか調べる
空白文字かどうか調べる
数字かどうか調べる
小文字かどうか調べる
大文字かどうか調べる
大文字に変換する
小文字に変換する
引数や戻り値を含め、それぞれの関数の使い方を調べる。わから
ないことを自分で調べて、他のこととつじつまがあったり、あわ
なかったりすることまで理解(納得)する経験や訓練を積む。
授業であつかわなかったこと
•
•
•
•
•
•
•
•
•
•
ビット演算
グローバル変数、スタティック変数
列挙型
構造体、共用体
ポインタ
動的メモリ確保
ファイル操作
ソケット(ネットワーク)プログラミング
マルチスレッドプログラミング
Makefile、分割コンパイル、extern
Fly UP