如何在C语言中将一个字符串分割为两个字符串

44

我在想,如何将一个字符串按照分隔符(比如空格)分成2个部分,并将这2个部分分别赋值给2个不同的字符串。我尝试使用 strtok() 函数,但没有成功。


大多数情况下,由于字符串不存在,它们是字符数组,因此您会发现在C中拆分字符串很困难。 - Woot4Moo
10
请展示你使用strtok()的尝试。 - Fred Larson
当你说“我尝试使用strtok();但是没有成功”时,为什么它没有起作用?你遇到了什么问题? - John Bode
你能展示一下使用strtok()的代码吗? - Naveen
重复:http://stackoverflow.com/questions/2523624 - Paul R
8个回答

65
#include <string.h>

char *token;
char line[] = "SEVERAL WORDS";
char *search = " ";


// Token will point to "SEVERAL".
token = strtok(line, search);


// Token will point to "WORDS".
token = strtok(NULL, search);

更新

请注意,在某些操作系统上,strtok的手册页中提到:

此接口已被strsep(3)取代。

下面是使用strsep的示例:

char* token;
char* string;
char* tofree;

string = strdup("abc,def,ghi");

if (string != NULL) {

  tofree = string;

  while ((token = strsep(&string, ",")) != NULL)
  {
    printf("%s\n", token);
  }

  free(tofree);
}

28
strtok() 修改了它的输入,所以在字符串常量上使用它是不好的行为(也称未定义行为)。 - John Bode
是的,我忘了提到。谢谢。 - ereOn
2
我认为如果你将 char *line = "SEVERAL WORDS" 改为 char line[] = "SEVERAL WORDS",一切都会就绪。 - Fred Larson
7
在C语言中,指针和数组是不同的东西,除非你在数组附近打喷嚏,否则它不会变成指针。这就是数组大小表达式 sizeof(arr)/sizeof(arr[0]) 的工作原理。 - David Thornley
4
strtok() 被弃用了?哇!strsep() 甚至不是标准的 C 函数。 - pmg
显示剩余5条评论

13

为了这样的目的,我倾向于使用strtok_r()而不是strtok()。

例如...

int main (void) {
char str[128];
char *ptr;

strcpy (str, "123456 789asdf");
strtok_r (str, " ", &ptr);

printf ("'%s'  '%s'\n", str, ptr);
return 0;
}

这将输出...

'123456' '789asdf'

如果需要更多的分隔符,那么可以使用循环。

希望这可以帮到你。


strtok_r()和strtok()有什么区别? - thecoshman
3
strtok_r()是strtok()的可重入版本。有关可重入性的更多信息,请参见:http://en.wikipedia.org/wiki/Reentrant_%28subroutine%29 - ereOn

4
char *line = strdup("user name"); // don't do char *line = "user name"; see Note

char *first_part = strtok(line, " "); //first_part points to "user"
char *sec_part = strtok(NULL, " ");   //sec_part points to "name"

注意:strtok会修改字符串,所以不要将其指向字符串字面量的指针传递给它。

3
你可以使用strtok()函数来实现这一点。 例如:它对我很有效。
#include <stdio.h>
#include <string.h>

int main ()
{
    char str[] ="- This, a sample string.";
    char * pch;
    printf ("Splitting string \"%s\" into tokens:\n",str);
    pch = strtok (str," ,.-");
    while (pch != NULL)
    {
        printf ("%s\n",pch);
        pch = strtok (NULL, " ,.-");
    }
    return 0;
}

2
如果您已经分配了一个字符数组,可以在任何位置放置一个'\0',然后将一个新的char *指针指向新插入的'\0'之后的位置。这会破坏原始字符串,具体取决于您放置'\0'的位置。

1
这是如何实现类似于 strtok() 的函数(来自{{link1:一个名为zString的C语言字符串处理库,采用BSD许可证}})。
下面的函数与标准的 strtok() 在识别连续分隔符的方式上有所不同,而标准的 strtok() 则不会这样做。
char *zstring_strtok(char *str, const char *delim) {
    static char *static_str=0;      /* var to store last address */
    int index=0, strlength=0;       /* integers for indexes */
    int found = 0;                  /* check if delim is found */

    /* delimiter cannot be NULL
    * if no more char left, return NULL as well
    */
    if (delim==0 || (str == 0 && static_str == 0))
        return 0;

    if (str == 0)
        str = static_str;

    /* get length of string */
    while(str[strlength])
        strlength++;

    /* find the first occurance of delim */
    for (index=0;index<strlength;index++)
        if (str[index]==delim[0]) {
            found=1;
            break;
        }

    /* if delim is not contained in str, return str */
    if (!found) {
        static_str = 0;
        return str;
    }

    /* check for consecutive delimiters
    *if first char is delim, return delim
    */
    if (str[0]==delim[0]) {
        static_str = (str + 1);
        return (char *)delim;
    }

    /* terminate the string
    * this assignmetn requires char[], so str has to
    * be char[] rather than *char
    */
    str[index] = '\0';

    /* save the rest of the string */
    if ((str + index + 1)!=0)
        static_str = (str + index + 1);
    else
        static_str = 0;

        return str;
}

以下是一个示例代码,演示了使用方法。
  Example Usage
      char str[] = "A,B,,,C";
      printf("1 %s\n",zstring_strtok(s,","));
      printf("2 %s\n",zstring_strtok(NULL,","));
      printf("3 %s\n",zstring_strtok(NULL,","));
      printf("4 %s\n",zstring_strtok(NULL,","));
      printf("5 %s\n",zstring_strtok(NULL,","));
      printf("6 %s\n",zstring_strtok(NULL,","));

  Example Output
      1 A
      2 B
      3 ,
      4 ,
      5 C
      6 (null)

你甚至可以使用while循环(标准库的strtok()也会得到相同的结果)

char s[]="some text here;
do {
    printf("%s\n",zstring_strtok(s," "));
} while(zstring_strtok(NULL," "));

1

如果你愿意改变原始字符串,你可以简单地用\0替换分隔符。原始指针将指向第一个字符串,而分隔符后面的指针将指向第二个字符串。好处是你可以在不分配任何新字符串缓冲区的情况下同时使用这两个指针。


虽然我似乎理解了答案,但一个简单的例子会帮助很多。例如,初学者可能会问:如何获取这两个指针? - Peaceful

1

你可以做:

char str[] ="Stackoverflow Serverfault";
char piece1[20] = ""
    ,piece2[20] = "";
char * p;

p = strtok (str," "); // call the strtok with str as 1st arg for the 1st time.
if (p != NULL) // check if we got a token.
{
    strcpy(piece1,p); // save the token.
    p = strtok (NULL, " "); // subsequent call should have NULL as 1st arg.
    if (p != NULL) // check if we got a token.
        strcpy(piece2,p); // save the token.
}
printf("%s :: %s\n",piece1,piece2); // prints Stackoverflow :: Serverfault

如果您期望多个标记,最好在 while 循环中调用第二个及后续的 strtok 调用,直到 strtok 的返回值变成 NULL

看起来不错,除了第二个strtok()调用使用了不同的分隔符。 - John Bode

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