C言語/文字と文字列

出典: フリー教科書『ウィキブックス(Wikibooks)』
ナビゲーションに移動 検索に移動

文字と文字列の基本[編集]

文字はコンピュータ内部では数値として扱われる。 ある文字がどんな数値で表現されているかを決めているものを、 文字コードという。 例えば、「a」という文字はASCII文字コードでは「0x61」という数値で表現される。

C言語で文字や文字列を扱うには、2つの方法がある。


「マルチバイト文字セット(MultiByte Character Set)」と「Unicode文字セット」である。 マルチバイト文字セット、Unicode文字セットの順で説明する。

マルチバイト文字セット[編集]

Windowsでは、マルチバイト文字セットでは、 日本語など1バイト文字だけでは表現できない文字セットを、 1バイトまたは2バイトのいずれかで表現する。 [1]

文字[編集]

1バイトで表される文字[編集]

マルチバイト文字セットで1バイトの数値で表現される文字には、 制御文字、半角文字などがある。 半角文字とは等幅フォントで見た場合に、横が縦の半分で表示される文字のことである。

上位ビッツ\下位ビッツ 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 IS4 IS3 IS2 IS1
2 SP ! " # $ % & ' ( ) * + , - . /
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
  • 半角カナ文字コード表[2][3]
上位ビッツ\下位ビッツ 0 1 2 3 4 5 6 7 8 9 A B C D E F
8 BPH NBH NEL SSA ESA HTS HTJ VTS PLD PLU RI SS2 SS3
9 DCS PU1 PU2 STS CCH MW SPA EPA SOS SCI CSI ST OSC PM APC
A
B ソ
C
D
E
F

C言語では、char型が文字型と呼ばれ、 文字を表現する際に使われる。 文字を「' '(シングルクォーテーション)」で囲むと、 その文字を表現する数値となる。

char型には、表現したい文字(1文字)に対応した1バイトの数値が格納される。char型に格納されているデータ自身は文字データではなく、ASCIIコードなどで表された、その文字に対応する数値である。ただし、printf関数などのような通常の用途でchar型の変数の中身を表示する場合、char型の変数の中身が対応する文字に変換される。(要出典)

//例 1バイトで表される文字を扱う。
#include <stdio.h>

int main(void)
{
	char c='a';//char型の変数cに文字'a'を格納する。
	printf("変数cに格納された文字は%c。\n", c);//cを文字として表示する。
	printf("変数cに格納された数値は%2x。\n", c);//cを数値として表示する。
}
実行結果
変数cに格納された文字はa。
変数cに格納された数値は61。

2バイトで表される文字[編集]

マルチバイト文字セットで2バイトの数値で表現される文字には 全角文字などがある。 全角文字とは等幅フォントで見た場合に、横が縦の等分で表示される文字のことである。

全角文字を表現する文字コードに「シフトJISコード」と呼ばれる文字コードがある。 シフトJISコードについては、JISX0208とその付属書1などを参照せよ。

半角文字と全角文字の区別については、 シフトJISコードでは、 上位バイトに、半角文字に使われていない数値である「81~9F」と「E0~EF」を使い、 下位バイトと組み合わせて、 2バイトの数値で全角文字を表現する。

C言語では、2バイトで表される文字を扱うには、 char型の配列を用いる必要がある。

//2バイトで表される文字を扱う
#include <stdio.h>

int main(void)
{
	unsigned char c[3]="あ";
	printf("cに格納された文字は%s。\n", c);//cを文字として表示する。
	printf("cに格納された数値は%2x%2x。\n", c[0], c[1]);//cを数値として表示する。
}
実行結果
cに格納された文字はあ@@。
cに格納された数値はe381。

文字列[編集]

C言語では、char型の配列が、 文字列を表現する際に使われる。 文字列を「""(ダブルクォーテーション)」で囲むと、 その文字列を表現する配列となる。 文字列は「'\0'」( ヌル文字、 0x00 )で終わる。

//例 配列を用いて文字列を扱う。
#include <stdio.h>

