std::string
『C++』の標準ライブラリが提供する std::string は、文字列を安全かつ柔軟に扱うためのクラスです。ここでは宣言・初期化・連結・検索・置換・数値変換など、日常的によく使うメソッドを一通り説明します。
構文
// ========================================
// std::string の主な操作構文
// ========================================
#include <string> // std::string を使うために必要です
#include <iostream> // 標準入出力に必要です
// --- 宣言・初期化 ---
std::string s1 = "Shinji"; // 代入初期化です
std::string s2("Rei"); // コンストラクタで初期化します
std::string s3(3, 'A'); // 同じ文字を n 個並べた文字列を作ります("AAA")
// --- 連結 ---
std::string full = s1 + " " + s2; // + 演算子で結合します
s1 += " Ikari"; // += で末尾に追加します
// --- 長さ・空判定 ---
std::size_t len = s1.size(); // 文字数を返します(length() と同義)
bool isEmpty = s1.empty(); // 空文字列なら true を返します
// --- 部分文字列 ---
std::string sub = s1.substr(0, 5); // 位置 0 から 5 文字を取り出します
// --- 検索 ---
std::size_t pos = s1.find("Ikari"); // 部分文字列の先頭位置を返します
// 見つからなければ std::string::npos を返します
// --- 置換 ---
s1.replace(pos, 5, "Shinji"); // pos から 5 文字を指定文字列で置き換えます
// --- 文字アクセス ---
char c = s1.at(0); // 添字アクセス(範囲外は例外 std::out_of_range)
char c2 = s1[0]; // 添字アクセス(範囲外チェックなし)
// --- C 文字列変換 ---
const char* cstr = s1.c_str(); // null 終端の C 文字列ポインタを返します
// --- 数値変換 ---
std::string numStr = std::to_string(42); // 数値を文字列に変換します
int n = std::stoi("14"); // 文字列を int に変換します
構文一覧
| 構文/関数 | 概要 |
|---|---|
| s.size() / s.length() | 文字列の文字数(バイト数)を返します。どちらも同じ結果です。 |
| s.empty() | 文字列が空(長さ 0)なら true を返します。 |
| s + t | 2 つの文字列を連結した新しい文字列を返します。 |
| s += t | 文字列 t を s の末尾に追加します。 |
| s.substr(pos, len) | 位置 pos から len 文字の部分文字列を返します。len を省略すると末尾まで取り出します。 |
| s.find(t) | 文字列 t が最初に現れる位置を返します。見つからなければ std::string::npos を返します。 |
| s.rfind(t) | 文字列 t が最後に現れる位置を返します。見つからなければ std::string::npos を返します。 |
| s.replace(pos, len, t) | 位置 pos から len 文字を文字列 t で置き換えます。 |
| s.at(i) | i 番目の文字を返します。範囲外アクセスは std::out_of_range 例外を投げます。 |
| s[i] | i 番目の文字を返します。範囲外チェックはありません。 |
| s.c_str() | null 終端の C 文字列(const char*)を返します。printf や C API との連携に使います。 |
| s.clear() | 文字列を空にします。 |
| s.erase(pos, len) | 位置 pos から len 文字を削除します。 |
| std::to_string(n) | 数値 n を std::string に変換します。int・long・double などに対応しています。 |
| std::stoi(s) | 文字列 s を int に変換します。stol / stof / stod なども同様です。 |
サンプルコード
eva_string.cpp
// ========================================
// eva_string.cpp — std::string の操作サンプルです
// エヴァンゲリオンのキャラクター名を使って
// 主要メソッドを一通り確認します
// ========================================
#include <iostream>
#include <string>
int main() {
// --- 宣言・初期化 ---
std::string firstName = "Shinji"; // 碇シンジです
std::string lastName = "Ikari"; // 苗字です
std::string pilotName = "Rei Ayanami"; // 綾波レイです
std::string callSign = "Unit-"; // エヴァの機体コールサインです
// --- 連結(+ 演算子)---
std::string fullName = firstName + " " + lastName;
std::cout << "フルネーム: " << fullName << std::endl;
// → Shinji Ikari
// --- += で末尾追加 ---
callSign += "01"; // Unit-01 になります
std::cout << "コールサイン: " << callSign << std::endl;
// → Unit-01
// --- size() で文字数確認 ---
std::cout << "pilotName の文字数: " << pilotName.size() << std::endl;
// → 11
// --- empty() で空判定 ---
std::string spare = "";
std::cout << "spare は空: " << std::boolalpha << spare.empty() << std::endl;
// → true
// --- substr() で部分文字列取得 ---
std::string firstName2 = pilotName.substr(0, 3); // "Rei" を取り出します
std::cout << "ファーストネーム: " << firstName2 << std::endl;
// → Rei
// --- find() で検索 ---
std::size_t pos = fullName.find("Ikari");
if (pos != std::string::npos) {
std::cout << "\"Ikari\" の位置: " << pos << std::endl;
// → 7
}
// --- replace() で置換 ---
// fullName 内の "Ikari" を "Rokubungi" に置き換えます(渚カヲルの苗字)
fullName.replace(pos, 5, "Rokubungi");
std::cout << "置換後: " << fullName << std::endl;
// → Shinji Rokubungi
// --- at() で文字アクセス ---
char initial = firstName.at(0); // 'S' を取り出します
std::cout << "イニシャル: " << initial << std::endl;
// → S
// --- c_str() で C 文字列に変換 ---
const char* cPilot = pilotName.c_str();
std::printf("printf 出力: %s\n", cPilot);
// → printf 出力: Rei Ayanami
// --- std::to_string() で数値を文字列に変換 ---
int unitNumber = 1;
std::string unitLabel = "EVA-" + std::to_string(unitNumber);
std::cout << "ユニット: " << unitLabel << std::endl;
// → EVA-1
// --- std::stoi() で文字列を数値に変換 ---
std::string scoreStr = "100";
int score = std::stoi(scoreStr);
std::cout << "シンクロ率: " << score + 41 << "%" << std::endl;
// → シンクロ率: 141%
return 0;
}
# C++17 規格でコンパイルします g++ -std=c++17 eva_string.cpp -o eva_string # 実行します(macOS / Linux) ./eva_string フルネーム: Shinji Ikari コールサイン: Unit-01 pilotName の文字数: 11 spare は空: true ファーストネーム: Rei "Ikari" の位置: 7 置換後: Shinji Rokubungi イニシャル: S printf 出力: Rei Ayanami ユニット: EVA-1 シンクロ率: 141%
数値変換と文字列操作の追加パターン
eva_string2.cpp
// ========================================
// eva_string2.cpp — erase・insert・rfind の確認サンプルです
// ========================================
#include <iostream>
#include <string>
int main() {
// --- erase() で部分削除 ---
std::string name = "Asuka Langley Soryu";
name.erase(6, 7); // "Langley" を削除します(位置 6 から 7 文字)
std::cout << "erase 後: " << name << std::endl;
// → Asuka Soryu
// --- insert() で挿入 ---
name.insert(6, "Shikinami "); // 位置 6 に挿入します
std::cout << "insert 後: " << name << std::endl;
// → Asuka Shikinami Soryu
// --- rfind() で後ろから検索 ---
std::string sentence = "Unit-01 Unit-02 Unit-01";
std::size_t last = sentence.rfind("Unit-01"); // 最後に現れる位置
std::cout << "最後の Unit-01 の位置: " << last << std::endl;
// → 16
// --- compare() で文字列比較 ---
std::string s1 = "Rei";
std::string s2 = "Rei";
std::string s3 = "Asuka";
std::cout << "s1 == s2: " << std::boolalpha << (s1 == s2) << std::endl;
// → true
std::cout << "s1 == s3: " << (s1 == s3) << std::endl;
// → false
// --- stod() で小数変換 ---
std::string syncRate = "141.7";
double rate = std::stod(syncRate);
std::cout << "シンクロ率(double): " << rate << std::endl;
// → 141.7
return 0;
}
# C++17 規格でコンパイルします g++ -std=c++17 eva_string2.cpp -o eva_string2 # 実行します ./eva_string2 erase 後: Asuka Soryu insert 後: Asuka Shikinami Soryu 最後の Unit-01 の位置: 16 s1 == s2: true s1 == s3: false シンクロ率(double): 141.7
よくあるミス: string と C 文字列の混同
std::string と const char*(C 文字列)は別の型です。+ 演算子で 2 つのリテラルをそのまま連結しようとするとコンパイルエラーになります。また、c_str() が返すポインタは元の string オブジェクトが変更・破棄されると無効になるため、ポインタを長期保持するのは危険です。
NG: リテラル同士の連結、c_str() ポインタの長期保持
// NG: リテラル同士の連結はできない(どちらも const char*)
// std::string result = "Rei " + "Ayanami"; // コンパイルエラー
// NG: c_str() のポインタを保存しておくのは危険
std::string result = "Rei Ayanami";
const char* ptr = result.c_str();
result += " Pilot"; // string が再確保されると ptr が無効になる可能性がある
// std::printf("%s\n", ptr); // 未定義動作の可能性あり
OK: 片方を std::string にする、c_str() は使う場所で渡す
// OK: 片方を std::string にする
std::string result = std::string("Rei ") + "Ayanami"; // "Rei Ayanami"
// または
std::string first = "Rei";
std::string result2 = first + " Ayanami"; // OK
// OK: c_str() は使うその場で渡す
std::printf("%s\n", result.c_str()); // その場で渡す
よくあるミス: substr の範囲外アクセス
substr(pos, len) の第 1 引数 pos が文字列長を超えると std::out_of_range 例外が送出されます。find() の戻り値が std::string::npos かどうかを確認せずに substr() に渡すのも同じ理由で危険です。
NG: npos チェックなしで substr() を呼ぶ
// NG: find() が npos を返した場合に無チェックで substr() を呼ぶ
std::string pilot = "Rei Ayanami";
std::size_t pos = pilot.find("Asuka"); // 見つからないので npos が返る
// std::string sub = pilot.substr(pos, 5);
// → pos == npos(非常に大きい値)なので std::out_of_range 例外
OK: npos チェックをしてから使う
std::string pilot = "Rei Ayanami";
std::size_t pos = pilot.find("Asuka");
if (pos != std::string::npos) {
std::string sub = pilot.substr(pos, 5);
std::cout << sub << std::endl;
} else {
std::cout << "見つかりませんでした" << std::endl;
}
概要
std::string は C++ 標準ライブラリが提供する文字列クラスで、#include <string> で使えるようになります。C 言語の char[] とは異なりメモリ管理が自動で、バッファオーバーフローの心配がありません。文字列の連結は + または += 演算子で直感的に書け、find() や replace() で検索・置換も簡単に行えます。find() が返す std::string::npos は「見つからなかった」を意味する特別な値なので、検索結果は必ず npos と比較して確認してください。数値との相互変換は std::to_string() と std::stoi()(または stol / stod)が担います。C ライブラリとの連携が必要なときは c_str() で const char* に変換してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。