会引起 Compile Error 的错误

由于这类错误过于简单,相信是个正常人都会修,故略写。

  • int main() 写为 int mian()

  • 写完 structclass 忘记写分号。

  • 数组开太大,(在 OJ 上)使用了不合法的函数(例如多线程),或者函数声明但未定义,会引起链接错误。

  • 使用 algorithm 中的 max 函数时,一个参数类型为 int 而另一个参数类型为 long long

    • 示例:

      printf("%lld\n", max(0, query(1, 1, n, l, r)); // query 返回 long long 类型
  • goto 的时候,跳过了一些局部变量的初始化。

-    `switch-case` 的时候,跳过了一些局部变量的初始化。

不会引起 Compile Error 但会引发 Warning 的错误

这类错误较难发现,但会在使用 -W{warningtype} 参数编译时被编译器指出,所以要多学会使用 -W{warningtype} 参数,常见的有 -Wall-Wextra-Wshadow 等。

  • 由于运算符优先级产生的错误。

    • 1 << 1 + 1 : 1 左移了 2,即该表达式返回的值是 4。
  • 不正确地使用 static 修饰符。
  • -1 >> 1 == 1
  • 赋值运算符和 == 不分。
    • 示例: cpp if (n = 1) puts("Yes"); else puts("No"); 无论 \(n\) 的值之前为多少,输出肯定是 Yes 。 Tips: 如果你的确是想在 if / while 直接用赋值运算符(比如 while (foo = bar) ),又不想收到 Warning,可以使用 双括号while ((foo = bar))
  • 使用 scanf 读入的时候没加取地址符 & 。更一般地,使用 scanfprintf 的时候参数类型与格式指定符不符。
  • 没有考虑数组下标出现负数的情况。
  • 同时使用位运算和逻辑运算符( == )并且未加括号(例如 (x>>j)&3==2 )。
  • int 字面量溢出,例如: long long x = 0x7f7f7f7f7f7f7f7f1<<62
  • 未初始化局部变量,导致局部变量被赋予垃圾初值。
  • 局部变量与全局变量重名,导致全局变量被意外覆盖。(开 -Wshadow 就可检查此类错误。)

既不会引起 Compile Error 也不会引发 Warning 的错误

这类错误无法被编译器发现,所以在调试时只能依靠你自己。

会导致 WA

  • 多组数据未清空数组。

  • 读入优化未判断负数。

  • 所用数据类型不够大导致溢出,即常见的“三年 OI 一场空,不开 long long 见祖宗”,意思是因为没有使用 long long (开 long long )导致大量丢分从而赛季作废。

  • 存图时,节点编号 0 开始,而题目给的边中两个端点的编号从 1 开始,读入的时候忘记 -1。

  • 大/小于号打错或打反。

  • 在执行 ios::sync_with_stdio(false); 后混用两种 IO,导致输入/输出错乱。

    • 可以参考这个例子。

      // 这个例子将说明,关闭与 stdio 的同步后,混用两种 IO 的后果
      // 建议单步运行来观察效果
      #include <cstdio>
      #include <iostream>
      int main() {
      std::ios::sync_with_stdio(false);
      // 关闭同步后,cin/cout 将使用独立缓冲区,而不是将输出同步至 scanf/printf
      // 的缓冲区,从而减少 IO 耗时
      std::cout << "a\n";
      // cout 下,使用'\n'换行时,内容会被缓冲而不会被立刻输出,应该使用 endl
      // 来换行并立刻刷新缓冲区
      printf("b\n");
      // printf 的 '\n' 会刷新 printf 的缓冲区,导致输出错位
      std::cout << "c\n";
      return 0; //程序结束时,cout 的缓冲区才会被输出
      }
    • 特别的,也不能在执行 ios::sync_with_stdio(false); 后使用 freopen

  • 由于宏的展开,且未加括号导致的错误:

    #define square(x) x* x
    printf("%d", square(2 + 2));

    该宏返回的值并非 \(4^2 = 16\) 而是 \(2+2\times 2+2 = 8\) 。

  • 哈希的时候没有使用 unsigned ,因为对负数的右移运算会在最高位补 1,详见 位运算

  • 没有删除调试信息。

  • 误加了 ;

    • 可以参考这个例子:

      /* clang-format off */
      while (1);
      printf("OI Wiki!\n");
  • 没有正确设置哨兵值。例如,平衡树的 0 节点。

  • 在类或结构体的构造函数中,使用 : 初始化变量,且变量声明顺序不符合初始化时候的依赖关系。因为成员变量的初始化顺序只与它们在类中声明的顺序有关,而与在初始化列表中的顺序无关。

  • 并查集合并集合时没有把两个元素的祖先合并:

f[a] = b;              //错误
f[find(a)] = find(b); // 正确

会导致 RE

  • 对整数除以 \(0\) 。

    • 对 \(0\) 求逆元。
  • 没删文件操作(某些 OJ)。

  • 排序时比较函数的错误 std::sort 要求比较函数是严格弱序: a<afalse ;若 a<btrue ,则 b<afalse ;若 a<btrueb<ctrue ,则 a<ctrue 。其中要特别注意第二点。 如果不满足上述要求,排序时很可能会 RE。 例如,编写莫队的奇偶性排序时,这样写是错误的:

    bool operator<(const int a, const int b) {
    if (block[a.l] == block[b.l])
    return (block[a.l] & 1) ^ (a.r < b.r);
    else
    return block[a.l] < block[b.l];

    上述代码中 (block[a.l]&1)^(a.r<b.r) 不满足严格弱序的要求 2。 改成这样就正确了。

    bool operator<(const int a, const int b) {
    if (block[a.l] == block[b.l])
    return (block[a.l] & 1) ? (a.r < b.r) : (a.r > b.r);
    else
    return block[a.l] < block[b.l];
  • 解引用空指针。

会导致 TLE

  • 分治未判边界导致死递归。

  • 死循环。

    • 循环变量重名。
    • 循环方向反了。
  • BFS 时不标记某个状态是否已访问过。

  • 使用宏展开编写 min/max

    这种做法虽然算不上是「错误」,但是这里还是要拎出来说一下。

    常见的写法是这样的:

    #define Min(x, y) ((x) < (y) ? (x) : (y))
    #define Max(x, y) ((x) > (y) ? (x) : (y))

    这样写虽然在正确性上没有问题,但是如果你直接对函数的返回值取 max,如 a = Max(func1(), func2()) ,而这个函数的运行时间较长,则会大大影响程序的性能,因为宏展开后是 a = func1() > func2() ? func1() : func2() 的形式,调用了三次函数,比正常的 max 函数多调用了一次。

    这种错误在初学者写线段树时尤为多见,会大大增加程序的运行时间,甚至直接影响代码的时间复杂度。例如这份错误代码:

    #define max(x, y) ((x) > (y) ? (x) : (y))
    
    int query(int t, int l, int r, int ql, int qr) {
    if (ql <= l && qr >= r) {
    ++ti[t]; // 记录结点访问次数方便测试
    return vi[t];
    } int mid = (l + r) >> 1;
    if (mid >= qr) {
    return query(lt(t), l, mid, ql, qr);
    }
    if (mid < ql) {
    return query(rt(t), mid + 1, r, ql, qr);
    }
    return max(query(lt(t), l, mid, ql, qr), query(rt(t), mid + 1, r, ql, qr));
    }

    会被卡到单次查询 \(\Theta(n)\) 导致 TLE。

  • 没删文件操作(某些 OJ)。

  • for (int i = 0; i < strlen(s); ++i) :在循环中重复执行复杂度非 \(O(1)\) 的函数。(严格来说,这可能会引起时间复杂度的改变。)

会导致 MLE

  • 数组过大。
  • STL 容器中插入了过多的元素。
    • 经常是在一个会向 STL 插入元素的循环中死循环了。
    • 也有可能被卡了。

未定义行为

  • 数组越界。上下都算。(多数是 RE。)

    • 未正确设置循环的初值导致访问了下标为 -1 的值。
    • 无向图边表未开 2 倍。
    • 线段树未开 4 倍空间。
    • 看错数据范围,少打一个零。
    • 错误预估了算法的空间复杂度。
    • 写线段树的时候, pushuppushdown 叶节点。
  • 解引用野指针。
    • 未初始化就解引用指针。
    • 指针指向的区域已经 freedelete

会导致常数过大

  • 定义模数的时候,使用了全局变量(如 int mod = 998244353 ,为方便编译器按常量处理,正确做法是 const int mod = 998244353 )。
  • 使用了不必要的递归(需要注意的是,尾递归不在此列)。
  • 将递归转化成迭代的时候,引入了大量额外运算。

只在程序在本地运行的时候造成影响的错误

  • 文件操作有可能会发生的错误:

    • 对拍时未清除文件指针即 fclose(fp) 就又令 fp = fopen() , 这会使得进程出现大量的文件野指针。
    • freopen() 中的文件名未加 .in / .out
  • 使用堆空间忘记 deletefree

OI 做题的常见错误的更多相关文章

  1. php求和为s的两个数字(多复制上面写的代码,有利于检查错误)(由浅入深,先写简单算法,做题的话够用就行)

    php求和为s的两个数字(多复制上面写的代码,有利于检查错误)(由浅入深,先写简单算法,做题的话够用就行) 一.总结 1.多复制上面写的代码,有利于检查错误 2.一层循环就解决了,前后两个指针,和大了 ...

  2. C语言初学者代码中的常见错误与瑕疵(5)

    问题: 素数 在世博园某信息通信馆中,游客可利用手机等终端参与互动小游戏,与虚拟人物Kr. Kong 进行猜数比赛. 当屏幕出现一个整数X时,若你能比Kr. Kong更快的发出最接近它的素数答案,你将 ...

  3. 初识JAVA(二)(送给Java和安卓初学者)----常见错误

    博主接着上篇的来讲哦,以后的更新中,博主会出一些练习题,有兴趣的可以做做然后吧代码粘贴到下面,大家可以一起研究学习,一起进步,本篇文章主要讲的是: 一.常见错误 二.连接上篇一起的训练 无论是什么方向 ...

  4. Android Fragment使用(二) 嵌套Fragments (Nested Fragments) 的使用及常见错误

    嵌套Fragment的使用及常见错误 嵌套Fragments (Nested Fragments), 是在Fragment内部又添加Fragment. 使用时, 主要要依靠宿主Fragment的 ge ...

  5. .Net常见错误

    常见错误 #1: 把引用当做值来用,或者反过来 C++ 和其他很多语言的程序员,习惯了给变量赋值的时候,要么赋单纯的值,要么是现有对象的引用.然而,在C# 中,是值还是引用,是由写这个对象的程序员决定 ...

  6. Python程序的常见错误(收集篇)

    关于Python Python是一门解释性的,面向对象的,并具有动态语义的高级编程语言.它高级的内置数据结构,结合其动态类型和动态绑定的特性,使得它在快速应用程序开发(Rapid Applicatio ...

  7. 一个超复杂的间接递归——C语言初学者代码中的常见错误与瑕疵(6)

    问题: 问题出处见 C语言初学者代码中的常见错误与瑕疵(5) . 在该文的最后,曾提到完成的代码还有进一步改进的余地.本文完成了这个改进.所以本文讨论的并不是初学者代码中的常见错误与瑕疵,而是对我自己 ...

  8. 分数的加减法——C语言初学者代码中的常见错误与瑕疵(12)

    前文链接:分数的加减法——C语言初学者代码中的常见错误与瑕疵(11) 重构 题目的修正 我抛弃了原题中“其中a, b, c, d是一个0-9的整数”这样的前提条件,因为这种限制毫无必要.只假设a, b ...

  9. 要心中有“数”——C语言初学者代码中的常见错误与瑕疵(8)

    在 C语言初学者代码中的常见错误与瑕疵(7) 中,我给出的重构代码中存在BUG.这个BUG是在飞鸟_Asuka网友指出“是不是时间复杂度比较大”,并说他“第一眼看到我就想把它当成一个数学问题来做”之后 ...

随机推荐

  1. ArcMap 0 (ArcGIS10.2安装)

    一如GIS深似海,从此相逢是故人(这句话适合初步接触GIS的,我算是初窥门径.还是道行太浅,只是多了感慨) 前言: 1. 本人GIS专业,对于ArcGIS较为熟悉.由于专业和其它经历需要,接触过不少各 ...

  2. Kubernetes笔记(二):了解k8s的基本组件与概念

    前文 Kubernetes笔记(一):十分钟部署一套K8s环境 介绍了如何快速搭建一个k8s系统.为了继续使用k8s来部署我们的应用,需要先对k8s中的一些基本组件与概念有个了解. Kubernete ...

  3. .NET Core+QQ第三方授权登录

    安装包 dotnet add package AspNet.Security.OAuth.QQ 接上文GitHub第三方授权登录 申请过程不介绍了,申请者资料,个人也是可以申请成功的. 这时候有二个参 ...

  4. Python Web实战:Python+Django+MySQL实现基于Web版的增删改查

    前言 本篇使用Python Web框架Django连接和操作MySQL数据库学生信息管理系统(SMS),主要包含对学生信息增删改查功能,旨在快速入门Python Web,少走弯路.效果演示在项目实战最 ...

  5. 心路历程-安装Docker

    心路历程-安装Docker 本机环境 Windows10 激活HyperV功能 新建CentOS虚拟机 centos docker安装 由于是新的虚拟机,所以没有docker旧版本的问题,不需要卸载旧 ...

  6. 【MySQL基础总结】常用函数库

    常用函数库 数学函数 分类及含义 示例 字符串函数 分类及含义 示例 日期时间函数 分类及含义 示例 条件判断函数 分类及含义 示例 系统函数 分类及含义 加密函数 分类及定义 其他常用函数 分类及含 ...

  7. CI与CD之Docker上安装Jenkins

    一.CI,CD,Jenkins的介绍 CI:持续集成(Continuous integration,简称 CI),在传统的软件开发环境中,有集成,但是没有持续集成这种说法,长时间的分支与主干脱离,导致 ...

  8. Luogu P5603 小C与桌游【贪心+拓扑排序】

    [Description]https://www.luogu.com.cn/problem/P5603 \(\;\) 题意可以简化为:一个不保证联通,n个点,m条边的DAG(有向无环图),构造一个拓扑 ...

  9. Ubuntu 18.04使用OpenSSL自签证书(证书支持多IP及多域名,谷歌浏览器无警告)

    前言 在HTTPS数据传输的过程中,需要用SSL/TLS对数据进行加密和解密,以保证网络传输过程中数据的机密性.HTTPS协议可以大致分为两个部分:其一是协商密钥,首先当Client向Web Serv ...

  10. 【SMB源码解析系列】——003.SMB游戏基本框架

    前面有了解到RESET中断相关代码,结尾处通过一句jmp进入了无限循环,之后CPU将会在每一帧PUU进入VBlank状态时,接收NMI中断信号, 跳转至NMI代码处继续执行,直到遇见RTI指令时又返回 ...