What’s wrong with my program – Common Programming Errors


This article is an attempt to explain the basic programming errors that beginners often make. It is an ongoing project that attempts to cover all the basic errors I get when people email me. If you’re just starting out programming, looking through it might be a good way to solidify your programming knowledge.

Undeclared Variables

int main()
{
cin>>x;
cout<<x;
}

“Huh? Why do I get an error?”

Your compiler doesn’t know what x means. You need to declare it as a variable.

int main()
{
int x;
cin>>x;
cout<<x;
}

Uninitialized variables

int count;
while(count<100)
{
cout<<count;
}

“Why doesn’t my program enter the while loop?”

In C++ variables are not initialized to zero. In the above snippet of code, count could be any value in the range of int. It might, for example, be 586, and in that situation the while loop’s condition would never be true. Perhaps the output of the program would be to print the numbers from -1000 to 99. In that case, once again, the variable was assigned a memory location with garbage data that happened to evaluate to -1000.

Remember to initialize your variables.

Setting a variable to an uninitialized value

int a, b;
int sum=a+b;
cout<<"Enter two numbers to add: ";
cin>>b;
cout<<"The sum is: "<<sum;
When Run:
Enter two numbers to add: 1 3
The sum is: -1393

“What’s wrong with my program?”

Often beginning programmers believe that variables work like equations – if you assign a variable to equal the result of an operation on several other variables that whenever those variables change (a and b in this example), the value of the variable will change. In C++ assignment does not work this way: it’s a one shot deal. Once you assign a value to a variable, it’s that value until you reassign the values. In the example program, because a and b are not initialized, sum will equal an unknown random number, no matter what the user inputs.

To fix this error, move the addition step after the input line.

int a, b;
int sum;
cout<<"Enter two numbers to add: ";
cin>>b;
cin>>a;
sum=a+b;
cout<<"The sum is: "<<sum;

Using a single equal sign to check equality

char x='Y';
while(x='Y')
{
//...
cout<<"Continue? (Y/N)";
cin>>x;
}

“Why doesn’t my loop ever end?”

If you use a single equal sign to check equality, your program will instead assign the value on the right side of the expression to the variable on the left hand side, and the result of this statement is TRUE. Therefore, the loop will never end. Use == to check for equality; furthermore, to avoid accidental assignment, put variables on the left hand side of the expression and you’ll get a compiler error if you accidentally use a single equal sign as you can’t assign a value to something that isn’t a variable.

char x='Y';
while('Y'==x)
{
//...
cout<<"Continue? (Y/N)";
cin>>x;
}

Undeclared Functions

int main()
{
menu();
}
void menu()
{
//...
}

“Why do I get an error about menu being unknown?”

The compiler doesn’t know what menu() stands for until you’ve told it, and if you wait until after using it to tell it that there’s a function named menu, it will get confused. Always remember to put either a prototype for the function or the entire definition of the function above the first time you use the function.

void menu();
int main()
{
menu();
}
void menu()
{
...
}

Extra Semicolons

int x;
for(x=0; x<100; x++);
cout<<x;

“Why does it output 100?”

You put in an extra semicolon. Remember, semicolons don’t go after if statements, loops, or function definitions. If you put one in any of those places, your program will function improperly.

int x;
for(x=0; x<100; x++)
cout<<x;

Overstepping array boundaries

int array[10];
//...
for(int x=1; x<=10; x++)
cout<<array[x];

“Why doesn’t it output the correct values?”

Arrays begin indexing at 0; they end indexing at length-1. For example, if you have a ten element array, the first element is at position zero and the last element is at position 9.

int array[10];
//...
for(int x=0; x<10; x++)
cout<<array[x];

Misusing the && and || operators

int value;
do
{
//...
value=10;
}while(!(value==10) || !(value==20))

“Huh? Even though value is 10 the program loops. Why?”

Consider the only time the while loop condition could be false: both value==10 and value==20 would have to be true so that the negation of each would be false in order to make the || operation return false. In fact, the statement given above is a tautology; it is always true that value is not equal to 10 or not equal to 20 as it can’t be both values at once. Yet, if the intention is for the program only to loop if value has neither the value of ten nor the value of 20, it is necessary to use && : !(value==10) && !(value==20), which reads much more nicely: “if value is not equal to 10 and value is not equal to 20”, which means if value is some number other than ten or twenty (and therein is the mistake the programmer makes – he reads that it is when it is “this” or “that”, when he forgets that the “other than” applies to the entire statement “ten or twenty” and not to the two terms – “ten”, “twenty” – individually). A quick bit of boolean algebra will help you immensely: !(A || B) is the equivalent of !A && !B (Try it and see). The sentence “value is other than [ten or twenty]” (brackets added to show grouping) is translatable to !(value==10 || value==20), and when you distribute the !, it becomes !(value==10) && !(value==20).

