如何将标记化的行与str“出口”进行比较?

时间:2019-04-11 07:45:25

标签: c

我不知道如何将行与单词“ exit”进行比较,以便在退出键盘输入时程序将退出。     #定义MAX_LINE 4096     #define MAX_WORDS MAX_LINE / 2

int main()
{
        char line[MAX_LINE], *words[MAX_WORDS], message[MAX_LINE];
        int stop=0,nwords=0;

        while(1)
        {
                printf("OSP CLI $ ");
        fgets(line,MAX_LINE,stdin);

        if(strcmp(line,"exit")==0)
        {
            exit(0);
        }   
void tokenize(char *line, char **words, int *nwords)
{
    *nwords=1;
    for(words[0]=strtok(line," \t\n");
       (*nwords<MAX_WORDS)&&(words[*nwords]=strtok(NULL, " \t\n"));
        *nwords=*nwords+1
    ); /* empty body */
    return;
}

该代码是正确的,但我不知道它的作用。因此,for(words [0] = strtok(line,“ \ t \ n”);读取该行的第一个单词。“ line”是用户在运行时输入的键盘输入,它只是一个字符串,如:hello worldblah dee doo。但是在那之后,下一行用nwords <.....在for之后就什么都不懂了。

2 个答案:

答案 0 :(得分:3)

for (a; b; c) d;

可以翻译为:

a;
while (b) {
   d;
   c;
}

所以:

void tokenize(char *line, char **words, int *nwords)
{
    *nwords=1;
    for(words[0]=strtok(line," \t\n");
       (*nwords<MAX_WORDS)&&(words[*nwords]=strtok(NULL, " \t\n"));
        *nwords=*nwords+1
    ); /* empty body */
    return;
}

可以翻译成(经过一些其他改进,例如int *a; if (a)int *a; if (a != NULL)相同)

void tokenize(char *line, char **words, int *nwords)
{
    *nwords = 1;
    words[0] = strtok(line, " \t\n");
    while ( 
             *nwords < MAX_WORDS && 
             (words[*nwords] = strtok(NULL, " \t\n")) != NULL
    ) {
        /* empty body */
        *nwords = *nwords + 1;
    }
}

让我们再详细一点:

void tokenize(char *line, char **words, int *nwords)
{
    *nwords = 1;
    words[0] = strtok(line, " \t\n");
    while (*nwords < MAX_WORDS) {
        words[*nwords] = strtok(NULL, " \t\n");
        if (words[*nwords] == NULL) {
            break;
        }
        /* empty body */
        *nwords = *nwords + 1;
    }
}

此函数很危险,或者可能是更大的一部分的一部分(不检查参数是否为null,如果行为空则省略)。

words是一个指针,它是char*指针的数组。 words指针的长度似乎至少为MAX_WORDS长。 nwords是指向words指针的返回长度的指针。调用者希望此函数用字符串中的标记填充words存储器和nwords存储器。假定所有指针都不是NULL且有效,MAX_WORDS > 0strlen(line) != 0或字符串line不仅仅由我们使用的" \t\n"分隔符组成,因此存在始终是第一个令牌。

  • 首先将nwords1初始化,然后提取第一个令牌words[0] = strtok(line, " \t\n");
  • 然后,直到令牌数量少于MAX_WORDS为止,提取下一个令牌words[*nwords] = strtok(NULL, " \t\n")
  • strtok手册开始-从strtok返回的值是“如果没有更多令牌,则返回NULL”。如果strtok返回NULL,则意味着我们完成了字符串-因此我们从函数返回。
  • 但是,如果令牌的数量少于MAX_WORDS,并且我们提取了下一个有效令牌,则会增加计数*nwords = *nwords + 1;
  • 通过words字符串内的指针初始化了line,并用令牌计数初始化了nwords后面的内存,并将line数组修改为用终止零'\0'代替令牌定界符。

答案 1 :(得分:2)

让我们重新编写代码,使其更简洁,更易读:

void tokenize(char *line, char **words, int *nwords)
{
  *nwords=1;
  words[0]=strtok(line," \t\n");
  while (*nwords < MAX_WORDS) {
    words[*nwords] = strtok(NULL, " \t\n");
    if (!words[*nwords])
      break;
    *nwords = *nwords + 1;
  }
}

使此代码更难理解的一件事是,它始终通过nwords指针间接访问单词数。没有这个速记,这里还有一个重写:

void tokenize(char *line, char **words, int *nwords)
{
  int wordCount = 1;
  words[0]=strtok(line," \t\n");
  while (wordCount < MAX_WORDS) {
    words[wordCount] = strtok(NULL, " \t\n");
    if (!words[wordCount])
      break;
    wordCount = wordCount + 1;
  }
  *nwords = wordCount;
}

最后,对于指针p,测试!p与测试p == NULL相同。因此,检查if (!words[wordCount])的意思是“如果words中当前的最后一个元素是空指针。”当strtok返回空指针,表明它已完成解析时,可能会发生这种情况。

希望现在已经清楚了。

通常,该函数使用strtokline中提取单词并将它们存储到数组words的连续元素中,存储的单词数返回到{{1} }。

它将重复提取一个单词,存储它,并增加单词数。这一直持续到以下任何一种情况:

    提取
  • nwords,或
  • MAX_WORDS返回一个空指针,表示strtok中没有剩余的单词。