从字符串

时间:2018-01-18 06:48:04

标签: c string segmentation-fault strtok

我正在尝试打印一个大字符串中包含的所有子字符串,每个字符串'/'个字符分隔。我的功能没有像我期望的那样工作,但我没有弄到它有什么问题。这是我写的函数:

void print_serial_list(char *serial_list) {
    char *iter = serial_list;
    while (*iter != '\0') { // Traverse the whole string
        char *tmp_fn;
        tmp_fn = strtok(iter,"/");
        printf("Extracted entry: '%s'\n", tmp_fn);
        iter = iter + sizeof(tmp_fn);
    }
}

直接传递字符串

如果我像这样运行这个函数:

char *string = "Lorem.ipsum/dolor-sit-amet/consectetur/adipiscing.elit/";
printf("%s\n", string);
print_serial_list(string);

我遇到了分段错误:

Lorem.ipsum/dolor-sit-amet/consectetur/adipiscing.elit/
Segmentation fault (core dumped)

使用get_string()函数

另一方面,如果我运行它:

char *string = get_string();
printf("%s\n", string);
print_serial_list(string);

我得到以下输出(仍然错误):

Lorem.ipsum/dolor-sit-amet/consectetur/adipiscing.elit/
Extracted entry: 'Lorem.ipsum'
Extracted entry: 'sum'
Extracted entry: 'r-sit-amet'
Extracted entry: 'et'
Extracted entry: 'ctetur'
Extracted entry: 'dipiscing.elit'
Extracted entry: 'g.elit'
Extracted entry: '�'
Extracted entry: 'x[�V'
Extracted entry: 'x[�V'

期望

为了清楚起见,我希望输出在两种情况下:

Lorem.ipsum/dolor-sit-amet/consectetur/adipiscing.elit/
Extracted entry: 'Lorem.ipsum'
Extracted entry: 'dolor-sit-amet'
Extracted entry: 'consectetur'
Extracted entry: 'adipiscing.elit'

注意 :我希望get_string()的代码不需要理解这个问题......我想尝试一下保持帖子不会太长

修改

在评论中提出了几条建议后,我以这种方式编辑了这个功能:

char *iter = serial_list;
bool first = true;
while (*iter != '\0') { // Traverse the whole string
    char *tmp_fn;
    if (first)
        tmp_fn = strtok(iter, "/");
    else
        tmp_fn = strtok(NULL, "/");
    size_t tmp_size = strlen(tmp_fn);
    printf("Extracted entry: '%s' - size = %zu\n", tmp_fn, tmp_size);
    iter = iter + tmp_size;
    first = false;
}

我得到的输出仍有一些问题,但与我想要的更相似!

Lorem.ipsum/dolor-sit-amet/consectetur/adipiscing.elit/
Extracted entry: 'Lorem.ipsum' - size = 11

1 个答案:

答案 0 :(得分:2)

  

If I run this function like this, I get a segmentation fault:

     

char *string = "Lorem.ipsum/dolor-sit-amet/consectetur/adipiscing.elit/";

您的程序正在尝试修改字符串文字时遇到undefined behavior,因为您正在将字符串文字传递给strtok()

  

char * strtok(char * str,const char * delimiters);

     

将字符串拆分为标记

     

对此函数的一系列调用将str拆分为标记,标记是由作为分隔符一部分的任何字符分隔的连续字符序列。

string是指向字符串文字的指针,其内容无法修改。并尝试通过指针修改它们是Undefined Behavior。

要解决此问题,您只需执行此操作:

char string[] = "Lorem.ipsum/dolor-sit-amet/consectetur/adipiscing.elit/";
           ^^

print_serial_list()函数中,你可以这样做:

void print_serial_list(char *serial_list) {
    char *iter = serial_list;

    if (serial_list == NULL)
            return;

    char *tmp_fn = strtok(iter, "/");
    while (tmp_fn != NULL)
    {
            printf ("Extracted entry: '%s'\n", tmp_fn);
            tmp_fn = strtok(NULL, "/");
    }
}

print_serial_list()输出(对于Lorem.ipsum/dolor-sit-amet/consectetur/adipiscing.elit/输入字符串):

Extracted entry: 'Lorem.ipsum'
Extracted entry: 'dolor-sit-amet'
Extracted entry: 'consectetur'
Extracted entry: 'adipiscing.elit'

此处需要注意的是print_serial_list()将修改字符串string,因为它会将其传递给strtok()。如果您不希望在调用print_serial_list()函数后修改输入字符串,请在print_serial_list()函数中复制它。

来自strtok

  

错误   使用这些功能时要小心。如果您确实使用它们,请注意:

     

*这些函数修改了他们的第一个参数。

     

*这些函数不能用于常量字符串。

     

*分隔字节的标识丢失。

感谢@David C. Rankin在评论中分享这些strtok()个错误。