以下の表記で先頭に 0x がついた数値は16進数を意味する。
コンピュータ上で扱う文字には、全て文字コードがついている。 代表的なコードはASCIIコードで、これは英数字と記号から成り立つ。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | NUL | SOH | STX | ETX | EOT | ENQ | ACK | BEL | BS | HT | LF | VT | FF | CR | SO | SI |
1 | DLE | DC1 | DC2 | DC3 | DC4 | NAK | SYN | ETB | CAN | EM | SUB | ESC | FS | GS | RS | US |
2 | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / | |
3 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? |
4 | @ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O |
5 | P | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ |
6 | ` | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o |
7 | p | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ | DEL |
この表は16進数で表したコード表で、たとえば文字コード 0x41 (10進数で
65)に対応するのが文字 'A'
を指している。
文字コード 0x00〜0x1F(10進0〜31)の文字は制御文字と 呼ばれ、画面に文字そのものを出すのではなく、出力すると特別な機能を もつような特別な文字となっている。制御文字をキーボードから入れるときは 文字コード0x40から0x5Fの文字を、Controlキーを押しながらタイプすれば 良い。
制御文字の働きは様々で、たとえば文字コード0x08のBS
は
「バックスペース」を意味し、直前の文字を消去する機能を持つ。
BackSpaceキーを押すのとC-hを押すのは同じ働きをする
ことが多い。また、文字コード0x0DのCR
は「キャリッジリターン」
を意味し、リターンキーを意味する。Returnキーを押すのと
C-mをタイプするのとでは同じことを意味することが多い。
C言語では文字をシングルクォートで括ると、その文字の文字コードを表す。
また、C言語での文字列は char 型配列で表現する。文字列 "hello"
を宣言する方法はいくつかある。以下のどれも同じ。
文字列 "123"
を数値に直す場合を考えてみよう。
この文字列は
添字 [0] [1] [2] [3] 値 '1'
'2'
'3'
'\0'
数値 49
0x3150
0x3251
0x330
0x0
という配列構成になっている。これを整数 123 (ひゃくにじゅうさん) に
直すには、1を100倍したものと、2を10倍したものと3を足せば良い。
文字列 "123"
の各要素から、1、2、3を取りだすには、
各要素に入っている数値(文字コード)から0x30('0'の文字コード)を引けば良い。
文字コードを、その文字コードが表す数値に直すには、文字コードから '0' (0x30=48) を引けば良い
文字列を、多倍長を表す配列に直すには、元となるchar型配列の各要素から '0'を引いた値を多倍長配列に入れて行けば良い。
char s[] = "123"; /* 元となる文字列 "123" */ char tabai[3]; /* 多倍長を入れる配列. 文字列じゃないので末尾の \0 を入れなくて良いので長さは3でよい */ tabai[0] = s[2] - '0'; /* '3' - '0' = 51 - 48 = 3 */ tabai[1] = s[1] - '0'; /* '2' - '0' = 50 - 48 = 2 */ tabai[2] = s[0] - '0'; /* '1' - '0' = 49 - 48 = 1 */
この操作で、配列tabai[]
の値は以下のようになる。
配列添字が右からになっていることに注意。
添字 [2]
[1]
[0]
値 1
2
3
上記のプログラムは、3桁決めうちで良くない。これを 任意の桁で可能になるようにforループで行なうと以下のようになる。
int len=strlen(s)-1; /* s[] = "123" の長さは3。1を引くと最後の添字 */ for (i=0; i<sizeof tabai; i++) { tabai[i] = s[len-i] - '0'; }
fgets()
関数で読み込んだ文字列を多倍長配列で
表した数値に直してみよう。
まず、最大桁数を100桁と見込んで文字列を読み込む部分を作ろう。
#define MAXKETA 100 int main() { char buf[MAXKEA+2]; /* 改行文字と \0 の分の2を足す */ printf("ながーい桁数の数を入れてね: "); fgets(buf, sizeof buf, stdin); : : }
これで char 型配列 buf
に数値を表す文字列を入れる。
ユーザが "2044628351"
と入力した場合を考えよう。
この場合、読み込んだ文字列のおしりの方から要素を1つずつ取り出し、
その値から '0' を引いたものを多倍長配列に入れていく。
読み込んだ文字列 | "2044628351\n" |
改行を切り取った文字列 | "2044628351" |
改行を切り取った長さ | 10 |
1の位のある添字位置 | 10-1=9 |
以上の考察から、buf
に読み込んだものを多倍長配列に
直すプログラム断片は以下のようになる。
char buf[MAXKEA+2]; char tabai[MAXKETA]; int i, tail; printf("ながーい桁数の数を入れてね: "); fgets(buf, sizeof buf, stdin); if ('\n' == buf[strlen(buf)-1]) { buf[strlen(buf)-1] = '\0'; /* 末尾の改行文字があれば潰す */ } tail = strlen(buf)-1; /* 文字列bufの末尾の添字位置 */ /* 最初に tabai 配列を全部0にする */ for (i=0; i<MAXDATA; i++) { tabai[i] = 0; } /* 続いて読み込んだbuf文字列を多倍長に変換 */ for (i=0; i<strlen(buf); i++) { tabai[i] = buf[tail-i] - '0'; }
これを利用して、キーボードから大きな数値を2つ読み込んで、
それを多倍長で足し算するプログラムを作ろう。先ほど作った
10keta.c
を改良し、
以下のようにした。
#include <stdio.h> #include <string.h> #define MAXKETA 100 /* 最大100桁 */ int main() { char buf[MAXKETA+2]; /* 読み込みバッファ */ char x[MAXKETA], y[MAXKETA]; /* 多倍長配列 */ char z[MAXKETA]; /* 答えを入れる配列 z[]; */ int i, tail, sum; /* sum は各桁を足した結果一時保存 */ int kuriage=0; /* 繰り上げを保存 */ /* まず多倍長配列の要素を全部0にしておく */ for (i=0; i<MAXKETA; i++) { x[i] = y[i] = z[i] = 0; } /* 巨大数値その1の読み込み */ printf("ながーい桁数の数(1)を入れてね: "); fgets(buf, sizeof buf, stdin); if ('\n' == buf[strlen(buf)-1]) { buf[strlen(buf)-1] = '\0'; /* 改行文字があれば潰す */ } tail = strlen(buf)-1; /* おしりの添字番号 */ for (i=0; i<strlen(buf); i++) { x[i] = buf[tail-i] - '0'; } /* 巨大数値その2の読み込み */ printf("ながーい桁数の数(2)を入れてね: "); fgets(buf, sizeof buf, stdin); if ('\n' == buf[strlen(buf)-1]) { buf[strlen(buf)-1] = '\0'; /* 改行文字があれば潰す */ } tail = strlen(buf)-1; /* おしりの添字番号 */ for (i=0; i<strlen(buf); i++) { y[i] = buf[tail-i] - '0'; } /* 実際の足し算 */ for (i=0; i<MAXKETA; i++) { sum = x[i]+y[i]+kuriage; z[i] = sum%10; /* 10で割った余り == その桁の答 */ kuriage = sum/10; /* 10で割った商 == 繰り上げ */ } for (i=MAXKETA-1; i>=0; i--) { printf("%d", z[i]); } puts(""); /* 改行のみ出力 */ }
コンパイルして、実行してみよう。
% ./tabaiadd
ながーい桁数の数(1)を入れてね: 555
ながーい桁数の数(2)を入れてね: 554
0000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000001109