web-dev-qa-db-ja.com

null終了文字でchar配列をmemsetする方法は?

Null終端文字で文字配列全体をmemsetするための正しい安全な方法は何ですか?いくつかの使用法をリストできます。

...
char* buffer = new char [ARRAY_LENGTH];

//Option 1:             memset( buffer, '\0', sizeof(buffer) );
//Option 2 before edit: memset( buffer, '\0', sizeof(char*) * ARRAY_LENGTH );
//Option 2 after edit:  memset( buffer, '\0', sizeof(char) * ARRAY_LENGTH );
//Option 3:             memset( buffer, '\0', ARRAY_LENGTH );
...
  • これらのどれかが他のものよりも大きな利点がありますか?
  • 使用法1、2、または3ではどのような問題に直面しますか?
  • このリクエストを処理する最良の方法は何ですか?
13
Koray

オプション1と2は間違っています。最初のものは、配列のサイズの代わりにポインターのサイズを使用するため、おそらく配列全体に書き込むことはありません。 2番目はsizeof(char*)の代わりにsizeof(char)を使用するため、配列の終わりを超えて書き込みます。オプション3は大丈夫です。これも使用できます

_memset( buffer, '\0', sizeof(char)*ARRAY_LENGTH );
_

ただし、sizeof(char)は1であることが保証されています。

20
Dirk Holsopple

慣用的な方法は、配列の値を初期化することです:

_char* buffer = new char [ARRAY_LENGTH]();
_

オプション1は、最初のsizeof(char*)バイトのみを0に設定するか、ARRAY_LENGHT < sizeof(char*)の場合は未定義の動作になります。

オプション2 ARRAY_LENGTHバイトを超えて設定しようとしているため、未定義の動作が発生します。 sizeof(char*)は、ほぼ確実に1より大きいです。

ただし、これはC++(Cではnewなし)なので、代わりに_std::string_を使用することをお勧めします。

Cの場合(_new[]_ではなくmallocと仮定)、次を使用できます。

_memset( buffer, 0, ARRAY_LENGTH );
_
13
Luchian Grigore

質問は常に変化しているため、以下を定義します。

1:memset( buffer, '\0', sizeof(buffer) );

2a:memset( buffer, '\0', sizeof(char*) * ARRAY_LENGTH );

2b:memset( buffer, '\0', sizeof(char) * ARRAY_LENGTH );

3:memset( buffer, '\0', ARRAY_LENGTH );

「この配列をゼロにする最良の方法」ではなく、「memsetを呼び出す正しい方法は何か」という質問であれば、2bまたは3のどちらかが正しいです。 1と2aは間違っています。

2b対3でスタイル戦争を起こすことができます。sizeof(char)を含めるかどうか-それは冗長であるために除外する人もいます(通常はそうします)。 intの配列を設定する同じコードとの整合性。つまり、サイズが1であることがわかっていても、常にサイズに要素数を掛けます。考えられる結論の1つは、bufferが指す配列をmemsetする「最も安全な」方法です。

_std::memset(buffer, 0, sizeof(*buffer) * ARRAY_LENGTH);
_

もちろん、バッファのタイプが変更されても、このコードは正しいままです。ただし、すべてのタイプの_ARRAY_LENGTH_要素が引き続き存在し、すべてのビットが正しい初期値のままであることが条件です。

「C++はCではない」プログラマーに愛されているもう1つのオプションは次のとおりです。

_/* never mind how buffer is allocated */
std::fill(buffer, buffer + ARRAY_LENGTH, 0);
_

気になる場合は、コンパイラが_std::memset_への同等の呼び出しを最適化するのと同じコードにこれを最適化するかどうかを自分で確認できます。

char *buffer = new char [ARRAY_LENGTH]();は気の利いたものですが、実際にはC++ではほとんど役に立ちません。最初にnewを使用して配列を割り当てることはほとんどないからです。

std::string buffer(ARRAY_LENGTH, 0);は、バッファを管理する特定の方法を導入します。これは、必要な場合もそうでない場合もありますが、多くの場合はそうです。場合によっては_char buffer[ARRAY_LENGTH] = {0};_について多くのことが言われます。

5
Steve Jessop
  • これらのどれかが他のものよりも大きな利点がありますか?
  • 使用法1、2、または3ではどのような問題に直面しますか?

sizeof(buffer) == sizeof(char*)であるため、1番目は間違っています。

2番目と3番目は問題ありません。

  • このリクエストを処理する最良の方法は何ですか?

なぜだけではありません:

_buffer[0] = '\0';
_

これがchar配列である場合、なぜ残りの文字に煩わされるのでしょうか?最初のバイトをゼロに設定すると、bufferに_""_と同等のものがあります。

もちろん、すべてのbufferをゼロにしたい場合は、_std::fill_で答えを使用してください。これが適切な方法です。 std::fill(buffer, buffer + ARRAY_LENGTH, 0);を意味します。

3
PiotrNycz

C++で生の配列を絶対に使用する必要がある場合(これは非常に良い考えではありません)、次のようにします。

char* buffer = new char [ARRAY_LENGTH]();

C++の場合、memsetは一般的に無能な人の最後の避難所ですが、過去数か月以内に許容可能なパフォーマンスを得るには、現在のツールでは、独自の文字列クラスを実装するときにそのレベルまで下げる必要があることを学びました。

memsetが必要と思われるこれらの生の配列などの代わりに、例えばstd::string(上記の場合)、std::vectorstd::arrayなど.

C++ 11以降では、以下を選択します。

#include <array>

std::array<char, ARRAY_LENGTH> buffer{ '\0' };

buffer.fill('\0');
1
Amit G.

まあ、個人的に私はオプション3が好きです:

memset( buffer, '\0', ARRAY_LENGTH )

ARRAY_LENGTHは、まさにメモリを埋めたいものです。

0
Simon Lau

Option 3: memset( buffer, '\0', ARRAY_LENGTH ):は配列の長さのみを提供しますが、実際にはこのパラメーターはメモリの総バイト数です。

Option 1: memset( buffer, '\0', sizeof(buffer) ):は、bufferが_char*_であるため、間違った答えを返します。 sizeof(buffer)は、配列全体のサイズだけではなく、ポインター変数のサイズを提供します。

オプション2が正しい。

0
taufique