文字列の扱い①
ここまででは、プログラムで文字を扱う方法は、ソースプログラムに書かれている文字をそのまま画面に表示することしかできません。ここでは、以下のようなことを取り扱えるようにしていきます。
- 文字を入力して、それを表示する
- 質問の答えを数値ではなく、文字で答えられるようにする
C言語での文字列
まず、文字を記憶する変数宣言はchar型を使います。
char 変数名;
この記述で、1文字を記憶する変数を用意できます。ただ、1つの変数に1つの文字しか記憶できません。日本語のひらがな等記憶するには、2文字分の変数が必要です。
文字列には配列を使う
数多くの数値を取り扱うときには、配列を用いる事を以前説明しました。文字列の場合でも同様に考えます。例えば、5文字の「Hello」という文字列を記憶するための配列mojiは、次のようにchar型を使って宣言し、代入して記憶させます。
char moji[6]; moji[0] = 'H'; moji[1] = 'e'; moji[2] = 'l'; moji[3] = 'l'; moji[4] = 'o'; moji[5] = '\0';
ここで、注意するのは、文字を代入するときは「’」シングルコーテーションで文字を囲むことです。また、最後の行に注目しましょう。文字列を扱う時は、必ず’\0’を入れる必要があります。これは空白文字Nullを意味します。そのため、配列は「記憶させたい文字数+1」の大きさで用意する必要があります。
文字列の代入
上記のように、文字を1文字ずつ代入していては、文字数が多い時に大変になります。そこでもっと便利な代入方法があります。次の例から説明していきます。
例題:入力された英字小文字を大文字に変換するプログラムを作成します。英数字は1行80文字まで入力でき、日本語や空白は入力しないものとする。
次のプログラムを作成していきます。
#include <stdio.h>
int main(){
char input[81]; //①文字列を記憶する1次元配列
int i;
/*初期化*/
for(i=0; i<81; i++){
input[i] = '\0'; //②配列をNullで初期化
}
/*入力*/
scanf("%s", input); //③文字列の入力を受付け
/*出力*/
printf("入力された文字\n%s\n", input); //④配列inputの文字列表示
/*1文字ずつ検査と表示*/
for(i=0; i<81; i++){
switch (input[i]){
case 'a':printf("A"); break;
case 'b':printf("B"); break;
case 'c':printf("C"); break;
case 'd':printf("D"); break;
case 'e':printf("E"); break;
case 'f':printf("F"); break;
case 'g':printf("G"); break;
case 'h':printf("H"); break;
case 'i':printf("I"); break;
case 'j':printf("J"); break;
case 'k':printf("K"); break;
case 'l':printf("L"); break;
case 'm':printf("M"); break;
case 'n':printf("N"); break;
case 'o':printf("O"); break;
case 'p':printf("P"); break;
case 'q':printf("Q"); break;
case 'r':printf("R"); break;
case 's':printf("S"); break;
case 't':printf("T"); break;
case 'u':printf("U"); break;
case 'v':printf("V"); break;
case 'w':printf("W"); break;
case 'x':printf("X"); break;
case 'y':printf("Y"); break;
case 'z':printf("Z"); break;
default :printf("%c", input[i]);
}
}
return(0);
}
①文字列を記憶するための1次元配列を用意
文字列を記憶する時には、①のように1次元配列として取り扱います。ここでは、1行最大80文字まで扱い、最後に付ける「何もない文字(’\0’)」の分も入れて81個の要素を用意します。
②配列の初期化
ここまででも、説明しましたが、変数や配列を宣言した時はそこに何の値が入っているかは決められていません。数値の変数や配列の時は0を代入して初期化をしてきました。文字列の場合、「何もない文字」を代入するという初期化をします。何もない文字をあらわす記述が「’\0’」になります。
③文字列の入力受け付け
ひと続きの文字列をまとめて読み込むための便利な記述方法が③の部分です。ひと続きの文字列を変換仕様で「%s」として表します。しかし、「Hello World」のように文字の間に空白が入ってしまったときには、文字が続いているはじめの部分のみが変数に記憶されます。以下の入力例をご覧ください。
入力 | 表示結果 | 記憶されなかった文字 |
Hello World | Hello | World |
I’m happy | I’m | happy |
3-years ago | 3-years | ago |
現実にもっと良く使われる場面を考えると、文字列では空白が入ることが多々あります。そのようなときに次の文字専用の入力関数 gets()を使います。
gets (文字配列名);
例えば、scanf(“%s”, input);の所をgets(input);と書き換えることができます。空白も正しく配列に記憶できます。
④配列に記憶されている文字列を画面に表示
この部分は、配列inputに記憶されている文字列を画面に表示する記述です。ここのprintf()では、「%s」を使っています。文字列の1次元配列を意味しており、「%c」では1文字だけだったのがまとめて表示できるようになっています。
文字と数字の関係
C言語での文字の扱いを知るため、以下のサンプルを作成してみてください。
#include <stdio.h>
int main(){
char input;
/*入力*/
scanf("%c", &input);
/*出力*/
printf("入力された文字[%c][%d]", input, (int)input);
return(0);
}
このプログラムでは、次の2つの処理をしています。
- 文字を入力し、文字型の変数inputに記憶する
- 変数inputに記憶されている文字と、inputに保存されている文字を「数値に変換した値」を表示する
ここでは、文字型の変数inputに対して「(int)input」として「%d」という変換仕様で表示しています。「文字型変数→整数型変換」と変換して値を取り出して整数値に変換したものを表示するという意味になります。コンピュータの内部では、文字も全て数値としてあらわすことができるのです。
上のプログラムの結果は以下の表のようになります。
入力文字 | 数値 | 入力文字 | 数値 | 入力文字 | 数値 |
a | 97 | A | 65 | 0 | 48 |
b | 98 | B | 66 | 1 | 49 |
c | 99 | C | 67 | 2 | 50 |
: | : | : | : | : | : |
z | 122 | Z | 90 | 9 | 57 |
この結果から次のことがわかります。
- アルファベットの小文字、大文字は違う数値で表される。アルファベットの「a」と「A」、」「z」と「Z」のように、小文字、大文字で違う数値で表されます。
- アルファベットの小文字、大文字はそれぞれ数値で表すと、順番に並んでいる。アルファベットの小文字は、「a」「b」「c」…は97、98、99…と順番になります。同じように、大文字についても65、66、67…と順番になります。文字を表す数値も、アルファベットの順に並びます。ただし、小文字の表す数値の方が大文字の数値よりも大きい値になります。
関係性としては、
小文字の数値 = 大文字の数値 + 32
になります。
- 数字の文字と文字が表す数値は一致しない。文字として入力した「0」「1」「2」…は、数値で表すと48、49、50となります。つまり、数字を表す文字は、表す数値と一致しません。ただ、数字の順には並んでいます。
関係性としては、
文字を表す数値 – 48
になります。
このように、コンピュータの中では、文字も全て数値として扱われていると考えることができます。以下の表のようにまとめることが出来ます。
10の位\1の位 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
0 | [無,\0] | |||||||||
1 | ||||||||||
2 | ||||||||||
3 | [空白] | ! | “ | # | $ | % | & | ‘ | ||
4 | ( | ) | * | + | , | – | . | / | 0 | 1 |
5 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; |
6 | < | = | > | ? | @ | A | B | C | D | E |
7 | F | G | H | I | J | K | L | M | N | O |
8 | P | Q | R | S | T | U | V | W | X | Y |
9 | Z | [ | \ | ] | ^ | _ | ` | a | b | c |
10 | d | e | f | g | h | i | j | k | l | m |
11 | n | o | p | q | r | s | t | u | v | w |
12 | x | y | z | { | ¦ | } | ~ |
上の表を利用して「数値→文字」に変換して表示するプログラムを作成してみましょう。
#include <stdio.h>
int main(){
int num;
/*入力*/
scanf("%d", &num);
/*出力*/
printf("入力された数値[%d][%c]\n", num, (char)num);
return(0);
}
大切なのは、「(char)num」の部分です。この記述が「数値→文字」のキャストを行っています。例えば、「65」と入力すれば、「A」が表示されるはずです。文字は数値で表すことができ、その数値は順番に並んでいるということを理解することが重要です。
文字を比較する
プログラムでは、数字と同じように文字も「どちらが大きいか?どちらが小さいか?」という比較もできます。まずは、以下のプログラムを書いて実行してみましょう。
#include <stdio.h>
int main(){
char input;
/*初期化*/
input = '\0';
/*入力*/
scanf("%c", &input);
/*小文字英文字の判定*/
if((input >= 'a') && (input <= 'z')){ //①
printf("小文字英字です。\n");
}else{
/*大文字英字の判定*/
if((input >= (char)65) && (input <= (char)90)){ //②
printf("大文字英字です。\n");
}else{
printf("英字以外の文字です。\n");
}
}
return(0);
}
①は、入力された文字(input)が’a’以上’z’以下であるかというif文の記述です。次のように書き換えることも可能です。
if((input >= (char)97) && (input <= (char)122))
②は、入力された文字(input)が文字を表す数値で65以上90以下であるかというif文の記述になります。次のように書き換えることも可能です。
if((input >= 'A') && (input <= 'Z'))
これらから以下のことが言えます。
- 文字も数字と同じように大小比較することができる
- 文字の大小関係は、文字を表す数値によって決まる