int main(void)
{
	char str[]="Hello, World!"; //char型の配列strに文字列"Hello, World!"を格納する。
	printf("%s\n", str); //strを表示する。
}
実行結果
Hello, World!


上の例では、配列strの値は次の表のようになる。

[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13]
'H' 'e' 'l' 'l' 'o' ',' ' ' 'W' 'o' 'r' 'l' 'd' '!' '\0'

また、同様の処理をポインタを用いて記述することができる。

//例 ポインタを用いて文字列を扱う。
#include <stdio.h>

int main(void)
{
	char *p="Hello, World!"; //char型のポインタpに文字列"Hello, World!"のアドレスを格納する。
	printf("%s\n", p); //ポインタpが指す文字列を表示する。
}
実行結果
Hello, World!

文字列の配列[編集]

複数の文字列を共通の名前でまとめて扱いたい場合、 多次元の配列を用いる。 一番右の次元の要素数で、 扱う文字列の長さ(ヌル文字を含む)を指定し、 残りの次元の要素数で、 扱う文字列の数を指定する。 文字列の配列のある文字列にアクセスしたい場合、 配列の添字に一番右の次元を除く次元を指定する。

//例 文字列の配列の配列の使用例
#include <stdio.h>

int main(void)
{
	char num[10][6]={
		"zero",
		"one",
		"two",
		"three",
		"four",
		"five",
		"six",
		"seven",
		"eight",
		"nine"
	}; //文字列の配列に0から9までの数字の英語の名前を格納する。
	int i;
	for(i=0;i<10;++i)
		printf("%s ", num[i]); //文字列の配列の配列の[i]番目の文字列を表示する。

	printf("\n ");
}
実行結果
zero one two three four five six seven eight nine 


また、同様の処理をポインタの配列を用いて記述することができる。

//例 文字列のポインタの配列の使用例
#include <stdio.h>

int main(void)
{
	char *p[10]={
		"zero",
		"one",
		"two",
		"three",
		"four",
		"five",
		"six",
		"seven",
		"eight",
		"nine"
	}; //ポインタの配列に0から9までの数字の英語の名前を格納する。
	int i;
	for(i=0;i<10;++i)
		printf("%s ", p[i]); //文字列のポインタの配列の[i]番目の文字列を表示する。

	printf("\n ");
}

文字操作の関数[編集]

標準ライブラリの文字操作の関数については、 C言語/標準ライブラリ/文字操作を参照せよ。

文字列操作の関数[編集]

標準ライブラリの文字列操作の関数については、 C言語/標準ライブラリ/文字列操作を参照せよ。

Unicode文字セット[編集]

Unicodeとは、すべての文字を16ビット以上(2バイト以上)で表現し、1つの文字コード体系で多国語処理を可能にしようとするものである。[4] UTF-16とは、Unicodeのエンコード方式の1つであり、WinodwsがUnicode用の標準エンコードとして採用しているため、下記ではこのUTF-16について記述する。

文字[編集]

Windwosにかぎらず、C言語では、wchar_t型がワイド文字型と呼ばれ、Unicode文字を表現する際に使われる。 文字を「L''」で囲むと、その文字を表現するワイド文字型の数値となる。なお、この「L」はリテラルという。

ワイド文字の具体的なバイト数は国際規格では定められてないが、通常、出回ってるOSでは、ワイド文字は2バイト以上(つまり16ビット以上)である。

規格では十分には、定められてないため、個別のOSの実装に依存する。

Windowsにおいては wchar_t 型は常に2バイトに固定されている[5]

Windowsにおいてwchar_t 型であるワイド文字セット(Unicode文字セット)は、制御文字、半角文字、全角文字など全ての文字が2バイトの数値で、wchar_t型に格納できる。

ただし、Winodwsにかぎらず、wchar_t 型を使用する際には、ロケール(地域)を設定する必要がある。


Windowsの場合、本来、2バイト(16ビット)では65536種類の文字までしか格納できないので、世界中のすべての文字を収録することは不可能であるので、代わりにロケール(地域)を使用して、文字を限定する必要がある。

