By now you must be aware that C has certain features that are easily amenable to bugs. Added to this, it does not check and report all kinds of run time errors. It is therefore, advisable to keep track of such errors and to see that these known errors are not present in the program. This section examines some of the more common programming errors that a less experienced C programmer could make.
Missing Semicolons
Every C statement must end with a semicolon. A missing semicolon may cause considerable confusion to the compiler and result in ‘misleading’ error messages. Consider the following statements:
a = x+y
b = m/n;
The compiler will treat the second line as a part of the first one and treat b as a variable name. You may therefore get an “undefined name” error message in the second line. Note that both the message and location are incorrect. In such situations where there are no errors in a reported line, we should check the preceding line for a missing semicolon.
There may be an instance when a missing semicolon might cause the compiler to go ‘crazy’ and to produce a series of error messages. If they are found to be dubious errors, check for a missing semicolon in the beginning of the error list.
Misuse of Semicolon
Another common mistake is to put a semicolon in a wrong place. Common programming errors consider the following code:
for (i = 1; i<=10; i++);
sum = sum + i;
This code is supposed to sum all the integers from 1 to 10. But what actually happens is that only the ‘exit’ value of i is added to the sum. Other examples of such mistake are:
- while (x < Max);
{
} - if(T>= 200);
grade = ‘A’ ;
A simple semicolon represents a null statement and therefore it is syntactically valid. The compiler does not produce any error message. Remember, these kinds of common programming errors are worse than syntax errors.
Use of = Instead of = =
It is quite possible to forget the use of double equal sings when we perform a relational test. Example:
if(code = 1)
count ++;
It is a syntactically valid statement. The variable code is assigned 1 and then, because code = 1 is true, the count is incremented. In fact, the above statement does not perform any relational test on code. Irrespective of the previous value of code, count ++; is always executed.
Similar mistakes can occur in other control statements, such as for and while. Such a mistake in the loop control statements might cause infinite loops.
Missing Braces
It is common programming errors to forget a closing brace when coding a deeply nested loop. It will be usually detected by the compiler because the number of opening braces should match with the closing ones. However, if we put a matching brace in a wrong place, the compiler won’t notice the mistake and the program will produce unexpected results.
Another serious problem with the braces is, not using them when multiple statements are to be grouped together. For instance, consider the following statements:
for(i=1; i <= 10; i++)
sum1 = sum 1 +i;
sum2 = sum2 + i*i;
Printf(“%d %d\n”, sum1, sum2);
This code is intended to compute sum1, sum2 for i varying from 1 to 10, in steps of 1 and then to print their values. But, actually the for loop treats only the first statement, namely,
sum = sum1 + i;
as its body and therefore the statement
sum2 = sum2 + i*i;
is evaluated only once when the loop is exited. The correct way to code this segment is to place braces as follows:
for(i=1; i<=10; i++)
{
sum1 = sum1 + i;
sum2 = sum2 +i*i;
}
printf(“%d %d\n”, sum1 sum2);
In case, only one brace is supplied, the behaviour of the compiler becomes unpredictable.
Missing Quotes
Every string must be enclosed in double quotes, while a single character constant in single quotes. If we miss them out, the string (or the character) will be interpreted as a variable name.
Examples: if(response ==YES) /* YES is a string */
Grade = A; /* A is a character constant */
Here YES and A are treated as variables and therefore, a message “undefined names” may occur.
Misusing Quotes
It is likely that we use single quotes whenever we handle single characters. Care should be exercised to see that the associated variables are declared properly. For example, the statement city ‘M’: would be invalid if city has been declared as a char variable with dimension.
Improper Comment Characters
Every comment should start with a /* and end with a */. Anything between them is ignored by the compiler. If we miss out the closing */, then the compiler searches for a closing */ further down in the program, treating all the lines as comments. In case, it fails to find a closing */, we may get an error message. Consider the following lines:
…..
/* comment line 1
statement1;
statement2;
/* comment line 2 */
statement 3;
…..
Since the closing */ is missing in the comment line 1, all the statements that follow, until the closing comment */ in comment line 2 are ignored.
We should remember that C does not support nested comments. Assume that we want to comment out the following segment:
…..
x = a-b;
Y = c-d;
/* compute ratio */
ratio = x/y;
…..
…..
we may be tempted to add comment characters as follows:
/* x = a-b;
y=c-d;
/* Compute ratio */
ratio = x/y; */
This is incorrect. The first opening comment matches with the first closing comment and therefore the lines between these two are ignored. The statement ratio = x/y; is not commented out. The correct way to comment out this segment is shown as:
/* x = a-b;
y = c-d; */
/* compute ratio */
/* ratio = x/y; */
Undeclared Variables
C requires every variable to be declared for its type, before it is used. During the development of a large program, it is quite possible to use a variable to hold intermediate results and to forget to declare it.
Forgetting the Precedence of Operators
Expressions are evaluated according to the precedence of operators. It is common among beginners to forget this. Consider the statement
if (value = product () >= 100)
tax = 0.05 * value;
The call product () returns the product of two numbers, which is compared to 100. If it is equal to or greater than 100, the relational test is true, and a 1 is assigned to value, otherwise a 0 is assigned. In either case, the only values value can take on are 1 or 0. This certainly is not what the programmer wanted.
The statement was actually expected to assign the value returned by product() to value and then compare value with 100. If value was equal to or greater than 100, tax should have been computed, using the statement tax = 0.05 * value;
The error is due to the higher precedence of the relational operator compared to the assignment operator. We can force the assignment to occur first by using parentheses as follows:
if(value = product()) >=100)
tax = 0.05 * value;
Similarly, the logical operators && and ll have lower precedence than arithmetic and relational operators and among these two, && has higher precedence than ll. Try, if there is any difference between the following statements:
- if(p>50|| c>50&& m>60&&T>180)
X=1; - if(p>50|| c>50&& m>60&&T>180)
X=1; - if(p>50|| c>50&& m>60&&T>180)
X=1;
Ignoring the Order of Evaluation of Increment/Decrement Operators
We often use increment or decrement operators in loops. Example
…..
i = 0;
while ((c = getchar()) != ‘/n’;
{
string[i++] = c;
}
string[i-1] = ‘\n’;
The statement string[i++] = c; is equivalent to:
string[i] = c;
i = i+1;
This is not the same as the statement string[++i] = c; which is equivalent to
i = i+1;
string[i] = c;
Forgetting to Declare Function Parameters : Remember to declare all function parameters in the function header.
Mismatching of Actual and Formal Parameter Types in Function Calls : When a function with parameters is called, we should ensure that the type of values passed, match with the type expected by the called function. Otherwise, erroneous results may occur. If necessary, we may use the type cast operator to change the type locally.
Example: y = cos ( (double)x);
Nondeclaration of Functions
Every function that is called should be declared in the calling function for the types of value it returns.
main()
{
float a =12.75;
float b = 7.36;
printf(“%f\n”, division(a,b));
}
double division(float x, float y)
{
return(x/y);
}
The function returns a double type value but this fact is not known to the calling function and therefore it expects to receive an int type value. The program produces either meaningless results or error message such as “redefinition”.
The function division is like any other variable for the main and therefore it should be declared as double in the main.
Now, let us assume that the function division is coded as follows:
division (float x, float y)
{
return(x/y);
}
Although the values x and y are floats and the result of x/y is also float, the function returns only integer value because no type specifier is given in the function definition. This is wrong too. The function header should include the type specifier to force the function to return a particular type of value.
Missing & Operator in scan Parameters
All non pointer variables in a scan call should be preceded by an & operator. If the variable code is declared as an integer, then the statement scanf(“%d”, code); is wrong. The correct one is scanf(“%d”, &code); Remember, the compiler will not detect this error and you may get a crazy output.
Crossing the Bounds of an Array
All C indices start from zero. A common mistake is to start the index from 1. For example, the segment
int x[10], sum i;
Sum = 0;
for (i = 1; i < = 10; i++)
sum = sum + x[i];
would not find the correct sum of the elements of array x. The for loop expressions should be corrected. for (i=0;i<10;i++)
Forgetting a Space for Null character in a String
All character arrays are terminated with a null character and therefore their size should be declared to hold one character more than the actual string size.
Using Uninitialized Pointers
An uninitialized pointer points to garbage. The following program is wrong:
main()
{
int a, *ptr;
a = 25;
*ptr = a+25;
}
The pointer ptr has not been initialized.
Missing Indirection and Address Operators
Another common programming errors is to forget to use the operators * and & in certain places. Consider the following program:
main()
{
int m, *pl;
m = 5;
p1 = m;
printf(“%d\n”, *p1);
}
This will print some unknown value because the pointer assignment p1 =m; is wrong. It should be: p1 = &m; Consider the following expressing: y = *p1 + 10;
Missing Parentheses in Pointer Expressions
The following two statements are not the same:
x = *p1 + 1;
x = * (p1 + 1);
The first statement would assign the value at location p1 plus 1 to x, while the second would assign the value at location p1+1.
Omitting Parentheses around Arguments in Macro Definitions
This would cause incorrect evaluation of expression when the macro definition is substituted.
Example: #define f(X) x* + 1
The call y=f(a+b);
will be evaluated as y=a+b+1; which is wrong.
Some other common programming errors that we commonly make are:
- Wrong indexing of loops.
- Wrong termination of loops.
- Unending loops.
- Use of incorrect relational test.
- Failure to consider all possible conditions of a variable.
- Trying to divide by zero.
- Mismatching of data specifications and variables in scanf and printf statements.
- Forgetting truncation and rounding off errors.
Read More Topics |
Program design in C language |
Application of Linked List Dynamic Memory Allocation |
Accessing Structure Members in C |
Nesting of Function in C |