1

C トークナイザーも参照してください。


これは私が書いた C 用の簡単な substr() です (はい、変数の初期化を関数の先頭などに移動する必要がありますが、アイデアはわかります)

私は、単純なワンライナー呼び出し strncpy() である substr() の多くの「スマートな」実装を見てきました!

それらはすべて間違っています (strncpy は null 終了を保証しないため、呼び出しによって正しい部分文字列が生成されない可能性があります!)

ここにもっと良いものがありますか?

バグを引き出す!

char* substr(const char* text, int nStartingPos, int nRun)
{
    char* emptyString = strdup(""); /* C'mon! This cannot fail */

    if(text == NULL) return emptyString;

    int textLen = strlen(text);

    --nStartingPos;

    if((nStartingPos < 0) || (nRun <= 0) || (textLen == 0) || (textLen < nStartingPos)) return emptyString;

    char* returnString = (char *)calloc((1 + nRun), sizeof(char));

    if(returnString == NULL) return emptyString;

    strncat(returnString, (nStartingPos + text), nRun);

    /* We do not need emptyString anymore from this point onwards */

    free(emptyString);
    emptyString = NULL;

    return returnString;
}


int main()
{
    const char *text = "-2--4--6-7-8-9-10-11-";

    char *p = substr(text, -1, 2);
    printf("[*]'%s' (\")\n",  ((p == NULL) ? "<NULL>" : p));
    free(p);

    p = substr(text, 1, 2);
    printf("[*]'%s' (-2)\n", ((p == NULL) ? "<NULL>" : p));
    free(p);

    p = substr(text, 3, 2);
    printf("[*]'%s' (--)\n", ((p == NULL) ? "<NULL>" : p));
    free(p);

    p = substr(text, 16, 2);
    printf("[*]'%s' (10)\n", ((p == NULL) ? "<NULL>" : p));
    free(p);

    p = substr(text, 16, 20);
    printf("[*]'%s' (10-11-)\n", ((p == NULL) ? "<NULL>" : p));
    free(p);

    p = substr(text, 100, 2);
    printf("[*]'%s' (\")\n", ((p == NULL) ? "<NULL>" : p));
    free(p);

    p = substr(text, 1, 0);
    printf("[*]'%s' (\")\n", ((p == NULL) ? "<NULL>" : p));
    free(p);

    return 0;
}

出力:

[*]'' (")
[*]'-2' (-2)
[*]'--' (--)
[*]'10' (10)
[*]'10-11-' (10-11-)
[*]'' (")
[*]'' (")
4

5 に答える 5

7

あなたの関数は、単純な操作であるべきものに対して非常に複雑に見えます。いくつかの問題があります (すべてがバグというわけではありません):

  • strdup()、およびその他のメモリ割り当て関数失敗する可能性があるため、考えられるすべての問題を考慮する必要があります。
  • 必要な場合にのみリソース (この場合はメモリ) を割り当てます。
  • エラーと有効な文字列を区別できるはずです。現時点では、のmalloc()失敗substr ("xxx",1,1)または作業substr ("xxx",1,0)によって空の文字列が生成されるかどうかはわかりません。
  • calloc()とにかく上書きすることを覚えておく必要はありません。
  • すべての無効なパラメーターは、エラーを引き起こすか、有効なパラメーターに強制する必要があります (API はどちらを文書化する必要があります)。
  • 解放した後にローカルの emptyString を NULL に設定する必要はありません。関数が戻ると失われます。
  • usr を使用する必要はありません。コピーを行う前に、使用可能なサイズとメモリを知ってstrncat()おく必要memcpy()があります。
  • 文字列オフセットに base-0 ではなく base-1 を使用していると、C の粒度に反します。

次のセグメントは、私がやりたいことです (文字列の末尾からカウントする負の値の Python イディオムが好きですが、末尾の位置ではなく長さを保持しています)。

char *substr (const char *inpStr, int startPos, int strLen) {
    /* Cannot do anything with NULL. */

    if (inpStr == NULL) return NULL;

    /* All negative positions to go from end, and cannot
       start before start of string, force to start. */

    if (startPos < 0)
        startPos = strlen (inpStr) + startPos;
    if (startPos < 0)
        startPos = 0;

    /* Force negative lengths to zero and cannot
       start after end of string, force to end. */

    if (strLen < 0)
        strLen = 0;
    if (startPos >strlen (inpStr))
        startPos = strlen (inpStr);

    /* Adjust length if source string too short. */

    if (strLen > strlen (&inpStr[startPos]))
        strLen = strlen (&inpStr[startPos]);

    /* Get long enough string from heap, return NULL if no go. */

    if ((buff = malloc (strLen + 1)) == NULL)
        return NULL;

    /* Transfer string section and return it. */

    memcpy (buff, &(inpStr[startPos]), strLen);
    buff[strLen] = '\0';

    return buff;
}
于 2009-05-17T10:33:52.740 に答える
1
char* emptyString = strdup(""); /* C'mon! This cannot fail? */

null をチェックする必要があります。null 文字に 1 バイトを割り当てる必要があることに注意してください。

于 2009-05-17T06:35:26.197 に答える
0

strdup が失敗する可能性があります (非常に可能性が低く、チェックする価値はありませんが、IMHO)。ただし、別の問題があります。これは標準 C 関数ではありません。malloc を使用することをお勧めします。

于 2009-05-17T06:48:48.740 に答える
0

memmove 関数を使用して、開始から長さまでの部分文字列を返すこともできます。paxdiablo のソリューションからの別のソリューションの改善/追加:

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>

    char *splitstr(char *idata, int start, int slen) {
            char ret[150];
            if(slen == NULL) {
                    slen=strlen(idata)-start;
            }
            memmove (ret,idata+start,slen);
            return ret;
    }

    /*
    Usage:
            char ostr[]="Hello World!";
            char *ores=splitstr(ostr, 0, 5);
            Outputs:
                    Hello
    */

それが役に立てば幸い。TCC C Compiler を使用した Windows 7 Home Premium でテスト済み。

于 2012-08-01T20:55:52.840 に答える