文字コード

以下の表記で先頭に 0x がついた数値は16進数を意味する。

ASCIIコード

コンピュータ上で扱う文字には、全て文字コードがついている。 代表的なコードはASCIIコードで、これは英数字と記号から成り立つ。

0123456789ABCDEF
0NULSOHSTXETXEOTENQACKBELBSHTLFVTFFCRSOSI
1DLEDC1DC2DC3DC4NAKSYNETBCANEMSUBESCFSGSRSUS
2 !"#$%&'()*+,-./
30123456789:;<=>?
4@ABCDEFGHIJKLMNO
5PQRSTUVWXYZ[\]^_
6`abcdefghijklmno
7pqrstuvwxyz{|}~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言語では文字をシングルクォートで括ると、その文字の文字コードを表す。 また、C言語での文字列は char 型配列で表現する。文字列 "hello" を宣言する方法はいくつかある。以下のどれも同じ。


文字コードを数値に直す

文字列 "123" を数値に直す場合を考えてみよう。 この文字列は

添字[0][1] [2][3]
'1''2' '3''\0'
数値49
0x31
50
0x32
51
0x33
0
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]
12 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を改良し、 以下のようにした。

tabaiadd.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

本日の目次