Although c_str() returns a null terminated version of the std::string, surprises may await when mixing C++ std::string with C char* strings.
Null characters may end up within a C++ std::string, which can lead to subtle bugs as C functions will see a shorter string.
Buggy code may overwrite the null terminator. This results in undefined behaviour.  C functions would then read beyond the string buffer, potentially causing a crash.
#include <string>
#include <iostream>
#include <cstdio>
#include <cstring>
int main()
{
    std::string embedded_null = "hello\n";
    embedded_null += '\0';
    embedded_null += "world\n";
    // C string functions finish early at embedded \0
    std::cout << "C++ size: " << embedded_null.size() 
              << " value: " << embedded_null;
    printf("C strlen: %d value: %s\n", 
           strlen(embedded_null.c_str()), 
           embedded_null.c_str());
    std::string missing_terminator(3, 'n');
    missing_terminator[3] = 'a'; // BUG: Undefined behaviour
    // C string functions read beyond buffer and may crash
    std::cout << "C++ size: " << missing_terminator.size() 
              << " value: " << missing_terminator << '\n';
    printf("C strlen: %d value: %s\n", 
           strlen(missing_terminator.c_str()), 
           missing_terminator.c_str());
}
Output:
$ c++ example.cpp
$ ./a.out
C++ size: 13 value: hello
world
C strlen: 6 value: hello
C++ size: 3 value: nnn
C strlen: 6 value: nnna