为什么 strtok() 在我的 C 程序中无法正常工作?

why is strtok() not working properly in my C program?

提问人:Stuart 提问时间:8/29/2023 最后编辑:Vlad from MoscowStuart 更新时间:8/29/2023 访问量:86

问:

我正在尝试开发一个小型控制台程序,该程序将字符串吐出为单独的单词(即标记)。大部分程序都在工作,但我的 strtok() 函数有问题。我已经查看了 strtok() 如何在 C 语言中将字符串拆分为标记中显示的代码,并在某种程度上基于我自己的代码。我的问题出在我的makeWordList()函数上,如下所示。

// Assumes a multi-word string was entered.
void makeWordList(char inString[], unsigned int wordCount, char * wordList[])    // Separate out words.
{
   unsigned int index = 0;
   const char * delimiter = " ";
   char * word;

   word = strtok(inString, delimiter);             // Get first word.

   while ((word != NULL) && (index < wordCount))
   {
      wordList[index++] = word;                    // Add word to list.
      word = strtok(inString, delimiter);          // Get next word.
   }  // end while()
}

就我而言,strtok() 函数似乎不会沿着(源)输入字符串 inString 移动。当程序运行时,它会生成以下输出

./ex8_4
Enter string to be processed:
three word string
You entered |three word string|

There are 3 words in the string.

There are 15 letters in the string.

The word list is as follows.
three
three
three

从上面显示的输出中可以很容易地看到 strtok() 成功读取了第一个令牌(并根据代码块监视面板以“\000”终止它),但没有读取 inString 中的后续令牌。 由于我使用 strtok() 的方式与上面链接的页面上的代码中显示的方式非常相似,有人可以解释一下我无法理解的内容吗?

C-strings strtok 函数调用

评论

2赞 Some programmer dude 8/29/2023
请尝试创建一个最小的可重现示例来向我们展示,包括您如何调用函数。对函数内的输入字符串进行硬编码。makeWordListmain
2赞 Scott Hunter 8/29/2023
发布的代码不会生成任何输出。
0赞 Gerhardh 8/29/2023
该函数的调用者如何知道找到了多少个单词?在调用该函数之前,它是否应该存储在 的所有元素中?NULLwordList
4赞 pmacfarlane 8/29/2023
从手册页:“在第一次调用 strtok() 时,应该在 str.在应分析同一字符串的每个后续调用中,str 必须为 NULL。你没有做 NULL 部分。strtok()
0赞 Gerhardh 8/29/2023
word = strtok(inString, delimiter); // Get next word.这不是工作方式。您必须传递除第一个调用之外的所有调用。strtokNULL

答:

0赞 Saran Kumar 8/29/2023 #1

问题在于,在循环的每次迭代中,您都使用相同的字符串指针 (inString) 调用 strtok()。这意味着 strtok() 将只从第一个令牌的末尾开始查找下一个令牌。在您的例子中,第一个标记是“three”,因此 strtok() 只会找到从“three”末尾开始的下一个标记。这就是为什么你的程序的输出是“三三三”。

    // Assumes a multi-word string was entered.
void makeWordList(char inString[], unsigned int wordCount, char * wordList[])    // Separate out words.
{
   unsigned int index = 0;
   const char * delimiter = " ";
   char * word;

   word = strtok(inString, delimiter);             // Get first word.

   while ((word != NULL) && (index < wordCount))
   {
      wordList[index++] = word;                    // Add word to list.

      // Get next word.
      word = strtok(NULL, delimiter);
   }  // end while()
}
3赞 Vlad from Moscow 8/29/2023 #2

在此 while 循环中

   while ((word != NULL) && (index < wordCount))
   {
      wordList[index++] = word;                    // Add word to list.
      word = strtok(inString, delimiter);          // Get next word.
   }  

更改此语句

  word = strtok(inString, delimiter);          // Get next word.

  word = strtok(NULL, delimiter);          // Get next word.

否则,该函数会尝试从头开始重新拆分字符串。strtok

来自 C 标准(7.23.5.8 strtok 函数)

2 对 strtok 函数的一系列调用中断了指向的字符串 通过 s1 进入一系列令牌,每个令牌都由 S2 指向的字符串中的字符。第一个调用 sequence 有一个非 null 的第一个参数;后续调用 sequence 的第一个参数为 null。指向的分隔符字符串 通过 S2 可能与呼叫不同。

请注意,当函数返回传递的字符串中的字数时会更好,例如

unsigned int makeWordList(char inString[], unsigned int wordCount, char * wordList[])    // Separate out words.
{
   unsigned int index = 0;

   //...

   return index; 
}

请记住,该函数在多线程环境中是不安全的,因为它使用静态变量。使用替代功能更安全。strtokstrtok_s