也可以看看 C 分词器


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

我见过许多 substr() 的“智能”实现,它们都是简单的一个衬垫调用 strncpy()!

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

这可能是更好的东西吗?

把 bug 拿出来!

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-)
[*]'' (")
[*]'' (")
有帮助吗?

解决方案

我想说的回报NULL如果输入不超过malloc()ed空字符串,而有效。这样,你可以测试功能是否失败或不符合if(p)而非if(*p == 0)

另外,我想是因为emptyString在一个条件仅free()d你的函数泄漏内存。你应该确保你的free()前右return它无条件地,即。

至于在strncpy()您的评论不是NUL终止字符串(这是真的),如果使用calloc()分配的字符串,而不是malloc(),这不会,如果你分配比复制一个字节更是一个问题,因为calloc()自动设定所有值(包括,在这种情况下,端部)设置为0。

我会给你更多的音符,但我讨厌读书驼峰代码。不是说有什么错。

编辑:至于你的更新:

注意,C标准定义sizeof(char)为1不管你的系统的。如果您使用的是在一个字节使用9位(但愿)的计算机,sizeof(char)仍在为1。不是说有什么不好说sizeof(char) - 这清楚地表明你的意图,并提供对称调用calloc()malloc()对于其他类型。但sizeof(int)实际上是有用的(ints可以在16位和32位和这些新奇64位计算机不同的尺寸)。你知道的越多。

我还想重申与大多数其它的C代码的一致性是上的错误,而不是返回NULL ""。我知道许多功能(如strcmp())可能会做不好的事情,如果你将它们传递NULL - 这是可以预期的。但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);

另外,strncpy()memcpy()将可能是一个(凌晨小)位更快/比strncat()更有效。

text + nStartingPos相同nStartingPos + text - 我会把char *第一,因为我认为这是更清晰,但你要把他们是你的什么顺序。此外,他们周围的括号是不必要的(但很好),因为+具有比,更高的优先级。

EDIT 2:三行代码不做同样的事情,但在这种情况下它们都将产生相同的结果。感谢赶上我这句话。

其他提示

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

  • strdup(), ,以及其他内存分配函数, 如果失败,您应该考虑到所有可能的问题。
  • 仅在需要时分配资源(在本例中为内存)。
  • 你应该能够区分错误和有效的刺痛。此刻,你不知道是否 malloc() 的失败 substr ("xxx",1,1) 或正在工作的 substr ("xxx",1,0) 产生一个空字符串。
  • 你不需要 calloc() 无论如何你都会覆盖的记忆。
  • 所有无效参数都应该导致错误或强制为有效参数(并且您的 API 应记录哪些参数)。
  • 释放本地空字符串后,无需将其设置为 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;
}
char* emptyString = strdup(""); /* C'mon! This cannot fail? */

您需要检查空。请记住,它仍然必须为空字符分配1个字节。

的strdup可能会失败(尽管它是不太可能,不值得检查,恕我直言)但它确实有一个问题 - 这是不是一个标准的C函数。这将是更好的使用malloc。

您还可以使用的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
    */

希望它能帮助。测试在Windows 7家庭高级与TCCÇCompilier。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top