web-dev-qa-db-ja.com

バッファを越えずに文字列をC ++のchar配列にコピーする方法

文字列をchar配列にコピーし、バッファをオーバーランさせたくない。

したがって、サイズ5のchar配列がある場合は、文字列から最大5バイトをコピーします。

それを行うコードは何ですか?

21
neuromancer

まず第一に、 strncpy はほぼ確実にnot欲しいものです。 strncpyは、かなり特定の目的のために設計されました。標準ライブラリにあるのは、それが一般的に有用だからではなく、すでに存在しているからです。

おそらくあなたがしたいことをする最も簡単な方法は次のようなものです:

sprintf(buffer, "%.4s", your_string.c_str());

strncpyとは異なり、これは結果がNULで終了することを保証しますが、ソースが指定よりも短い場合、ターゲットに余分なデータを入力しません(ターゲットの長さが5)。

20
Jerry Coffin

これはまさにstd::stringのコピー機能は機能します。

#include <string>
#include <iostream>

int main()
{

    char test[5];
    std::string str( "Hello, world" );

    str.copy(test, 5);

    std::cout.write(test, 5);
    std::cout.put('\n');

    return 0;
}

Null終了が必要な場合は、次のようにする必要があります。

str.copy(test, 4);
test[4] = '\0';
39
CB Bailey

機能を使用 strlcpyリンク切れ、リンク先サイトで素材が見つかりません 実装が1つを提供する場合(関数は標準Cライブラリにありません)、それでもゼロ終了文字列の「安全な」制限された長さのコピー関数の事実上の標準名としてかなり広く受け入れられています。

実装がstrlcpy関数を提供しない場合、自分で実装します。たとえば、このような何かがあなたのために働くかもしれません

char *my_strlcpy(char *dst, const char *src, size_t n)
{
  assert(dst != NULL && src != NULL);

  if (n > 0)
  {
    char *pd;
    const char *ps;

    for (--n, pd = dst, ps = src; n > 0 && *ps != '\0'; --n, ++pd, ++ps)
      *pd = *ps;

    *pd = '\0';
  }

  return dst;
}

(実際には、事実上受け入れられたstrlcpysize_tので、私が上でやったのではなく、受け入れられた仕様を実装することを好むかもしれません。

その目的で strncpy を使用することを推奨する回答に注意してください。 strncpyは安全な制限された長さの文字列コピー関数ではなく、その目的で使用されることは想定されていません。その目的のためにstrncpyを強制的に「動作」させることができますが、それでもハンマーで木ねじを打つことに似ています。

7
AnT

一部のNice libcバージョンは、非標準ですが、strcpy(3)/strncpy(3)- strlcpy(3) の優れた代替品を提供します。

そうでない場合、ソースコードは自由に入手できます here from OpenBSD repository.

3

更新:いくつかの答えを結び付けようと思ったのですが、私自身の最初のひざまずきの反応は貧弱だと確信していた答えです。

まず、AndreyTがこの質問へのコメントで述べたように、切り捨て方法(snprintf、strlcpy、およびstrncpy)は、しばしば良い解決策ではありません。多くの場合、文字列string.size()のサイズをバッファーの長さに対してチェックし、エラーを返す/スローするか、バッファーのサイズを変更する方が適切です。

あなたの状況で切り捨てがOKなら、IMHO、 strlcpy が最良の解決策であり、ヌル終端を保証する最速/最小のオーバーヘッド方法です。残念ながら、多く/すべての標準ディストリビューションには含まれていないため、移植性はありません。これらの多くを行っている場合、独自の実装を提供する価値があるかもしれません、AndreyTは example を与えました。 O(result length)で実行されます。また、参照仕様はコピーされたバイト数を返します。これは、ソースが切り捨てられたかどうかの検出に役立ちます。

他の良い解決策は sprintfsnprintf です。これらは標準であるため、移植性があり、安全なnull終了結果を提供します。 strlcpy(フォーマット文字列指定子と変数引数リストの解析)よりもオーバーヘッドが大きくなりますが、これらの多くを実行しない限り、おそらく違いに気付かないでしょう。また、O(result length)で実行されます。 snprintfは常に安全であり、書式指定子を間違えるとsprintfがオーバーフローする可能性があります(他の人が指摘したように、書式文字列は_"%.<N>s"_ではなく_"%<N>s"_である必要があります)。これらのメソッドは、コピーされたバイト数も返します。

特別な場合の解決策は strncpy です。 O(buffer length)で実行されます。これは、srcの最後に到達すると、バッファの残りをゼロで消去するためです。バッファのテールをゼロにする必要がある場合、または宛先とソースの文字列の長さが同じであると確信している場合にのみ有用です。また、文字列が必ずしもヌルで終了するわけではないため、安全ではないことに注意してください。ソースが切り捨てられた場合、nullは追加されないので、nullを確実に終了するためにnull割り当てを使用して順番に呼び出してください:strncpy(buffer, str.c_str(), BUFFER_LAST); buffer[BUFFER_LAST] = '\0';

3
academicRobot
void stringChange(string var){

    char strArray[100];
    strcpy(strArray, var.c_str()); 

}

これでうまくいくと思います。フォーム文字列をchar配列にコピーします。

2
Sunil

snprintf()は非常に安全でシンプルだと思います

snprintf ( buffer, 100, "The half of %d is %d", 60, 60/2 );

ヌル文字は自動的に追加されます:)

1
Dark Corp
_std::string str = "Your string";
char buffer[5];
strncpy(buffer, str.c_str(), sizeof(buffer)); 
buffer[sizeof(buffer)-1] = '\0';
_

Strncpyは文字列をNULで終了させることが保証されていないため、最後の行が必要です(昨日、動機についての議論がありました)。

sizeof(buffer)の代わりにワイド文字列を使用した場合、sizeof(buffer)/sizeof(*buffer)を使用します。

_#define ARRSIZE(arr)    (sizeof(arr)/sizeof(*(arr)))
/* ... */
buffer[ARRSIZE(buffer)-1]='\0';
_
0
Matteo Italia
char mystring[101]; // a 100 character string plus terminator
char *any_input;
any_input = "Example";
iterate = 0;
while ( any_input[iterate] != '\0' && iterate < 100) {
    mystring[iterate] = any_input[iterate];
    iterate++;
}
mystring[iterate] = '\0';

これが基本的な効率的な設計です。

0
user922475
std::string my_string("something");
char* my_char_array = new char[5];
strncpy(my_char_array, my_string.c_str(), 4);
my_char_array[4] = '\0'; // my_char_array contains "some"

strncpy を使用すると、最大でn文字をコピー元からコピー先にコピーできます。ただし、ソース文字列の長さが最大n文字の場合、宛先はヌルで終了しません。終端のヌル文字を自分で挿入する必要があります。

長さが5のchar配列には、最大で4文字の文字列を含めることができます。これは、5番目が終端のヌル文字でなければならないためです。したがって、上記のコードでは、n= 4。

0
Péter Török