C言語/文字と文字列

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

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

C言語には文字列を扱う機能が組み込まれていないので、文字列は文字の配列として定義されています。Cでは、文字配列を文字のリストではなく、文字列で表現することができ、末尾には自動的にヌル終端文字('\0')が追加されます。例えば、"String" という文字列を格納するには、次のように書きます。

char string[7] = "String";

あるいは

char string[7] = { 'S', 't', 'r', 'i', 'n', 'g', '\0' };

最初の例では、文字列の末尾にコンパイラによって自動的にヌル文字が付加されます。規約としてライブラリ関数は文字列の末尾にヌル文字('\0')が付加されることを想定しています。 後者の宣言では、個々の要素を示しているため、ヌル文字の終端を手動で追加する必要があります。

文字列は、必ずしも明示的な変数に代入する必要はありません。文字列は無名の文字列(文字列リテラルといいます)として直接作成し使用することができます(printf関数の第一引数など)。

特別に長い文字列を作成するには、文字列を複数のセクションに分割し、最初のセクションを引用符で閉じて、次の行で文字列を再開する必要があります(これも引用符で始まり、引用符で終わります)。

char string[58] = "This is a very, very long "
                "string that requires two lines.";

文字列は、行末にバックスラッシュ文字を置くことで複数行にまたがることもできますが、この方法は非推奨です。

文字列処理ルーチンの便利なライブラリがありますので、別のヘッダファイルをインクルードすることで使用できます。

#include <string.h> //新しいヘッダーファイル

この標準的な文字列ライブラリ <stding.h> は、文字列に対して様々な処理を行うことができます。

構文[編集]

C言語では、文字列定数(リテラル)は、"Hello world!"のように二重引用符(")で囲まれ、指定されたcharの値の配列にコンパイルされ、さらに文字列の終わりを示すヌル終端文字('\0')コードが付加されます。文字列定数の型はchar []です。

バックスラッシュのエスケープについて[編集]

文字列リテラルは、ソースコードに直接、改行などの制御文字や、文字列の中で特別な意味を持つ文字を埋め込んではいけません。

このような文字を文字列に含めるためには、次のようにバックスラッシュ・エスケープ[1]を使用することができます。

バックスラッシュ・エスケープと意味
バックスラッシュ・エスケープ 意味
\n 改行(New line)
現在の印字位置を次の行の先頭位置に移動する
\t タブ(horizontal Tab)
次の水平タブ位置に移動する
\b バックスペース(Backspace)
現在の行で前に移動する。先頭にある場合は不定。
\r キャリッジリターン(carriage Return)
現在の行の先頭位置に移動
\f ページフィード(Form Feed)
次の論理ページの最初に移動
\' シングルクォーテーション(single quotation mark)
一重引用符
\" ダブルクォーテーション(double quotation mark)
二重引用符
\0 ヌル文字(null)
空文字(実際は8進数表記の1ケース)
\\ 円記号(\)
\? クエスチョンマーク
\a ベル音(Alert)
ベル音を鳴らす。印字位置は不変
\xhh 16進拡張(heXadecimal)
16進でhhのコードを持つ文字
\ooo 8進拡張(octal)
8進でoooのコードを持つ文字

文字列[編集]

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言語はワイド文字列をサポートしています。ワイド文字列はwchar_t型の配列として定義され、(少なくとも)16ビットの値を持ちます。文字列の前にLを付けて次のように書きます。

wchar_t *p = L "Hello world!";

この機能により、256種類以上の文字が必要な文字列が可能になります(可変長のchar文字列も使用可能です)。これらの文字列はゼロ値のwchar_tで終わります。これらの文字列は<string.h>の関数ではサポートされていません。その代わり、<wchar.h>で宣言された独自の関数を持っています。

char16_t, char32_t型[編集]

ワイド文字は、型のサイズや符号化形式が規定されておらずプラットフォームおよび処理系依存で、Unicodeが普及するにつれて移植性の問題が表面化してきました。

ISO/IEC 9899:2011(通称C11) では、新たに2つの文字型 char16_tchar32_t が導入されました[2]。 これらはそれぞれ UTF-16 と UTF-32 を内部表現とします。 u'c'U'c' あるいは u"str"U"str" のように小文字の u あるいは大文字の U を前置することで、それぞれ char16_tchar32_t の文字定数・文字列リテラルを表現します。 また、u8 を前置することで UTF-8 の文字列リテラルを表現します[3]が、char8_t 型は存在せず、従来の char 型で代用します。

char16_tおよびchar32_tはそれぞれuint_least16_tおよびuint_least32_tのtypedefエイリアスです。

char16_t型のサイズは16ビットよりも大きい可能性があるが、格納される値は16ビット幅です[4]。同様に、char32_t型のサイズは32ビットよりも大きい可能性があるが、格納される値は32ビット幅である[5]

char16_t の使用例
#include <uchar.h>
#include <stdio.h>
 
int main(void)
{
    char16_t c16s[] = u"👿"; // または u"\U0001F47F"
    printf("%zu UTF-16 code units: [ ", sizeof c16s / sizeof *c16s);
    for (size_t n = 0; n < sizeof c16s / sizeof *c16s; n++) printf("%#x ", c16s[n]);
    printf("]\n");
}
実行結果
3 UTF-16 code units: [ 0xd83d 0xdc7f 0 ]

文字エンコーディング[編集]

charwchar_tがどのような文字エンコーディングを表すかは、C言語の標準では規定されていませんが、0x00と0x0000という値は文字列の終わりを示しており文字ではありません。 文字エンコーディングの影響を直接受けるのは、入力コードと出力コードです。その他のコードはあまり影響を受けないはずです[6]。また、ソースコードに文字列を書き込めるようにするためには、エディターもエンコーディングに対応していなければならない。

符号化方式には大きく分けて3種類あります。

  • 1文字に1バイト。通常はASCIIをベースにしています。文字数は255文字までで、これに0の終端文字を加えたものになります。
  • 可変長のchar文字列で、255種類以上の文字が使用できます。このような文字列は、通常のcharベースの配列として書かれます。これらのエンコーディングは通常ASCIIベースで、UTF-8やShiftJISなどがその例です。
  • ワイド文字列。wchar_tの値の配列です。UTF-16は最も一般的なエンコーディングで、可変長であるため、1つの文字が2つのwchar_tになることもあります。
    • ワイド文字列にUTF-16を選んでしまった場合[7]サロゲートペアの存在が問題になります。サロゲートペアは一部の文字を16bit整数2個で表す機能で、1文字がwchar_tの配列の要素に対応する前提が崩れていまいます。典型的なサロゲートペアでエンコードされた文字にemoji(👿など)があります。

脚註[編集]

  1. ^ JIS語では逆斜線表記
  2. ^ C11: WG14/N1570 Committee Draft — April 12, 2011 ISO/IEC 9899:201x. ISO/IEC. (2011-04-12). p. 398,§ 7.28 Unicode utilities. http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf. 
  3. ^ 文字列リテラル - cppreference.com
  4. ^ char16_t - cppreference.com
  5. ^ char32_t - cppreference.com
  6. ^ この仮定でプロクラムを作るとエンコーディングの種類によっては(例えば ShiftJISでは)1つの文字の2バイト目に '\ の様なエスケープ文字が現れた時、正しくエンコーディング出来ず、場合によってはバッファオーバーフロー等を引き起こします。
  7. ^ WindowsやJavaが該当します。