我是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)
中调用了它。
无论如何要绕过它?如果没有,我怎么能分裂一个字符串?
答案 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()
可能不在某些运行时库中,但是您可以通过在线搜索找到实现。