Here are a few:
* Not actually thinking of a solution to the problem before starting to write a program; not soliciting requirements.
* ALL of the mistakes covered by this article. Struggling CS majors are often (not always) really, really horrible at math, and this -- more than anything else -- really holds them back from writing correct programs.
* Off-by-one and the functional equivalents
* Infinite loops in exception handling
* not enough input validation; too much input validation
* Reinventing bad versions of existing algorithms (Dijkstra's algorithm is a good example) and in general not enough research before implementation.
* The other side of that coin is taking stack overflow upvoted answers as gospel (basically our equivalent of trusting the calculator)
* Fundamental incomprehension of boolean algebra, which gives rise to all sorts of errors:
incorrect paren placement
Obscenely complicated conditions and/or absurd if conditions because they don't understand boolean algebra (e.g. I've seen conditions that eventually simplify to a || !a)
Complicated programs and grandois bug-hunting because they couldn't figure how a simple boolean expression (there was a post on HN a while back about Javascript == vs === where the developer basically wasted a day going down a rabbit hole he attributed to == vs === but was actually completely avoidable if he had taken an undergraduate discrete math course that hammered home boolean algebra.)
* This page contains a very useful implementation details section which describes some common errors implementing quicksort: http://algs4.cs.princeton.edu/23quicksort/
* As a general rule, any program written by a student containing concurrency is always wrong, unless concurrency was explicitly taught (many schools just have a short unit in a course or two, instead of integrating the topic throughout the curriculum).
edit: oh, also, I guess literally off-by-one errors are also possible in any language that allows any sort of side effect, but that's kind of a stupid degenerate case :-) (edit: possible, definitely not popular... wrong word there, sorry).
- Confusing asymptotic upper bounds with worst-cases,
- Assuming asymptotic bounds can only refer to running times,
- Not being clear about what "n" represents in O(f(n)),
- Not specifying a model of computation before talking about complexity,
- Confusing (complexity-class) hardness with completeness,
- Confusing Turing recognisability with decidability,
- Confusing decision problems with function problems,
- Assuming proofs of decidability must be constructive,
- Assuming O(2^n) == O(3^n),
- Not recognising O(lg(n)) == O(ln(n)).
For programming, I think simple type mistakes are a biggie...
- Not understanding/using variable scoping
- Insufficiently-exhaustive case checking (especially if there are multiple variables)
- Using built-in data-types that do not have the functionality or invariants that you need instead of making custom types
--- (subcase) Using the wrong number type: Using floats for any non-integer, when sometimes you want Decimal or need to hand-roll a fixed-point number; Not thinking about the size of your integer type.
--- (subcase) Encoding data as strings, parsing out and concating in as needed. For some reason, this is surprisingly common in 101-level beginners.