1

strsep与多个分隔符一起使用时,我目前有一些奇怪的结果。我的分隔符包括 TAB 字符、空格字符以及>and <

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

int main()
{
    char buffer[50];
    char *curr_str = NULL;
    const char delim[4] = "\t >";
    //const char delim[4] = "\t ><"; // This does not work
  
    snprintf(buffer, 50, "%s", "echo Hello");
  
    char *str_ptr = buffer;
  
    curr_str = strsep(&str_ptr, delim);
  
    if (curr_str != NULL)
        printf("%s\n", curr_str);

    curr_str = strsep(&str_ptr, delim);
    if (curr_str != NULL)
        printf("%s\n", curr_str);
    return (0);
}

这个输出是我所期望的。

echo 
Hello

但是,只要我为分隔符添加 '<' 字符,我就会得到

cho

不知何故,第一个字符被切断了。发生这种情况是否有原因?

谢谢你。

4

3 回答 3

2

, 的第二个参数strsepdelim一个以 null 结尾的字符串(就像 C 中的所有字符串一样),因此您必须为终止字符留出空间:

const char delim[5] = "\t ><"; // This does work
//const char delim[] = "\t ><"; // or this

如果您不结束字符串,它将去探索数组之外的内存并找到许多新的分隔字符来使用,这就是您的情况。

于 2021-05-11T18:29:54.253 回答
0

const char delim[4] = "\t ><";没有定义正确的 C 字符串,因为空终止符没有空间。因此,内存中跟随的任何非零字节delim都将成为分隔符字符串的一部分。

这当然是未定义的行为,在您的情况下,编译器可能会delimbuffer没有任何填充的情况下定位,有效地继续使用 string 中的所有字符的定界符序列"echo Hello"。这会导致第一次调用strsep返回一个空字符串。

您可以检查这个Godbolt 实例,在 32 位模式下确实是这种情况,但在 64 位模式下却不是(删除-m32编译器选项)。

这个问题很容易解决。您可以让编译器确定delim数组的长度:

const char delim[] = "\t ><";

或者您可以使用指向字符串常量的指针:

const char *delim = "\t ><";
于 2021-05-11T18:57:58.240 回答
0

“......第一个字符被切断了。发生这种情况有什么原因吗?”

是的,由 C 字符串函数中使用的非空终止字符数组引起的未定义行为。

如果填充时 const char delim[4]不包含空终止符,它将只是一个char数组,而不是C 字符串它可能表现出奇怪的行为,也可能不表现出奇怪行为,但如果与任何C 字符串函数(例如.curr_str = strsep(&str_ptr,delim);

const char delim[4];

有 4 个字符的空间。

"\t ><"  //contains exactly 4 char

在内存中可以这样概念化:

|\t| |>|<|?|?|?|  // ? = unknown content, possibly no null termination
         ^end of owned memory

它应包含以下内容:

|\t| |>|<|\0|?|?|  // null termination  
            ^end of owned memory (5 char wide)

在声明中需要更多空间,例如以下两个选项之一:

const char delim[5] = "\t ><";

或者

const char delim[] = "\t ><";
于 2021-05-11T18:38:21.413 回答