如何在没有strtok的情况下拆分字符串?

时间:2016-10-31 01:39:19

标签: c string strtok c-strings

我是C的初学者,请不要打击我。 所以,我有这个函数获取" ip / mask"的掩码。字符串类型:

char *getmask(char n[]) {
    char x[255] = { 0 };
    strcpy(x, n);
    char *mask;
    mask = strtok(x, "/");
    mask = strtok(NULL, "/");
    return mask;
}

问题是我需要在多个" ip / mask"这些都在一个字符串中。所以当我这样做时:

net = strtok(x4, " ");
net = strtok(NULL, " ");
while (net != NULL) {
    net = strtok(NULL, " ");
    strcpy(masca, "\n");
    strcpy(masca, getmask(net));
    //some other code
}

问题在于strtok()发生故障,因为我在最初的时候调用了它,但随后又在getmask(net)中调用了它。

无论如何要绕过它?如果没有,我怎么能分裂一个字符串?

3 个答案:

答案 0 :(得分:2)

使用strtok_r()。它与strtok的行为相同,但允许您使用多个字符串"同时"。

char *strtok_r(char *str, const char *delim, char **saveptr);
  

strtok_r()函数是一个可重入的版本strtok()。 saveptr参数是一个指向char *变量的指针,该变量由strtok_r()在内部使用,以便在解析相同字符串的连续调用之间维护上下文。

     

在第一次调用strtok_r()时,str应指向要解析的字符串,并忽略saveptr的值。在后续调用中,str应为NULL,并且自上次调用以来saveptr应保持不变。

     

可以使用指定不同saveptr参数的strtok_r()调用序列同时解析不同的字符串。

来源:Linux人strtok_r

答案 1 :(得分:0)

您的函数getmask()调用未定义的行为:

  • 将字符串参数复制到本地数组x;
  • 你用strtok()解析它,它会将指针返回到同一个本地数组x
  • 将此指针mask返回给调用者。退出此功能后,此指针将变为无效。

您应该返回一个指向此数组的已分配副本的指针,以便在您返回调用方后它仍然有效。

此外,您确实应该避免使用strtok()因为它不可重入:正如您所注意到的,您无法使用此函数实现嵌套解析器。

其他函数可用于解析字符串:

  • strchr()在字符串中找到一个字符;
  • strstr()在字符串中找到子字符串;
  • strspn()匹配字符串开头的一组字符;
  • strcspn()匹配字符串开头的一组字符的补充;
  • 您也可以手动解析字符串,在循环中测试字符。

以下是一个例子:

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

char *getmask(const char *s) {
    /* allocate a copy of the mask part
     *  the mask starts after the first '/'
     *  and stops at the first space or another '/'
     */
    len - 0;
    s = strchr(s, '/');
    if (s != NULL) {
        s++;
        len = strcspn(s, "/ \t\r\n");
    }
    /* allocate space for the mask string */
    char *mask = malloc(len + 1);
    if (mask != NULL) {
        /* copy the mask string */
        memcpy(mask, s, len);
        mask[len] = '\0';
    }
    return mask;
}

该功能很麻烦但非常精确。它的行为与您对strtok()的行为几乎相同,唯一的区别是处理多个连续的/字节strtok()会跳过而strchr()不会。

以下是sscanf()的替代方案:

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

char *getmask(const char *s) {
    char mask[256];
    /* skip characters different from /, then skip slashes, then
     * copy characters until another / or whitespace
     */
    if (sscanf(s, "%*[^/]%*[/]%255[^/ \t\n]", mask) != 1) {
        *mask = '\0';
    }
    return strdup(mask);  /* POSIX function to allocate a copy of a string */
}

它更简单,但如果字符串以/开头,则会失败。

strdup()是分配字符串副本的非常有用的函数。它适用于POSIX兼容系统。它没有它,它可以很容易地实现为:

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

char *strdup(const char *s) {
    char *p = malloc(strlen(s));
    if (p != NULL) {
        strcpy(p, s);
    }
    return p;
}

getmask()分配的字符串应在不再需要时由free()释放。

在调用getmask()之前,您可以使用类似的方法将输入字符串解析为ip / mask地址对。

您还可以为getmask()提供目标缓冲区,以避免内存管理的复杂性:

char *getmask(char *dest, size_t size, const char *s) {
    if (dest != NULL && size > 0) {
        char mask[256];
        /* skip characters different from /, then skip slashes, then
         * copy characters until another / or whitespace
         * dest cannot be used directly because size cannot be passed
         * sscanf easily
         */
        *dest = '\0';
        if (sscanf(s, "%*[^/]%*[/]%255[^/ \t\n]", mask) != 1) {
            strncat(dest, mask, size - 1);
        }
    }
    return dest;
}

解析很棘手,因为你必须小心处理所有情况。规范通常不够精确,因此实施者必须为特殊情况做出选择。 C库提供的用于解析的工具陈旧且笨重,尤其是strtok()sscanf()。使用这些时要小心,即使是有经验的程序员也会因副作用和缺点而受到伤害。

答案 2 :(得分:0)

*不能用逗号分隔的字符串,如果那里有空值,例如“一,二,四,五,八”。

使用strtok()将返回“一个”,“两个”,“四个” ...,您可能会认为在“两个”之后将返回空字符串“”。尝试解析GPS接收器的输出时,这让我感到困惑。

请改为使用strtok(token,","),它像strsep()一样是线程安全的,但是将返回零长度的字符串,即前面的示例中的“一个”,“两个”,“”,“四个”...。

strtok_r()可能不在某些运行时库中,但是您可以通过在线搜索找到实现。