Appendix D. Common Programming Mistakes

THE FOLLOWING LIST SUMMARIZES SOME OF the more common programming mistakes made in C. They are not arranged in any particular order. Knowledge of these mistakes will hopefully help you avoid them in your own programs.

  1. Misplacing a semicolon.

    Example

    if ( j == 100 );
         j = 0;

    In the previous statements, the value of j will always be set to 0 due to the misplaced semicolon after the closing parenthesis. Remember, this semicolon is syntactically valid (it represents the null statement), and, therefore, no error is produced by the compiler. This same type of mistake is frequently made in while and for loops.

  2. Confusing the operator = with the operator ==.

    This mistake is usually made inside an if, while, or do statement.

    Example

    if ( a = 2 )
       printf ("Your turn.
    ");

    The preceding statement is perfectly valid and has the effect of assigning 2 to a and then executing the printf call. The printf function will always be called because the value of the expression contained in the if statement will always be nonzero. (Its value will be 2.)

  3. Omitting prototype declarations.

    Example

    result = squareRoot (2);

    If squareRoot is defined later in the program, or in another file, and is not explicitly declared otherwise, the compiler assumes that the function returns an int. Furthermore, the compiler converts float arguments to double, and _Bool, char, and short arguments to int. No other conversion of arguments is done. Remember, it’s always safest to include a prototype declaration for all functions that you call (either explicitly yourself or implicitly by including the correct header file in your program), even if they’re defined earlier.

  4. Confusing the precedences of the various operators.

    Examples

    while ( c = getchar ()  !=  EOF )
       ...
    if ( x & 0xF  ==  y )
       ...

    In the first example, the value returned by getchar is compared against the value EOF first. This is because the inequality test has higher precedence than the assignment operator. The value that is therefore assigned to c is the TRUE/FALSE result of the test: 1 if the value returned by getchar is not equal to EOF, and 0 otherwise. In the second example, the integer constant 0xF is compared against y first because the equality test has higher precedence than any of the bitwise operators. The result of this test (0 or 1) is then ANDed with the value of x.

  5. Confusing a character constant and a character string.

    In the statement

    text = 'a';

    a single character is assigned to text. In the statement

    text = "a";

    a pointer to the character string "a" is assigned to text. Whereas, in the first case, text is normally declared to be a char variable, in the second case, it should be declared to be of type "pointer to char".

  6. Using the wrong bounds for an array.

    Example

    int  a[100], i, sum = 0;
       ...
    for ( i = 1;  i <= 100;  ++i )
       sum += a[i];

    Valid subscripts of an array range from 0 through the number of elements minus one. Therefore, the preceding loop is incorrect because the last valid subscript of a is 99 and not 100. The writer of this statement also probably intended to start with the first element of the array; therefore, i should have been initially set to 0.

  7. Forgetting to reserve an extra location in an array for the terminating null character of a string.

    Remember to declare character arrays so that they are large enough to contain the terminating null character. For example, the character string "hello" would require six locations in a character array if you wanted to store a null at the end.

  8. Confusing the operator -> with the operator . when referencing structure members.

    Remember, the operator . is used for structure variables, whereas the operator -> is used for structure pointer variables. So, if x is a structure variable, the notation x.m is used to reference the member m of x. On the other hand, if x is a pointer to a structure, the notation x->m is used to reference the member m of the structure pointed to by x.

  9. Omitting the ampersand before nonpointer variables in a scanf call.

    Example

    int  number;
       ...
    scanf ("%i", number);

    Remember that all arguments appearing after the format string in a scanf call must be pointers.

  10. Using a pointer variable before it’s initialized.

    Example

    char  *char_pointer;
    *char_pointer = 'X';

    You can only apply the indirection operator to a pointer variable after you have set the variable pointing somewhere. In this example, char_pointer is never set pointing to anything, so the assignment is not meaningful.

  11. Omitting the break statement at the end of a case in a switch statement.

    Remember that if a break is not included at the end of a case, then execution continues into the next case.

  12. Inserting a semicolon at the end of a preprocessor definition.

    This usually happens because it becomes a matter of habit to end all statements with semicolons. Remember that everything appearing to the right of the defined name in the #define statement gets directly substituted into the program. So the definition

    #define    END_OF_DATA   999;

    leads to a syntax error if used in an expression such as

    if ( value == END_OF_DATA )
       ...

    because the compiler will see this statement after preprocessing:

    if ( value == 999; )
       ...
  13. Omitting parentheses around arguments in macro definitions.

    Example

    #define   reciprocal(x)    1 / x
            ...
    w = reciprocal (a + b);

    The preceding assignment statement would be incorrectly evaluated as

    w = 1 / a + b;
  14. Leaving a blank space between the name of a macro and its argument list in the #define statement.

    Example

    #define MIN (a,b)  ( ( (a) < (b) ) ? (a) : (b) )

    This definition is incorrect, as the preprocessor considers the first blank space after the defined name as the start of the definition for that name. In this case, the statement

    minVal = MIN (val1, val2);

    gets expanded by the preprocessor into

    minVal = (a,b)  ( ( (a) < (b) ) ? (a) : (b) )(val1,val2);

    which is obviously not what is intended.

  15. Using an expression that has side effects in a macro call.

    Example

    #define  SQUARE(x)  (x) * (x)
       ...
    w = SQUARE (++v);

    The invocation of the SQUARE macro causes v to be incremented twice because this statement is expanded by the preprocessor to

    w = (++v) * (++v);
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.118.103