简体   繁体   English

C - strtok上的意外分段错误(...)

[英]C - Unexpected Segmentation Fault on strtok(…)

I am using strtok(...) of the library and it appears to be working fine until the end condition, where it results in a segmentation fault and program crash. 我正在使用库的strtok(...),它似乎工作正常,直到结束条件,它导致分段错误和程序崩溃。 The API claims that strtok(...) will output a NULL when there are no more tokens to be found, which meant, I thought, that you had to catch this NULL in order to terminate any loops that you were running using strtok(...). API声称strtok(...)将在没有找到更多令牌时输出NULL,这意味着,我想,你必须捕获这个NULL才能终止你使用strtok运行的任何循环( ...)。 What do I need to do to catch this NULL to prevent my program from crashing? 我需要做什么才能捕获此NULL以防止程序崩溃? I imagined the NULL was allowed for use as a terminating condition. 我想象允许使用NULL作为终止条件。

I have prepared a SSCCE for you to observe this behavior. 我准备了一个SSCCE供你观察这种行为。 I need strtok(...) to work for a much larger piece of software I am writing, and I am getting the exact same segmentation behavior. 我需要strtok(...)来处理我正在编写的更大的软件,并且我得到完全相同的分段行为。 The output at the command line is shown below this code vignette (yes I know you use <...> to enclose libraries, but I was having difficulty getting this post to display the code libraries). 命令行的输出显示在此代码插图下方(是的,我知道您使用<...>来封装库,但是我很难获得此帖子来显示代码库)。 I am using gcc version 4.5.3, on a Windows 8 OS, and below shows two different flavors of how I imagine one could try to catch the NULL in a loop. 我在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);
  }
}
############ OUTPUT: ############

$ ./test
12
34
56
78
Segmentation fault (core dumped)

strtok modifies its first argument. strtok修改了它的第一个参数。 You are passing it a string from read-only memory, and the segfault occurs when strtok tries to change it. 您从只读内存传递一个字符串,当strtok尝试更改它时发生segfault。 Try changing from: 尝试改变:

char* from = "12.34.56.78";

to

char from[] = "12.34.56.78";

you are first checking if token is not equal to NULL(when it is, it breaks out of the while loop). 你首先检查token是否不等于NULL(当它是,它突破了while循环)。 Then you are comparing token , which is a NULL with a constant NUMBER? 然后你比较token ,这是一个NULL与常数NUMBER? here: strcmp(token, 0) when strcmp expects 2 strings, you provide a number. 这里: strcmp(token, 0)strcmp需要2个字符串时,你提供一个数字。 strcmp will try to fetch a string at 0th address(or NULL) giving you a segmentation fault. strcmp将尝试在第0个地址(或NULL)获取字符串,从而为您提供分段错误。

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

Also this piece of code should be something like the following: 此代码也应如下所示:

change 更改

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

to

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

This is a problem: 这是个问题:

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

You're checking for NULL, but then calling strtok again and not checking after that but before printing. 你正在检查NULL,但是再次调用strtok而不是在那之后但是在打印之前检查。

There are other problems with the code, but I suspect this is why it crashes where it does now. 代码还有其他问题,但我怀疑这就是它崩溃的原因。

The problem is that even though you terminate the loop when strtok() returns NULL , you try to print the NULL first: 问题是即使你在strtok()返回NULL时终止循环,你首先尝试打印NULL

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

It turns out there are several opportunities in addition to this one for segfaults in this example, as pointed out by other answers. 事实证明,除了这个例子之外,在这个例子中还有几个机会用于segfaults,正如其他答案所指出的那样。

Here's one way to handle your example tokenization: 这是处理示例标记化的一种方法:

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

If purpose of code is only to print element separated by '.', Only change in char declaration and before printing token check for its value NULL or not ! 如果代码的目的只是打印以'。'分隔的元素,则只更改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 OUTPUT
  ./test1 12 12 34 56 78 100 101 

You have both memory access errors and logic errors. 您有内存访问错误和逻辑错误。 I will only address the memory access errors that are causing your program to crash. 我只会解决导致程序崩溃的内存访问错误。

strtok modifies it's first argument. strtok修改了它的第一个参数。 Since you are passing in a string literal, it is unable to modify the string (string literals are not modifiable.) 由于传入字符串文字,因此无法修改字符串(字符串文字不可修改。)

Here's a possible fix to define from as a modifiable string array: 这是一个可能的修复, from一个可修改的字符串数组定义:

char from[] = "12.34.56.78";

Because strtok modifies the string passed into it, you cannot process that string again in your second while loop. 因为strtok修改了传入其中的字符串,所以在第二个while循环中不能再次处理该字符串。 You are essentially passing in a NULL into the strcmp function there. 您实际上是将NULL传入strcmp函数。 A possible fix would be to copy the from array into another buffer each time you wish to use strtok . 可能的解决方法是每次要使用strtok时将from数组复制到另一个缓冲区。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM