使用strtok在c中拆分字符串

问题描述

在下面的代码中,我尝试将字符串拆分为从字符串中以“,”分隔的名称

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


int main(void)
{
    char *st = "Addison,Jayden,Sofia,Michael,Andrew,Lily,Benjamin";
    char *name[7];
    char *separate = ",";

    char *token = strtok(st,separate);
    int i = 0;
    while(token != NULL)
    {
        strcpy(name[i],token);
        token = strtok(NULL,",");
        i++;
    }
    for (int j = 0; j < 7; j++)
    {
        printf("%s\n",name[j]);
    }
}

但是,当我尝试运行代码时,我遇到了分段错误。我尝试对其进行调试,看来这行特定的代码错误的出处:

char *token = strtok(st,separate);

谁能告诉我我做错了什么吗?

解决方法

您声明了一个指向字符串文字的指针

char *st = "Addison,Jayden,Sofia,Michael,Andrew,Lily,Benjamin";

您不得更改字符串文字。尝试更改字符串文字会导致未定义的行为。

根据C标准(6.4.5字符串文字)

7不确定这些数组是否有区别,只要它们的 元素具有适当的值。 如果程序尝试执行以下操作 修改这样的数组,行为是不确定的

另一方面,标准C函数strtok更改传递给它的字符串。

根据C标准(7.23.5.8 strtok函数)

4然后,strtok函数从那里搜索一个字符,该字符是 当前分隔符字符串中包含的内容。如果没有这样的字符 找到后,当前标记扩展到指向的字符串的末尾 按s1,随后对令牌的搜索将返回空指针。 如果找到了这样的字符,则会被空字符覆盖, 终止当前令牌。 strtok函数保存一个 指向以下字符的指针,从下一个搜索 令牌将启动。

所以用声明代替

char st[] = "Addison,Benjamin";

您还声明了一个未初始化的指针数组。

char *name[7];

所以这句话

strcpy(name[i],token);

还会调用未定义的行为。

相反,您只能写

name[i] = token;

并且由于变量i包含tfoken的数量,因此通常会出现此循环

for (int j = 0; j < 7; j++)
{
    printf("%s\n",name[j]);
}

至少应重写为(不使用魔术数字7)

for (int j = 0; j < i; j++)
{
    puts( name[j] );
}
,

但是,尝试运行代码时遇到段错误

两个问题:

  • 尝试更改不可编辑的字符串。
  • 尝试访问不属于进程的位置。

任何一种都可能导致崩溃。 (段错误)

内存分配问题
声明:

  char *name[7];

创建一个包含7个指针的数组。它们中的每一个都需要先分配内存,然后才能以这种方式使用它:

strcpy(name[i],token);

内存分配示例:

for(int i=0;i<7;i++)
{
    name[i] = malloc((maxNameLen+1)*sizeof(name[i]));
    if(!name[i]) 
    {
        //handle error
    }
}
//now each pointer has space for up to maxNameLen+1 characters

不可编辑的字符串

char *st = "Addison,Benjamin";

要编辑的字符串不能采用这种形式(即string literal)。它必须采用可编辑的形式,以便strtok()对其进行更改,就像在解析时一样。有许多可编辑的 string 形式,以下是两个示例:

//Create an editable form:
char st[] = {"Addison,Benjamin"};

//Create an editable copy of original: (requires freeing when done using)
char *duplicate = strdup(st);
if(duplicate)
{
    //success duplicating,now parse duplicate.

another discussion here解释了C语言中的可编辑/不可编辑字符串。