【问题标题】:Strtok_r segmentation faultstrtok_r 分段错误
【发布时间】:2015-12-16 16:56:15
【问题描述】:

我知道以前有人问过这个问题,但以前的答案说你不能修改字符串文字,除非我误解我不是。我可以成功使用 strtok_r 直到输入的最后一行,然后我得到一个段错误。为什么会发生这种情况?这是我的代码的简化版本。从打印我知道它通过 get b 处理,但是有一个段错误?

#include <stdio.h>
#include <string.h>   //strlen
#include <stdlib.h>

    void handler(char * input){
    char * end_str;
    char * token =strtok_r(input, "\n", &end_str);
    char * endd_str;
    char * token2= strtok_r(token, " ", &endd_str);
    while(token!=0){
        printf("%s\n",token);
        token=strtok_r(NULL,"\n",&end_str);
        while(token2 !=0){
            token2 =strtok_r(NULL," ",&endd_str);
            printf("%s\n",token2);}
    }

}

int main(int argc , char *argv[])
{
    char test[100]="set a,10.5\nset b,11.5\nget b\nadd e,a,b\nsub g,a,b";
    handler(test);
    return 0;
}

【问题讨论】:

  • 提供的代码是否也失败了?如果没有,您没有提供足够的数据让任何人告诉您失败的原因。见stackoverflow.com/help/mcve
  • 无法使用您提供的示例代码重新创建 seg 错误。您确定是strtok_r 导致了段错误,而不是其他原因。
  • 为什么你认为程序执行会产生一些有意义的东西?您可以查看生成的二进制代码以了解您的情况。

标签: c


【解决方案1】:

您正在交错使用同一字符串的 strtok_r 调用。在内部while 循环的第二次迭代中,在调用token2 =strtok_r(NULL," ",&amp;endd_str); 之前,endd_str 指向一个空字符串,因为它匹配的字符串到达​​了末尾,所以strtok_r 返回NULL。将 NULL 传递给 printf 会导致段错误。

每次解析 "\n" 分隔符后,重新开始循环遍历 " " 分隔符。在你用尽内部的之前,不要再做外部的。此外,将您的 strtok_r 调用移至循环末尾,以便 while 条件正确检查它们。

您需要执行以下操作:

void handler(char * input){
    char * end_str;
    char * token =strtok_r(input, "\n", &end_str);
    while(token!=0){
        printf("%s\n",token);
        char * endd_str;
        char * token2= strtok_r(token, " ", &endd_str);
        while(token2 !=0){
            printf("%s\n",token2);
            token2 =strtok_r(NULL," ",&endd_str);    // call at end of loop
        }
        token=strtok_r(NULL,"\n",&end_str);          // call at end of loop
    }
}

输出:

set a,10.5
set
a,10.5
set b,11.5
set
b,11.5
get b
get
b
add e,a,b
add
e,a,b
sub g,a,b
sub
g,a,b

【讨论】:

    【解决方案2】:

    非常适合我(MS Visual C++)。唯一的区别是使用 strtok_s 而不是 strtok_r 考虑到它是 Windows 而不是 POSIX。

    这里我对你的代码做了一些修改。

    #include <string.h>   //strlen
    #include <stdlib.h>
    
    void handler(char * input){
        char * end_str;
        char * token =strtok_s(input, "\n", &end_str); // tokenize input string
        char * endd_str;
        char * token2 = NULL;
    
        while(token!=0){
    
            printf("%s\n",token);
    
            token2 = strtok_s(token, " ", &endd_str); // retokenize first token
            while(token2 !=0){
                printf("%s\n",token2); // replace printf call to avoid null string output and first token miss
                token2 =strtok_s(NULL," ",&endd_str);}
    
            token = end_str; // "important" restore char pointer to point the last untokenized input character
    
            token=strtok_s(token,"\n",&end_str); // the same as printf issue is for all loops body
        }
    
    }
    
    int main(int argc , char *argv[])
    {
        char test[100]="set a,10.5\nset b,11.5\nget b\nadd e,a,b\nsub g,a,b";
        handler(test);
        return 0;
    }
    

    【讨论】:

    • 我不认为当前提出的问题提供了 MCVE
    • 介意解释 _s 和 _r 之间的区别吗?
    • @Mr_Pouet:对于 Windows 操作系统,其功能相同 _s,对于 POSIX,其功能相同 _r,只是命名不同。
    猜你喜欢
    • 2018-07-20
    • 1970-01-01
    • 2011-01-14
    • 2020-03-02
    • 1970-01-01
    • 2021-01-01
    • 2019-03-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多