The proper way to rewrite the program:

int value;
do
{
//...
value=10;
}while(!(value==10) && !(value==20))

CHASING THE BUGS


C Programmers are great innovators of our times. Unhappily, among their most enduring accomplishment are several new techniques for wasting time. There is no shortage of horror stories about programs that took twenty times to ‘debug’ as they did to ‘write’. And one hears again and again about programs that had to be rewritten all over again because the bugs present in it could not be located.
A typical C programmer’s morning after is red eyes, blue face and a pile of crumpled printouts and dozens of reference book all over the floor. Bugs are C programmer’s birth right. But how do we chase them away. No sure-shot way for that. I thought if I make a list of more common programming mistakes it might be of help. They are not arranged in any particular order. But as you would realize surely a great help!

a.     Omitting the ampersand before the variables used in scanf(  )
For example, 
int choice ; 
scanf ( ” %d “, choice ) ; 
  
Here, the & before the variable choice is missing. Another common mistake with scanf( ) is to use blanks either just before the format string or immediately after the format string as in, 
int  choice ; 
scanf ( ” %d “, choice ) ; 
  
Note that this is not a mistake, but till you don’t understand scanf( ) thoroughly, this is going to cause trouble. Safety is in eliminating the blanks. Thus, the correct from would be, 
int choice ; 
scanf ( ” %d “, &choice ) ; 
b.    Using the operator = instead of the operator ==. 
What do you think will be the output of the following program: 
main( ) 
{ 
int i = 10 ; 
while ( i = 10 ) 
{ 
printf ( “got to get out” ) ; 
i++ ; 
} 
} 
  
At first glance it appears that the message will be printed once and the control will come out of the loop since i becomes 11. But, actually we have fallen in an indefinite loop. This is because the = used in the condition always assigns the value 10 to i, and since i is non-zero the condition is satisfied and the body of the loop is executed over and over again. 
c.     Ending a loop with a semicolon. Observe the following program. 
main(  ) 
{ 
int j = 1 ; 
while ( j <= 100 ) ; 
{ 
printf ( “\nCompguard” ) ; 
j++ ; 
} 
} 
  
Inadvertently, we have fallen in an indefinite loop. Cause is the semicolon after while. This in effect makes the compiler feel that you wanted the loop to work in the following manner: 
while ( j <= 100 ) ; 
  
By all means an indefinite loop since j never gets incremented and hence eternally remains less that 100. 
d.    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 will continue into the next case. 
  
main( ) 
{ 
int ch = 1 ; 
switch ( ch ) 
{ 
case1 : 
printf ( “\nGoodBye” ) ; 
case 2 : 
printf ( “\nLieutenant” ) ; 
} 
} 
  
Here, since the break has not been given after the printf( ) in case 1, the control runs into case 2 and executes the second printf( ) as well. However, this sometimes turns out to be a blessing in disguise, especially, in cases when we are checking whether the values of a variable equals a capital letter or a small case letter. 
e.     Using continue in a switch. It is a common error to believe that the way the keyword break is used with while, for, do-while and a switch, similarly the keyword continue can also be used with them. Remember, continue works only in loop, never with a switch
f.     A mismatch in the number, type and order of actual and formal argument. 
yr= romanise ( year, 1000, ‘m’ ) ; 
  
Here, three arguments in the order intint and char are being passed to romanise( ). When romanise( ) receives these arguments they must be received in the same order by the formal arguments. A careless mismatch might give strange results. 
g.    Omitting provisions for returning non-integer value from a function. 
If we make the following function call,  
area = area_circle ( 1.5 ) ; 
  
then while defining area_circle( ) function later in the program, care should be taken to make it capable of returning a floating point value. Note that unless otherwise mentioned, the compiler will assume that function returns a value of the type int. 
h.     Inserting a semicolon at the end of a macro definition. How do you recognize a C programmer? Ask him to write a paragraph in English and watch whether he ends each sentence with a semicolon. This usually happens because a C programmer becomes habitual to ending all statements with a semicolon. However, a semicolon at the end of a macro definition might create a problem. 
For example, 
#define UPPER 25; 
  
