为什么strtok会改变输入的内容?

23

好的,我知道strtok会修改其输入参数,但在这种情况下,它将输入字符串缩减为仅第一个标记。为什么会这样,我该怎么做才能解决这个问题?(请注意,我不是在谈论变量“temp”,它应该是第一个标记,而是变量“input”,在调用一次strtok后变为“this”)

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char* argv[]) {
   char input[]="this is a test of the tokenizor seven";
   char * temp;
   temp=strtok(input," ");
   printf("input: %s\n", input); //input is now just "this"
}
3个回答

39

strtok()函数在找到一个分隔符时,会将该分隔符后面的字符替换成\0,然后返回指向该标记的指针。下一次调用它时,使用NULL参数,则它从终止第一个标记的分隔符(即\0)之后开始查找,或者更远的位置。

现在,字符串开头的原始指针仍然指向字符串开头,但是第一个标记已经以\0结尾——也就是说,printf()认为标记的结尾是字符串的结尾。余下的数据仍然存在,但是那个\0会阻止printf()将其显示出来。如果你使用一个for循环遍历原始输入字符串,直到原始字符数为止,你会发现数据仍然在那里。


3
哦,我懂了。我对strtok的理解完全错误了——我以为它会切断标记,然后将输入指针滑动到分隔符后的第一个字符。无论如何,谢谢!这是一个非常清晰和有用的回答。 - user1209326
但是,在strtok完成并返回NULL(因为没有更多的标记)之后,初始字符串是否会恢复?或者为了安全地使用strtok,您应该复制源字符串吗?另外,如果在strtok完成之前停止它,我的原始字符串会发生什么? - Cătălina Sîrbu
2
@CătălinaSîrbu 如果您需要保留字符缓冲区的原始内容,那么是的,您需要进行复制。但实际上这种情况很少发生。 - Ernest Friedman-Hill
我需要再澄清一下,我正在阅读这个_A very important remark has to be made here: the function modifies the string pointed to by the first argument (it places null characters at the ends of the tokens – but they’ll all be removed after the last invocation)_. 从我的理解来看,这是错误的,源字符串在最后一次调用strtok(也就是返回NULL的调用)之后将不会被恢复。是这样吗? - Cătălina Sîrbu
1
@CătălinaSîrbu 是的,那个引用(它来自哪里?)是不正确的。strtok在任何情况下都不会恢复原始字符串。如果它这样做了,它将使其创建的所有标记无效,这意味着您必须复制它们才能有用 - 但事实并非如此。 - Ernest Friedman-Hill
非常感谢!现在清楚了。这是来自cpp研究所CLP高级C编程课程的引用(它们有很多错误,但没关系,因为我总是会仔细检查并更加注意)。 - Cătălina Sîrbu

5

您应该打印从strtok接收到的令牌,而不必担心输入数组,因为strtok将插入NULL。 您需要多次调用以获取所有令牌:

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char* argv[]) {
  char input[]="this is a test of the tokenizor seven";
  char * temp;
  temp=strtok(input," ");
  while( temp != NULL ) {
    printf("temp is \"%s\"\n", temp );
    temp = strtok( NULL, " ");
  }
}

1
就像我之前所说的,显然我对strtok如何实际分词有错误的想法。感谢你的帮助! - user1209326

2

这是因为strtok在每个分隔符中插入了null,这就是为什么你需要重复调用strtok来获取每个标记。一旦开始使用strtok,输入字符串就不能再次使用。你不能“修复”它--这就是它的工作原理。


感谢您的迅速回复。当然,当我说“修复它”时,我的意思是“我如何获得我想要的结果”,但我很感激您抽出时间来帮助我。 - user1209326
如果您需要一个未受影响的输入字符串副本,则需要在执行 strtok 操作之前先复制它。 - Joe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接