はじめに
C++のstd::vectorやstd::stringは、内部的に連続したメモリ領域(配列)を使ってデータを管理しています。通常、これらのコンテナの要素には .at() や [] 演算子でアクセスしますが、時には、C言語スタイルの古い関数(printf や memcpy など)と連携するために、コンテナが管理する生データへの直接的なポインタが必要になることがあります。
この記事では、std::vector と std::string が持つ、内部データへのポインタを取得するための2つの重要なメンバ関数、.data() と .c_str() について解説します。
1. .data() メンバ関数 (vector, string, array)
.data() メンバ関数は、コンテナが管理するメモリ領域の先頭要素を指すポインタを返します。
サンプルコード
このコードは、vector<char> の内容を、.data() で取得したポインタを使って、C言語スタイルの char 配列に memcpy でコピーします。
#include <iostream>
#include <vector>
#include <cstring> // memcpy
using namespace std;
int main() {
vector<char> char_vector = {'H', 'e', 'l', 'l', 'o'};
// コピー先のC言語スタイルchar配列
char char_buffer[10] = {}; // ゼロで初期化
// 1. .data()でvectorの先頭要素へのポインタを取得
// 2. memcpyで、vectorの全要素をbufferにコピー
memcpy(char_buffer, char_vector.data(), char_vector.size());
cout << "コピーされたC言語スタイルの文字列: " << char_buffer << endl;
return 0;
}
解説: memcpy のようなC言語の関数は、std::vector を直接受け取ることはできませんが、.data() が返す char* 型のポインタを渡すことで、シームレスに連携できます。
注意点: .data() が返すポインタは、vector の再確保(push_back などで capacity が変化する時)が起こると無効になります。取得したポインタは、再確保が起こらないことが保証される短い寿命で使う必要があります。
2. .c_str() メンバ関数 (string のみ)
.c_str() メンバ関数は、std::string の内容を表す、終端Null文字 (\0) で終わるC言語スタイルの文字列へのポインタ(const char*)を返します。
サンプルコード
#include <iostream>
#include <string>
using namespace std;
int main() {
string my_string = "Welcome";
// .c_str()で、終端ヌル文字付きのC文字列へのポインタを取得
const char* c_style_string = my_string.c_str();
// printfのような、C言語スタイルの文字列を要求する関数に渡すことができる
printf("C言語スタイルで出力: %s\n", c_style_string);
return 0;
}
.data() と .c_str() の違い (C++11以降)
C++11以降、std::string の .data() も、.c_str() と同様に、終端Null文字で終わる文字列へのポインタを返すことが保証されるようになりました。そのため、現代のC++では、両者はほぼ同じように使えます。
.c_str():const char*を返す。伝統的にC言語関数との連携で使われる。.data():const char*を返す(C++11以降)。std::vectorなど他のコンテナとの一貫性がある。
まとめ
今回は、std::vector や std::string の内部データへの生ポインタを取得する方法を解説しました。
.data():vector,string,arrayなどで利用でき、コンテナの先頭要素へのポインタを返す。.c_str():string専用で、終端ヌル文字付きのC言語スタイル文字列へのポインタを返す。- これらの関数は、主にC言語スタイルのAPIや関数との連携のために使われる。
通常はコンテナのメンバ関数(.at(), []など)を使う方が安全ですが、C言語ライブラリと連携する必要がある場合に、これらの関数は不可欠な架け橋となります。
