3

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

我为您准备了一个 SSCCE 来观察这种行为。我需要 strtok(...) 来为我正在编写的更大的软件工作,并且我得到了完全相同的分段行为。命令行的输出显示在此代码小插图下方(是的,我知道您使用 <...> 来包含库,但我很难让这篇文章显示代码库)。我在 Windows 8 操作系统上使用 gcc 版本 4.5.3,下面显示了我想象的两种不同风格的尝试在循环中捕获 NULL 的方式。

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

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);
  }
}
############ 输出: ############

$ ./测试
12
34
56
78
分段错误(核心转储)
4

6 回答 6

4

strtok修改它的第一个参数。您正在从只读内存中传递一个字符串,并且在strtok尝试更改它时会发生段错误。尝试更改:

char* from = "12.34.56.78";

char from[] = "12.34.56.78";
于 2013-03-12T05:00:52.650 回答
3

您首先检查是否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);
  }
于 2013-03-12T05:01:22.170 回答
3

这是个问题:

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

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

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

于 2013-03-12T05:02:18.690 回答
2

问题是即使您在strtok()返回时终止循环NULL,您也会尝试打印第NULL一个:

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

事实证明,除了这个例子中的段错误之外,还有几个机会,正如其他答案所指出的那样。

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

char from[] = "12.34.56.78";
char * ch = ".";
char * token = strtok(from, ch);
while (token != NULL){
    printf("%s\n", token);
    token = strtok(NULL, ch);
}
于 2013-03-12T05:01:34.410 回答
2

如果代码的目的只是打印由 '.' 分隔的元素,则仅在 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);
        }
   }
输出
  ./test1
 12
 12
 34
 56
 78
 100
 101
于 2013-03-12T06:27:00.377 回答
1

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

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

from这是定义为可修改字符串数组的可能修复方法:

char from[] = "12.34.56.78";

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

于 2013-03-12T05:23:50.763 回答