- A common mistake is to type `=' instead of `=='.
if (i=3)
return 1;
else
return 0;
will always return 1 because the assignment `i=3' has the
value 3 and 3 is true! gcc's warning option can alert you
to this. You might also try to get into the habit of writing expressions
like if (3==i) to safeguard yourself from this kind of error.
- Comments in C can't be nested. Use the preprocessor directives to
temporarily `comment out' blocks of code. Suppose you had the following
code.
if (i=6)
z=mean(x,y); /* get the xy mean */
mean(z,y);
If you decided not to risk running mean you might do
/* comment this fragment out
if (i=6)
z=mean(x,y); /* get the xy mean */
mean(z,y);
*/
but it wouldn't work because the first `/*' would be matched
by the `*/' on the `mean(x,y)' line (the `/*' on that
line being
ignored), and `mean(z,y);' wouldn't be commented out at all.
In this case the final `*/' would be flagged as an error,
but you won't always be so lucky.
...
i = 3;
j = 10;
while (i<100);
i = i+j;
...
This while loop will go on for ever. The semicolon after the
while condition is a null statement which forms the body of the loop so
i will always be 3.
Take away that semicolon and i = i+j becomes the body, which is
probably what was intended.
- When you have an if-else statement nested in another if statement,
always put braces around the if-else. Thus, never write like this:
if (foo)
if (bar)
win ();
else
lose ();
(the else matches the closest if), always like this:
if (foo)
{
if (bar)
win ();
else
lose ();
}
- Don't be fooled by indentation. In the following fragment only the
execution of the `j = 7;' statement is conditional upon the
value of i.
...
if (i==7)
j = 7;
k = 7;
...
- The order of operations in an expression isn't guaranteed to be
left-to-right. A line like
a[i++] = b[i++];
will have different results according to whether or not the
i on the left-hand side is calculated before the right-hand side
is evaluated.
- The order of operator precedence sometimes surprises people.
...
FILE *fp;
...
if (fp=fopen(filename, "r") == NULL)
return (NULL);
Here the intention is to try opening a file, then compare the resulting
fp to NULL to see if fopen failed. Unfortunately,
what actually happens first is the test (fopen(filename, "r") == NULL)
which has an integer result (non-zero if the statement is true). This
result is then assigned to fp. The compiler should warn you about
this problem. The code should have some extra brackets:-
...
FILE *fp;
...
if ((fp=fopen(filename, "r")) == NULL)
return (NULL);
- The following won't work as expected because the `
~' character
needs to be interpreted by the shell.
if ((fp=fopen("~/data", "r")) == NULL)
return (NULL);
You'll have to find out your home directory (use getenv("HOME"))
and append to it.
- scanf takes pointers to the variables that are going to be set.
The following fragment will cause a crash
...
int i;
scanf("%d",i); /* this should be scanf("%d",&i) */
- The most uncomfortable bugs are those that seem to move as you hunt
them down. Put in some printf() statements and they just
disappear - or seem to. This could mean that you're writing off
the end of an array or that one of your pointers has gone astray.
You can protect against this by doing something like
#define BUFLEN 10
int x[BUFLEN], y;
...
if (y >= BUFLEN || y<0)
[error code here]
else
x[y] = 255;
...
- There's a big difference between
'\0' and "\0". Suppose
you had
char str[100];
char *str_ptr;
str_ptr = str;
then str_ptr and str would both point to the first element in
the array. Suppose you wanted to initialise this string by making the first
element a zero byte. You could do
strcpy(str_ptr, "\0") /* or strcpy(str_ptr, "") */
or
*str_ptr = '\0';
but
str_ptr = "\0";
would do something quite different. It would create a string in your
executable (namely "\0") and set str_ptr to point to it
with potentially disastrous effects.
- Turning on optimisation may change the behaviour of your program,
especially if the program isn't perfect.
For instance, if optimisation re-positions a variable into a
register it's less likely to be 0 initially, so if you've
not initialised variables before use you might get a surprize.
- A function that returns a pointer either (1) takes a pointer
as a parameter or (2) uses malloc to allocate memory to
store the data in or (3) returns a pointer to a static
buffer. As the user of a function, you must know which
of the three it is in order to use the function; the
manual page describing the function should give you
this information.