
C++入門|stringクラスの便利な使い方
文字数を測り、狙った文字を読み取り、必要な部分だけを切り出す。stringを使えば、技名や修行メッセージを自在に操れます。
C++で文字列を扱うときに、よく使われるのがstringクラスです。
これまでのプログラムでも、戦士名、技名、流派名、修行メッセージなどを保存するためにstringを使ってきました。
stringは、文字列を保存するだけの入れ物ではありません。
文字数を調べたり、特定の位置にある文字を取り出したり、文字列の一部分だけを切り出したりできます。
さらに、C言語で使われるchar型の配列からstringへ変換したり、stringの内容をC言語形式の文字列として取り出したりすることもできます。
ドラゴンボール風にたとえるなら、stringは神殿にある文字列解析スカウターです。
技名全体を記録するだけでなく、その技名が何文字あるのかを測定し、特定の位置にある文字を読み取り、必要な部分だけを抽出できます。
今回確認する主な機能は、次のとおりです。
| 機能 | 役割 |
|---|---|
| length | 文字列の長さを取得する |
| size | lengthと同じように文字列の長さを取得する |
| 添字 | 指定した位置の文字を取得する |
| substr | 文字列の一部分を切り出す |
| コンストラクタ | char型の文字列からstringを作る |
| c_str | stringをC言語形式の文字列として取り出す |
stringクラスを使う準備
stringクラスを使うには、stringヘッダーをインクルードします。
#include <string>画面に文字列を表示するため、iostreamも使用します。
#include <iostream>今回のサンプルでは、標準名前空間を使います。
using namespace std;string型の変数は、次のように宣言して初期化できます。
string techniqueName = "Sky Burst";この場合、techniqueNameにはSky Burstという文字列が保存されます。
stringはクラスですが、基本的な変数とよく似た感覚で扱えます。
string message;
message = "Training Start";文字列同士を比較したり、連結したり、さまざまなメンバ関数を呼び出したりできる点が、char型の配列よりも扱いやすいところです。
stringクラスの便利な機能を確認する
最初のサンプルでは、技名としてSky Burstを保存します。
その文字列に対して、次の処理を行います。
文字列全体を表示します。
文字列の長さを調べます。
先頭の文字を取得します。
添字4の文字を取得します。
添字4から5文字を切り出します。
プロジェクト/ファイル名: Chap7_04/technique_string.cpp
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char** argv) {
// 解析する技名
string techniqueName = "Sky Burst";
// 文字列全体を表示する
cout << "技名[" << techniqueName << "]" << endl;
// 文字列の長さを取得する
cout << "文字数:" << techniqueName.length() << endl;
// 先頭の文字を取得する
cout << "先頭の文字:" << techniqueName[0] << endl;
// 添字4の文字を取得する
cout << "添字4の文字:" << techniqueName[4] << endl;
// 添字4から5文字を切り出す
cout << "添字4から5文字:"
<< techniqueName.substr(4, 5) << endl;
return 0;
}実行結果
技名[Sky Burst]
文字数:9
先頭の文字:S
添字4の文字:B
添字4から5文字:BurstSky Burstは、空白を含めて9文字です。
文字列中の空白も1文字として数えられます。
また、文字列の位置を表す添字は0から始まります。
そのため、先頭のSは添字0です。
空白は添字3です。
Bは添字4です。
図:stringの文字数と添字

この図が示していること
この図では、Sky Burstを1文字ずつ区切り、それぞれの添字を表示しています。
文字列の長さは9です。
添字は0から始まるため、最後の文字tの添字は8になります。
先頭の文字を取得する場合は添字0を使います。
Bを取得する場合は添字4を使います。
lengthで文字列の長さを取得する
文字列の長さを調べるには、lengthを使います。
techniqueName.length()サンプルで使用している文字列は、次の内容です。
Sky Burst文字数を分けて確認すると、次のようになります。
S k y B u r s t
1 2 3 4 5 6 7 8 9S、k、yの3文字に加えて、空白が1文字あります。
そのあとに、B、u、r、s、tの5文字があります。
したがって、合計は9文字です。
lengthのイメージを図で表すと、次のようになります。

