next up previous
Next: About this document

27 Rookie Mistakes of C++ Programmers
and How to Avoid Them

A. Program Design

Mistake tex2html_wrap260
The programmer does not plan the program ahead, and just sits in front of the computer and begins typing.

Consequence: The program is developed very slowly, if at all.

Solution: Do not imagine that you can just sit down and write a program off the top of your head. You will not succeed. Do not stare at a computer monitor for inspiration. The monitor will offer none. Instead, take the time to develop the program correctly. This will save you time.

  1. First, put on your problem solving hat. Get out a piece of paper. Think about how the problem will be solved. Identify a subproblem that you will need to solve. Try a few examples of the subproblem by hand. See if you can generalize the examples to a general method. Don't think too much about the programming language during the initial problem solving stage. Concentrate on the method of solving the problem, and do not go on until you understand the method.
  2. Write a contract for a function that solves the subproblem. A contract states exactly what the function will do, and exactly what it requires of its inputs.
  3. Start thinking about the programming language, and write the function. Test it.
  4. Move on to other subproblems.

Summary: Think about your programs before writing them.

Mistake tex2html_wrap261
The programmer does not give contracts for functions until after the program is written, or writes the contracts in a vague way, or does not write them at all. The programmer does not distinguish between what a function does and how the function works.

Consequence: The programmer spends too much time debugging the program, finding errors that would easily have been avoided by having contracts. Untold hours have been wasted fixing errors that would have vanished immediately had contracts been used.

Solution: Give a contract for each function before writing the function. The contract is a clear description of what the function must do. It is a contract between the function and the caller of the function. The function says, if inputs are provided satisfying certain preconditions, then the function will produce a certain kind of return value, and will possibly cause certain postconditions to become true.

Be sure to include in the contract information about the purpose of each and every parameter, and the meaning of the returned value, if there is one. Check the contract to see that each parameter is discussed.

Imagine trying to do business by writing and signing contracts only after the work has been done. The contractor does not know what he or she has signed on to do, and the person hiring the contractor does not know what he or she will get. Therein lies insanity. Yet, rookie programmers invariably try to work this way. If you find that you cannot think of an appropriate contract for a function, then you do not understand it well enough to write it. Think some more about what the function is supposed to do for its caller. Make the contract clear and precise.

A contract should not tell how a function works. It should tell what the function accomplishes. When writing a contract, you should not describe things that only make sense if you read the body of the function (the part after the heading). A person reading the contract should not have to read the body of the function to make sense of what the contract is saying.

Summary: Write clear and precise contracts.

Mistake tex2html_wrap262
The programmer does not think logically about what functions should do, and is instead driven by a very detailed view of what is happening at one point in a program. For this reason, the programmer does not delegate responsiblities in a reasonable way among the parts of his or her program.

Consequence: The program is exceptionally difficult to understand and modify. It probably does not work.

Solution: Think about functions at a conceptual level before working out details. Be sure to start by asking what the function does. Do not think about how it should work too soon. Ask if the conceptual view of what the function is supposed to do makes sense. If, for example, you are writing an instance method for a class Rabbit, ask whether it makes sense to ask a rabbit to do the things that this function does. If the rabbit is apparently being asked to take on the resposibilities of a tractor, then think again. Similarly, make sure each function has a focus, and that it does not try to do several unrelated tasks.

Look at the parameters of the function. Ask whether each parameter is required, and whether it is reasonable for the function to ask for them. You must have a contract for each function. What you are doing here is making sure the contract is simple and reasonable. Choose your functions so that the contracts can be made short and simple, without making them imprecise or vague. If your contract is exceptionally complicated, then you have probably broken the problem into functions in a bad way.

Summary: Make your contracts short and simple, without making them imprecise.

Mistake tex2html_wrap263
The programmer writes function definitions that do not fulfill their contracts. Rather than fixing the function definitions or the contracts, he or she tries to work with the incorrect functions.

Consequence: Your program is very difficult to get working. You spend long hours trying to put bad parts together, hoping to get a working whole.

