Search

7.14 — Common semantic errors in C++

In lesson %Failed lesson reference, id 7940%, we covered syntax errors, which occur when you write code that is not valid according to the grammar of the C++ language. The compiler will notify of you these type of errors, so they are trivial to catch, and usually straightforward to fix.

We also covered semantic errors, which occur when you write code that does not do what you intended. The compiler generally will not catch semantic errors (though in some cases, smart compilers may be able to generate a warning).

Semantic errors can cause most of the same symptoms of undefined behavior, such as causing the program to produce the wrong results, causing erratic behavior, corrupting program data, causing the program to crash -- or they may not have any impact at all.

When writing programs, it is almost inevitable that you will make semantic errors. You will probably notice some of these just by using the program: for example, if you were writing a maze game, and your character was able to walk through walls. Testing your program (7.12 -- Introduction to testing your code) can also help surface semantic errors.

But there’s one other thing that can help -- and that’s knowing which type of semantic errors are most common, so you can spend a little more time ensuring things are right in those cases.

In this lesson, we’ll cover a bunch of the most common types of semantic errors that occur in C++ (most of which have to do with flow control in some way).

Conditional logic errors

One of the most common types of semantic errors is a conditional logic error. A conditional logic error occurs when the programmer incorrectly codes the logic of a conditional statement or loop condition. Here is a simple example:

Here’s a run of the program that exhibits the conditional logic error:

Enter an integer: 5
5 is greater than 5

When the user enters 5, the conditional expression x >= 5 evaluates to true, so the associated statement is executed.

Here’s another example, using a for loop:

This program is supposed to print all of the numbers between 1 and the number the user entered. But here’s what it actually does:

Enter an integer: 5

It didn’t print anything. This happens because on entrance to the for loop, count > x is false, so the loop never iterates at all.

Infinite loops

In lesson 7.7 -- Intro to loops and while statements, we covered infinite loops, and showed this example:

In this case, we forgot to increment count, so the loop condition will never be false, and the loop will continue to print:

1 1 1 1 1 1 1 1 1 1

until the user shuts down the program.

Here’s another example that teachers love asking as a quiz question. What’s wrong with the following code?

This program is supposed to print 5 4 3 2 1 blastoff!, which it does, but it doesn’t stop there. In actuality, it prints:

5 4 3 2 1 blastoff! 4294967295 4294967294 4294967293 4294967292 4294967291

and then just keeps decrementing. The program will never terminate, because count >= 0 can never be false when count is an unsigned integer.

Off-by-one errors

An off-by-one error is an error that occurs when a loop executes one too many or one too few times. Here’s an example that we covered in lesson 7.9 -- For statements:

This code is supposed to print 1 2 3 4 5, but it only prints 1 2 3 4 because the wrong relational operator was used.

Incorrect operator precedence

From lesson 5.7 -- Logical operators, the following program makes an operator precedence mistake:

Because logical NOT has higher precedence than operator>, the conditional evaluates as if it were written (!x) > y, which isn’t what the programmer intended.

As a result, this program prints:

5 is greater than 7

This can also happen when mixing Logical OR and Logical AND in the same expression (Logical AND takes precedent over Logical OR). Use explicit parenthesization to avoid these kind of errors.

Precision issues with floating point types

The following floating point variable doesn’t have enough precision to store the entire number:

As a consequence, this program prints:

0.123457

In lesson 5.6 -- Relational operators and floating point comparisons, we talked about how using operator== and operator!= can be problematic with floating point numbers due to small rounding errors (as well as what to do about it). Here’s an example:

This program prints:

not equal

The more arithmetic you do with a floating point number, the more it will accumulate small rounding errors.

Integer division

In the following example, we mean to do a floating point division, but because both operands are integers, we end up doing an integer division instead:

This prints:

5 divided by 3 is: 1

In lesson 5.2 -- Arithmetic operators, we showed that we can use static_cast to convert one of the integral operands to a floating point value in order to do floating point division.

Accidental null statements

In lesson %Failed lesson reference, id XX%, we covered null statements, which are statements that do nothing.

In the below program, we only want to blow up the world if we have the user’s permission:

However, because of an accidental null statement, the function call to blowUpWorld() is always executed, so we blow up it regardless:

Should we blow up the world again? (y/n): n
Kaboom!

Not using a compound statement when one is required

Another variant of the above program that always blows up the world:

This program prints:

Should we blow up the world again? (y/n): n
Kaboom!

A dangling else (covered in lesson %Failed lesson reference, id XX%) also falls into this category.

What else?

The above represents a good sample of of the most common type of semantic errors new C++ programmers tend to make, but there are plenty more. Readers, if you have any additional ones that you think are common pitfalls, leave a note in the comments.


7.15 -- Detecting and handling errors
Index
7.13 -- Code coverage

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">