使用指向字符的指针作为 strtok 的参数

Using pointer to character as the argument of strtok

我尝试使用 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);

请帮助理解这个问题。

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

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

s1 指向一个字符串文字,它是常量,尝试修改字符串文字将导致段错误。

Battousai,首先你需要使用武士刀的反面,利用readable/writable区域来达到你的目的。如果你不这样做,除非compiler/OS(神谷薰)不阻止你, Shishio Makoto 可能会通过 Sojiro Seta 毁掉对你和你身边重要的人,如 Sanosuke Sagara, 明神弥彦.

strtok writes into the string you give it - overwriting the separator character with null and keeping a pointer to the rest of the string.

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.

问题是 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 节 - "String literals":

"It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined."