Common Mistakes
This page lists some common mistakes that many contestants frequently make in competitions.
Errors Caused by Environment Differences
- Using
%I64dformat specifier withscanforprintfon Linux may cause input/output format errors.
Errors That Cause CE
These errors are mostly lexical, syntactic, and semantic errors. They are relatively simple to cause and easy to fix.
Examples:
-
Spelling errors like writing
int main()asint mian(). -
Forgetting to add a semicolon after writing a
structorclass. -
Declaring an array too large, using illegal functions (e.g., multithreading) on OJ, or declaring but not defining a function, which causes linking errors.
-
Mismatched function parameter types.
-
Example: When using the
maxfunction from the<algorithm>header, passing aninttype parameter and along longtype parameter.1 2 3 4
// query is a custom function returning long long printf("%lld\n", max(0, query(1, 1, n, l, r)); // Error: no overloaded function "std::max" matches the argument list
-
-
Using
gotoandswitch-caseto skip the initialization of some local variables.
Errors That Do Not Cause CE but Cause Warnings
Programs with such errors can compile but are likely to produce incorrect results. These errors are pointed out by the compiler when compiling with the -W{warningtype} parameter.
-
Confusing the assignment operator
=with the comparison operator==.-
Example:
1 2 3 4 5 6 7 8 9
std::srand(std::time(nullptr)); int n = std::rand(); if (n = 1) printf("Yes"); else printf("No"); // Regardless of the random value of n, the output will always be Yes. // Warning: Incorrect operator: constant assignment performed in Boolean context. Consider using '==' instead. -
If you indeed want to use
=where==should be used (e.g.,while (foo = bar)), and you don't want to receive a warning, you can use double parentheses:while ((foo = bar)).
-
-
Errors due to operator precedence.
-
Example:
1 2 3 4 5 6
// Wrong // std::cout << (1 << 1 + 1); // Correct std::cout << ((1 << 1) + 1); // Warning: '<<': check for possible operator precedence error; use parentheses to clarify precedence
-
-
Incorrect use of the
staticmodifier. -
Forgetting to add the address-of operator
&when usingscanffor input. -
Mismatch between parameter types and format specifiers when using
scanforprintf. -
Using bitwise operators and the logical operator
==together without parentheses.- Example:
(x >> j) & 3 == 2
- Example:
-
Integer literal overflow for
int.- Example:
long long x = 0x7f7f7f7f7f7f7f7f,1<<62.
- Example:
-
Uninitialized local variables.
What happens with uninitialized variables?
Original text: https://loj.ac/d/3679 by @hly1204
For example, when we declare an
int a;in C++ without initializing it, sometimes we might thinkais a "random" (though not truly random) value, or we might think it's a fixed value, but that's not actually the case.In a simple test code:
https://wandbox.org/permlink/T2uiVe4n9Hg4EyWT
The code is:
1 2 3 4 5 6 7
#include <iostream> int main() { int a; std::cout << std::boolalpha << (a < 0 || a == 0 || a > 0); return 0; }With optimizations enabled on some compilers and environments, the output is false.
If interested, you can read https://www.ralfj.de/blog/2019/07/14/uninit.html, although it uses Rust for experiments, the essence is the same.
-
Local variables having the same name as global variables, causing the global variables to be accidentally overwritten. (Enable
-Wshadowto check for such errors.) -
Output errors caused by operator overloading.
-
Example:
1 2 3 4 5 6
// Intention: The first << is the overloaded operator for output; the second << is the shift operator, shifting 1 left by 1 bit. // But due to forgetting parentheses, the compiler treats the second << as an output operator as well, resulting in output different from expected. // Wrong std::cout << 1 << 1; // Correct std::cout << (1 << 1);
-
Errors That Cause Neither CE nor Warnings
These errors cannot be detected by the compiler and must be identified by the programmer.
Errors That Cause WA
-
Not clearing arrays before reading the next set of data after processing the previous set.
-
Fast input optimization not handling negative numbers.
-
Insufficient bit width of the data type used, causing overflow.
- As described by the saying "Three years of OI, all in vain, without
long longyou'll see your ancestors." Contestants fail to score because they didn't uselong long(defining integers aslong longtype) in the right places.
- As described by the saying "Three years of OI, all in vain, without
-
When storing a graph, node numbering starts from 0, but the edges given in the problem have endpoints numbered from 1, forgetting to subtract 1 when reading.
-
Mistyping or reversing greater-than/less-than signs.
-
Mixing
scanf/printfandstd::cin/std::coutIO after executingios::sync_with_stdio(false);, causing input/output disorder.-
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// This example demonstrates the consequences of mixing two IO methods after disabling synchronization with stdio. // It's recommended to step through to observe the effect. #include <cstdio> #include <iostream> int main() { // After disabling synchronization, cin/cout will use independent buffers instead of synchronizing output to scanf/printf's buffer, reducing IO overhead. std::ios::sync_with_stdio(false); // With cout, when using '\n' for newline, content is buffered and not output immediately. std::cout << "a\n"; // printf's '\n' flushes printf's buffer, causing misaligned output. printf("b\n"); std::cout << "c\n"; // The cout buffer is output only when the program ends. return 0; }
-
-
Errors due to macro expansion without parentheses.
-
Example: This macro returns \(2+2\times 2+2 = 8\) instead of \(4^2 = 16\).
1 2
#define square(x) x* x printf("%d", square(2 + 2));
-
-
Computational errors in hashing due to not using
unsigned.- Right-shifting negative numbers fills the highest bit with 1. See: Bit Operations
-
Not removing or commenting out debug output statements.
-
Accidentally adding an extra
;.-
Example:
1 2 3
/* clang-format off */ while (1); printf("OI Wiki!\n");
-
-
Incorrect sentinel value setting. For example, the
0node in a balanced tree. -
When initializing variables with
:in a class or struct constructor, the declaration order of variables does not match the dependency order during initialization.- The initialization order of member variables is related to their declaration order in the class, not the order in the initialization list. See: "Initialization order" in Constructors and member initializer lists
-
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#include <iostream> class Foo { public: int a, b; // a will be initialized before b, its value is indeterminate. Foo(int x) : b(x), a(b + 1) {} }; int main() { Foo bar(1, 2); std::cout << bar.a << ' ' << bar.b; } // Possible output: -858993459 1
-
Not merging the ancestors of two elements when merging sets in a union-find.
-
Example:
1 2
f[a] = b; // Wrong f[find(a)] = find(b); // Correct
-
-
Using
afor append mode infreopen- CCF's testing environment does not clear the output file. Using
awill cause the previous contestant's output to be read by the judge, leading to WA.
- CCF's testing environment does not clear the output file. Using
Different Newline Characters
Warning
In official competitions, efforts are made to ensure the contestant's environment matches the final testing environment.
This section applies only to practice contests, etc., and we also recommend problem setters to make data conform to the Data Format.
Different operating systems use different symbols to mark newlines. Here are the newline characters for several commonly used systems:
-
LF (represented by
\n):UnixorUnix-compatible systems -
CR+LF (represented by
\r\n):Windows -
CR (represented by
\r):Mac OSversion 9 and earlier
C/C++ uses the escape sequence \n for newline, which may lead us to believe that newline characters in input are also represented by \n. Reading only one character to represent a newline may cause incomplete reading of the input file.
Solutions:
-
Use
getchar()multiple times until the desired character is read. -
Use
cinfor input, which may increase code constant. -
Use
scanf("%s",str)to read a string, then takestr[0]as the read character. -
Use
scanf(" %c",&c)to filter out all whitespace characters.
Errors That Cause Undefined Results
Undefined behavior leads to unknown results, which could be WA, RE, etc. Compilers usually assume your program does not have undefined behavior, so code behavior may differ with and without O2 optimization.
-
Division by 0 (finding the inverse of 0)
Example
1cout << x / 0 << endl; -
Array (index) out of bounds
For example:
-
Incorrect loop initial value causing access to index -1.
-
Undirected graph edge list not opened to twice the size.
-
Segment tree not opened to 4 times the space.
-
Misreading data range, missing a zero.
-
Incorrectly estimating algorithm space complexity.
-
Calling
pushuporpushdownon leaf nodes in a segment tree.Correct approach: Do not go out of bounds, check your code to ensure index accesses
xare within defined bounds.
-
-
Non-main function with a return value executes to the end without any return statement
Even if one branch has a return, but others do not, the result is undefined.
You can add
-Wallto compilation options to check if the compiler gives warnings about functions not returning. -
Attempting to modify string literals
Example
1 2 3
char *p = "OI-wiki"; p[0] = 'o'; p[1] = 'i';Attempting to modify string literals causes undefined behavior. Use other appropriate data types, such as
std::stringandchar[]. -
Multiple deallocations / illegal dereferencing of memory
For example:
-
Dereferencing a pointer without initialization.
-
Pointer points to already freed memory.
When using
erase,delete, orfree, be careful not to use them multiple times on the same address/object.
-
-
Attempting to free part of memory allocated by
new []For example:
1 2 3 4 5 6
object *pool = new object[POOL_SIZE]; object *pointer = pool + 10; // Error! delete pointer;Common when using a memory pool to pre-allocate a block of memory, then trying to use
deleteorfree()to release a single object obtained from the pool. -
Dereferencing null/wild pointers
For null pointers: First check for null, using
p == nullptror!p.For wild pointers: Set the pointer to
nullptrwhen freeing to avoid. -
Signed integer overflow
For example, we have an expression
x+1 > x.The normal output should be
true, but whenxisINT_MAX, the output isfalse. This is calledsigned integer overflow.Use larger data types (e.g.,
long longor__int128), or check for overflow. If negative numbers are guaranteed not to occur, unsigned integers can also be used.Signed integer overflow may affect compiler optimization. For example, the code:
1 2 3 4
int foo(int x) { if (x > x + 1) return 1; return 0; }May be optimized by the compiler directly to:
1int foo(int x) { return 0; }Because the compiler can assume signed integers never overflow, so
x > x + 1never holds. -
Using uninitialized variables
Example
1 2 3 4 5
int foo(int a) { int t; /* not initialized */ if (/* using */ t > 3) return a; return 0; }
Errors That Cause RE
-
Not removing file operations (on some OJs).
-
Incorrect comparison function for sorting:
std::sortrequires a strict weak ordering:a<aisfalse; ifa<bistrue, thenb<aisfalse; ifa<bistrueandb<cistrue, thena<cistrue. Pay special attention to the second point. If these requirements are not met, sorting may cause RE. For example, when writing parity sorting for Mo's algorithm, this is wrong:1 2 3 4 5 6
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]; }In the above code,
(block[a.l]&1)^(a.r<b.r)does not satisfy the second requirement. Changing it to this is correct:1 2 3 4 5 6 7 8 9
bool operator<(const int a, const int b) { if (block[a.l] == block[b.l]) // Wrong: does not satisfy strict weak ordering requirements // return (block[a.l] & 1) ^ (a.r < b.r); // Correct return (block[a.l] & 1) ? (a.r < b.r) : (a.r > b.r); else return block[a.l] < block[b.l]; } -
Insufficient stack space on Windows, causing stack overflow. Windows sends a SIGSEGV signal to the program, terminating it and returning 3221225725 (i.e., 0xC00000FD, NTSTATUS defined as
STATUS_STACK_OVERFLOW).
If using the gcc compiler, you can add the command-Wl,--stack=SIZEduring compilation to specify the stack size limit, whereSIZEis the stack size in bytes.Insufficient stack space on Linux causes stack overflow. Linux writes
head_inforandomly in the stack heap, which in most cases causes the program to exit immediately, displaying messages likesegmentation fault (core dumped).
You can useulimit -s SIZEin the terminal to modify the stack size limit for the current terminal, whereSIZEis the stack size in kilobytes (KB).
Note: If you set the stack size limit too large, infinite recursion may cause the recursion stack to become too large and crash the system.
Errors That Cause TLE
-
Not checking boundaries in divide-and-conquer, causing infinite recursion.
-
Infinite loop.
-
Loop variable name conflict.
-
Loop direction reversed.
-
-
Not marking whether a state has been visited in BFS.
-
Using macro expansion to write min/max
This error can greatly increase program runtime and even directly affect code time complexity. It is especially common among beginners writing segment trees.
A common wrong way:
1 2
#define Min(x, y) ((x) < (y) ? (x) : (y)) #define Max(x, y) ((x) > (y) ? (x) : (y))Although correct in terms of correctness, if you directly take max of function return values, like
a = Max(func1(), func2()), and the function runtime is long, it will greatly affect program performance because after macro expansion it becomesa = func1() > func2() ? func1() : func2(), calling the function three times, one more than the normal max function. Note: Iffunc1()returns different answers each time, thismaxwriting may also cause errors. For example,func1()isreturn ++a;andais a global variable.Example: The following code can be slowed down to \(\Theta(n)\) per query, causing TLE.
1 2 3 4 5 6 7 8 9 10 11 12 13
#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]; // Record node visit count for debugging 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)); } -
Using the
+operator to append characters to astd::stringclass stringThis error creates a temporary
stringvariable, modifies it, then assigns it back to the original variable. This error cannot be optimized by the compiler and may cause time complexity degradation with large data.Common wrong way:
1 2 3
std::string a; char b = 'c'; a = a + b;When executing this code, the program first creates a temporary
stringvariable, stores the value ofainto it, appendsbat the end, then stores it back intoa.From the assembly result,
a = a + bcalls three functions fromstd::__cxx11::basic_string:operator+,operator=, and variable creation.The correct way should be:
1 2 3
std::string a; char b = 'c'; a += b;This way directly appends character
bto stringa, callingoperator+=only once. For a more detailed performance comparison, refer to Benchmark. -
Not removing file operations (on some OJs).
-
Repeatedly executing functions with complexity not \(O(1)\) in
for/whileloops. Strictly speaking, this may change time complexity. -
Incorrect midpoint formula or termination condition in binary search.
Errors That Cause MLE
-
Array too large.
Detailed Explanation of Memory Usage Indicators on Linux
TL;DR: If you declare a particularly large global static array during CCF-style exams, be especially careful. Because the array declared by the program is fully counted in memory usage (unlike most online judges which only count actual usage), in some cases this may even cause the entire problem to MLE.
-
-
VSZ (Virtual Memory Size)3
VSZ represents the virtual memory size of a process, the total size of virtual address space the process can access, usually displayed in KB.
Virtual memory is a logical concept, usually much larger than actual memory usage.
On Linux, you can use the
topcommand to view the memory composition of a process, where theVIRTcolumn represents its virtual memory.Virtual memory generally includes address space allocated but not actually used by the process. Simply put, virtual memory is approximately what you requested.
It is particularly important to note that common online judges usually only count physical memory usage. But CCF's judging environment counts virtual memory, meaning if you declare a large global static array, even if you only use a small part, it occupies a lot of space.
-
RSS (Resident Set Size)4
RSS represents the actual physical memory size occupied by a process, i.e., the size of page frames resident in RAM, usually displayed in KB.
Similarly, you can use
topto view a process's physical memory in theREScolumn.RSS generally only includes parts actually loaded into physical memory, meaning actual usage is what counts.
-
-
Memory Usage Behavior Analysis
Assume the following array is declared:
1 2
const int SIZE = 1e8; int arr[SIZE]; // Space occupied: 4 bytes * 100 million = 400 MBThis is a static array allocated in the global data segment. This array is not explicitly initialized, usually allocated in the BSS segment (if explicitly initialized (e.g., all zeros or other values), allocated in the DATA segment).
-
When the array is completely unused (assuming the compiler does not optimize it away)
- Physical memory: If the array is not accessed, demand paging mechanism prevents memory pages from being loaded into physical memory. Physical memory does not increase or increases only slightly (maybe some metadata pages are loaded).
- Virtual memory: The array size is counted in virtual memory (increases by
400MB), because the entire array's virtual address space has been allocated.
-
When partially using the array
Assume only a few elements of the array are used, e.g.:
1 2
arr[0] = 1; arr[999999] = 2;- Virtual memory: Virtual memory does not change, still
400MB. - Physical memory: Each time an array element is accessed, the corresponding virtual page is loaded into physical memory. Assuming system page size is
4KB, each page contains \(4 \text{KB} ÷ 4 \text{B} = 1024\)intelements. Accessing the array twice may load 2 pages, increasing physical memory by about \(2 \times 4 \text{KB} = 8 \text{KB}\).
- Virtual memory: Virtual memory does not change, still
-
When most of the array is used
Assume assigning values to the first \(50,000,000\) elements:
1 2 3
for (int i = 0; i < 50000000; ++i) { arr[i] = i; }- Virtual memory (VSZ): VSZ remains
400MB, unchanged. -
Physical memory (RSS): This is sequential access (the accessed \(50,000,000\) elements are adjacent in memory addresses), the number of pages to load is \(\left\lceil \dfrac{50,000,000}{1024} \right\rceil = 48,828\) pages.
Assuming each page is
4KB, total is \(48,828 \times 4 \text{KB} \approx 190 \text{MB}\), physical memory increases to about190MB.Note: If assigning values to the array with random indices, physical memory usage may differ significantly from prediction (because memory pages are loaded based on address, causing random assignments to load many memory pages).
Brief summary: As the proportion of accessed parts increases, physical memory approaches virtual memory (assuming no page reclamation).
- Virtual memory (VSZ): VSZ remains
-
-
Inserting too many elements into STL containers.
-
Often due to an infinite loop in a loop that inserts elements into STL.
-
Possibly being deliberately exploited (e.g., anti-hash tests).
-
Errors That Cause Large Constant Factors
-
Not defining modulus as a constant.
-
Example:
1 2
// int mod = 998244353; // Wrong const int mod = 998244353; // Correct, helps compiler treat it as a constant
-
-
Using unnecessary recursion (tail recursion is not included here).
-
Introducing a large amount of extra computation when converting recursion to iteration.
Errors That Only Affect Local Execution
-
Possible errors with file operations:
-
Not closing file pointer
fclose(fp)before settingfp = fopen()again during stress testing. This creates many file wild pointers in the process. -
Not adding
.in/.outto filenames infreopen().
-
-
Forgetting to
deleteorfreeafter using heap space.
References and Notes
本页面最近更新:,更新历史
发现错误?想一起完善? 在 GitHub 上编辑此页!
本页面贡献者:OI-wiki
本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用