0

演習の一環として、文字列圧縮アルゴリズムを少し書きました (基本的には、文字列 "aaaabbbccc" を受け取り、"a4b3c3" を返します)。コードは次のとおりです。

char *compress(char string[])
{
    char buffer[256];
    char *pBuffer = buffer;

    char* pStr = (string - 1);
    char currentCharacter = 0;
    int length = 0;

    while (*++pStr != 0)
    {
        currentCharacter = *pStr;
        int currentCharacterLength = 1;

        while ((*(pStr + 1) == currentCharacter) && (*pStr != 0))
        {
            currentCharacterLength++;
            ++pStr;
        }

        *pBuffer++ = currentCharacter;
        *pBuffer++ = (char)currentCharacterLength;
    }

    (*pBuffer) = 0;
    return buffer;
}

しかし、それを見ると、返された文字列の正しいサイズに実際に適合する別のバッファーを作成するべきではないかどうか疑問に思っています。明らかに、これを行うとより多くの処理時間が必要になりますが、より厳密なソリューションが得られます。だから私は、このようなものの一般的な慣行は何だろうと思っています。(一般的に)メモリのために速度を犠牲にする方が良いですか、それともそのままにしておく方が良いですか?

またはさらに良いことに、私が気付いていないこのソリューションを作成するより良い方法はありますか?

4

4 に答える 4

3

C++ の場合、実際には std::string 型を使用する方が適切な方法です。

もちろん、ポインター/配列/文字列がどのように動作するか、または C ライブラリを扱っているかを理解しようとしている場合は、ある時点で char を使用する必要があります。

関数から (char *) およびその他の種類のポインターを返すときの最大の問題は、そのポインターの所有権をどのように処理するかです。このポインターが指すコンテンツをいつ削除しますか? コードの複数のスコープで使用でき、あらゆる種類のメモリ リークや未処理の例外が発生する可能性があります。

C++ を使用している場合、関数からポインターを返す最善の方法は std::shared_ptr を使用することです。これは、そのポインターのメモリ解放を直接処理する必要がないためです。

ああ、もちろん、スタックに割り当てられたメモリへのポインターを返します。

char buffer[256];
char *pBuffer = buffer;

あなたのコードの最大の間違いです。

正しいアプローチは、それをヒープに割り当てることです。

char *pBuffer = new char[256]; 
于 2013-05-16T18:53:13.307 に答える
3

戻りbufferは未定義の動作です。関数が存在するとすぐに、そのバッファーの内容は何でもかまいません。メモリを動的に割り当てる必要があります-少なくとも、 return strdup(buffer).

これは C++ であるため、使用std::stringが推奨されます。メモリが適切に管理されるため、文字列のサイズを正しく推測できなくても、バッファ オーバーランは発生しません。圧縮された文字列が 256 文字を超えると、現在のソリューションは失敗します。をstd::stringベースにしたソリューションには、この欠点がありません。

于 2013-05-16T18:53:43.503 に答える
1

ポインターを使用する場合は、次のようにします。

 bool compress(char string[], char* encodedOut, int &encodedSize);

エンコードされた配列のサイズとスコープの問題が処理されることがわかります。

于 2013-05-16T19:05:03.847 に答える