6

我有一个 Visual Studio 2008 C++03 应用程序,我想在其中从 std::string 复制到 char 数组,但我需要 char 数组以空终止,即使它必须截断字符串才能这样做。

例如,这可以按需要工作:

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;
}

示例:http: //ideone.com/0EBYb

有没有更短、更有效的方法来做到这一点?

谢谢

4

5 回答 5

12

是的,使用strncpy,定义在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 样式字符串来实现,尽管在大多数情况下可能是这种情况。

于 2012-06-05T18:58:37.507 回答
9

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

inline void CopyAndNullTerminate( const std::string& source, 
                                  char* dest, 
                                  size_t dest_size )
{
    dest[source.copy(dest, dest_size-1)] = 0;
}

在 C++11 和所有积极维护的 C++03 实现(包括 Visual Studio)中,std::string具有连续存储,就像std::vector. 因此,您可以使用memcpy代替std::string::copy并比较性能。

同样,您可以比较strncpystd::copystd::copy_nstrcpy_s以及可能我忘记的其他内容,看看哪个是最佳优化的。在每种情况下,您都可以将要复制的字节数计算为std::min(source.size(), dest_size-1). 这也避免了最低效的情况strncpy(将小字符串复制到大缓冲区中)。

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

于 2012-06-05T20:10:30.003 回答
4

如果您首先初始化您的目标字符串(为 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);

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

于 2012-06-05T19:09:28.353 回答
3

这里有一对更短的:

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());
}

效率可能会引发更多问题,但我认为没有任何理由相信两者都会特别慢。

于 2012-06-05T20:26:05.400 回答
1

好的 ole' C strcpy_s 怎么样?

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

我更喜欢这个strncpy。(strcpy_s和它的老表亲strlcpy)复制循环将在复制 '\0' 后终止,但strncpy总是会写出指定的字节数(如果源字符串较短,则用 '\0' 填充)。

于 2012-06-05T19:01:24.093 回答