would lead to a syntax error if used in an _expression such as  
if ( counter == UPPER ) 
  
This is because on preprocessing the if statement would take the form 
if ( counter == UPPER; ) 
i.      Omitting parentheses around a macro expansion. 
#define SQR(x) x*x 
main( ) 
{ 
int a ; 
a=25 / SQR ( 5 ) ; 
printf ( “\n%d”, a ) ; 
} 
  
In this example we expect the value of a to be 1, whereas it turns out to be 25. This so happens because on 
preprocessing the arithmetic statement takes the following form: 
a = 25 / 5 * 5 ; 
j.      Leaving a blank between the macro template and the macro expansion. 
#define ABS (a) ( a=0 ? a : -a ) 
  
Here, the space between ABS and (a) makes the preprocessor believe that you want to expand ABS into (a), which is certainly not what we want. 
k.     Using an _expression that has side effects in a macro call. 
#define SUM(a) (a+a) 
main( ) 
{ 
int w, b = 5; 
w= SUM ( b++ ) ; 
printf ( “\n%d”, w ) ; 
} 
On preprocessing the macro would be expanded to, w=(b++) +(b++); If you are wanting to first get sum 5 and 5 and them increment b to 6, that would not happen using the above macro definition. 
l.      Confusing a character constant and a character string 
In the statement 
ch = ‘z’; 
  
a single characters is assigned to ch. In the statement 
ch = “z” 
a pointer to the characters string “a” is assigned to ch
  
Note that in the first case, the declaration of ch would be, 
char ch ; 
  
whereas in the second case it would be, 
char*ch; 
m.   Forgetting the bounds of an array. 
main( ) 
{ 
int num[50], i ; 
for ( i =1; i <= 50 ; i++ ) 
num[i] = i * i ; 
} 
  
Here, in the array num there is no such element as num[50]. Since array counting begins with 0 and not 1. Compiler would give no warning if our program exceeds the bounds. If not taken care of, in extreme cases the computer might even hang.  
n.     Forgetting to reserve an extra location in a character array for the null terminator. Remember each characters array ends with a ”, therefore its dimension should be declared big enough to hold the normal characters as well as the ”. 
For example, the dimension of the array word[ ] should be 9 if a string “Jamboree” is to be stored in it. 
o.    Confusing the precedence of the various operations. 
main( ) 
{ 
char ch ; 
FILE *fp ; 
fp = fopen ( “text.c”, “r” ) ; 
while ( ch = getc ( fp ) != EOF ) 
putch ( ch ) ; 
fclose ( fp ) ; 
} 
  
Here, the value returned by getc( ) will be first compared with EOF, since != has a higher priority than =. As a result, the value that is assigned to ch will be the true/false result of the test: 1 if the values returned by getc( ) is not equal to EOF, and 0 otherwise. The correct from of the above while would be,   
while ( ( ch = getc ( fp ) ) != EOF ) 
putch ( ch ) ; 
p.    Confusing the operator -> with the operator ‘.’, while referring to a structure element. Remember, on the left of the operator ‘.’ only a structure variable can occur, whereas on the left of the operator -> only a pointer to a structure can occur.  
main( ) 
{ 
struct emp 
{ 
char name[35] ; 
int age ; 
} ; 
struct emp e = {“Dubhashi”, 40 } ; 
struct emp *ee ; 
printf ( “\n%d”, e.age ) ; 
ee = &e ; 
printf ( “\%d”, ee -> age ) ; 
} 
q.    Forgetting to use the far keyword for referring memory location beyond the data segment. 
main( ) 
{ 
unsigned int*s; s = 0x413 ; 
printf ( “\n%d”, *s ) ; 
} 
  
Here, it is necessary to use the keyword far in the declaration of variable s, since the address that we are storing in s (0x413) is address of a location present in BIOS Data Area, which is far away from the data segment. Thus, the correct declaration would be unsigned int far*s ;  
r.      Exceeding the range of integers and chars. 
main( ) 
{ 
char ch ; 
for ( ch = 0 ; ch <= 255 ; ch++ ) 
printf ( “\n%c %d, ch, ch ) ; 
} 
  
Can you believe that this is an indefinite loop? Probably, a closer look would confirm it. Reason is, ch has been declared as a char and the valid range of char constant is -128 to +127. Hence, the moment ch tries to become 128 (through ch++), the value exceeds the character range, therefore the first number from the negative side of the range, i.e. -128, gets assigned to ch. Naturally the condition is satisfied and the and the control remains within the loop eternally.