C言語 - 文字と文字列と文字列の配列
C言語 - 文字と文字列と文字列の配列
C言語での文字の扱いを整理する。
文字
C言語で文字を扱うときは文字型(char 型)のデータを使う。
1つの半角文字はシングルクォート('
)で囲む。
char ch = 'A';
NOTE: 半角文字=ASCIIコード表に定義された文字
文字列
複数の半角文字、あるいは全角文字はダブルクォート("
)で囲む。
変数に入れるときは、文字型の配列とし、配列の最後にヌル文字('\0'
)を置く。
C言語のデータ型には文字列を表す型がないため、このようにして表現する必要がある。
変数の宣言と同時に値を設定する場合、ヌル文字('\0'
)は自動で追加される。
次の場合、変数 chs は “ABC” とヌル文字が格納された、要素数4の文字型の配列となる。
char chs[] = "ABC";
全角文字も同様に文字型の配列で表現する。
char str[] = "あ";
半角文字の文字列だったら、1文字ずつ取り出すのも簡単にできる。
1つずつ要素にアクセスしていけばいい。
char chs[] = "ABC";
printf("%c\n", chs[0]);
// → A
printf("%c\n", chs[1]);
// → B
printf("%c\n", chs[2]);
// → C
しかし、全角文字も含まれていると一気に面倒になる。
UTF-8 で gcc でコンパイルした場合、全角文字は1文字あたり3バイトになる。
1文字取り出すのに配列の要素3つにアクセスしないといけない。
char mchs[] = "あいう";
printf("%c%c%c\n", mchs[0], mchs[1], mchs[2]);
// → あ
printf("%c%c%c\n", mchs[3], mchs[4], mchs[5]);
// → い
printf("%c%c%c\n", mchs[6], mchs[7], mchs[8]);
// → う
半角と全角文字の混在なんて考えただけで面倒くさい。
文字列の配列
複数の文字列を表すには、文字型の二次元配列を使えば良い。
char strlist[][128] = { "ABC", "あいうえお", '\0' };
int i;
int len = sizeof(strlist) / sizeof(strlist[0]);
for (i = 0; i < len; i++) {
printf("%d: %s\n", i + 1, strlist[i]);
}
二次元配列を宣言と同時に初期化する場合、一次元目の要素数は省略できる。
char strlist[][128] = { "ABC", "あいうえお", '\0' };
一次元目の要素数は、配列全体のサイズ ÷ 二次元目の配列サイズ で求められる。
(この場合 384 ÷ 128 = 3 となる)
int len = sizeof(strlist) / sizeof(strlist[0]);
動的にメモリを確保する方法もある
ちなみに配列ではなく動的にメモリを確保する方法もある。
(今回の例だと動的に確保するメリットはないんだけど、一応こんなやり方もあるよ、という意味で載せておく)
文字列
次のプログラムは “あいう” をメモリに格納し、標準出力に出力する。
int bytelen = sizeof(char) * (strlen("あいう") + 1);
char *mchs = (char *)malloc(bytelen);
if ( mchs == NULL ) {
perror("malloc err");
return 1;
}
if ( strcpy_s(mchs, bytelen, "あいう") != 0 ) {
perror("strcpy_s err");
} else {
printf("%s\n", mchs);
}
free(mchs);
まず malloc
関数でメモリを動的に確保する。
int bytelen = sizeof(char) * (strlen("あいう") + 1);
char *mchs = (char *)malloc(bytelen);
次に strcpy_s
関数で文字列をメモリに入れる。
strcpy_s(mchs, bytelen, "あいう")
最後に free
関数で確保したメモリを解放する。
free(mchs);
文字列の配列
次のプログラムは “ABC” 、 “あいうえお” 、空文字の3つをそれぞれメモリに格納し、標準出力に出力する。
char **strlist = (char **)malloc(sizeof(char *) * 3);
if ( strlist == NULL ) {
perror("malloc err");
return 1;
}
int i;
for (i = 0; i < 3; i++) {
int bytelen = sizeof(char) * 128;
strlist[i] = (char *)malloc(bytelen);
if ( strlist[i] == NULL ) {
perror("malloc err");
continue;
}
switch (i) {
case 0:
strcpy_s(strlist[i], bytelen, "ABC");
break;
case 1:
strcpy_s(strlist[i], bytelen, "あいうえお");
break;
case 2:
strcpy_s(strlist[i], bytelen, '\0');
break;
}
}
for (i = 0; i < 3; i++) {
if ( strlist[i] != NULL ) {
printf("%d: %s\n", i + 1, strlist[i]);
free(strlist[i]);
}
}
free(strlist);
まずは3つの文字列を入れるためのメモリを確保する。
char **strlist = (char **)malloc(sizeof(char *) * 3);
次にループでそれぞれの文字列を入れるためのメモリを確保する。
確保できたらメモリに文字列を入れる。
(strcpy_s 関数のエラー処理は面倒なので省略)
for (i = 0; i < 3; i++) {
int bytelen = sizeof(char) * 128;
strlist[i] = (char *)malloc(bytelen);
:
switch (i) {
case 0:
strcpy_s(strlist[i], bytelen, "ABC");
break;
:
そして新しいループでメモリに入れた文字列を順番に出力する。
その後、それぞれで確保したメモリを解放する。
for (i = 0; i < 3; i++) {
if ( strlist[i] != NULL ) {
printf("%d: %s\n", i + 1, strlist[i]);
free(strlist[i]);
}
}
最後に全体のメモリを解放する。
free(strlist);
何度も書くがあまり良い例ではなかった。
これなら静的メモリ確保(配列使用)で十分だろう。
動的メモリ確保のちゃんとしたやつは、何かのタイミングで書き残しておきたい。
アカウントを作成 して、もっと沢山の記事を読みませんか?
この記事にコメントをしてみませんか?