はじめに
- これまでの学習に続いて、今回は文字列の基本的なルールについて学んだ結果をまとめてみました。
- 【C】初めてのC言語(1. Hello world)
- 【C】初めてのC言語(2. 四則演算とフォーマット指定子)
- 【C】初めてのC言語(3. ポインタ)
- 【C】初めてのC言語(4. 構造体)
- 【C】初めてのC言語(5. 関数)
- 【C】初めてのC言語(6. 配列)
- 【C】初めてのC言語(7. for文)
- 【C】初めてのC言語(8. 2次元配列)
- 【C】初めてのC言語(9. 関数のプロトタイプ宣言)
- 【C】初めてのC言語(10. 構造体配列)
- 【C】初めてのC言語(11. ヘッダファイル)
- 【C】初めてのC言語(12. 3つのからくり構文+ポインタ演算)
- 【C】初めてのC言語(13. メモリを扱う標準関数)
- 【C】初めてのC言語(14. ヒープの利用)
- 【C】初めてのC言語(15. sizeofの注意点)
- 【C】初めてのC言語(16. 文字列の基本)
学習環境
- 今回はpaiza.ioのC言語のエディタを使いました。
文字列リテラルの機能
- ダブルクォーテーションで囲まれた文字列(文字列リテラル)は、自動的に末尾に「\0」を付ける処理が入っています。
- ダブルクォーテーションを使わず、char型の配列として文字列を作る場合は終端文字として「\0」を入れます。
- 以下のコード中の3つの配列(str1~str3)は全く同じ内容の文字列(Hello)を表しています。
Main.c
#include <stdio.h>
int main(void){
const char str1[10] = "Hello";
const char str2[10] = {'H', 'e', 'l', 'l', 'o', '\0'};
const char str3[10] = {72, 101, 108, 108, 111, 0};
printf("%s\n", str1);
printf("%s\n", str2);
printf("%s\n", str3);
return 0;
}
実行結果
Hello
Hello
Hello
文字列宣言でよくある誤り
- 以下のように、「n文字を格納するために用意する配列の要素数がn(=nバイト)」だと、最後に「\0」を入れる要素が足りなくなってしまいます。
Main.c
#include <stdio.h>
// よくある誤り
int main(void){
const char str[5] = "Hello"; // 配列の要素数が「文字列の長さと等しい」と、終端文字を入れられない!
printf("%s\n", str);
return 0;
}
- そのため、次のように「配列の要素数を文字列の長さ(バイト数)+1(=n+1バイト)」にする必要があります。
Main.c
#include <stdio.h>
// 誤りを修正したコード
int main(void){
const char str[6] = "Hello"; // 配列の要素数は「文字列の長さ(バイト数)+1」
printf("%s\n", str);
return 0;
}
- あるいは要素数を省略して、
char 変数名[] = "初期値"
という形で宣言すれば、「\0」を含めた必要な要素数が自動的に確保されます。 - そのため、文字列宣言時のオーバーランを防ぐことができます。
Main.c
#include <stdio.h>
int main(void){
const char str[] = "Hello";
printf("%s\n", str);
return 0;
}
- 一方で、
char 変数名[] = "初期値"
という形で宣言して防げるのは「文字列宣言時のオーバーラン」だけなので、以下のように長い文字列で上書きするとオーバーランが発生してしまいます。 - そのため以下の例では、memcpyによるコピー先(※ここでは
str1
)で確保されているメモリ領域を確認しておく必要があります。
Main.c
#include <stdio.h>
int main(void){
char str1[] = "Hello";
char str2[] = "Hello,world!";
memcpy(str1, str2, 13); // 長い文字列で上書きはNG
return 0;
}
参考URL
-
スッキリわかるC言語入門 第2版
- p.403~p.405