アプローチに最小限の変更を加えている場合は、この関数を使用できますmemmove()
。これは、独自の手動バージョンよりも高速になる可能性があります。memcpy()
メモリの領域が重複することは許可されていないため、あるコメンターのアドバイスに従って使用することはできません(重複した場合の動作は未定義です)。
ストレージのタイプやアルゴリズムを変更せずにできることは他にあまりありません。ただし、リンクされたリストを使用するように変更すると、より多くのメモリ割り当てを行うことになりますが、操作は大幅に効率的になります。割り当てが本当に問題である場合 (限られた組み込みシステムを使用している場合を除き、おそらくそうではないでしょう)、プール アロケーターまたは同様のアプローチが役立つ可能性があります。
編集: あなたの質問を読み直して、あなたが実際に Heapsort を使用していないと推測しています。配列がヒープに割り当てられ(つまり、 を使用malloc()
)、単純な挿入 sortを行っていることを意味します。その場合、以下の情報は直接的にはあまり役に立ちませんが、挿入ソートは、一括挿入の後に優れたソート アルゴリズム (たとえば、標準ライブラリ関数を使用して実装できるクイックソートqsort()
) に比べて非常に非効率的であることに注意してください。 )。完全にソートされた順序ではなく、最下位 (または最上位) の項目のみが必要な場合でも、Heapsort は有用な読み物です。
標準のヒープソートを使用している場合、この操作はまったく必要ありません。項目は配列の最後に追加され、「ヒープ化」操作を使用してそれらをヒープ内の正しい位置にスワップします。各スワップには、2 つのアイテムを交換するための一時変数が 1 つ必要です。コード スニペットのようにシャッフルする必要はありません。char
配列内のすべてが同じサイズ(固定サイズのインプレース文字列、またはおそらくポインターのいずれか)である必要がありますが、コードはすでにそれを想定しているようです(そして、標準配列で可変長文字列を使用するとやっているのはかなり奇妙なことです)。
厳密に言えば、ヒープソートは二分木で動作することに注意してください。配列を扱っているので、インデックスのノードの子がそれぞれインデックスに格納される連続した配列が使用される実装を使用していると思いn
ます。そうでない場合、またはヒープソートをまったく使用していない場合は、より役立つ回答を得るために何をしようとしているのかを詳しく説明する必要があります。2n
2n+1
編集: 以下は、上記の更新されたコードへの応答です。
解放中に問題が発生する主な理由は、メモリを踏みにじった場合です。つまり、割り当てた領域のサイズを超えて何かをコピーしている場合です。システムが割り当てを追跡するために使用している値を上書きし、通常はプログラムのクラッシュにつながるあらゆる種類の問題を引き起こすため、これは非常に悪いことです。
まず、メモリの割り当てと割り当て解除の性質について、少し混乱しているようです。の配列を割り当てますがchar*
、それ自体は問題ありません。char
次に、文字列ごとに配列を割り当てますが、これも問題ありません。free()
ただし、最初の配列を呼び出すだけです。これでは十分ではありません。free()
への各呼び出しに対応する への呼び出しがmalloc()
必要なので、割り当てた各文字列を解放してから初期配列を解放する必要があります。
次に、sizeToMove
の倍数に設定しますがsizeof(MAX_STRING_SIZE)
、これはほぼ確実に望んでいるものではありません。MAX_STRING_SIZE
これは、定数を格納するために使用される変数のサイズです。代わりに、必要ですsizeof(char*)
。一部のプラットフォームでは、これらは同じである可能性があり、その場合でも機能しますが、その保証はありません。たとえば、32 ビット プラットフォーム (int
とchar*
は同じサイズ) では動作すると思いますが、64 ビット プラットフォーム (同じサイズではない) では動作しません。
第三に、文字列定数 (例: "hello world"
) を割り当てられたブロックに割り当てることはできません。ここで行っているのは、ポインターの置き換えです。strncpy()
またはのようなものを使用memcpy()
して、割り当てられたブロックに文字列をコピーする必要があります。結果を無効にすることを保証しないという問題があるsnprintf()
ため、便宜上お勧めしますが、それはあなた次第です。strncpy()
第 4 に、アイテムをシャッフルするmemcpy()
のではなく、まだ使用しています。memmove()
new
最後に、 andを使用する必要があるというコメントを見ましたdelete
。これらに相当するものはありませんがrealloc()
、すべてが事前にわかっていれば問題ありません。あなたがやろうとしていることは次のようなものです:
bool addItem(const char *item, char *list[], size_t listSize, size_t listMaxSize)
{
// Check if list is full.
if (listSize >= listMaxSize) {
return false;
}
// Insert item inside list.
for (unsigned int i = 0; i < listSize; ++i) {
if (strcmp(list[i], item) > 0) {
memmove(list + i + 1, list + i, sizeof(char*) * (listSize - i));
list[i] = item;
return true;
}
}
// Append item to list.
list[listSize] = item;
return true;
}
私はそれをコンパイルしてチェックしていないので、off-by-one エラーなどに気をつけてください。この関数はmalloc()
、 andfree()
またはnew
andを使用するかどうかに関係なく機能するはずですが、もちろんポインターを格納するだけなので、保持する割り当てられたバッファーにdelete
文字列が既にコピーされていることを前提としています。item
もちろん、この関数の外で自分自身を更新する必要があることを思い出してくださいlistSize
。これは、配列内の正しいポイントにアイテムを挿入するだけです。関数が返された場合はtrue
、のコピーをlistSize
1 増やします。返されfalse
た場合は、十分なメモリを割り当てなかったため、アイテムは追加されませんでした。
また、C と C++ では、配列list
の構文&list[i]
とlist + i
は完全に同等であることに注意してくださいmemmove()
。理解しやすい場合は、呼び出し内で代わりに最初のものを使用してください。