为什么我在这里出现细分错误

时间:2019-06-19 13:29:49

标签: c string segmentation-fault strtok string-literals

我已将代码从here修改为以下代码中的char [50]替换为char *:

#include <stdio.h>
#include <string.h>
int main ()
{
  // change made in following line from char string[50]
  char *string ="Test,string1,Test,string2:Test:string3"; 
  char *p;
  printf ("String  \"%s\" is split into tokens:\n",string);
  p = strtok (string,",:");
  while (p!= NULL)
  {
    printf ("%s\n",p);
    p = strtok (NULL, ",:");
  }
  return 0;
}

但是,我得到了以上代码的segmentation fault

如何在上述代码中使用指针版本?

还有,segmentation fault会损坏磁盘上的数据吗?

2 个答案:

答案 0 :(得分:3)

在此声明中

char *string ="Test,string1,Test,string2:Test:string3"; 

定义了一个指向字符串文字的第一个字符的指针。

然后您尝试使用指针来更改字符串文字。

考虑到标准函数strtok更改了传递给它的字符串,在分隔符的位置插入了空终止符。

您不得在C(和C ++)中更改字符串文字。他们是一成不变的。尝试更改字符串文字会导致未定义的行为。

您可以使用函数strtokstrspn代替函数strcspn来提取令牌。在这种情况下,您可以处理字符串文字,因为这些函数不会更改传递给它们的字符串。

答案 1 :(得分:0)

回答您的问题。 这就是为什么您会收到段错误的原因:

字符串文字(例如用char *string="Test,string1,Test,string2:Test:string3";声明的文字)和字符数组(使用char[50]的引用版本)之间存在根本的区别。

要提供不同的错误提示,请参见编译期间发生的情况。

在两种情况下,常量字符串"Test,string1,Test,string2:Test:string3"存储在二进制文件的只读数据部分中。使用char *string时,您是将常量字符串(在.rodata中)的位置(指针)分配给堆栈上的变量。当您使用char string[50]时,实际上是在将一个char数组声明为堆栈上的存储,而不是char指针。编译器实际上以与您期望的方式不同的方式执行此分配。在许多情况下,它将添加一个函数调用,例如memcpy来初始化字符数组。像这样:

char string [50]
memcpy(string,"Test,string1,Test,string2:Test:string3",0x32);

这具有创建局部堆栈变量的优点,该变量可以通过其他功能(例如strtok)进行操作。但是,您当然不能使用相同的函数来操作二进制文件的只读部分中的原始字符串。那是根本的区别。

莫斯科@Vlad提到的所有其他内容也都相关。

下一个问题:分段错误还会导致磁盘上的数据损坏吗?

当在不允许这种操作的内存段中发生操作(读,写,执行)时,就会发生分段错误。通常,这是由于尝试从无效指针引用的位置读取或写入而发生的。这完全是一个运行时概念。故障包含在进程的虚拟内存中。一般来说,这不会对任何二级存储造成损害。可能存在边缘情况(部分将数据写入文件后发生段错误),其中二级存储中的文件可能已损坏,但是您所显示的示例并非如此。总而言之,除非在写入磁盘的过程中发生段错误,否则磁盘应该没问题。