【问题标题】:Using strtok to split a string in c使用strtok在c中拆分字符串
【发布时间】:2020-09-17 15:01:52
【问题描述】:

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

#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);

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

【问题讨论】:

  • strcpy(name[i], token); 你还没有初始化数组中的指针。简单的解决方案:char name[7][128]; 否则可以使用malloc()
  • 哦,对了...如果我使用 char *name,我必须在使用前使用 malloc() 为其分配内存。谢谢。

标签: c undefined-behavior c-strings strtok string-literals


【解决方案1】:

你声明了一个指向字符串字面量的指针

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,Jayden,Sofia,Michael,Andrew,Lily,Benjamin";

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

char *name[7];

所以这个说法

strcpy(name[i], token);

还调用未定义的行为。

你可以直接写

name[i] = token;

由于变量 i 包含 tfokens 的数量,所以一般来说这个循环

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

至少应该重写为(不使用幻数 7)

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

【讨论】:

  • 这正是我的代码的问题,在我将 char * st 复制到另一个 char 数组 char str[] 并将 str 作为参数传递给 strtok() 之后,现在一切正常,但我仍然不明白为什么我必须这样做。 char* 和 char 数组有什么区别,我以为是一样的。
  • @heihei 原始声明 char st = /...*/;声明一个指向字符串文字的指针。您不能更改字符串文字。此声明 char * st[] = /*...*/;声明一个由字符串文字的元素初始化的数组。您不能更改数组的任何字符。并且函数 strtok 更改传递给它的字符串。
【解决方案2】:

但是,当我尝试运行代码时遇到了分段错误

两个问题:

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

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

内存分配问题
声明:

  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,Jayden,Sofia,Michael,Andrew,Lily,Benjamin";

要编辑的字符串不能采用这种形式(即string literal)。它必须是可编辑的形式,以便strtok() 能够更改它,就像解析时一样。可编辑的字符串形式有很多,这里举两个例子:

//Create an editable form:
char st[] = {"Addison,Jayden,Sofia,Michael,Andrew,Lily,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 中可编辑/不可编辑的字符串。

【讨论】:

  • 非常感谢,使用指针数组之前忘记分配内存了。
  • 感谢您添加和解释不可编辑的字符串部分。
猜你喜欢
  • 1970-01-01
  • 2014-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-23
相关资源
最近更新 更多