C:将strtok令牌分配给char * Segfault

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C:将strtok令牌分配给char * Segfault相关的知识,希望对你有一定的参考价值。

为什么我会使用以下代码获得段错误?

#include <stdio.h>

int main()
{
    char * tmp = "0.1";
    char * first = strtok(tmp, ".");
    return 0;
}

编辑:

#include <stdio.h>

int main()
{
    char tmp[] = "0.1";
    char *first = strtok(tmp, ".");
    char *second = strtok(tmp, "."); // Yes, should be NULL
    printf("%s
", first);       
    printf("Hello World
");
    return 0;
}

可以在这里的在线gdb上复制段错误:https://www.onlinegdb.com/online_c_compiler

答案

你的第一个代码的问题是tmp指向一个字符串文字,这是只读的。当strtok尝试修改字符串时,它会崩溃。


您的第二个代码的问题是缺少包括:

#include <string.h>

这个缺少的标题意味着strtok在您的程序中未声明。 C编译器假定所有未声明的函数都返回int。对于返回strtokchar *来说,情况并非如此。您的示例中可能导致崩溃的原因是代码在64位计算机上运行,​​其中指针为8字节宽,但int仅为4字节。这会弄乱strtok的返回值,所以first是一个垃圾指针(当printf尝试使用它时崩溃)。

您可以通过这样做来自己确认

char *first = strtok(tmp, ".");
printf("%p %p
", (void *)tmp, (void *)first);

tmpfirst打印的地址应该是相同的(如果你是#include <string.h>,那就是它们)。


有趣的是,gcc可以警告你这些问题:

main.c: In function 'main':
main.c:6:19: warning: implicit declaration of function 'strtok' [-Wimplicit-function-declaration]
     char *first = strtok(tmp, ".");
                   ^
main.c:6:19: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
main.c:7:20: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
     char *second = strtok(tmp, "."); // Yes, should be NULL
                    ^

...并且onlinegdb将向您显示这些警告,但仅限于编译失败!

因此,要在onlinegdb上查看编译器警告,您必须向代码添加一个硬错误(例如,将@放在文件的最后一行)。

另一答案

函数strtok的行为是这样的:

  1. 接受字符串str或NULL以及一串分隔符字符。
  2. 然后strtok函数开始处理给定的字符串str,其中它逐字符地读取字符串,直到它遇到所提供的分隔符字符中存在的字符。
  3. 如果到达分隔符字符串之前遇到的字符数> 0,则用' n'替换分隔符字符,并返回指向此迭代中第一个字符的指针,该字符不是分隔符。
  4. 否则,如果到达分隔符字符串之前遇到的字符数是== 0,则继续迭代字符串的其余部分,而不用' n'替换此分隔符。

我已经创建了一些代码片段,可以帮助您更好地理解函数的性质,https://ideone.com/6NCcrRhttps://ideone.com/KVI5n4

现在回答你的问题,包括string.h标题和设置char tmp[] = "0.1";应该解决你的问题。

另一答案

使用char * tmp = "0.1";tmp指向无法修改的字符串文字,strtok尝试通过用.替换''来修改字符串。

避免使用segfault的另一种方法是使用strchr查找点和精度字段来打印有限数量的字符。子字符串也可以复制到其他变量。

#include <stdio.h>
#include <string.h>

int main ( void) {
    char * tmp = "0.1";
    char * first = strchr(tmp, '.');
    char * second = first + 1;
    if ( first) {
        printf ( "%.*s
", first - tmp, tmp);
        printf ( "%s
", second);
    }
    printf ( "Hello World
");
    return 0;
}
另一答案

tmp不是字符串文字,因为很少有答案或评论指出。

char * tmp =“0.1”这是一个字符串文字。

char tmp [] =“0.1”是一个字符数组,可以对它们执行所有数组操作。

出现段错误是因为未找到strtok的函数声明,因为string.h未包含在内,并且gcc或其他c编译器默认将返回类型隐式声明为int。

现在取决于平台,如果int size是4字节并且指针大小分别是8字节,则整数大小可以变化

char * first =(int)strtok(tmp,“。”);

截断发生在strtok返回的指针地址上,然后在打印时,您将取消引用首先包含的地址值,该地址值可能是一个超出范围的内存区域,从而导致分段错误或未定义的行为。

如果你可以将strtok的输出类型转换为8字节的类型(在我的情况下很长),那么就不会有段错误,尽管这不是一个干净的方法。

包括适当的头文件以避免未定义的行为。

以上是关于C:将strtok令牌分配给char * Segfault的主要内容,如果未能解决你的问题,请参考以下文章

在 strtok 之后将 arg 传递给 execl

Strtok_r 返回 NULL

使用strtok从字符串中解析空标记

将字符串*分配给char * c ++ [关闭]

字符串分割strtok_s

c-strtok