以下の表記で先頭に 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]値 123
上記のプログラムは、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