拆分字符串以在分隔符后删除所有内容

时间:2018-02-28 21:57:54

标签: c strtok

我正在尝试从sip uri中解析电话号码,或者如果字符串只是一个数字,则返回该数字。基本上,如果它存在,我想切断@及其后的任何内容 我使用strtok()编写了一个小函数,但该函数始终返回NULL 谁能告诉我我在这里做错了什么?

char* GetPhoneNumber(const char* sCallee) {
    char* buf = (char*)malloc(strlen(sCallee) + 1);
    strcpy(buf, sCallee);
    char *p = strtok (buf, "@");
    char *q = strtok (p, ":");
    if (buf) {
        free(buf);
    }
    return q;
}

int main() {
    const char* raw_uri = "2109999999@10.0.0.1";
    char* number = GetPhoneNumber(raw_uri);
    if (number == NULL) {
        printf("I am screwed! %s comes out null!", raw_uri);
    }
    char* second = GetPhoneNumber("2109999999");
    if (second == NULL) {
        printf("This does not work either.");
    }
}

2 个答案:

答案 0 :(得分:3)

修改

  

如果它返回NULL,因为当whileqNULL循环结束。所以我   假设q = strtok (NULL, ":");也返回NULL,这就是原因   离开了循环。

没有任何意义,因为您已经编辑了问题并删除了代码 问题。

结束修改

无论如何,你使用它是错误的。

strtok返回指向原始字符串的指针以及标记该字符串的偏移量 下一个标记的开头。指针的偏移量为buf。所以,当你 执行free(buf),您使strtok返回的指针也无效。

如果malloc返回NULL,您还应检查第一次,然后尝试解析 它。解析后检查malloc返回NULL是错误的。还有你 需要复制你要返回的值。

char* GetPhoneNumber(const char* sCallee) {
    char* buf = malloc(strlen(sCallee) + 1);
    if(buf == NULL)
        return NULL;

    strcpy(buf, sCallee);

    char *p = strtok (buf, "@");
    if(p == NULL)
    {
        // no token found
        free(buf);
        return NULL;
    }

    char *q = strtok (p, ":"); // makes no sense after your edit
                               // I don't see any colons in your input
                               // but I leave this to show you how
                               // it would be done if colons were present

    if(q == NULL)
    {
        // no token found
        free(buf);
        return NULL;
    }

    char *copy = malloc(strlen(q) + 1);
    if(copy == NULL)
    {
        free(buf);
        return NULL;
    }

    strcpy(copy, q);
    free(buf);

    return copy;
}

此外,当您调用此函数时,您必须记住释放指针 由GetPhoneNumber返回。

<强> EDIT2

说实话,我不明白为什么你甚至使用strtok如果数字出现之前 @。您可以改为使用strchr

char* GetPhoneNumber(const char* sCallee) {

    if(sCallee == NULL)
        return NULL;

    char *p = strchr(sCallee, '@');

    if(p == NULL)
        return NULL; // wrong format

    char *q = calloc(1, p - sCallee + 1);

    if(q == NULL)
        return NULL;

    strncpy(q, sCallee, p - sCallee);

    // q already \0-terminated because of calloc

    return q;
}

答案 1 :(得分:3)

您的代码运行正常,在返回之前您不能free(buf)或者释放持有numbersecond导致未定义行为的内存。您还需要验证每个步骤。建议类似:

注意:已更新,以防范'@'中的sCallee':'p中的NULL导致#include <stdio.h> #include <stdlib.h> #include <string.h> char *GetPhoneNumber(const char* sCallee) { if (*sCallee == '@') { /* protect against leading '@' */ fprintf (stderr, "invalid sCallee - leading '@'\n"); return NULL; } char* buf = malloc (strlen(sCallee) + 1); if (!buf) { /* if you allocate/validate */ perror ("malloc - buf"); return NULL; } strcpy(buf, sCallee); char *p = strtok (buf, "@"); /* get first token with '@' */ if (!p) { /* validate */ fprintf (stderr, "error: strtok with '@' failed.\n"); return NULL; } if (*p == ':') { /* protect against leading ':' */ fprintf (stderr, "invalid p - leading ':'\n"); free (buf); return NULL; } char *q = strtok (p, ":"); /* get first token with ':' */ // free(buf); return q; } int main () { const char* raw_uri = "2109999999:abc@10.0.0.1"; char* number = GetPhoneNumber(raw_uri); if (number == NULL) { printf("I am screwed! %s comes out null!\n", raw_uri); } else { printf ("number: %s\n", number); free (number); } char* second = GetPhoneNumber("2109999999"); if (second == NULL) { printf("This does not work either.\n"); } else { printf ("second: %s\n", second); free (second); } } 被退回)

malloc

注意:无需强制转换$ ./bin/strtokpnum number: 2109999999 second: 2109999999 ,这是不必要的。请参阅:Do I cast the result of malloc?

示例使用/输出

valgrind

内存使用/错误检查

在你编写的动态分配内存的任何代码中,你有2个职责关于任何分配的内存块:(1)总是保留一个指向起始地址的指针内存块,(2)当不再需要时,它可以释放

对于Linux $ valgrind ./bin/strtokpnum ==24739== Memcheck, a memory error detector ==24739== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==24739== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info ==24739== Command: ./bin/strtokpnum ==24739== number: 2109999999 second: 2109999999 ==24739== ==24739== HEAP SUMMARY: ==24739== in use at exit: 0 bytes in 0 blocks ==24739== total heap usage: 2 allocs, 2 frees, 35 bytes allocated ==24739== ==24739== All heap blocks were freed -- no leaks are possible ==24739== ==24739== For counts of detected and suppressed errors, rerun with: -v ==24739== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 是正常的选择。每个平台都有类似的记忆检查器。它们都很简单易用,只需通过它运行程序即可。

'@'

始终确认已释放已分配的所有内存并且没有内存错误。

防范所有角落案件

虽然不是问题的一部分,但在辅助字符串中可能存在多个前导':'和多个前导'@'等极端情况。如果您要防止在辅助字符串中有多个前导':'分隔符或多个前导sCallee的可能性,那么只需使用多重分配方法即可。添加任何其他检查,您也可以向下指针char *gettok (const char *s, const char *d1, const char *d2) { char *buf = malloc (strlen (s) + 1), *p = NULL, *q = NULL, *s2 = NULL; if (!buf) { /* validate allocation */ perror ("malloc - buf"); return NULL; } strcpy (buf, s); /* copy s to buf */ if (!(p = strtok (buf, d1))) { /* if token on d1 fails */ free (buf); /* free buf */ return NULL; } if (!(q = strtok (p, d2))) { /* if token on d2 fails */ free (buf); /* free buf */ return NULL; } /* allocate/validate return */ if (!(s2 = malloc (strlen (q) + 1))) { perror ("malloc - s2"); return NULL; } strcpy (s2, q); /* copy token */ free (buf); /* free buf */ return s2; /* return token */ }

gettok ("@@@@@:::::2109999999:abc@10.0.0.1", "@", ":');

在这种情况下,您只需致电

list.count(item)

你受到了保护。

(如果你从sip uri那里获得类似的字符串,请修复该过程)