strtok没有按预期工作

时间:2012-12-25 12:04:10

标签: c strtok

我尝试编写一个函数,该函数获取指向char数组的指针,从用户读取一个字符串并删除字符串开头的所有空格,直到出现第一个不是字符串的char。最后在开头的时候返回没有space / s的字符串副本。

例如,

对于输入abcd,该函数应返回指向字符串abcd的指针。

对于输入123 123,该函数应该返回指向字符串123 123的指针。

该功能如下所示,

void read_RemoveSpace(char * str)/**read the rest of string**/
{
    char tempRead[30];
    fgets(tempRead,30,stdin);
    char *ptr = strtok(tempRead, " "); /**remove spaces between command and other data**/
    strcpy(str,ptr); /**copy the new string without the spaces.**/
}

但是某些原因导致函数strtok()没有按预期工作。

如果输入:

   123 456

该函数只返回没有空格而不是字符串其余部分的第一部分,即它指向

123

有什么建议吗?

3 个答案:

答案 0 :(得分:4)

strtok完全按预期工作。它将输入分成字符串123456

strtok (tempRead, " "); /* Returns 123 */
strtok (NULL, " "); /* Returns 456 */

我认为您可以使用更简单的解决方案:

int i = 0;
char tempRead[30];
...
while (tempRead[i] == ' ' && tempRead[i])
  i++;
strcpy(str,tempRead+i);

答案 1 :(得分:2)

它的工作方式完全符合预期。

第一次调用strtok将返回第一次出现的令牌;只要您将第一个参数提供为NULL,后续调用将一次返回一个标记的其余部分;当标记耗尽时,strtok将返回NULL。

编辑:
有些事情可能会导致奇怪的错误,所以我在这里引用手册页提到的内容以及使用strtok时应该始终牢记的内容:

  

使用这些功能时要小心。如果您确实使用它们,请注意   的是:

     
      
  • 这些函数修改了他们的第一个参数。

  •   
  • 这些函数不能用于常量字符串。

  •   
  • 分隔字符的标识将丢失。

  •   
  • strtok()函数在解析时使用静态缓冲区,所以不是    线程安全。如果这对您很重要,请使用strtok_r()

  •   

答案 2 :(得分:0)

使用strtok()并不是明显的方法。

void read_RemoveSpace(char *str)
{
    char *dst = str;
    char tempRead[30];
    if (fgets(tempRead, sizeof(tempRead), stdin) != 0)
    {
        char *src = tempRead;
        char c;
        while ((c = *src++) != '\0')
        {
            if (c != ' ')
                *dst++ = c;
        }
    }
    *dst = '\0';
}

这会将tempRead中的非空格复制到str,包括换行符;如果您愿意,可以使用isspace()中的isblank()#include <ctype.h>。我不相信30对于本地字符串来说是一个很好的长度,但这就是你在问题中所拥有的。可以说,您应该指定接口中提供的字符串大小:void *read_RemoveSpace(char *buffer, size_t buflen)。你也可以让函数返回指向字符串末尾的null的指针(从而间接地给出字符串的长度减去空格)。

void read_RemoveSpace(char *buffer, size_t buflen)
{
    char *dst = buffer;
    char tempRead[buflen];
    if (fgets(tempRead, sizeof(tempRead), stdin) != 0)
    {
        char *src = tempRead;
        char c;
        while ((c = *src++) != '\0')
        {
            if (!isspace((unsigned char)c))
                *dst++ = c;
        }
    }
    *dst = '\0';
    return dst;
}

没有太大的不同,但更安全。它使用本地VLA - 可变长度数组 - 它是C99的一部分。有可能放弃VLA并直接将副本复制到目标缓冲区中:

void read_RemoveSpace(char *buffer, size_t buflen)
{
    char *dst = buffer;
    if (fgets(buffer, buflen, stdin) != 0)
    {
        char *src = buffer;
        char c;
        while ((c = *src++) != '\0')
        {
            if (!isspace((unsigned char)c))
                *dst++ = c;
        }
    }
    *dst = '\0';
    return dst;
}

直到第一个空格,这个复制是无操作的;之后,它将字符复制到最终位置。