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

时间:2018-09-01 20:03:10

标签: c arrays pointers segmentation-fault

为什么使用以下代码会出现段错误?

#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\n", first);       
    printf("Hello World\n");
    return 0;
}

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

4 个答案:

答案 0 :(得分:4)

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


第二个代码的问题是缺少以下内容:

#include <string.h>

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

您可以通过执行此操作自己确认

char *first = strtok(tmp, ".");
printf("%p %p\n", (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上的编译器警告,您必须在代码中添加一个硬错误(例如,通过在文件的最后一行放置@)。

答案 1 :(得分:3)

函数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";应该可以解决您的问题。

答案 2 :(得分:2)

对于char * tmp = "0.1";tmp指向一个不能被修改的字符串文字,strtok尝试通过将.替换为'\0'来修改该字符串。 / p>

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

#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\n", first - tmp, tmp);
        printf ( "%s\n", second);
    }
    printf ( "Hello World\n");
    return 0;
}

答案 3 :(得分:0)

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

char * tmp =“ 0.1”,这是字符串文字

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

出现段错误是因为未找到strtok的功能声明,因为未包含 string.h ,并且gcc或其他c编译器隐式声明了默认情况下,返回类型为int

现在取决于平台,整数大小可能会有所不同,如果int大小分别为 4字节并且指针大小为 8字节

  

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

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

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

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