C/C++ .size()函数的智障问题(关于codeforce的一次"Exit code is 3"的弱智经历)

2023.7.31

提交样例
题目
Exit code is 3

蒙了,检查题目思路绝对没问题,但是运行错误
开始逐步排查代码,缩小可能出错的范围,用时1h,终于定位出错误

下面是出错样例代码


string substr(string &t,int st,int len)
{
	string res;
	int n = t.size();
	// debug2(n,len);
	for(int i = st;i < st+len;i ++){
		res += t[i];
		// if(i >= n)debug5(i,n,st,len,st+len);
	}
	return res;
}


void solve()
{
	string s;cin >> s;
	vector<int> res;
	// debug2(s,s.size());
	int n = s.size();
	for(int i = 0;i < s.size()-2;i ++)
	{
		// debug2(i,s.substr(i,3));
		// debug2(n,s.size());
		// assert(n == s.size());
		// debug3(i,(s.size() - 4),(i < s.size() - 4));
		if(i < s.size() - 4 && substr(s,i,5) == "twone")
		{
			
			res.push_back(i+1+2);
			i += 4;
		}
		else if(substr(s,i,3) == "one" || substr(s,i,3) == "two")
		{
			res.push_back(i+1+1);
			i += 2;
		}
		
	}
	cout << res.size() << endl;
	for(auto x:res)cout << x << " ";
	cout << endl;
	
}

发现问题出在在for循环结束条件i < s.size()-2和第一个判断条件i < s.size() - 4

本意是判断边界,防止出现越界的情况

但是当我打印出它的值却发现是一个20多位的正整数

这下问题就很明显了,可能是数据类型越界

打开一看.size()函数的源码,发现

在 C++ 中,std::vector 的 size() 函数返回的是无符号整数类型 size_type,它通常是 std::size_t 类型。std::size_t 是无符号整数类型,它的取值范围是非负整数,因此当使用 res.size()-2 这样的表达式时,如果 res.size() 的值比 2 小,那么结果将会出现意外的行为。

终于找到问题了,在res.size()-2 这样的表达式中res.size()类型较高,-2不会改变类型,产生溢出,导致边界判断失效

怎么改应该很简单了,但是这个问题真的很烦人,不了解C/C++一点底层知识,根本不知道怎么办

不过总算解决了,贴一个代码

2023.7.18

Roulette

  • 1 << k+1这句代码很容易产生越界,1是一个常量int类型,在编译器中还是一个int,尽管后面的k是long long(相当于无视)
  • 即使#define int long long也没有用
  • 所以不建议每次都是用定义int 为 long long,要仔细考虑代码的每一个地方
  • 不要使用快速幂对想要的幂次数,因为1 << k+1这句代码要的结果是不对mod取模的,除非再写一个快速幂不带模

2023.5.26

img
img

  • https://codeforces.com/contest/1837/my
  • 如图,当把所有的逻辑都做完之后,错在了在线上,直接return了,G
  • 一定要有良好的逻辑分支,做到一丝不苟!
  • 当出现bug时,只有两种情况,要么是别人错了,要么是我的代码某个地方错了,这个地方,一定可能是任何地方!

2023.4.27

2023.4.25

  • https://codeforces.com/contest/1822/my
  • 卡常教训:把所有的内存占用都移出栈区,数据量很大的时候,在栈区里面开空间非常耗费时间!
  • 尽量少使用vector当成数组!!!
  • 卡常很极限可以用map和set等stl在特殊的地方优化

2023.4.2

  • 还是数学有关的
  • 会超出LL,需要做一些特殊处理
    img
  • 如图,sqrt在对64位整数运算时会产生极大的误差,必须再手动校准(sqrtl也没有好到哪里去)
  • 找到第一个小于等于m开平方数字
int limit = sqrtl(m);
    while((limit - 1)*(limit - 1) >= m)
        limit--;
    while ((limit + 1) * (limit + 1) < m)
        limit++;
  • 找到第一个大于等于m开平方数字
    LL x = sqrtl(m);
    for(;x*x>m;x--){}
    for(;x*x<=m;x++){}
  • 还有很重要的一点,cout会自动把double转为科学计数法,这必须要注意!!!

2023.3.24

  • 炸裂的精度ceil,long long类型数字开平方sqrt有非常多的精度损失
  • 导致ceil的准确率非常低
  • 所以开平方禁止使用sqrt,尤其是在此情况下

debug2(ceil(2 + eps),2+eps)
double只有8字节,相当于只能存储20位整数,包括小数和整数部分的位数和,所以这样后的表达式double类型为2,精度损失
输出为ceil(2 + eps) = 2 2+eps = 2

2023.3.11

  • 不要使用INT_MAX等宏定义做变量,很容易产生越界
  • lower_bound和upper_bound都会在set.end()越界,必须特判
  • 分类讨论太多的时候必须非常细致
  • 边界问题,尽量不要用特殊值替代(除非很熟练),做到能用自然语言描述就好
  • https://codeforces.com/contest/1802/my

2023.2.27

  • debug就是逐步缩小范围,甚至是一句一句调试

2023.2.14

2023.1.30

2023.1.19

posted @   俄罗斯刺沙蓬  阅读(213)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
返回顶端
点击右上角即可分享
微信分享提示