日本語の常用漢字の数は約2000個なので、65536種類の文字を格納できる2バイトでも十分に日本の文字を格納できる。


このため、Windowsのワイド文字は、英語以外の世界各国の文字が混在するような用途には(例えば日本語とアラビア語とスペイン語が混在するような事例には)、適さない。


//例 文字を扱う。
//Windowsの場合。

#include <stdio.h>
#include <locale.h>
#include <stdlib.h> // 「続行するには何かキーを押してください . . .」

int main()
{
	wchar_t wc = L'a'; //wchar_t型の変数wcに文字L'a'を格納する。
	_wsetlocale(LC_ALL, L"japanese"); //ロケール(地域)を設定する。
	wprintf(L"変数wcに格納された文字は%c 。\n", wc); //wcを文字として表示する。
	wprintf(L"変数wcに格納された数値は%4x 。\n", wc); //wcを数値として表示する。

	system("pause"); // 「続行するには何かキーを押してください . . .」
	
    return 0;
}
実行結果
変数wcに格納された文字はa 。
変数wcに格納された数値は  61 。
続行するには何かキーを押してください . . .

mac OS や Linux では、ワイド文字型は通常は 32ビットであるので、Winodws用の(16ビットを前提とした)ワイド文字型のCプログラムをそのまま利用すると文字化けをすることがある。


Linuxの場合、下記のようなコードになる(一例として、Fedora 28 で実行した例を表す)。

// Linux の場合
#include <stdio.h>
#include <wchar.h> // linuxでwcharを使うには、これが必要
#include <locale.h>

int main()
{
	wchar_t wc = L'a'; //wchar_t型の変数wcに文字L'a'を格納する。
	setlocale(LC_ALL,"ja_JP.UTF-8");; // wが冒頭に付かないことに注意。L""としない事に注意。
	wprintf(L"変数wcに格納された文字は%c 。\n", wc); //wcを文字として表示する。
	wprintf(L"変数wcに格納された数値は%4x 。\n", wc); //wcを数値として表示する。
	
	return 0;
}
実行結果
変数wcに格納された文字はa 。
変数wcに格納された数値は  61 。


なおLinuxのターミナル画面(コマンドプロンプトの画面)で locale と入力すると、言語ロケールが報告される。 自分の国の言語ロケール名称が分からない場合には、この locale コマンドで確認すればよい。

[@localhost ~]$ locale
LANG=ja_JP.UTF-8
LC_CTYPE="ja_JP.UTF-8"
LC_NUMERIC="ja_JP.UTF-8"
LC_TIME="ja_JP.UTF-8"
LC_COLLATE="ja_JP.UTF-8"
LC_MONETARY="ja_JP.UTF-8"
LC_MESSAGES="ja_JP.UTF-8"
LC_PAPER="ja_JP.UTF-8"
LC_NAME="ja_JP.UTF-8"
LC_ADDRESS="ja_JP.UTF-8"
LC_TELEPHONE="ja_JP.UTF-8"
LC_MEASUREMENT="ja_JP.UTF-8"
LC_IDENTIFICATION="ja_JP.UTF-8"
LC_ALL=


2011年に策定された国際規格だが、

つねに16ビットの文字型である事を示す char16_t 型と、
同様に常に32ビットの文字型である char32_t 型

という新しい型が策定されているので、 将来的には、この新規格の文字型に置き換える必要があるかもしれない。

文字列[編集]

C言語では、wchar_t型の配列が、Unicode文字列を表現する際に使われる。 文字列を「L""」で囲むと、その文字列を表現する配列となる。 文字列はナルワイド文字(コード値0のワイド文字)で終わる。

Windowsの場合
//例 文字列を扱う。
#include <stdio.h>
#include <locale.h>

int main(void)
{
	wchar_t ws[]=L"Hello, World!\n"; //wchar_t型の配列wsに文字列L"Hello, World!"を格納する。
	_wsetlocale(LC_ALL, L""); //ロケール(地域)を設定する。
	wprintf(ws); //wsを表示する。
}


実行結果
Hello, World!
続行するには何かキーを押してください . . .


