C++ string.length() 奇怪的行为

Posted

技术标签:

【中文标题】C++ string.length() 奇怪的行为【英文标题】:C++ string.length() Strange Behavior 【发布时间】:2015-06-17 00:28:45 【问题描述】:

我刚刚遇到了一个非常奇怪的问题。我的功能很简单:

int strStr(string haystack, string needle) 

    for(int i=0; i<=(haystack.length()-needle.length()); i++)
        cout<<"i "<<i<<endl;
    
    return 0;

那如果我调用strStr("", "a"),虽然haystack.length()-needle.length()=-1,这不会返回0,你可以自己试试……

【问题讨论】:

@aslg 不,你也可以试试 size(),同样的行为。 @aslg 根据docs,它们并没有什么不同。 据我所知,长度和大小是相同的。 i=0; i &lt;= -1; i++ 需要一段时间才能到达出口案例。 @user4581301 为什么要花一点时间?根本不应该进入循环 因为 -1 是一个无符号整数。 【参考方案1】:

这是因为.length()(和.size())返回size_t,这是一个无符号整数。你认为你得到一个负数,而实际上它下溢回到size_t 的最大值(在我的机器上,这是 18446744073709551615)。这意味着您的 for 循环将遍历 size_t 的所有可能值,而不是像您期望的那样立即退出。

要获得您想要的结果,您可以将大小显式转换为 ints,而不是 unsigned ints(请参阅 aslgs 答案),尽管对于具有足够长度的字符串(足以溢出/不足),这可能会失败一个标准的int)

编辑: 来自以下 cmets 的两个解决方案:

    (Nir Friedman) 不要像 aslg 的回答那样使用 int,而是包含标题并使用 int64_t,这将避免上述问题。

    (rici) 将您的 for 循环转换为 for(int i = 0;needle.length() + i &lt;= haystack.length();i ++),通过重新排列等式来避免所有减法,从而避免所有问题。

【讨论】:

由于您提到的原因, int 不是一个很好的建议。在大多数体系结构中,int 只有 32 位。相反,我建议 #include 并使用 int64_t 或 long long int(保证至少 64 位)。这适用于所有字符串,除非您的计算机有 2^63 字节的 RAM。 或者通过将条件写为:needle.length() + i &lt;= haystack.length() 来避免问题【参考方案2】:
(haystack.length()-needle.length())

length 返回一个size_t,换句话说,一个无符号整数。给定字符串的大小,分别为 0 和 1,当您计算差异时,它会下溢并成为 unsigned int 的最大可能值。 (对于 4 个字节的存储,这大约是 42 亿,但可能是不同的值)

i<=(haystack.length()-needle.length())

编译器将索引器i 转换为无符号整数以匹配类型。所以你必须等到i 大于无符号整数的最大可能值。它不会停止。

解决方案:

你必须将每个方法的结果转换为int,像这样,

i <= ( (int)haystack.length() - (int)needle.length() )

【讨论】:

以上是关于C++ string.length() 奇怪的行为的主要内容,如果未能解决你的问题,请参考以下文章

奇怪的编译器行为 (C++)

gcc 的奇怪行为。带有 和 = 的 C++ 对象定义是不是相等?

C++ while循环奇怪的行为

C++ 初始化奇怪的行为

C++ 向下转换对象的奇怪行为

C++ 中 operator= 的奇怪行为