【发布时间】:2011-06-26 07:11:16
【问题描述】:
如何在 C 中检查读取的字符串中的子字符串?
如果我有以下情况
char name[21];
fgets(name, 21, stdin);
如何检查字符串中的一系列子字符串?
如何在字符之前检查子字符串?例如,如何检查= 符号之前的子字符串?
【问题讨论】:
-
发布示例输入字符串。如果 strtok 无法对其进行标记,那么您可能只需要逐个字符地扫描并挑选出子字符串。
如何在 C 中检查读取的字符串中的子字符串?
如果我有以下情况
char name[21];
fgets(name, 21, stdin);
如何检查字符串中的一系列子字符串?
如何在字符之前检查子字符串?例如,如何检查= 符号之前的子字符串?
【问题讨论】:
警惕strtok();它不是可重入的。除此之外,这意味着如果您需要在一个函数中调用它,然后再调用另一个函数,并且如果另一个函数也使用strtok(),那么您的第一个函数就搞砸了。它还在分隔符上写入 NUL ('\0') 字节,因此它会随时修改输入字符串。如果您要查找多个终止符,则无法确定找到了哪一个。此外,如果您编写了一个库函数供他人使用,但您的函数使用strtok(),您必须记录这一事实,以便您的函数的调用者不会被他们自己的代码的失败所困扰调用你的函数后使用strtok()。换句话说,它是有毒的;如果你的函数调用strtok(),一般来说,它会使你的函数不可重用;同样,您使用strtok() 的代码也无法调用也使用它的其他人的函数。
如果你仍然喜欢这个功能的想法——有些人喜欢(但我几乎总是避免它)——那么在你的系统上寻找strtok_r()。它是可重入的;它需要一个额外的参数,这意味着其他函数可以使用strtok_r()(或strtok())而不影响您的函数。
有多种选择可能是合适的。显而易见的是strchr()、strrchr()、strpbrk()、strspn()、strcspn():这些都不会修改他们分析的字符串。它们都是标准 C 的一部分(strtok() 也是如此),因此它们基本上随处可用。在单个字符之前寻找材料建议您应该使用strchr()。
【讨论】:
strtok 问题是我以前从未想过的。
size_t * 输出参数)?还是应该将缓冲区和长度作为参数并尝试填充它们?还是应该返回一个用于数组目的的用户定义结构?同样,它应该如何分配字符串?
使用strtok() 将字符串拆分为标记。
char *pch;
pch = strtok (name,"=");
if (pch != NULL)
{
printf ("Substring: %s\n",pch);
}
您可以继续调用strtok() 以查找= 之后的更多字符串。
【讨论】:
=之前的字符串。所有字符串比较都在 C 中使用 strcmp()(或类似 strncmp() 的变体)完成,因此只需使用 pch 作为参数之一。
您可以使用strtok,但它不可重入并且会破坏原始字符串。其他(也许更安全的)函数是strchr、strstr、strspn,也许还有mem* 的变体。一般来说,我避免使用strn* 变体,因为虽然它们进行“绑定检查”,但它们仍然依赖于 nul 终止符。它们可能会在恰好比您预期处理的长的有效字符串上失败,并且除非您知道缓冲区大小,否则它们实际上不会防止缓冲区溢出。最好(恕我直言)忽略终止符,并确切知道每次 mem* 函数的工作方式时您正在使用多少数据。
【讨论】:
strchr 和strspn 时,它并不是真正的手动扫描,但阵列存储是您必须自己做的事情。 C 不像大多数其他语言那样具有内置的动态数组类型。