这是C的好子系统吗?

Poo*_*zer 1 c substring substr

另请参见C Tokenizer


这是我写的C的快速substr()(是的,变量初始化需要移动到函数的开始等,但你明白了)

我已经看到很多substr()的"智能"实现,简单的一行调用strncpy()!

它们都是错的(strncpy不保证空终止,因此调用可能不会产生正确的子字符串!)

这可能更好吗?

带出虫子!

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;
}
Run Code Online (Sandbox Code Playgroud)

输出:

[*]'' (")
[*]'-2' (-2)
[*]'--' (--)
[*]'10' (10)
[*]'10-11-' (10-11-)
[*]'' (")
[*]'' (")
Run Code Online (Sandbox Code Playgroud)

pax*_*blo 7

对于应该是简单的操作,您的功能似乎非常复杂.有些问题(并非所有这些都是错误):

  • strdup()和其他内存分配函数,可能会失败,您应该允许所有可能的问题.
  • 只在需要时分配资源(在这种情况下是内存).
  • 你应该能够区分错误和有效的蜇伤.目前,您不知道malloc()失败substr ("xxx",1,1)或工作是否substr ("xxx",1,0)产生空字符串.
  • calloc()无论如何你都不需要记忆.
  • 所有无效参数都应该导致错误或被强制转换为有效参数(并且您的API应该记录哪些参数).
  • 释放后,您不需要将本地emptyString设置为NULL - 它将在函数返回时丢失.
  • 你不需要使用usr strncat()- 在进行任何复制之前你应该知道你可用的大小和内存,以便你可以更快地使用(最有可能)memcpy().
  • 你使用base-1而不是base-0来进行字符串偏移与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;
}
Run Code Online (Sandbox Code Playgroud)


Chr*_*utz 5

NULL如果输入无效而不是malloc()ed空字符串,我会说返回.这样你就可以测试函数是否失败,if(p)而不是if(*p == 0).

此外,我认为你的函数泄漏内存,因为emptyString只有free()一个条件.你应该free()无条件地确保它,即在之前return.

至于你的注释strncpy()不是NUL - 终止字符串(这是真的),如果你calloc()用来分配字符串而不是malloc(),如果你分配比复制更多的一个字节,这将不会有问题,因为calloc()自动设置所有值(包括,在这种情况下,结束)为0.

我会给你更多的笔记,但我讨厌阅读camelCase代码.并不是说它有什么问题.

编辑:关于您的更新:

请注意,sizeof(char)无论您的系统如何,C标准都定义为1.如果你使用的是一个字节中使用9位的计算机(上帝保佑),那么sizeof(char)它仍然是1.并不是说它有任何问题sizeof(char)- 它清楚地显示了你的意图,并提供对称calloc()malloc()其他类型的调用.但sizeof(int)实际上是有用的(int在16和32-以及这些新奇的64位计算机上可以有不同的大小).你知道的越多.

我还要重申,与大多数其他C代码的一致性是返回NULL错误而不是"".我知道很多函数(比如strcmp())如果你传递它们可能会做坏事 - 这是可以预料的.但是C标准库(以及许多其他C API)采取的方式是"调用者负责检查NULL,而不是函数负责给他/她做好准备,如果他没有." 如果你想以另一种方式做到这一点,这很酷,但这与C界面设计中的一个更强大的趋势背道而驰.

另外,我会使用strncpy()(或memcpy())而不是strncat().使用strncat()(和strcat())模糊了你的意图 - 这会让某人看着你的代码认为你想要添加到字符串的末尾(你做了,因为之后calloc(),结束是开始),当你想要做的是设置串.strncat()使它看起来像你正在添加一个字符串,而strcpy()(或另一个复制例程)会使它看起来更像你的意图.在这种情况下,以下三行都做同样的事情 - 选择你认为最好的那一行:

strncat(returnString, text + nStartingPos, nRun);

strncpy(returnString, text + nStartingPos, nRun);

memcpy(returnString, text + nStartingPos, nRun);
Run Code Online (Sandbox Code Playgroud)

另外,strncpy()并且memcpy()可能比(小)更快/更高效strncat().

text + nStartingPos是相同的nStartingPos + text- 我会把第char *一个,因为我认为更清楚,但无论你想把它们放在哪个顺序取决于你.此外,它们周围的括号是不必要的(但很好),因为它+具有更高的优先级,.

编辑2:三行代码不做同样的事情,但在这种情况下,它们都会产生相同的结果.谢谢你抓住我.