Linuxの場合
//例 文字列を扱う。
//Linuxの場合
#include <stdio.h>
#include <wchar.h> // linuxでwcharを使うには、これが必要
#include <locale.h>

int main()
{
	wchar_t ws[]=L"Hello, World!\n"; //wchar_t型の配列wsに文字列L"Hello, World!"を格納する。
	setlocale(LC_ALL, "ja_JP.UTF-8"); //ロケール(地域)を設定する。
	wprintf(ws); //wsを表示する。
}


実行結果
Hello, World!


備考[編集]

ネット上の伝聞などによると、Windowsでいう自称「Unicode」(自称「UTF-16」)とは、けっして純粋な意味での国際規格のユニコードのことではなくて、近年のWindowsがシステム内部で使用している固定2バイト文字や固定4バイト文字などシステム内の幾つかの固定バイト長の文字のエンコード方式について、「マイクロソフト社は一応、少々は国際規格のUTF-16にも配慮していますよ」ぐらいの意味であるらしい。

このため、macやLinuxのUTF-16とは、Windowsの自称「UTF-16」は、完全には互換しない可能性があることを、使用時に気をつける必要がある。

Windowsの自称「UTF-16」は、CP932(いわゆるShift-JIS)などの過去のWindows文字コードを、国際規格対応のために拡張した、マイクロソフト独自の文字コードである。


コンパイラ Visual Studio では、文字コードが標準設定で自称「Unicode」になっているが、これは、「Windowsのシステム内部用の文字コードを使います」という意味である。

なので、macやLinuxなどに、Windows自称「Unicode」でエンコードされた拡張子cや拡張子cppのプログラムを持っていっても、macやLinuxでは文字化けしてしまい、読み込めない。

そのcファイルやcppファイルをmacやLinuxで読みたい場合、アクセサリ「メモ帳」などで、いったん自称「ANSI」や自称「UTF-8」などのWindowsシステム外の文字コードにエンコードにしてから、それをmacやLinux上で読み込む必要がある。


なお、Unicodeだけでなく、「ANSI」もまた、マイクロソフト社のいう、自称「ANSI」規格である。マイクロソフト社の言う「ANSI」とは、けっして本物のANSI(いわゆるASCII(アスキー)コード)ではなく、マクロソフト社コード番号 CP932 という、ASCIIを拡張して日本JIS漢字規格など各国の規格などを追加したマイクロソフト社独自の文字コードのことである。日本では Shift-JIS として知られる。


自称「ANSI」の実態は、マイクロソフト社の1980~1990年代くらいの古い文字コードを基盤としたものである。1980~90年代当時の過去のユーザーが作ったテキストファイルとの互換性を維持するため、マイクロソフト社は、2010年を過ぎた現在でも、古い文字コードを維持しつづけているのである。


マイクロソフト社 Windows は、OS内部の深い部分の文字コードには自称「Unicode」というマイクロソフト社の新コードを使い、メモ帳など個別のアプリの浅い部分の文字コードでは自称「ANSI」というマイクロソフト社の旧コードを標準設定で使っている。


もしユーザーが、作成したテキストファイルやソースコードの、他OSへの互換性を重視したい場合には、UTF-8を用いる必要がある。

多くのLinuxもUTF-8を標準の文字コードに設定している。

文字操作の関数[編集]

標準ライブラリのワイド文字の文字操作の関数については、 C言語/標準ライブラリ/ワイド文字種分類及びワイド文字大文字小文字ユーティリティを参照せよ。

文字列操作の関数[編集]

標準ライブラリのワイド文字の文字列操作の関数については、 C言語/標準ライブラリ/多バイト文字及びワイド文字拡張ユーティリティを参照せよ。

脚注[編集]

  1. ^ https://msdn.microsoft.com/ja-jp/library/5z097dxa.aspx
  2. ^ 2.0 2.1 『JISX0201:1997』
  3. ^ 3.0 3.1 『JISX0211:1994』
  4. ^ http://e-words.jp/w/Unicode.html
  5. ^ char、wchar_t、char16_t、char32_t