Solution: If a function does not fulfill its contract, fix it. Occasionally, you need to change the contract, but that is rare. Fix the function.

Summary: Make your functions fulfill their contracts.

Mistake tex2html_wrap264
The programmer makes all functions application-specific. That is, they can only work in very specific ways within this one program.

Consequence: The program is difficult to modify, because the functions are not sufficiently general that they can be used at several places in the program. Any modification of the program usually involves modifying many functions.

Solution: Write functions in as general a way as is reasonable. Use parameters. Wherever possible, write the functions so that they might very well be used in another program. That way, it will be easy to use them in more than one way, and at more than one place, in this program.

Summary: Choose general functions where possible.

Mistake tex2html_wrap265
The programmer chooses poor names for functions and variables.

Consequence: The program is difficult to understand, and the misleading names lead the programmer into mistakes.

Solution: Choose names that reflect what a function really does, or what a variable holds or is used for. If you have a variable that tells how many widgets you have, call it something like numberOfWidgets. Do not call it x, or even count. Make the name as specific as possible. If you have a function that computes the discriminant of an equation, call it something like computeDiscriminant. If it returns the discriminant as its value, call it discriminant.

You can go too far in this. Avoid extremely long names. A rough rule of thumb is that a name of 30 or more characters is probably too long to be practical.

Summary: Use descriptive names.

Mistake tex2html_wrap266
The programmer uses very long functions.

Consequence: The program is difficult to read, and difficult to get working.

Solution: Break the program into small functions. A rule of thumb is that a function should be no more than about 40 lines, excluding comments. In some cases this rule must be broken, but try to follow it wherever possible. Much shorter functions are even better.

Be sure to have a clear contract for each function, and to choose your functions so that they have a focus, and have short descriptions.

Summary: Break your program into short functions.

B. Being Prepared for Errors

Mistake tex2html_wrap267
The programmer does not proofread and try (by hand simulation) code before trying it by computer.

Consequence: The program does not work, and the programmer spends a long time on debugging.

Solution: It is tempting to be optimistic, and after writing some code, just try it on the computer to see if it works. Unfortunately, that is a waste of time unless you have a good reason for believing that the code works. Instead, try a few small inputs by hand. See if the code seems to be doing the right thing. This will save you time.

Summary: Check your function definitions by hand on small inputs.

Mistake tex2html_wrap268
The programmer thinks that getting the program to compile is the major hurdle.

Consequence: The programmer does not leave enough time for debugging, and cannot complete the program on time.

Solution: Remember that, after you get the program to compile, the problem of getting the program to work has only begun. Leave adequate time for testing and debugging.

Summary: Getting a program to compile is the beginning of getting it to work, not the end.

Mistake tex2html_wrap269
The programmer does not test anything until the whole program is written.

Consequence: The program does not work. The programmer has no idea where the mistake is. In reality, there are almost always several mistakes, and each acts to hide the others.

Solution: Develop your program in pieces. Write a contract for a function, write the function, then write a small program that tests the function, to see whether it seems to be meeting its contract. This way, if an error occurs, the error is almost always in the small part that was just written. Sometimes you need to write and test two or three functions together, but keep the number to a minimum.

It is very tempting to jump ahead too quickly. After you write part of a program, you will want to move ahead to the next part, so that you can get finished quickly. But if you move ahead to the next part before this part is working, you are only making much more work for yourself. You will spend time trying to fix a part that is correct, not realizing that another part is broken. Do not let yourself get caught in this trap.

Summary: Check each piece as you write it, even pieces that you are sure must work.

Mistake tex2html_wrap270
The programmer does not thoroughly test the program.

Consequence: The program does not work, and the fact that it does not is readily apparent to those who use the program.

Solution: This mistake might be due to an assumption that a program that compiles and works on simple inputs must work on more difficult inputs too. But that is not the case at all. Programs that work on some inputs, but not others, are very common. Do thorough testing. Try several cases, including relatively complicated or extreme cases. Be sure to do enough tests that every part of your program is used.

