C – strtok上的意外分段错误(…)

我正在使用库的strtok(…),它似乎工作正常,直到结束条件,它导致分段错误和程序崩溃。 API声称strtok(…)将在没有更多令牌被找到时输出NULL,这意味着,我想,你必须捕获这个NULL才能终止你使用strtok运行的任何循环( …)。 我需要做什么才能捕获此NULL以防止程序崩溃? 我想象允许使用NULL作为终止条件。

我准备了一个SSCCE供你观察这种行为。 我需要strtok(…)来处理我正在编写的更大的软件,并且我得到完全相同的分段行为。 命令行的输出显示在此代码插图下方(是的,我知道您使用来封装库,但是我很难获得此post来显示代码库)。 我在Windows 8操作系统上使用gcc 4.5.3版本,下面显示了两种不同的方式,我想象一个人可以尝试在循环中捕获NULL。

#include  #include  #include  #include  #include  #include  #include  main(){ char* from = "12.34.56.78"; char * ch = "."; char * token = strtok(from, ch); printf("%s\n",token); while(token != NULL){ token = strtok(NULL, ch); printf("%s\n", token); } printf("Broke out of loop!"); while(strcmp(token, 0) != 0){ printf("%s\n",token); token = strtok(NULL, ch); } } 
 ############ OUTPUT:############

 $ ./test
 12
 34
 56
 78
分段故障(核心转储)

你首先检查token是否不等于NULL(当它是,它突然出现在while循环中)。 然后你比较token ,这是一个NULL与常数NUMBER? 这里: strcmp(token, 0)strcmp需要2个字符串时,你提供一个数字。 strcmp将尝试获取第0个地址(或NULL)的字符串,从而给出分段错误。

 while(strcmp(token, 0) != 0){ token = strtok(NULL, ch); printf("%s\n",token); } 

此代码也应如下所示:

更改

  char * token = strtok(from, ch); printf("%s\n",token); while(token != NULL){ token = strtok(NULL, ch); printf("%s\n", token); } 

  char * token = strtok(from, ch); printf("%s\n",token); while(token != NULL){ printf("%s\n", token); token = strtok(NULL, ch); } 

strtok修改了它的第一个参数。 您从只读内存传递一个字符串,当strtok尝试更改它时发生segfault。 尝试更改:

 char* from = "12.34.56.78"; 

 char from[] = "12.34.56.78"; 

这是个问题:

  while(token != NULL){ token = strtok(NULL, ch); printf("%s\n", token); } 

您正在检查NULL,但之后再次调用strtok而不是在此之后但在打印之前进行检查。

代码还有其他问题,但我怀疑这就是它崩溃的原因。

问题是即使你在strtok()返回NULL时终止循环,你首先尝试打印NULL

  while(token != NULL){ token = strtok(NULL, ch); printf("%s\n", token); // not good when token is NULL } 

事实certificate,除了这个例子之外,在这个例子中还有几个机会用于segfaults,正如其他答案所指出的那样。

这是处理示例标记化的一种方法:

 char from[] = "12.34.56.78"; char * ch = "."; char * token = strtok(from, ch); while (token != NULL){ printf("%s\n", token); token = strtok(NULL, ch); } 

如果代码的目的只是以’。’分隔的打印元素,则只更改char声明并在打印令牌之前检查其值是否为NULL!

  main(){ char from[] = "12.34.56.78.100.101"; char * ch = "."; char * token = strtok(from, ch); //printf("%s\n",token); while(token != NULL){ printf("%s\n", token); token = strtok(NULL, ch); } } 

OUTPUT

  ./test1 12 12 34 56 78 100 101 

您有内存访问错误和逻辑错误。 我只会解决导致程序崩溃的内存访问错误。

strtok修改了它的第一个参数。 由于传入字符串文字,因此无法修改字符串(字符串文字不可修改。)

这是一个可能的修复, from一个可修改的字符串数组定义:

 char from[] = "12.34.56.78"; 

因为strtok修改了传入其中的字符串,所以在第二个while循环中无法再次处理该字符串。 您实际上是将NULL传入strcmp函数。 可能的解决方法是每次要使用strtok时将from数组复制到另一个缓冲区。