lengthは、文字列に含まれる要素数を返します。
戻り値は整数として扱えます。
cout << techniqueName.length() << endl;sizeでも文字列の長さを取得できる
stringには、lengthと同じように文字列の長さを返すsizeもあります。
techniqueName.size()今回の文字列では、どちらも9を返します。
cout << techniqueName.length() << endl;
cout << techniqueName.size() << endl;実行結果は次のようになります。
9
9stringでは、lengthとsizeは同じ結果になります。
| メンバ関数 | 得られる結果 |
|---|---|
| techniqueName.length() | 文字列の長さ |
| techniqueName.size() | 文字列の長さ |
文字列の長さを調べていることを分かりやすく表現したい場合は、lengthという名前が直感的です。
一方、vectorなどほかのSTLコンテナと書き方をそろえたい場合は、sizeが使われることもあります。
添字を使って特定の文字を取得する
stringでは、配列と同じように角括弧と添字を使って、特定の位置の文字を取得できます。
techniqueName[0]添字は0から始まります。
Sky Burstの各文字と添字は、次のようになります。
文字 S k y 空白 B u r s t
添字 0 1 2 3 4 5 6 7 8先頭の文字Sを取得する場合は、添字0を指定します。
techniqueName[0]添字4を指定すると、Bを取得できます。
techniqueName[4]特定の位置の文字を取得するイメージは、次のとおりです。

ここで注意したいのは、日常的な数え方と添字の違いです。
添字4のBは、文字列全体では5文字目にあります。
添字は0から始まるため、位置の数え方が1つずれます。
| 日常的な数え方 | 添字 | 文字 |
|---|---|---|
| 1文字目 | 0 | S |
| 2文字目 | 1 | k |
| 3文字目 | 2 | y |
| 4文字目 | 3 | 空白 |
| 5文字目 | 4 | B |
存在しない添字を指定しない
Sky Burstの長さは9なので、有効な添字は0から8までです。
有効な添字:0~8添字9は文字列の範囲外です。
techniqueName[9]範囲外の添字を角括弧で指定した場合、安全に文字を取得できる保証はありません。
そのため、添字を使う前に、lengthやsizeで文字列の長さを確認することが大切です。
if (index < techniqueName.length()) {
cout << techniqueName[index] << endl;
}このif文では、indexが文字列の長さより小さい場合だけ、文字を取得しています。
atで範囲を確認しながら取得する
特定の位置の文字を取得する方法には、atもあります。
techniqueName.at(4)この処理では、添字4のBを取得できます。
角括弧とatの大きな違いは、範囲外の位置を指定した場合の動作です。
atは範囲外の位置を指定すると、std::out_of_rangeという例外を送出します。
| 取得方法 | 範囲確認 |
|---|---|
| techniqueName[4] | 範囲外を自動では検査しない |
| techniqueName.at(4) | 範囲外なら例外を送出する |
今回の中心は角括弧による取得ですが、安全性を高めたい場面ではatも利用できます。
substrで文字列の一部分を切り出す
文字列の一部分だけを取得したいときは、substrを使います。
基本的な形は次のとおりです。
文字列.substr(開始位置, 文字数)第1引数には、切り出しを開始する添字を指定します。
第2引数には、そこから何文字を切り出すかを指定します。
今回のサンプルでは、次のように使用しています。
techniqueName.substr(4, 5)開始位置は添字4です。
Sky Burstの添字4にある文字はBです。
そこから5文字を切り出すため、結果はBurstになります。

第2引数は終了位置ではありません。
何文字取り出すかを表します。
この点は、間違えやすいので注意しましょう。
| 指定 | 意味 |
|---|---|
| substr(4, 5) | 添字4から5文字を取得する |
| substr(4, 3) | 添字4から3文字を取得する |
| substr(0, 3) | 先頭から3文字を取得する |
図:substrによる部分文字列の切り出し