This mistake might also be due might be due to a belief that what you don't know cannot hurt you. (``I want it to work, and don't want to do a test that might show me that it does not work.'') If you find yourself reluctant to do tests for fear of finding further errors, take a break. Come back to the program when you are prepared to deal with errors. Look at debugging as a challenge, like working a crossword puzzle.

Summary: Test each part of your program thoroughly.

Mistake tex2html_wrap271
The programmer does not program defensively. He or she assumes that all will go well.

Consequence: All does not go well. The programmer is unprepared to catch the mistakes in his or her program.

Solution: Program defensively. What that means is, wherever it is easy to do so, include extra tests in your program to see that things are the way that you think they are.

Suppose that you have a function that takes an integer parameter, and that integer is required to be positive. (So the contract says that the integer must be positive.) The rookie programmer assumes that he or she will not make a mistake, and pass a nonpositive number to this function. The expert programmer is wary, and includes a test to see that the integer is indeed positive.

If you have a value that you know must be either 1 or 2 or 3, don't presume that you will not make a mistake and use a different value. Put a check in the program. If things are not right, the program can just print a message and stop.

Summary: Program defensively. Put extra tests in your program to check that all is well.

Mistake tex2html_wrap272
The programmer fails to keep backups of earlier work.

Consequence: The programmer makes changes that turn out to be the wrong thing to do. There is no way to get back to the previous version of the program. The programmer must try to recreate that version. This needlessly consumes time.

Solution: Keep backup files. Before you embark on a major change of a program, back it up so that you can return to the former version.

Summary: Keep backup files.

C. Fixing Errors

Mistake tex2html_wrap273
The programmer gives up when faced with a compile error that he or she cannot understand.

Consequence: The programmer gets nothing close to a working program.

Solution: If you see a compile error that you do not understand, examine the program carefully to see what is wrong. Use the following hints. If none of them help, and you cannot see what is wrong, then ask for help from somebody else.

  1. If you misspell the name of a type, you will often get a mysterious syntax error. Check spelling. Be careful to check the case of letters. For example, if your type is called Stack, but you write stack, then you have a spelling error. Remember that type int must be spelled with all lower case letters.
  2. If you leave out a semicolon, or forget a right brace, you will often get a mysterious compile error after the point of the actual error. If all looks well where the compiler says the error occurs, look at the preceding line or lines. Especially look for missing semicolons or right braces.
  3. If you put a semicolon after the heading of a function definition, you have created a function prototype. The compiler will give a mysterious compile error when it begins to read the body of the function. Check for a semicolon after the function heading.
  4. Do not try to compile a header file by itself. You can get compile errors because the wrong kind of compiler is used. If you get mysterious compile errors, make sure you are not asking the compiler to compile a header file. The same kind of thing can happen if you try to compile a file that has the wrong extension. A C++ program should be in a file with a name that ends on .cpp on a pc, or on .cc under Unix.
  5. Sometimes, if you forget to include a header file, you will get a compile error. Check that the necessary header files are included.
  6. If there is an error in a header file, sometimes it only shows up after the compiler finishes reading that header file and continues with the next file.

Summary: Do not let compile errors stop you.

Mistake tex2html_wrap274
The programmer ignores warning messages given by the compiler.

Consequence: The programmer spends a lot of debugging time trying to fix a mistake that the compiler warned was present.

Solution: Pay attention to warnings. They often indicate genuine errors. Fix your program so that it compiles without warnings.

Summary: Make your program compile without warnings.

Mistake tex2html_wrap275
The programmer tries to fix a mistake without understanding what is wrong. Instead, he or she tries random changes to see if the program will work.

Consequence: The programmer spends long hours trying random changes, only to find in the end that he or she has done nothing but ruin the program.

Solution: If you are a doctor, you do not cure a patient by trying random drugs until one works. You will almost certainly kill the patient before hitting upon the correct medication. You must find out what is wrong before you try to fix it.

