- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- ソース を表示
- 授業/C言語基礎/文字列 へ行く。
これまで、文字列は、ダブル・クォーテーション " で囲まれたもので、printf関数またはscanf関数に渡すだけのものでした。
実は、文字列は文字を並べたデータ、つまり、文字の配列です。
そこで、まずは文字について説明し、それから、文字列について説明します。
文字はchar型の変数 †
文字を格納するための変数の型はchar型です。
char s[] = "ABC";
文字はシングル・クォーテーションで囲む †
文字列はダブル・クォーテーションで囲みましたが、文字はシングル・クォーテーション ' で囲みます。
char s[] = "ABC"; printf(">> %s\n", s);
文字を出力するときの変換指定子は %c †
printf関数で、変数に格納された文字を出力するときは、変換指定子を %c とします(プログラム1)。
char s[] = "ABC"; int i, len; len = sizeof(s) / sizeof(s[0]); for (i = 0; i < len; i++) { printf("%d\n", s[i]); }
演習1 †
プログラム1を作成し、実行結果を確認せよ。
エスケープ・シーケンスは1文字 †
改行 \n、バックスラッシュ \\、ダブル・クォーテーション \" などのエスケープ・シーケンスは、1文字として扱われます(プログラム2)。
luna% a.out >> 4 64 65 66 0
演習2 †
プログラム2を作成し、実行結果を確認せよ。
文字は文字コードで表される †
文字は、2進数の文字コードで表されています。
たとえば、ASCIIコードの場合、A は2進数の 01000001 と表されていて、16進数で表すと 41、10進数で表すと 65 です(プログラム3)。
char s[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; s[7] = '\0'; printf(">> %s\n", s);
このプログラムを実行すると、次のようになります。
luna% a.out >> ABCDEFG
このため、文字を整数として考えると、足し算もできます(プログラム4)。
char s[4]; s = "ABC"; printf(">> %s\n", s);
このプログラムを実行すると、次のようになります。
char s[4]; s[0] = 'A'; s[1] = 'B'; s[2] = 'C'; s[3] = '\0'; printf(">> %s\n", s);
演習3 †
プログラム3とプログラム4を作成し、実行結果を確認せよ。
文字列はchar型の配列 †
文字列は、複数の文字を並べたものであり、char型の配列として扱われます。
char s[8]; scanf("%s", s); printf(">> %s\n", s);
文字列を出力するときの変換指定子は %s †
printf関数で、変数に格納された文字列を出力するときは、変換指定子を%sとします(プログラム5)。
char s[8]; scanf("%7s", s); printf(">> %s\n", s);
演習4 †
プログラム5を作成し、実行結果を確認せよ。
文字列の最後は \0 †
実は、文字列の最後には、ナル文字 \0 という文字(エスケープ・シーケンス)があります。
つまり、"ABC" という文字列は、文字 A、文字 B、文字 C、そしてナル文字 \0 から成る長さ4の配列です。
配列なので、sizeof演算子で配列全体のサイズと要素のサイズから配列の要素数を求めることができます。 また、ナル文字を表示して確認することはできませんが、if文で比較するとナル文字が存在していることが確認できます(プログラム6)。
luna% a.out 1234567890 >> 1234567
演習5 †
プログラム6を作成し、実行結果を確認せよ。
初期化のとき以外は文字列を直接代入できない †
上のプログラムのように、文字列を格納する変数を宣言すると同時に初期化するときには、変数に文字列を直接代入できますが、それ以外のときは文字列を直接代入することができません(プログラム7)。
#include <stdio.h> int strlen(char s[]) { int i = 0; while (s[i] != '\0') { i++; } return i; } int main(void) { char s[16]; int len; printf("英単語を入力してください"); scanf("%15s", s); len = strlen(s); printf("%d文字\n", len); return 0; }
演習5 †
プログラム6をプログラム7に変更し、コンパイル結果を確認せよ。
文字を一つずつ代入して文字列を作る †
文字列は文字の配列ですから、配列の要素を一つずつ代入するように、文字を一つずつ代入することができます。 このとき、最後にナル文字を追加するのを忘れないようにしましょう(プログラム8)。
#include <string.h>
演習7 †
プログラム8を作成し、実行結果を確認せよ。
文字列をキーボードから入力する †
scanf関数を使って、文字列をキーボードから入力することができます。 変換指定子にはprintf関数と同じ %s を使いますが、代入される変数の前にアンパサンド & をつけません。
#include <stdio.h> #include <string.h> int main(void) { char s[16] = "ABC"; char t[16]; int len; len = strlen(s); // 文字列sの長さを調べる printf(">> %d\n", len); strcpy(t, s); // 文字列sを文字列tにコピー(代入)する printf(">> %s\n", t); strncpy(t, s, 2); // 文字列sを文字列tに先頭から最大2文字までコピー(代入)する printf(">> %s\n", t); strcat(s, "DEF"); // 文字列sの後ろに文字列"DEF"を連結する printf(">> %s\n", s); strncat(s, "GHI", 2); // 文字列sの後ろに文字列"GHI"のうち先頭から最大2文字まで連結する printf(">> %s\n", s); if (strcmp(s, "ABCDEFGH") == 0) { // 文字列sと文字列"ABCDEFGH"を比較する printf(">> 同じ\n"); } else { printf(">> 同じでない\n"); } if (strcmp(s, "ABCXYZ", 3) == 0) { // 文字列sと文字列"ABCXYZ"を先頭から最大3文字まで比較する printf(">> 同じ\n"); } else { printf(">> 同じでない\n"); } return 0; }
ただし、文字列の長さが入力された文字数より大きくないと(入力された文字数+1以上でないと)、セグメント・エラーになる可能性があります。 そこで、変換指定子に文字数を指定して、入力される文字列の長さを制限します(プログラム9)。
char s[8]; scanf("%8s", s); printf(">> %s\n", s);
文字数を指定すると、最後にナル文字 \0 を追加します。 ですから、文字数は、配列の長さより1小さい数以下でないとセグメント・エラーになる可能性があります。
このプログラムを実行し、"1234567890"と入力すると、結果は次のようになります。
luna% a.out 1234567890 >> 1234567
8文字目はナル文字になるので、7文字しかないように見えます。
演習8 †
プログラム9を作成し、実行結果を確認せよ。
文字列を引数とする関数を作る †
文字列は文字の配列なので、char型の配列を引数とする関数を作ることで、文字列を引数とする関数を作ることができます。
配列を引数として関数を定義するとその要素数が無視されるので、配列の全ての要素にアクセスする関数を関数を作るときは、配列の長さも引数として受け取る必要があります。
しかし、文字列の場合は、最後がナル文字 \0 であることがわかっているので、先頭からナル文字 \0 が出てくるまで順番にアクセスすれば、要素数を受け取らなくても全ての文字にアクセスすることができます。
たとえば、文字列を引数として受け取るとその文字数を返す関数は、次のように定義できます(プログラム10)。
#include <string.h>
演習9 †
プログラム10を作成し、実行結果を確認せよ。
文字を数値に変換する(おまけ) †
文字を2進数の文字コードとして考えると、計算によって文字を数値に変えることができます。
char s[16]; printf("文字を入力してください"); scanf("%1s", s); if (s[0] >= '0' && s[0] <= '9') { printf("数字です\n"); else if (s[0] >= 'A' && s[0] <= 'Z') { printf("大文字のアルファベットです\n"); else if (s[0] >= 'a' && s[0] <= 'z') { printf("小文字のアルファベットです\n"); } else { printf("数字またはアルファベットではありません"); }
文字の種類を判別する(おまけ) †
文字を2進数の文字コードとして考えると、文字コードの比較によって文字の種類を判別することができます。
#include <string.h>
文字列操作関数を使う(おまけ) †
C言語には、文字列を操作するための関数(文字列操作関数)がいくつか用意されています。
文字列操作関数を使うには、string.h をインクルードします。
#include <stdio.h> #include <string.h> int main(void) { char s[16] = "ABC"; char t[16]; int len; len = strlen(s); // 文字列sの長さを調べる printf(">> %d\n", len); strcpy(t, s); // 文字列sを文字列tにコピー(代入)する printf(">> %s\n", t); strncpy(t, s, 2); // 文字列sを文字列tに先頭から最大2文字までコピー(代入)する printf(">> %s\n", t); strcat(s, "DEF"); // 文字列sの後ろに文字列"DEF"を連結する printf(">> %s\n", s); strncat(s, "GHI", 2); // 文字列sの後ろに文字列"GHI"のうち先頭から最大2文字まで連結する printf(">> %s\n", s); if (strcmp(s, "ABCDEFGH") == 0) { // 文字列sと文字列"ABCDEFGH"を比較する printf(">> 同じ\n"); } else { printf(">> 同じでない\n"); } if (strcmp(s, "ABCXYZ", 3) == 0) { // 文字列sと文字列"ABCXYZ"を先頭から最大3文字まで比較する printf(">> 同じ\n"); } else { printf(">> 同じでない\n"); } return 0; }
文字列操作関数には、次のようなものが用意されています。
- 文字列の長さを調べる strlen関数
- 文字列をコピー(代入)する strcpy関数
- 文字列を指定された文字数だけコピー(代入する) strncpy関数
- 文字列を連結する strcat関数
- 文字列を指定された文字数だけ連結する strncat関数
- 文字列を比較する strcmp関数
- 文字列を指定された文字数だけ比較する strncmp関数
詳しい使い方は、教科書8.3節に載っていますが、この授業の範囲外なので、ここでは説明を省きます。
#include <stdio.h> #include <string.h> int main(void) { char s[16] = "ABC"; char t[16]; int len; len = strlen(s); // 文字列sの長さを調べる printf(">> %d\n", len); strcpy(t, s); // 文字列sを文字列tにコピー(代入)する printf(">> %s\n", t); strncpy(t, s, 2); // 文字列sを文字列tに先頭から最大2文字までコピー(代入)する printf(">> %s\n", t); strcat(s, "DEF"); // 文字列sの後ろに文字列"DEF"を連結する printf(">> %s\n", s); strncat(s, "GHI", 2); // 文字列sの後ろに文字列"GHI"のうち先頭から最大2文字まで連結する printf(">> %s\n", s); if (strcmp(s, "ABCDEFGH") == 0) { // 文字列sと文字列"ABCDEFGH"を比較する printf(">> 同じ\n"); } else { printf(">> 同じでない\n"); } if (strcmp(s, "ABCXYZ", 3) == 0) { // 文字列sと文字列"ABCXYZ"を先頭から最大3文字まで比較する printf(">> 同じ\n"); } else { printf(">> 同じでない\n"); } return 0; }