【问题标题】:Using pointer to character as the argument of strtok使用指向字符的指针作为 strtok 的参数
【发布时间】:2020-07-16 15:45:17
【问题描述】:

我尝试使用strtok 函数拆分字符串。但是如果我使用指向字符的指针作为这个函数的参数,程序就会失败。

如果我将字符串初始化为s2s3,则程序运行良好。但是如果我使用指向字符的指针s1,程序会得到Segmentation fault (core dumped)

char *s1 = "1A 2B 3C 4D";
char s2[] = "1A 2B 3C 4D";
char s3[20] = "1A 2B 3C 4D";

问题在于其他函数,printfstrlen 正常工作,但只有 strtok 出错。

完整代码如下:

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

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

int main()
{
    char *s1 = "1A 2B 3C 4D";
    char s2[] = "1A 2B 3C 4D";
    char s3[20] = "1A 2B 3C 4D";
    printf("size of s1 = %ld, s2 = %ld, s3 = %ld\n", strlen(s1), strlen(s2), strlen(s3));
    printf("s1: %s\ns2: %s\ns3: %s\n",s1,s2,s3);
    printf("split s2: \n");
    split_string(s2);
    printf("split s3: \n");
    split_string(s3);
    printf("split s1: \n");
    split_string(s1);
    return 0;
}

运行后的结果:

size of s1 = 11, s2 = 11, s3 = 11
s1: 1A 2B 3C 4D
s2: 1A 2B 3C 4D
s3: 1A 2B 3C 4D
split s2: 
1A
2B
3C
4D
split s3: 
1A
2B
3C
4D
split s1: 
Segmentation fault (core dumped)

strtok 来自man 页面:char *strtok(char *str, const char *delim);

请帮助理解这个问题。

【问题讨论】:

    标签: c arrays string pointers strtok


    【解决方案1】:

    Battousai,首先你需要使用你的武士刀的反面通过使用可读/可写区域来实现你的目标。如果你不这样做,除非编译器/OS(Kamiya Kaoru) 不会阻止你, Shishio Makoto 可能会通过 Sojiro Seta 毁掉对你和你周围重要的人,生活在你的记忆中,例如 Sanosuke SagaraYahiko Myojin .

    strtok 写入你给它的字符串 - 覆盖 带有 null 的分隔符并保持指向其余部分的指针 字符串。

    char *s1 = "1A 2B 3C 4D"; // you have a pointer to some read-only characters
    char s2[] = "1A 2B 3C 4D"; // same, decay into pointer
    char s3[20] = "1A 2B 3C 4D"; // a twenty element array of characters that you can do what you like with.
    

    【讨论】:

      【解决方案2】:

      strtok 修改给它的数据并且字符文字是只读的。这将导致问题,在这种情况下是段错误。

      其他形式将导致制作只读数据的副本,以便它们正常工作。

      【讨论】:

        【解决方案3】:

        s1 指向一个字符串字面量,它是常量,任何修改字符串字面量的尝试都会导致段错误。

        【讨论】:

        • s1 是指向字符串文字的指针。这不是字符串文字,不是吗?
        • @Hitokiri,是的,这是正确的,我澄清了我的答案。
        【解决方案4】:

        问题是strtok() 修改了它的参数指向的字符串 - (它不只解析它)并且通过将s1 作为参数你试图修改一个字符串文字。


        在你的情况下:

        char s2[] = "1A 2B 3C 4D";
        char s3[20] = "1A 2B 3C 4D";
        

        s2s3 都是可修改的 char 数组,每个数组都包含一个字符串,而:

        char *s1 = "1A 2B 3C 4D";
        

        s1 是指向字符串文字"1A 2B 3C 4D" 的指针,它是只读的,不能修改。

        任何修改字符串文字的尝试都会导致未定义的行为,在您的情况下会导致内存中的分段错误。

        来自 ISO:IEC 9899:2018 (C18) 第 6.4.5/7 节 - “字符串文字”:

        "不确定这些数组是否是不同的,只要它们的 元素具有适当的值。 如果程序试图 修改这样的数组,行为未定义。"

        【讨论】:

        • s2 可以修改吗? s2[15] = 'X' 可能吗?
        • @snr 是的,s2 是可修改的,例如s2[0] = 'X'; 是可能的。我并没有说允许超出数组的范围写入。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-03
        • 1970-01-01
        • 1970-01-01
        • 2011-01-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多