Often, rookie programmers resort to random trial when they are tired, and they just want the program to work so they can go do something else. If you are tired, and cannot concentrate on your program, take a break. Think about something that you find relaxing. Resist the temptation to try random changes. Remember that they will almost certainly only make matters worse, not better.

Summary: To fix a program, find out what is wrong with it.

Mistake tex2html_wrap276
The programmer forgets about what the program is supposed to do while trying to get rid of compile errors, and is willing to write almost anything to get the compiler to accept the program.

Consequence: The programmer ruins the program while trying to fix it.

Solution: If you get a compile error, understand why the compiler is complaining. See how to fix it, while keeping the program doing what you want it to do. Do not abandon your problem solving capabilities just because the compiler complains.

In some ways, the compiler is quite stupid. The error message that it gives might suggest a way to fix the error. But that way might not be the right way for your program. Do not let the compiler push you into a fix that is inappropriate for this program. For example, do not throw in a semicolon just because the compiler complains of a missing semicolon, unless that is clearly the right fix. Do not define a type just because the compiler complains that the type is undefined, unless that is the right thing to do. You are the boss, not the compiler.

Here is an example that actually happened. A student had a character variable called op that contained '+' or '-' or '*'. He wanted to compute a+b if op = '+', a-b if op = '-' and a*b if op = '*'. He wrote

        result = a op b;
hoping that it would do the right thing. This is not correct C++ syntax, and the compiler gave an error message. The programmer changed this part of the program to
        result = a; op; b;
to try to get the compiler to accept it. The compiler did indeed accept it. The new program has the following meaning.
  1. Set result = a.
  2. Get the value of variable op, and ignore it.
  3. Get the value of variable b, and ignore it.
This means something, but not what the programmer desired.

Summary: Do not let the compiler push you around.

Mistake tex2html_wrap277
A test shows that the program does not do the right thing. Inspection of the program does not reveal the error. So the programmer gives up.

Consequence: The program is never made to work.

Solution: Develop and employ debugging skills. There are two common ways of localizing and diagnosing errors.

  1. Insert some extra prints into your program. Show what is happening. Make each print show which function it is in, and what it is printing. Study what is printed, to see if it looks correct.

    When deciding what to print, think about what might be wrong. Remember that, since the program does not work, at least one of your assumptions is incorrect. So print things that you think you know, to see if your are right. Show the input. Show intermediate results. Concentrate on those parts of the program that are directly concerned with what is not working. You will find this much easier if you test individual components as you create them. The error is usually in the new components.

    Print to a file, since the output is usually too long to fit on a screen.

  2. Use a debugger. If you don't know how to use a debugger, find out. Run the program to a point where the error has happened, or is about to happen. Look at where the program is, and at the values of variables.

Summary: Learn and employ debugging skills.

D. Using the Language

Mistake tex2html_wrap278
The programmer invents his or her own language constructs and meaning.

Consequence: The program does not compile, or does not have the desired effect.

Solution: Keep a core subset of the programming language that you use for writing programs. Stick to this subset. As you learn more about the language, add more to your core subset.

As an example of making up the language, see the above item, where a programmer wrote a op b.

Summary: Know the language subset that you use, and stick with it.

Mistake tex2html_wrap279
The programmer does not indent the program well during development, deciding to indent it nicely after it works.

Consequence: The programmer makes silly mistakes that would be apparent if the program were well indented during development, and spends hours trying to find them. Syntax errors due to mismatched braces are unnecessarily difficult to find.

Solution: Indent the program well during development. It does not take much time, and can save a lot of time.

Do not over-indent, and do not indent for no reason. Indent the body of an if-statement, while-statement, etc. about two spaces. Keep everything that belongs at the same level at the same indentation. If you have several if's in a row, do not indent deeper and deeper. Think of the if's as checking for several conditions. So you write

     if(...) {
       ... (indented)
     }
     else if(...) {
       ... (indented)
     }
     else if(...) {
       ... (indented)
     }
     else {
       ... (indented)
     }

