C++ 从std::string复制到char数组并使用null终止结果

C++ 从std::string复制到char数组并使用null终止结果,c++,string,C++,String,我有一个VisualStudio2008C++03应用程序,我想从std::string复制到char数组,但是我需要将char数组以null结尾,即使它必须截断字符串才能这样做 例如,这可以根据需要工作: inline void CopyAndNullTerminate( const std::string& source, char* dest,

我有一个VisualStudio2008C++03应用程序,我想从std::string复制到char数组,但是我需要将char数组以null结尾,即使它必须截断字符串才能这样做

例如,这可以根据需要工作:

inline void CopyAndNullTerminate( const std::string& source, 
                                  char* dest, 
                                  size_t dest_size )
{
    source.copy( dest, dest_size );
    using std::min;
    char* end = dest + min( dest_size - 1, source.size() );
    *end = '\0';
}

int main()
{
    enum{ MAX_STRING_SIZE = 15 };
    char dest[ MAX_STRING_SIZE ];
    std::string test = "This is a test";

    CopyAndNullTerminate( test, dest, MAX_STRING_SIZE );

    assert( strcmp( test.c_str(), dest ) == 0 );
    return 0;
}
例如:

有没有一种更短、更有效的方法

谢谢是的,请使用
cstring
中定义的:

void copyString(const std::string& input, char *dst, size_t dst_size)
{
    strncpy(dst, input.c_str(), dst_size - 1);
    dst[dst_size - 1] = '\0';
}

请注意,对于
std::string
(正如@K-ballo所指出的)的一些实现,这可能更短,但效率更低。这是因为
std::string
不能保证使用C-syle字符串实现,尽管在大多数情况下可能是这样。

好的ole'C strcpy如何

strcpy_s(dest, MAX_STRING_SIZE, test.c_str());

我更喜欢这个而不是strncpy。
strcpy\u s
(以及它的前辈
strlcpy
)复制循环将在复制“\0”后终止,但
strncpy
将始终写出指定的字节数(如果源字符串较短,则用“\0”填充)。

如果首先初始化目标字符串(为null),然后,如果不覆盖数组中的最后一个元素,它将以null结尾

enum{ MAX_STRING_SIZE = 15 };

char dest[ MAX_STRING_SIZE ] = {0}; // all elements are initialized to 0
std::string test = "This is a test";

// determine the length to copy, it will be the min of MAX_STRING_SIZE-1 
// or test.size.  This will ensure that even if the string it shorter than
// the MAX_STRING_SIZE, that it will copy properly -- without reading past the
// array bounds of the string.
auto copy_len = std::min(test.size(), MAX_STRING_SIZE - 1);

std::copy(
   test.begin(),
   test.begin() + copy_len,
   dest);

这将最多向
dest
对象复制14个字符。如果测试字符串短于14个字符,它将只复制测试字符串的长度。所有未复制的元素将保持其初始值(null)。

假设
dest_size
保证至少为1(这对我来说似乎是合理的,因为否则不可能将任何内容复制和null终止到缓冲区中):

在C++11和所有主动维护的C++03实现(包括Visual Studio)中,
std::string
具有连续存储,就像
std::vector
一样。因此,您可以使用
memcpy
而不是
std::string::copy
并比较性能

同样,您可以比较
strncpy
std::copy
std::copy\n
strcpy\s
,以及我可能忘记的其他内容,看看哪一个优化得最好。在每种情况下,您都可以将要复制的字节数计算为
std::min(source.size(),dest\u size-1)
。这还避免了最低效的情况,即
strncpy
(将小字符串复制到大缓冲区)


在执行所有这些操作时,您可以依赖这样一个事实:调用
源代码[0]
是有效的,即使
源代码是空字符串。

这里有几个较短的字符串:

inline void CopyAndNullTerminate( const std::string& source, 
                                  char* dest, 
                                  size_t dest_size )
{
    *dest = '\0'; // assumes `dest_size > 0`
    strncat(dest, source, dest_size);
}

void CopyAndNullTerminate(std::string const &source,
                          char *dest,
                          size_t dest_size) { 
    sprintf(dest, "%*s", dest_size, source.c_str());
}

高效可能还有更多的问题,但我看不出有任何理由相信这两种方法都会特别慢。

这有一个不幸的副作用,那就是必须为
std::string
的那些实现构造一个有效的以null结尾的C字符串,而这些实现不使用它作为内部表示。@K-ballo true,但对于大多数实现,我假设这就是所使用的实现……效率低下的真正原因是它用空值填充缓冲区,即使只需要一个。@PaulH不,这是必要的,因为如果
strncpy
达到分配大小的末尾,它不会自动追加
\0
。@RichardJ.RossIII-
strncpy
在我的测试中似乎是
std::string::copy
的两倍。所以,你赢了!不幸的是,
strlcpy
不是C标准的一部分,据我所知,它是一个BSD函数,在VS 2008中不可用。@RichardJ.RossIII,顺便说一句,我喜欢这些函数的原因是
strncpy
总是写出第三个参数中指定的字节数,如果源字符串长于指定的字节,则不以null结尾。@user315052-函数不会自动截断。他们反而因不快乐而爆发。
inline void CopyAndNullTerminate( const std::string& source, 
                                  char* dest, 
                                  size_t dest_size )
{
    *dest = '\0'; // assumes `dest_size > 0`
    strncat(dest, source, dest_size);
}

void CopyAndNullTerminate(std::string const &source,
                          char *dest,
                          size_t dest_size) { 
    sprintf(dest, "%*s", dest_size, source.c_str());
}