この図が示していること
この図では、substr(4, 5)によって、添字4から5文字を切り出す流れを表しています。
添字4にあるBから切り出しを開始し、B、u、r、s、tの5文字を取得します。
第2引数の5は、添字5までという意味ではありません。切り出す文字数が5文字という意味です。
substrの第2引数を省略する
substrでは、第2引数を省略することもできます。
techniqueName.substr(4)この場合、添字4から文字列の最後までを切り出します。
Sky Burstでは、結果はBurstです。
Sky Burst
↑
添字4から最後まで
結果:Burst途中から末尾までを取り出したい場合は、第2引数を省略すると簡潔に書けます。
stringとchar型文字列の違い
C++では、文字列を扱うためにstringを使えます。
一方、C言語では、一般的にchar型の配列を使って文字列を表します。
char message[] = "Training Start";C++ではC言語向けの関数やライブラリを利用することもあります。
そのような場面では、char型の文字列とstringの間でデータを受け渡す必要があります。
| 文字列の表現 | 主に使われる場面 |
|---|---|
| string | C++の文字列処理 |
| char型の配列 | C言語形式の文字列処理 |
| const char* | C言語形式の読み取り専用文字列へのポインタ |
stringは、長さの管理や連結、比較などをクラス側が行ってくれるため、C++ではとても扱いやすい文字列型です。
char型の配列からstringへ変換する
char型の文字列からstringを作るには、stringのコンストラクタへchar型の文字列を渡します。
char message[] = "Training Start";
string trainingMessage(message);trainingMessageには、Training Startと同じ内容が保存されます。
この変換は、C言語形式の文字列をC++のstringとして扱いたい場合に便利です。
stringからC言語形式の文字列を取得する
stringの内容をC言語形式で利用したいときは、c_strを使います。
trainingMessage.c_str()c_strの戻り値は、文字列の内容を指すconst char*です。
読み取り専用なので、取得した文字列の内容を直接書き換えることはできません。
const char* text = trainingMessage.c_str();printfの%sへ渡すこともできます。
printf("%s\n", trainingMessage.c_str());char型文字列との変換を確認するサンプル
次のプログラムでは、char型の配列からstringを作り、そのあとstringをc_strでC言語形式の文字列としてprintfへ渡します。
プロジェクト/ファイル名: Chap7_05/string_char_conversion.cpp
#include <iostream>
#include <string>
#include <cstdio>
using namespace std;
int main(int argc, char** argv) {
// C言語形式のchar型文字列
char oldMessage[] = "Training Start";
// char型文字列からstringを生成する
string trainingMessage(oldMessage);
// stringとして表示する
cout << trainingMessage << endl;
// C++のstringを用意する
string techniqueMessage = "Power Charge";
// c_strでC言語形式の文字列を取得して表示する
printf("%s\n", techniqueMessage.c_str());
return 0;
}実行結果
Training Start
Power Chargechar型文字列からstringが作られる流れ
次の配列には、C言語形式の文字列が保存されています。
char oldMessage[] = "Training Start";このoldMessageをstringのコンストラクタへ渡します。
string trainingMessage(oldMessage);コンストラクタは、新しいstringオブジェクトを作るときに呼び出される特別な関数です。
この処理によって、oldMessageと同じ内容を持つtrainingMessageが作られます。
char型の文字列
Training Start
↓
stringのコンストラクタ
↓
string型の文字列
Training Startstringのコンストラクタには、次のような形式があります。
string(const char* text);const char*で受け取っているため、渡されたC言語形式の文字列を変更せずに読み取り、stringの内容として保存します。
c_strの戻り値
c_strは、stringが管理している文字列をC言語形式で参照するためのメンバ関数です。
techniqueMessage.c_str()戻り値はconst char*です。
const char* text = techniqueMessage.c_str();constが付いているため、textを通して文字列を書き換えることはできません。
text[0] = 'X';この処理は許可されません。
c_strで取得した文字列は、読み取り専用として扱います。
c_strはchar型の配列を新しく作る処理ではない
c_strは、独立したchar型配列を新しく作って返すわけではありません。
stringが内部で管理している文字列データへのポインタを返します。
そのため、元のstringを変更すると、以前に取得したポインタをそのまま使えない場合があります。
string message = "Power";
const char* text = message.c_str();
// stringの内容を変更する
message += " Charge";messageの変更によって内部の保存場所が変わると、textが以前指していた場所が無効になる可能性があります。
安全に使うため、c_strで得たポインタは、必要な場所ですぐに利用するのが基本です。
printf("%s\n", message.c_str());書き換え可能なchar型配列が必要な場合
c_strの戻り値はconst char*なので、内容を変更できません。
書き換え可能なchar型配列が必要な場合は、必要な大きさの配列を用意し、文字列をコピーする処理が必要です。
ただし、単にC言語の表示関数へ文字列を渡すだけなら、c_strで十分です。
| 目的 | 適した方法 |
|---|---|
| printfで表示したい | c_strを使う |
| C言語関数へ読み取り専用で渡したい | c_strを使う |
| 独立した書き換え可能な配列が必要 | 別の配列へコピーする |
| C++内で文字列を編集したい | stringのまま扱う |
図:char型文字列とstringの相互変換

