C++ string クラスの size や length は strlen とは違う †
C/C++で文字列を char
の配列で持つ場合、特定の位置以降を切り捨てる方法の1つとして、 '\0'
を代入するという方法があります。
- ソースコード
-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
!
| #include <iostream>
#include <cstring>
int main(int, char**)
{
using namespace std;
char text[] = "ABCDEFGH";
cout << "[Before]" << endl;
cout << "text : " << text << endl;
cout << "strlen(text) : " << std::strlen(text) << endl;
text[4] = '\0';
cout << "[After]" << endl;
cout << "text : " << text << endl;
cout << "strlen(text) : " << std::strlen(text) << endl;
return 0;
}
|
- 実行結果(VC++ 2010 および gcc 4.3.0)
1
2
3
4
5
6
| [Before]
text : ABCDEFGH
strlen(text) : 8
[After]
text : ABCD
strlen(text) : 4
|
ですが、同じことを std::string
でやろうとすると、 size
メンバ関数や length
メンバ関数の挙動が違うことに気付くと思います。
- ソースコード
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
!
| #include <iostream>
#include <string>
int main(int, char**)
{
using namespace std;
std::string text = "ABCDEFGH";
cout << "[Before]" << endl;
cout << "text : " << text << endl;
cout << "text.size() : " << text.size() << endl;
cout << "text.length() : " << text.length() << endl;
text[4] = '\0';
cout << "[After]" << endl;
cout << "text : " << text << endl;
cout << "text.size() : " << text.size() << endl;
cout << "text.length() : " << text.length() << endl;
return 0;
}
|
- 実行結果(VC++ 2010)
1
2
3
4
5
6
7
8
| [Before]
text : ABCDEFGH
text.size() : 8
text.length() : 8
[After]
text : ABCD FGH
text.size() : 8
text.length() : 8
|
- 実行結果(gcc 4.3.0)
1
2
3
4
5
6
7
8
| [Before]
text : ABCDEFGH
text.size() : 8
text.length() : 8
[After]
text : ABCDFGH
text.size() : 8
text.length() : 8
|
なお、 c_str
メンバ関数や data
メンバ関数で取得できる文字列は "ABCD"
になります。
この結果から次のことがわかると思います。
std::string
内部において '\0'
は単に要素としてとりうる値の1つに過ぎない。
size
メンバ関数や length
メンバ関数は内部でアサインされている要素の数を返す。
strlen
関数のように '\0'
の前までの文字数を返すわけではない。
std::ostream
の <<
演算子の std::string
用オーバロードは size
メンバ関数が返すサイズ値を基に文字列を出力する。*1
ただし、 const char*
を引数に取るコンストラクタや =
演算子のオーバロード等では最初の '\0'
の前までを取り出して内部に設定してくれます。
これは単にそれらのメンバ関数がそういう実装になっているというだけであり、 std::string
内部での持ち方が変わるわけではありません。
size
メンバ関数や length
メンバ関数の上述のような仕様は、特に std::ostringstream
等でバイナリデータを扱う場合に意味があります。
バイナリデータには当然値が 0
のデータも普通にあるわけで、 strlen
関数のような仕様では正しいデータサイズが取れなくなってしまいます。
普通に文字列データとして std::string
を使っている分にはあまり気にする必要のないことですが、混同しないようにしましょう。