Comments
Description
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