この図が示していること
この図では、char型の文字列からstringを作る流れと、stringからC言語形式の文字列を取り出す流れを表しています。
char型の文字列からstringを作る場合は、stringのコンストラクタへ文字列を渡します。
stringをC言語形式で使う場合は、c_strを呼び出してconst char*を取得します。
c_strで得られる文字列は読み取り専用なので、内容を直接変更できません。
stringを使う利点
stringは、文字列の長さを自分で管理する必要がありません。
char型の配列では、配列の大きさや終端のヌル文字を意識する必要があります。
stringでは、文字列の保存や長さの管理をクラスが行います。
さらに、メンバ関数を使ってさまざまな文字列処理を行えます。
| 処理 | stringでの書き方 |
|---|---|
| 長さを取得する | lengthまたはsize |
| 特定の文字を取得する | 角括弧またはat |
| 一部分を切り出す | substr |
| C言語形式で取得する | c_str |
| char型文字列から作る | コンストラクタへ渡す |
ドラゴンボール風に考えるなら、stringは技名や修行メッセージを管理する高性能な文字列スカウターです。
単に文字を保存するだけでなく、文字数を測り、特定の位置を読み取り、必要な部分を切り出せます。
length、添字、substrの関係
今回の最初のサンプルでは、Sky Burstという文字列を調べました。
lengthによって文字列全体の長さを取得しました。
techniqueName.length()角括弧によって特定の位置の文字を取得しました。
techniqueName[0]
techniqueName[4]substrによって文字列の一部分を切り出しました。
techniqueName.substr(4, 5)これらの処理は、すべて文字列中の位置を使っています。
添字は0から始まるため、文字数と最後の添字は一致しません。
文字数が9なら、最後の添字は8です。
文字数 9
有効な添字 0~8この関係を理解しておくと、添字やsubstrを正しく使いやすくなります。
stringクラスで身につけたい感覚
stringクラスには、文字列を扱うための便利なメンバ関数が用意されています。
文字列の長さを調べるときはlengthまたはsizeを使います。
techniqueName.length()特定の位置にある文字を取得するときは、角括弧と添字を使います。
techniqueName[0]文字列の一部分を切り出すときは、substrを使います。
techniqueName.substr(4, 5)char型の文字列からstringを作るときは、stringのコンストラクタへ渡します。
string trainingMessage(oldMessage);stringをC言語形式の文字列として利用するときは、c_strを使います。
printf("%s\n", techniqueMessage.c_str());c_strの戻り値はconst char*なので、読み取り専用として扱います。
ドラゴンボール風にたとえるなら、lengthは技名の文字数を測るスカウターです。
角括弧は、技名の特定位置へ照準を合わせる機能です。
substrは、技名の中から必要な部分だけを切り出す解析装置です。
c_strは、C++の文字列データをC言語の通信装置でも読める形式へ変換する接続機能です。
stringの便利な機能を使い分けられるようになると、入力された文章の解析、ファイル名の処理、コマンドの判定、メッセージの切り出しなど、さまざまな文字列処理を作れるようになります。
