在C语言中使用strtok()和strtok_r()函数

时间:2020-02-23 14:32:07  来源:igfitidea点击:

在本文中,我们将介绍如何在C语言中使用strtok()和strtok_r()函数。

如果要标记字符串,这些功能非常有用。
C提供了这些方便的实用程序函数,可将我们的输入字符串拆分为标记。

让我们通过适当的示例来看看如何使用这些功能。

使用strtok()函数

首先,让我们看一下strtok()函数。

该函数是<string.h>头文件的一部分,因此必须在程序中包含它。

#include <string.h>

char* strtok(char* str, const char* delim);

这将接受输入字符串str和分隔符delim

strtok()会根据定界字符将字符串拆分为标记。

我们期望来自strtok()的字符串列表。
但是该函数返回一个字符串!为什么是这样?

原因是该函数如何处理标记化。
调用strtok(input,delim)之后,它返回第一个令牌。

但是我们必须继续在输入为NULL的字符串上反复调用该函数,直到得到NULL!

基本上,我们需要继续调用strtok(NULL,delim),直到它返回NULL

似乎令人困惑?让我们看一个例子来清除它!

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

int main() {
  //Our input string
  char input_string[] = "Hello from theitroad!";

  //Our output token list
  char token_list[20][20]; 

  //We call strtok(input, delim) to get our first token
  //Notice the double quotes on delim! It is still a char* single character string!
  char* token = strtok(input_string, " ");

  int num_tokens = 0; //Index to token list. We will append to the list

  while (token != NULL) {
      //Keep getting tokens until we receive NULL from strtok()
      strcpy(token_list[num_tokens], token); //Copy to token list
      num_tokens++;
      token = strtok(NULL, " "); //Get the next token. Notice that input=NULL now!
  }

  //Print the list of tokens
  printf("Token List:\n");
  for (int i=0; i < num_tokens; i++) {
      printf("%s\n", token_list[i]);
  }

  return 0;
}

因此,我们有输入字符串" Hello from theitroad!",我们正在尝试用空格标记它。

我们使用`strtok(input,"")"获得第一个令牌。
请注意双引号,因为分隔符是单个字符串!

之后,我们继续使用strtok(NULL,"")"获得令牌并循环,直到从strtok()获得NULL`。

现在来看一下输出。

输出

Token List:
Hello
from
theitroad!

实际上,我们似乎已经获得了正确的令牌!

同样,现在让我们看看使用strtok_r()

使用strtok_r()函数

这个函数与strtok()函数非常相似。
关键区别在于_r表示这是一个可重入函数。

可重入函数是可以在其执行期间中断的函数。
也可以再次安全地调用此类函数,以恢复执行!

这就是为什么它是"可重入"功能的原因。
只是因为它可以安全地再次进入!

因此,重入函数是线程安全的,这意味着它们可以安全地被线程中断,因为它们可以再次恢复而不会造成任何伤害。

现在,类似于strtok()strtok_r()函数是它的线程安全版本。

但是,这有一个另外的参数,称为上下文。
我们需要这样做,以便函数可以从正确的位置恢复。

注意:如果您使用的是Windows,则等效功能为strtok_s()。
strtok_r()适用于基于Linux/Mac的系统!

#include <string.h>

char *strtok_r(char *str, const char *delim, char **context);

参数" context"是指向字符的指针," strtok_r"在内部用于保存其状态。

通常,我们可以从用户声明的指针传递它。

让我们看一下" strtok()"的相同示例,现在使用" strtok_r()"(或者Windows上的" strtok_s()")。

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

int main() {
  //Our input string
  char input_string[] = "Hello from theitroad!";

  //Our output token list
  char token_list[20][20]; 

  //A pointer, which we will be used as the context variable
  //Initially, we will set it to NULL
  char* context = NULL;

  //To get the value of the context variable, we can pass it's address
  //strtok_r() to automatically populate this context variable, and refer
  //it's context in the future
  char* token = strtok_r(input_string, " ", &context);

  int num_tokens = 0; //Index to token list. We will append to the list

  while (token != NULL) {
      //Keep getting tokens until we receive NULL from strtok()
      strcpy(token_list[num_tokens], token); //Copy to token list
      num_tokens++;
      token = strtok_r(NULL, " ", &context); //We pass the context variable to strtok_r
  }

  //Print the list of tokens
  printf("Token List:\n");
  for (int i=0; i < num_tokens; i++) {
      printf("%s\n", token_list[i]);
  }

  return 0;
}

输出

Token List:
Hello
from
theitroad!

虽然我们得到相同的输出,但是此版本更好,因为它是线程安全的!