C++ size()函数的异常访问越界问题
先解释原因,size()函数返回的时一个无符号数,而无符号数在和有符号数比较时,两个数都会变为无符号数。
下面是我自己的探究过程:
在提交LeetCode 122 买卖股票的最佳时机 II 的解答时,我发现出现了异常的数据越界问题源代码如下:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int res = 0;
int n = prices.size();
for(int i=0; i<prices.size()-1; ++i){
if(prices[i] < prices[i+1])
res += prices[i+1] - prices[i];
}
return res;
}
};
运行后LeetCode提示数组访问越界,输入向量为prices = [],但是我们把prices放进去计算,其size()大小为0,在for循环的时候,直接会判断出不符合循环条件返回res=0。这是怎么出现访问越界的问题呢?在整个程序运行的时候根本就没有访问过vector的任何元素,何来越界之说。
之后在继续提交时,我将 i<prices.size()-1 改为 i<n-1 后竟然通过了。遇到这种奇怪的事情估计没人不想知道为什么,我就开始一步一步寻找原因。
首先,数组访问越界问题的出现一定是由于进行了数组元素的访问,废话,虽然这么说,但是确定是这个原因还是要仔细思考一下,怀疑一下自己的 既然出现了数组元素的访问,那么for循环的判断条件一定是通过的,为此我还去确定了for循环各语句的执行顺序,就是说 i < prices.size() - 1是成立的。从表面上看这就是 0 < 0 ,简直离谱。此时要么就是i 有问题,要么就是prices.size() - 1有问题,我们知道for循环实际上只有执行顺序的要求,对于执行语句无限制,因此就有了一下代码:
int res = 0;
int n = prices.size()-1;
cout<<prices.size()-3<<endl;
cout<<prices.size()-2<<endl;
for(int i=0; cout<<i<<endl<<prices.size()<<endl<<prices.size()-1<<endl<<(i<prices.size()-1); ++i) {}
结果如下:
可以很容易发现是prices.size()这个函数的返回值出现了问题,它不是正常的零值。这个时候我还怀疑是STL对于size()函数的定义是不是有什么特殊的地方,跑去看了半小时的stl.h文件。相信有些人已经发现了,这个prices.size()-1的返回值4294967295是个特殊值,它等于2的32次方减一。由于每次运行程序都出现该数值,让我相信这是一个特殊值,百度一搜,它就是32位无符号数所能表示的最大值,那么显而易见,prices.size()就是32位无符号数 0 了。接着就是0 < 4294967295了。
这里仍需注意,此处的0 < 4294967295 是有符号数和无符号数的比较,当有符号数和无符号数比较时,两者都会被转换为无符号数,此处恰巧成立,还有许多恰好不成立的情况。以下例程可以佐证:
#include <iostream>
using namespace std;
int main() {
unsigned a = 0;
int b = -1;
if(a > b)
cout << "0 > -1" << endl;
else
cout << "0 < -1" << endl;
cout << "a-1 = 0-1 = " << a-1 << endl;
}
这个问题我花了一两个小时才搞明白,不过竟然让我这种对学习提不起什么兴趣的人感到探索的乐趣,真是神奇~