拆分字符串以删除定界符后的所有内容
Splitting a string to remove everything after a delimiter
我正在尝试从 sip uri 中解析 phone 数字,或者如果字符串只是一个数字,则返回它。基本上,我想砍掉 @ 和它后面的任何东西(如果它存在的话)。
我使用 strtok()
写了一个小函数,但函数总是 returns 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.");
}
}
编辑
这个
If it's returning NULL
because the while
loops ends when q
is NULL
. So I
assume that the q = strtok (NULL, ":");
also returns NULL
and that's why it
leaves the loop.
不再有意义,因为您已经编辑了问题并删除了代码
有问题。
结束编辑
无论如何,你用错了。
strtok
returns 指向原始字符串的指针加上标记
下一个标记的开始。指针的偏移量为 buf
。所以当你
执行 free(buf)
,您会使 strtok
返回的指针也无效。
你还应该先检查 if malloc
returns 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 [=11=]-terminated because of calloc
return q;
}
你的代码工作正常,你只是不能在 return 之前 free(buf)
或者你释放持有 number
和 second
的内存导致 Undefined行为。您还需要验证每个步骤。建议如下:
(注意: 已更新以防止 sCallee
中的前导 '@'
或 p
中的前导 ':'
结果在 NULL
被 returned)
#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
的return,没必要。见:Do I cast the result of malloc?)
例子Use/Output
$ ./bin/strtokpnum
number: 2109999999
second: 2109999999
内存Use/Error检查
在您编写的任何动态分配内存的代码中,您对分配的任何内存块负有 2 责任:(1) 始终保留指向内存块的起始地址 因此,(2) 当不再需要它时可以释放。
对于Linux valgrind
是正常的选择。每个平台都有类似的内存检查器。它们都很简单易用,只需运行你的程序就可以了。
$ 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", "@", ":');
你受到保护。
(如果您从您的 sip uri 中获取类似的字符串,请修复该过程)
我正在尝试从 sip uri 中解析 phone 数字,或者如果字符串只是一个数字,则返回它。基本上,我想砍掉 @ 和它后面的任何东西(如果它存在的话)。
我使用 strtok()
写了一个小函数,但函数总是 returns 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.");
}
}
编辑
这个
If it's returning
NULL
because thewhile
loops ends whenq
isNULL
. So I assume that theq = strtok (NULL, ":");
also returnsNULL
and that's why it leaves the loop.
不再有意义,因为您已经编辑了问题并删除了代码 有问题。
结束编辑
无论如何,你用错了。
strtok
returns 指向原始字符串的指针加上标记
下一个标记的开始。指针的偏移量为 buf
。所以当你
执行 free(buf)
,您会使 strtok
返回的指针也无效。
你还应该先检查 if malloc
returns 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 [=11=]-terminated because of calloc
return q;
}
你的代码工作正常,你只是不能在 return 之前 free(buf)
或者你释放持有 number
和 second
的内存导致 Undefined行为。您还需要验证每个步骤。建议如下:
(注意: 已更新以防止 sCallee
中的前导 '@'
或 p
中的前导 ':'
结果在 NULL
被 returned)
#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
的return,没必要。见:Do I cast the result of malloc?)
例子Use/Output
$ ./bin/strtokpnum
number: 2109999999
second: 2109999999
内存Use/Error检查
在您编写的任何动态分配内存的代码中,您对分配的任何内存块负有 2 责任:(1) 始终保留指向内存块的起始地址 因此,(2) 当不再需要它时可以释放。
对于Linux valgrind
是正常的选择。每个平台都有类似的内存检查器。它们都很简单易用,只需运行你的程序就可以了。
$ 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", "@", ":');
你受到保护。
(如果您从您的 sip uri 中获取类似的字符串,请修复该过程)