【问题标题】:using strcpy() with strtok将 strcpy() 与 strtok 一起使用
【发布时间】:2016-07-30 09:45:56
【问题描述】:

我正在尝试拆分从文件中读入的一行,并使用strcpy() 将我找到的数据复制到一个字符数组中错误,尽管我也尝试过使用确定的缓冲区大小与strncpy() 以及strncat() 相同的结果。在我的 sn-p 中,我尝试简单地在令牌末尾添加一个空终止字符。

这是我失败的代码的 sn-p:

    token = strtok(line, s);
    strcpy(update, token);
    token = strtok(NULL, s);
    token = token + '\0';
    strcpy(firstName, token);
    token = strtok(NULL, s);

此函数中的第一个strcpy() 调用尚未失败。我第二次调用strcpy()每次尝试运行它都会失败。

我的其余代码可以在here找到

【问题讨论】:

  • 您希望通过声明 token = token + '\0'; 实现什么目标? updatefirstName 是如何定义的?
  • 你需要显示update是什么。
  • 不知道更新和名字是如何定义的和/或他们指出的这个问题无法回答。
  • 我链接了完整的代码,因为我认为在此页面上以文本形式发布会太长。但是 update 和 firstName 是定义在结构内部的字符数组。
  • 至于token = token + '\0'; 语句,我天真地希望我可以在token 的末尾添加空终止字符,这样strcpy() 就可以在不读取缓冲区的情况下停止。跨度>

标签: c segmentation-fault strcpy strcat


【解决方案1】:

复制前需要检查空指针。

token = strtok(line, s);
strcpy(update, token);
token = strtok(NULL, s);
//token = token + '\0';
if(NULL != token)
{
    strcpy(firstName, token);
    token = strtok(NULL, s);
}

【讨论】:

  • 我没有注意到我的测试打印语句的最后一个值是NULL。空终止字符不是问题,我试图使用strcpy() 将任何内容复制到firstName,这导致了分段错误。谢谢!
  • @SuperNoobAttack:如果您费心阅读我的回答,您会更早知道:“如果您的第二个 strcpy 失败,可能是因为 strtok 失败并且返回一个空指针。”我因此而被否决。 “但我很苦吗?不。好吧,也许有点。”
【解决方案2】:

strtok 返回空指针或指向以 NUL 结尾的字节序列的指针(即有效的 C 字符串)。

您的token = token + '\0'; 没有按照您(几乎可以肯定)的想法行事。由于token 是一个指针(这是strtok 的返回类型),它正在执行指针运算。幸运的是,'\0'0 的一种冗长的说法(目前的琐事:C 中的字符文字具有类型 int,而不是类型 char),所以至少它没有改变指针。

检查strtok 返回的值。如果第二个 strcpy 失败,可能是因为 strtok 失败并返回空指针。

也就是说,鉴于您使用单个固定字符串来定义分隔符,您可能可以使用sscanf 更轻松(也更干净)完成这项工作。例如,如果s 包含,.-+,您可以使用:

sscanf(input, "%1[^,.-+]%*c%9[^,.-+]", update, firstname);

我暂时忽略了对strtok 的第三次调用,因为您永远不会从其返回值复制到目标(当然,重复上述模式将适用于更多变量)。注意% 和扫描集 ([^...]) 之间数字的使用。您总是希望在使用 %s 或 %[...]. The size you specify should always be one smaller than the buffer into which you're having them write (because they always append a trailing'\0'` 时指定缓冲区的大小。

如果s 实际上是您从外部源读取的字符串(或按该顺序读取的字符串,因此您不能轻易将其内容放入字符串文字中),您可以在运行时合成您的格式字符串-如果需要的话:

char template[] = "%%[^%s]%%*c%%[^%s]";
char format[512];

sprintf(format, template, s, s);
sscanf(input, format, update, firstname);

[虽然格式字符串通常是文字,但这不是必需的。]

编辑:我认为您最初没有链接代码,但它至少揭示了一个问题:char update[1];。使用它作为strcpy 的目标是一个问题,因为它总是附加一个尾随'\0' 来终止字符串。在这种情况下,您只分配了一个字符,因此您只有终止符的空间,而不是任何实际数据。您需要将其扩展为至少两个字符。鉴于您要复制到固定大小的缓冲区中,您可能希望在复制之前检查字符串是否适合您的缓冲区,或者使用某些内容来限制它将复制的数据大小(并且仍然始终包括终结者,不像strncpy)。

【讨论】:

  • 所有这些,甚至没有提到我们不知道updatefirstName 是什么。我的赌注未分配char*
  • @John3136:可能,是的,第一个strcpy 破坏内存并导致第二个问题的可能性很小。根据我的经验,这并不是特别可能是问题的根源。当然可以,但它也可能是一个太短的固定缓冲区,s 未初始化或为空,因此第一次调用strtok 会消耗整个输入,等等。
  • token = strtok(NULL, s); 语句用于获取我要拆分为标记的行的下一个值。我通过打印出来测试了这些语句中的每一个,它们看起来都是正确的值。
猜你喜欢
  • 2018-11-29
  • 1970-01-01
  • 2010-09-22
  • 2013-02-08
  • 2023-04-07
  • 2013-04-23
  • 2011-08-16
  • 1970-01-01
  • 2017-04-09
相关资源
最近更新 更多