size()函数的访问越界问题

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;
}

这个问题我花了一两个小时才搞明白,不过竟然让我这种对学习提不起什么兴趣的人感到探索的乐趣,真是神奇~

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值