OSDN Git Service

Update common-mistakes.md
authorTrisolaris HD <36555123+TrisolarisHD@users.noreply.github.com>
Wed, 27 Mar 2019 08:15:38 +0000 (16:15 +0800)
committerGitHub <noreply@github.com>
Wed, 27 Mar 2019 08:15:38 +0000 (16:15 +0800)
更改了该页面的排版。

docs/intro/common-mistakes.md

index f5671f5..44c37bd 100644 (file)
@@ -1,43 +1,30 @@
 本页面主要分享一下在竞赛中经常/很多人会出现的错误。
 
--  由于运算符优先级产生的错误。
-    -    `1 << 1+1` : 1 左移了 2,即该表达式返回的值是 `4` 。
-    -   由于宏的展开,且未加括号导致的错误:
-        ```cpp
-        #define pwr(x) x* x
-        pwr(2 + 2)
-        ```
-        该宏返回的值并非 $4^2 = 16$ 而是 $2+2\times 2+2 = 8$ 。
+## 会引起 Compile Error 的错误
 
--  文件操作有可能会发生的错误。
+由于这类错误过于简单,~~相信是个正常人都会修~~,故略写.
 
-    -   对拍时未清除文件指针即 `fclose(fp)` 就又令 `fp = fopen()` , 这会使得进程出现大量的文件野指针。
-    -    `freopen()` 中的文件名未加 `.in` / `.out` 。
+-  `int main()` 写为 `int mian()` 。
 
--   `int mian()` 
+-  写完 `struct` 或 `class` 忘记写分号
 
--  无向图边表未开 2 倍。
 
--  线段树未开 4 倍空间。
+## 不会引起 Compile Error 但会引发 Warning 的错误
 
--  多组数据未清空数组
+这类错误较难发现,但会在使用 `-W{warningtype}` 参数编译时被编译器指出,所以要多学会使用 `-W{warningtype}` 参数,常见的有 `-Wall`,`-Wextra`,`-Wshadow` 等
 
--  分治未判边界导致死递归。
+-  由于运算符优先级产生的错误。
+    -  `1 << 1 + 1` : 1 左移了 2,即该表达式返回的值是 `4` 。
 
--  读入优化未判断负数。
+-  文件操作有可能会发生的错误。
+
+    -   对拍时未清除文件指针即 `fclose(fp)` 就又令 `fp = fopen()` , 这会使得进程出现大量的文件野指针。
+    -   `freopen()` 中的文件名未加 `.in` / `.out` 。
 
 -  不正确地使用 `static` 修饰符。
 
 -  `-1 >> 1 == 1` 。
 
-- 写完 `struct` 或 `class` 忘记写分号。
-
-- 存图下标从 0 开始输入节点未 -1。
-
--  BFS 时不标记某个状态是否已访问过。
-
--  大/小于号打错或打反。
-
 - 赋值运算符和 `==` 不分。
     - 示例:
       ```cpp
       else puts("No");
       ```
       无论 $n$ 的值之前为多少,输出肯定是 `Yes`。
-      
 
-- 没有考虑数组下标出现负数的情况
+- 使用 `scanf` 读入的时候没加取地址符 `&``。
+
+- 没有考虑数组下标出现负数的情况。
+
 
-- scanf 读入的时候没加 & 取地址符
+## 既不会引起 Compile Error 也不会引发 Warning 的错误
 
-- 在执行 `ios::sync_with_stdio(false);` 后混用两种 IO,导致输出错乱。
-    - 可以参考这个例子。
+这类错误无法被编译器发现,所以在调试时只能依靠你自己.
+
+-  无向图边表未开 2 倍。
+
+-  线段树未开 4 倍空间。
+
+-  多组数据未清空数组。
+
+-  分治未判边界导致死递归。
+
+-  读入优化未判断负数。
+
+-  存图下标从 0 开始输入节点未 -1。
+
+-  BFS 时不标记某个状态是否已访问过。
+
+-  大/小于号打错或打反。
+
+-  在执行 `ios::sync_with_stdio(false);` 后混用两种 IO,导致输入/输出错乱。
+     - 可以参考这个例子。
       ```cpp
       //这个例子将说明,关闭与 stdio 的同步后,混用两种 IO 的后果
       //建议单步运行来观察效果
-      #include <iostream>
       #include <cstdio>
-      using namespace std;
+      #include <iostream>
       int main() {
-       ios::sync_with_stdio(false);
-       //关闭IO后,cin/cout将使用独立缓冲区,而不是将输出同步至scanf/printf的缓冲区,从而减少IO耗时
-       cout<<"a\n";
-       //cout下,使用'\n'换行时,内容会被缓冲而不会被立刻输出,应该使用endl来换行并立刻刷新缓冲区
-       printf("b\n");
-       //printf的'\n'会刷新printf的缓冲区,导致输出错位
-       cout<<"c\n";
-       return 0;//程序结束时,cout的缓冲区才会被输出
+          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 的缓冲区才会被输出
       }
       ```
+
+-   由于宏的展开,且未加括号导致的错误:
+       ```cpp
+       #define square(x) x * x
+       printf("%d", square(2 + 2));
+       ```
+       该宏返回的值并非 $4^2 = 16$ 而是 $2+2\times 2+2 = 8$ 。
+
+-  使用宏展开编写 min/max
+    这种做法虽然算不上是「错误」,但是这里还是要拎出来说一下。
+       常见的写法是这样的:
+       ```cpp
+       #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 函数多调用了一次。
+       这种错误在初学者写线段树时尤为多见。