std :: string的字符引用

时间:2009-09-02 08:05:18

标签: c++ stdstring

我有以下字符串:

index                                       0   1   2   3   4   5   6   7
std::string myString with the content of "\xff\xff\xff\x00\xff\x0d\x0a\xf5"

当我引用myString [3]时,我得到了预期的'\ x00'值。

但是当我提到myString [5]时,我得到两个值“\ x0d \ x0a”而不是'\ x0d'。

更有趣的是myString [6]值,即'\ xf5'。这次它就像\ x0d不存在而且引用了正确的位置。

我的问题是:std:string对象中的\ x0d字符有什么特别之处?为什么索引时会跳过它?这就像这样计算:

index                     0   1   2   3   4   5   5   6
std::string myString = "\xff\xff\xff\x00\xff\x0d\x0a\xf5"

作为注释,'\ x0d'字符是第13个ASCII字符“回车”,'\ x0a'是换行符。

更新:是否可以将std :: string视为“\ x0d \ x0a”作为单个字符,因此只占用字符串中的一个位置?这个'\ x0d'是关于std :: string的“神秘”字符吗?

附加信息:http://en.wikipedia.org/wiki/Newline

5 个答案:

答案 0 :(得分:9)

你确定std::string发生了这种情况吗? std::string::operator[]会返回const char &,那么如何返回两个字符('\x0d' '\x0a')?

也就是说,"\x0d\x0a"通常用于Windows下的行结尾,而在Linux下只使用'\x0a',因此在Windows下将前者转换为后者相对常见 - 例如,我正在考虑使用fopen调用时"wt"的行为。我猜你会发生类似的情况。

编辑:根据您对原始问题的评论,我想我可以猜到发生了什么。

我相信你的字符串并不真正包含你认为它包含的内容。您被误导是因为您用于将字符串输出到文件(可能是ofstream?)的机制正在执行行尾转换。这意味着'\n'(Unix行尾代码)正在转换为'\r\n'(Windows行尾代码)。行尾转换的目的是使代码在操作系统之间更加可移植。您可以通过在二进制模式下打开文件来禁止它;对于ofstream,这是通过在打开文件时指定ios_base::binary标志来完成的,但默认情况下不设置此标志。

(有关不同操作系统上行尾标记的详细信息,请参阅此Wikipedia article。)

这是我认为正在发生的事情。你的字符串实际上包含

index                 0   1   2   3   4   5   6
myString contents  "\xff\xff\xff\x00\xff\x0a\xf5"

你输出的是这样的东西:

ofstream file("myfile.txt");
for(size_t i=0; i<myString.size(); i++)
    ofstream << myString[i];

由于上面提到的行尾翻译,'\x0a'中的myString[5]输出为'\x0d\x0a',这就是让您感到困惑的原因。

答案 1 :(得分:9)

这里出现的问题是以下行没有达到您的预期:

std::string myString = "\xff\xff\xff\x00\xff\x0d\x0a\xf5";

这将调用std::string(const char *)构造函数,该构造函数用于将C样式的以null结尾的字符串转换为C ++ std::string。此构造函数从给定指针开始读取字节,并将它们复制到新的std::string,直到它到达空字节(\ x00)。这与C函数的行为一致,例如strlen()

因此,当构造myString时,它由一个长度为3的字符串组成,其中包含bytes \ xff,\ xff,\ xff。对大于2的索引的访问是访问数组末尾的字节(最多会产生运行时错误,或者最坏的情况下会产生未定义的行为)。

请注意,std::string可以保存中间空字节,但是不能使用上面的构造函数来初始化这样的字符串,因为空字节被解释为终止传递的C样式字符串到构造函数。

将\ x00字节改为其他内容再次尝试代码是值得的,只是为了看看它与你已经描述的有什么不同:

std::string myString = "\xff\xff\xff\x01\xff\x0d\x0a\xf5"

另外,在上面的构造函数之后检查myString.length(),看看你得到了什么。

答案 2 :(得分:2)

使用以下构造函数创建字符串:string(char const *)

它收到NUL终止的C字符串。所以它根据前0个字符找到它的长度。

您应该使用指定大小的其他构造函数:string(char const *,size_t n),方法是调用:

std::string myString("\xff\xff\xff\x00\xff\x0d\x0a\xf5",8);

有关详细信息,请参阅http://www.cplusplus.com/reference/string/string/string/

答案 3 :(得分:0)

您可能误用[]运算符。

[]运算符返回一个const char。但是你可能使用它作为指针,从而得到两个字符 - 我们需要看到你的实际代码来确认这一点。

0x00是c-string的空终止符,因此这可能就是为什么你只得到一个(正确的)字符。

当你得到[4]时会发生什么?

答案 4 :(得分:0)

在visual studio 2008中,\ x00被认为是字符串的结尾。所以myString.lenght返回3.当你尝试访问myString [5]时会出现错误。