6

std ::stringからchar配列にコピーしたいVisualStudio2008 C ++ 03アプリケーションがありますが、文字列を切り捨てる必要がある場合でも、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;
}

例: 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::stringCスタイルの文字列を使用して実装されることが保証されていないという事実によるものですが、ほとんどの場合はおそらくそうです。

于 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してパフォーマンスを比較できます。

同様に、、、、、およびおそらく私が忘れてしまった他のものを比較して、strncpyどれが最適化されているかを確認できます。いずれの場合も、コピーするバイト数をとして計算できます。これにより、 (小さな文字列を大きなバッファにコピーする)という最も非効率的なケースも回避されます。std::copystd::copy_nstrcpy_sstd::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のCstrcpy_sはどうですか?

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

私はこれを好むstrncpy。(strcpy_sおよびそれより古いいとこstrlcpy)コピーループは、「\ 0」をコピーした後に終了しますが、strncpy常に指定されたバイト数を書き出します(ソース文字列が短い場合は「\ 0」でパディングします)。

于 2012-06-05T19:01:24.093 に答える