vector (primarily) and
string::c_str and
string::data (secondarily) are the best way to communicate data with non-C++ APIs in general, and C libraries in particular.
vector 's storage is always contiguous, so accessing the address of its first element returns a pointer to its contents. Use
&*v.begin(), &v[0] , or
&v.front() to get a pointer to
v 's first element. To get a pointer to a
vector 's
n -th element, prefer to do the arithmetic first and take the address later (e.g.,
&v.begin()[n] or
&v[n] ) instead of fetching a pointer to
front and then doing pointer arithmetic (e.g.,
(&v.front())[n] ). This is because in the former case you are giving a checked implementation a crack at verifying that you don't access an element outside
v 's bounds (see Item 83).
Do not assume that
v.begin() returns a pointer to the first element, or in general that
vector iterators are pointers. Although some STL implementations do define
vector<T>::iterator s as bare
T* pointers, iterators can be, and increasingly are, full-blown types (see again Item 83).
Although most implementations use contiguous memory for
string , that's not guaranteed, so never take the address of a character in a
string and assume it points to contiguous memory. The good news is that
string::c_str always returns a null-terminated C-style string. (
string::data also returns a pointer to contiguous memory, except that it's not guaranteed to be zero-terminated.)
When you pass pointers into a
vector v 's data, C code can both read from and write to
v 's elements but must stay within
size 's bounds. A well-designed C API takes a maximum number of objects (up to
v.size() ) or a past-the-end pointer (
&*v.begin()+v.size() ).
If you have a container of
T objects other than
vector or
string and want to pass its contents to (or populate it from) a non-C++ API that expects a pointer to an array of
T objects, copy the container's contents to (or from) a
vector<T> that can directly communicate with the non-C++ API.