4

独自のバージョンの strtok を開発しました。ポインターの使用を練習するだけです。

誰でもこれで制限を見ることができますか、とにかく私は改善できます.

void stvstrtok(const char *source, char *dest, const char token) 
{
    /* Search for the token. */
    int i = 0;
    while(*source)
    {
        *dest++ = *source++;
        if(*source == token)
        {
            source++;
        }
    }
    *dest++ = '\0';
    }

int main(void)
{
    char *long_name = "dog,sat ,on ,the,rug,in ,front,of,the,fire";
    char buffer[sizeof(long_name)/sizeof(*long_name)];

    stvstrtok(long_name, buffer, ',');

    printf("buffer: %s\n", buffer);

   getchar();

   return 0;
}
4

7 に答える 7

7

補足: 通常、「トークン」という言葉は、返される文字列の部分を表すために使用されます。区切り文字は、トークンを区切るものを記述するために使用されます。したがって、コードをより明確にするために、トークンの名前を delimiter に変更し、dest の名前を token_dest に変更する必要があります。

関数と strtok の違い:

関数と strtok にはいくつかの違いがあります。

  • 関数が行うことは、単にトークン区切り記号を削除することです
  • 関数を 1 回だけ呼び出して、文字列のすべての部分を処理します。strtok を使用すると、文字列の各部分に対して複数回呼び出します (最初のパラメーターとして NULL を使用してその後)。
  • strtok はソース文字列も破棄しますが、コードは独自のバッファーを使用します (あなたが行ったように独自のバッファーを使用する方が良いと思います)。
  • strtok は、最初のパラメーターが NULL である各呼び出しの後に、次のトークンの位置を格納します。この位置は、その後の呼び出しに使用されます。ただし、これはスレッドセーフではなく、関数はスレッドセーフになります。
  • strtok では複数の異なる区切り記号を使用できますが、コードでは 1 つのみを使用します。

そうは言っても、strtokの実装に近い関数ではなく、より良い関数を作成する方法について提案します。

関数を改善する方法 (strtok をエミュレートしない):

以下の変更を加えた方が良いと思います。

  • 関数が「次の」トークンを返すようにする
  • *source または *source == 区切り文字がある場合、ループから抜け出します
  • 次のトークンを含むソース文字列の最初の文字へのポインターを返します。このポインターは、後続の呼び出しに使用できます。
于 2009-03-23T16:01:42.807 に答える
3

このコードは、のようにはまったく機能しませんstrtok()。正確に何をしようとしていましたか?しかし、改善に関しては、コードに重大なバグがあります。sourceの発生数を差し引いたtoken長さがdest、非常に古典的なStackオーバーフローを取得した場合、これは現時点では皮肉なことのようです。 。mainこれはあなたが使用したものでは起こりませんが、他の場所で関数を使用すると、不確実性と絶望の淵へとあなたを導くことになります。

于 2009-03-23T19:30:45.223 に答える
1

また、strtok(...)は複数の区切り文字をサポートしています。strtok(...)を再実装するために使用できるstrspn(...)とstrcspn(...)の定義を調べてください。

于 2009-03-23T19:53:18.557 に答える
1

strtok() はいくつかの状態を保存するため、複数回呼び出して複数のトークンを取得できます。また、 strtok() はソース文字列を「分割」するため、それぞれがトークンである複数の宛先文字列を取得します。

私が見たところ、あなたのコードはすべて、トークン区切り記号に等しい入力文字を無視し、ソースのヌル終端にコピーし続けるだけです。

編集: さらに、2 つのシーケンス トークン セパレーターがあることを考慮してください: 最初のものは関数によって無視され、2 つ目は宛先に書き込まれますが、strtok() は 2 つ以上の区切り文字のシーケンスを単一の区切り文字として定義します (manページ: http://man.cx/?page=strtok )

于 2009-03-23T15:58:24.533 に答える
1

strtok は入力文字列を NUL 文字で破壊するため、一種の敵対的になります。

「,」が区切り文字である場合、「xyz,,pdq」の場合も考慮する必要があります。

この場合、関数に何をさせたいですか?

于 2009-03-23T19:40:29.320 に答える
1

ちなみに、long_name は char へのポインタ、sizeof(long_name) は sizeof(char*) です。long_name が指すサイズではありません。

于 2009-05-22T10:28:41.483 に答える
1

strtok を使用すると、すべてのトークンを反復処理できます。これは、ソース文字列が書き込み可能であると想定し、トークンの区切りで null を挿入することによって行われます。デスティネーション バッファは、ソース バッファ内の文字オフセットへのポインタです。この事実を使用して、いつ終了したかを知ることができます + また、呼び出し間で「状態」を保持します。

Strtok は、ソース文字列を破棄するため、使用するのに適した関数ではありません。また、再入可能ではありません。

于 2009-03-23T15:55:54.773 に答える