5

私はいくつかのコードをJavaからCに移植していますが、これまでのところ順調に進んでいます。

StringBuilderただし、Javaには、次のようにを自由に使用する特定の関数があります。

StringBuilder result = new StringBuilder();
// .. build string out of variable-length data
for (SolObject object : this) {
    result.append(object.toString());
}
// .. some parts are conditional
if (freezeCount < 0) result.append("]");
else result.append(")");

SOはコード翻訳サービスではないことは承知していますが、上記のコードを翻訳してくれる人を求めているわけではありません。

このタイプの大量の文字列の連結をCで効率的に実行する方法を考えています。ほとんどは小さな文字列ですが、それぞれが条件によって決定されるため、単純なsprintf呼び出しにそれらを組み合わせることができません。

このタイプの文字列連結を確実に行うにはどうすればよいですか?

4

5 に答える 5

4

多数の「オブジェクト」を文字列に変換するためのかなり「賢い」方法は次のとおりです。

 char buffer[100];
 char *str = buffer;
 str += sprintf(str, "%06d", 123);
 str += sprintf(str, "%s=%5.2f", "x", 1.234567);

sprintfはコピーされた文字列の長さを返すため、これはかなり効率的です。したがって、戻り値でstrを前方に「移動」し、入力を続けることができます。

もちろん、真のJavaオブジェクトがある場合は、JavaスタイルのToString関数をCのprintfファミリで「%somethign」にする方法を理解する必要があります。

于 2013-01-10T23:23:51.863 に答える
2

のパフォーマンス上の問題は、宛先文字列への追加を開始する前にstrcat()、宛先文字列をスキャンして終了を見つける必要があることです。\0'

ただし、文字列を引数として使用するのではなく、ポインタを使用することを忘れstrcat()ないでください。

追加する文字列の終了を常に指す別のポインタを維持している場合は'\0'、そのポインタをの最初の引数として使用でき、strcat()毎回再スキャンする必要はありません。さらに言えば、strcpy()よりも評価者を使用できますstrcat()

このポインタの値を維持し、十分なスペースがあることを確認することは、演習として残されています。

注:strncat()宛先配列の終わりを上書きしないようにするために使用できます(ただし、データはサイレントに切り捨てられます)。strncpy()この目的での使用はお勧めしません。主題に関する私の暴言を参照してください。

システムがそれらをサポートしている場合、(非標準の)関数strcpy()strlcat()関数はこの種のことに役立ちます。どちらも、作成しようとした文字列の全長を返します。ただし、これらを使用すると、コードの移植性が低下します。一方、どこでも使用できるオープンソースの実装があります。

strlen()別の解決策は、追加する文字列を呼び出すことです。これは理想的ではありません。これは、2回、1回ずつ、1回ずつスキャンされるためstrcat()ですstrlen()。ただし、少なくとも、宛先文字列全体の再スキャンは回避されます。

于 2013-01-10T23:12:09.557 に答える
2

文字列を連結するときのパフォーマンス低下の原因は、メモリの再割り当てです。Joel Spolskyは、彼の記事Backtobasicsでこれについて説明しています。彼は、文字列を連結する素朴な方法について次のように説明しています。

シュレミエルは通りの画家としての仕事に就き、道路の真ん中に点線を描きます。初日、彼はペンキの缶を道路に持ち出し、300ヤードの道路を終えました。「それはかなりいいです!」上司は「あなたは速い労働者だ!」と言います。そして彼にコペイカを支払います。

翌日、シュレミエルは150ヤードしか完成しません。「まあ、それは昨日ほど良くはありませんが、あなたはまだ速い労働者です。150ヤードは立派です」と彼にコペイカを支払います。

翌日、シュレミエルは道路の30ヤードをペイントします。「たった30!」上司が叫ぶ。「それは受け入れられない!初日にあなたはその10倍の仕事をした!何が起こっているのか?」

「私はそれを助けることはできません」とシュレミエルは言います。「毎日、ペンキ缶からどんどん遠ざかっていきます!」

可能であれば、宛先バッファーを割り当てる前に、宛先バッファーのサイズを知る必要があります。strlenこれを行う唯一の現実的な方法は、連結するすべての文字列を呼び出すことです。次に、適切な量のメモリを割り当て、わずかに変更されたバージョンを使用してstrncpy、宛先バッファの最後へのポインタを返します。

// Copies src to dest and returns a pointer to the next available
// character in the dest buffer.
// Ensures that a null terminator is at the end of dest.  If
// src is larger than size then size - 1 bytes are copied
char* StringCopyEnd( char* dest, char* src, size_t size )
{
    size_t pos = 0;
    if ( size == 0 ) return dest;

    while ( pos < size - 1 && *src )
    {
        *dest = *src;
        ++dest;
        ++src;
        ++pos;
    }
    *dest = '\0';
    return dest;
}

size宛先バッファーの終わりまでの残りのバイト数になるようにパラメーターを設定する方法に注意してください。

テスト関数の例を次に示します。

void testStringCopyEnd( char* str1, char* str2, size_t size )
{
    // Create an oversized buffer and fill it with A's so that 
    // if a string is not null terminated it will be obvious.
    char* dest = (char*) malloc( size + 10 ); 
    memset( dest, 'A', size + 10 );
    char* end = StringCopyEnd( dest, str1, size );
    end = StringCopyEnd( end, str2, size - ( end - dest ) );
    printf( "length:  %d - '%s'\n", strlen( dest ), dest );
}

int main(int argc, _TCHAR* argv[])
{
    // Test with a large enough buffer size to concatenate 'Hello World'.
    // and then reduce the buffer size from there
    for ( int i = 12; i > 0; --i )
    {
        testStringCopyEnd( "Hello", " World", i );
    }
    return 0;
}

生成するもの:

length:  11 - 'Hello World'
length:  10 - 'Hello Worl'
length:  9 - 'Hello Wor'
length:  8 - 'Hello Wo'
length:  7 - 'Hello W'
length:  6 - 'Hello '
length:  5 - 'Hello'
length:  4 - 'Hell'
length:  3 - 'Hel'
length:  2 - 'He'
length:  1 - 'H'
length:  0 - ''
于 2013-01-10T23:43:05.297 に答える
1

このような操作が非常に頻繁に行われる場合は、独自のバッファクラスに実装できます。例(簡潔にするためにエラー処理は省略されています;-):

struct buff {
        size_t used;
        size_t size;
        char *data;
        } ;

struct buff * buff_new(size_t size)
{
struct buff *bp;
bp = malloc (sizeof *bp);
bp->data = malloc (size);
bp->size = size;
bp->used = 0;
return bp;
}

void buff_add_str(struct buff *bp, char *add)
{
size_t len;
len = strlen(add);

        /* To be implemented: buff_resize() ... */
if (bp->used + len +1 >= bp->size) buff_resize(bp, bp->used+1+len);

memcpy(buff->data + buff->used, add, len+1);

buff->used += len;
return;
}
于 2013-01-10T23:37:32.427 に答える
0

strcat文字列が非常に小さく見えることを考えると、パフォーマンスが問題になる場合は、使用して再検討する傾向があります。

文字列の長さを記憶する独自のメソッドを作成して、文字列を反復処理して末尾を見つける必要がないようにすることができます(長い文字列に多くの追加を行う場合、これは潜在的にstrcatの遅いビットです)

于 2013-01-10T23:12:08.060 に答える