问题描述
在下面的代码中,我尝试将字符串拆分为从字符串中以“,”分隔的名称。
#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语言中的可编辑/不可编辑字符串。