You will find tabs problematic. Different text editors might use a different amount of space for a tab. A good idea is only to use spaces. You can turn off the use of tabs in auto-indenting editors.

Summary: Keep your program well-indented during development.

Mistake tex2html_wrap280
The programmer declares variables in the global scope.

Consequence: The program is mistake-prone, and is difficult to modify.

Solution: Declare variables in the local scope of functions. Use parameters and return values to communicate between functions.

There are exceptions to this rule. Sometimes, it makes sense to put variables in the global scope. Rookie programmers tend, however, to overuse global variables, so try to avoid them. You will learn later of occasions to use global variables.

Summary: Avoid global variables.

Mistake tex2html_wrap281
The programmer does not distinguish between a function and the result of running the function.

Consequence: The program either does not compile or does not do what was intended. (The former case is more desirable.)

Solution: Keep in mind that, to run a function, you must give a parameter list, even if there are no parameters. If you write

        if(cin.fail) {
          ...
        }
you are asking whether function cin.fail is 0. It is not, since it is a function. If you want to ask whether the last operation of cin failed, you write
        if(cin.fail()) {
          ...
        }

Summary: Always give a parameter list when running a function.

Mistake tex2html_wrap282
The programmer uses a reserved word as a variable or function name.

Consequence: The program does not compile, and there is usually a mysterious compile error message.

Solution: Learn the reserved words. The reserved words of C++ are as follows. (Some of these are reserved only in certain versions of C++.)

tabular169

Summary: At a compile error, check for reserved words.

Mistake tex2html_wrap283
The programmer fails to allocate memory where allocation is necessary.

Consequence: The program does not work, and has very mysterious behavior. The error is difficult to isolate.

Solution: This error only occurs in more advanced programs that do dynamic memory allocation. To avoid it, keep in mind that just because you have created a pointer variable does not mean that it is pointing to something. Think about the memory.

Summary: Pay attention to the values of pointer variables.

Mistake tex2html_wrap284
The programmer fails to deallocate memory.

Consequence: There are no bad consequences for short runs. For long runs, your program runs out of memory.

Solution: Be sure to deallocate dynamically allocated memory that was allocated using new. Use delete to deallocate. But also be careful not to deallocate something that you need. A good idea is to make it possible to suppress deallocation, so that you can check whether that is causing a problem.

Summary: Pay careful attention to deallocating memory.

Mistake tex2html_wrap285
The programmer does not bother to read about what library functions do.

Consequence: The program does not work because the programmer misunderstood the library functions.

Solution: Make sure you understand the contract for a library function before you use it. Do not presume that you understand the function just because the name suggests something to you.

Summary: Find out about library functions before using them.

Mistake tex2html_wrap286
The programmer uses = where == is intended, or compares strings (type char*) using == or <.

Consequence: The program does not work.

Solution: This is not really entirely a rookie mistake. Seasoned C++ programmers make these mistakes occasionally. Your best way to guard against them is to remember them, and to check for them carefully when reading your program. If you write

       if(x = y) ...
you do not get a test whether x and y have the same value, as you would with ==. Instead, your program does an assignment, forcing x to be equal to y. The value that is tested is the value of y. You can avoid the problem of using = for == when you are asking whether a variable is equal to a constant by putting the constant first. So you can write if(0 == x) rather than if(x == 0). If you accidentally write if(0 = x), you will get a compile error. If you accidentally write if(x = 0), you will not get a compile error. You would prefer to get the compile error here, since you have made a mistake.

If you write

       if(s == t) ...
where s and t are of type char*, then you are not asking whether the two strings are the same; you are asking instead whether they are stored at the same memory address. To compare strings, use library function strcmp. strcmp(s,t) returns 0 if strings s and t are the same, -1 if s is alphabetically smaller than t, and 1 if s is alphabetically larger than t.

Summary: Be careful in using =, ==, <, etc.




next up previous
Next: About this document

Karl Abrahamson
Sun May 16 11:08:13 EDT 1999