我正在尝试从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.");
}
}
答案 0 :(得分:3)
修改强>
此
如果它返回
NULL
,因为当while
为q
时NULL
循环结束。所以我 假设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)
或者释放持有number
和second
导致未定义行为的内存。您还需要验证每个步骤。建议类似:
(注意:已更新,以防范'@'
中的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那里获得类似的字符串,请修复该过程)