Copyright ©1999 by David Matuszek
Modified with permission in 2002 by Pat Palmer
C is an old but still popular algorithmic language. Its primary advantage is that programs written in C can be very efficient; its primary disadvantage is that programming in C is very error-prone.
Many things in C are system dependent: they may differ from one compiler to another. Because portability across systems is important, it is poor programming practice to rely on the way your particular system implements these features. I will flag system dependent features with [SD].
Variable names consist of letters, digits, and/or underscores; the first character must
be a letter or underscore. Case is significant. Names may be any length, but characters
beyond 31 may [SD] be ignored. By convention, lowercase letters are preferred, with
multiword variable names separated by underscores, e.g. total, max_value.
Function names and the names of external variables may have fewer significant characters [SD]. External variables may use as few as six significant characters [SD], and may ignore case [SD].
The following are keywords in C, and may not be used as names:
autodoubleintstructbreakelselongswitchcaseenumregistertypedefcharexternreturnunionconstfloatshortunsignedcontinueforsignedvoiddefaultgotosizeofvolatiledoifstaticwhile
A comment begins with /* and ends with */; it may span many
lines. Comments cannot be nested, that is, you can't put one comment inside another.
Inside a quoted string, /* does not start a comment.
You should have comments:
int-32768..32767. Octal numbers are written with a preceding zero, e.g. 0777.
Hexadecimal numbers are written with a preceding 0x or 0X, e.g. 0x7FFF.
long or long intL (preferably uppercase), e.g. 0L, 100L, 12345678L.
short or short intint, but occasionally represented
with fewer bits. char 'a', '5'.
Other common characters can be represented by "escaping" them with a backslash:
\aalert (bell) \rcarriage return \'single quote \bbackspace \thorizontal tab \"double quote \fform feed \vvertical tab \0null character \nnewline \\backslash
Less common characters can be represented as one-, two-, or three-digit octal or
hexadecimal numbers: '\013', '\xFF'.
Characters are considered to be integers; for example, you can do arithmetic with them:
'a'+1 gives 'b'. You can also read and print characters as
integers, or read and print (small) integers as characters.
Integer types other than char are signed (i.e. may hold either positive or
negative values) by default, but may be declared signed or unsigned. An
unsigned integer cannot take on negative values, but the maximum positive value is twice
as large as the signed version. Constants are written with a u or U
suffix, e.g. 45u; unsigned long constants are written with a ul
or UL suffix, e.g. 99999ul.
A char may also be declared signed or unsigned, but whether char
is signed or unsigned by default is system dependent. However, all printable characters
are positive numbers.
double3.1416, 1e12, -6.69E-24. The e
or E stands for "times 10 to the power".floatf or F, e.g. 1e12f.long doublel or L, e.g. 1e12L."\"Don't go,\" she said.\n".
Single quotes in strings don't need to be backslashed. Every string is terminated by a
zero byte, '\0', which is supplied by the compiler, not by the programmer.type*char* is
a pointer to a char, an int* is a pointer to an int,
and a double** is a pointer to a pointer to a double. type[]int[] is an array of
integers, while a double[][] is an array of arrays of double. struct name {type1 name1;
type2 name2; ...}struct name) containing named fields,
which may be of different types. Structures are useful in representing complex objects,
such as "dates" or "employees." typeR name (type1 name1,
type2 name2, ...)type1, type2,
... as arguments and returns a typeR result.
Declarations normally occur as the first thing inside a function, and the scope of the declaration (the part of the code that can use the declared variables) is the entire function. In addition, declarations may occur immediately following the opening brace of any compound statement, and the scope is the entire compound statement.
The general form of a declaration is
type variable1, variable2, ... ;
Individual variables can be initialized when they are declared:
type variable1 = value1, variable2 = value2, ... ;
The type modifiers prefix * (pointer to) and suffix [] (array
of) also apply to individual variables, e.g.
int *ptr_to_int, array_of_int[100];
A variable declaration may begin with the word const to indicate that the
value of the variable will not be changed by the program, e.g.
const double pi = 3.1415926536, e = 2.718281828459045;
The enum declaration creates a list of named integer constants; unless
otherwise indicated, the first name gets the value zero, the second gets one, and so on.
If a value is explictly given, counting proceeds from there. For example,
enum people {BABY, BOY, GIRL, MAN=1, WOMAN, PC=5};
is equivalent to
const int BABY=0, BOY=1, GIRL=2, MAN=1, WOMAN=2, PC=5;
Notice that the enum declaration is one of the (rare) places in C where
you need a semicolon after a close brace.
An array is a fixed size, ordered collection of values, all of the same type. It is declared as
type name[size];
An individual value in the array can be referenced by giving the name of the array and,
in brackets, the index (position) of the value as a integer from 0 to one less than
the size of the array, e.g. a[5].
An array may hold any (one) type of data. There is a special notation for arrays of
arrays, for example, int a[3][5] denotes an array of 15 integers
arranged in 3 rows and 5 columns; it can be indexed in the same way, e.g. a[i][j].
An array can be initialized (given initial values) at the time it is declared. When you initialize an array you can specify the size, or just let the compiler count how many values you supplied. The syntax is:
int a[] = {1, 1, 2, 3, 5, 8};
char *numbers[3][2] = {{"one", "eins"}, {"two", "zwei"}, {"three", "drei"}};
When you define a function that takes an array as a parameter, you do not need to
specify the number of rows, but you do need to specify any subsequent sizes, e.g. int saddle_point (int a[][10]) {...code...}.
A pointer contains the address of ("refers to") something else in
memory. The & operator, applied to a variable, returns its address; the *
operator, applied to a pointer, dereferences the pointer, that is, it returns the
thing pointed to. For example,
char letter, letter2; /* Declare some chars */
char *letter_ptr; /* Declare a pointer to a char */
letter_ptr = &letter; /* Give the pointer a value */
letter2 = *letter_ptr; /* Dereference the pointer */
The predefined constant NULL is an "unattached" pointer value
that doesn't point anywhere; it is numerically equal to zero, and its type is void*.
Arrays are closely related to pointers. The name of an array a, used by
itself, is actually a pointer to the zero-th element of the array a, while a[i]
is the same as *(a + i). It is often more convenient to use
pointers than subscripts, particularly when working with strings.
There are no operations defined for entire arrays. In particular, reading or writing an array must be done one element at a time.
A struct groups a number of variables into a single data type; the individual variables are called fields of the struct. For example, in
struct date {
int day;
char month[3];
int year;
}
the new data type is called a struct date, and it has fields day,
month, and year. You can declare variables of this new type,
e.g.
struct date yesterday, today, tomorrow;
and you can access the fields of a struct with "dot notation," e.g.
tomorrow.day = today.day + 1;
If you are given a pointer to the struct (as happens a lot in functions), you can refer
to the fields with -> instead of dot, e.g.
struct date *now;
now -> year = 1999;
You can also assign one struct variable to another struct variable (of the same type), and you can pass a struct into a function and return a struct as the value of a function. There is no I/O provided for entire structs.
Declarations usually declare the type of variables. However, if you put the word typedef
in front of any variable declaration, the names (which would otherwise be variable names)
become names for the type. For example, the declaration
char *str;
declares the variable string to be of type char*, but the
declarations
typedef char *string;
string str;
first declare string to mean the type char*, then
declare a variable str of type string (that is, type char*).
This is especially useful for struct definitions. For example, you might declare and use a "complex number" type as
typedef struct cplx {double re; double im;} complex;
complex p1, p2;
p1.re = 2.5; p1.im = 7.2;
p2 = p1;
Now complex is a synonym for struct cplx (and you
probably won't actually use the name cplx for anything).
Terminology in C is inconsistent. What we have been calling "declarations" actually both declare variables (tell what type they are) and define them (allocate space for them). Variables (and functions) can be defined only once, but they may be declared in many places.
Variable definitions may occur outside any function. Such variables are called external
variables, and their scope is the entire remainder of the file. For example, if you
define int totals[50] outside a function definition, you can access that
variable from other C files (or from an earlier location in the same file) by declaring
that variable in those files with an extern statement, such as extern
int totals[] or extern int totals[50]. To allow access within the file
but disallow access from other files, put the word static in front of the
function or variable definition.
External variables are initialized to zero by the compiler. Other (internal) variables may contain garbage when the program starts [SD].
An expression is any C code that results in a value. Expressions may be as simple as a single constant or single variable.
Operators with higher precedence (indicated by smaller numbers) are
performed before those with lower precedence. For example, in the expression 2*3+4*5,
the multiplications are done before the addition, because multiplication has higher
precedence than addition.
When operators have equal precedence, the associativity ("left to
right," or "right to left") determines which operations are done first. For
example, substraction has left to right associativity, so 10-5-3 means (10-5)-3
rather than 10-(5-3). Assignment has right to left associativity, so a=b=c+5
means a=(b=c+5) rather than (a=b)=c+5. Most common operators,
other than the assignment operators, associate left to right.
Parentheses can be used to override the above rules and specify an explicit order of evaluation. Parentheses are also used to show the order of evaluation when it might not be obvious.
Operator |
Meaning |
Position |
Precedence |
Associativity |
|---|---|---|---|---|
function_name () |
Call the function | postfix | 1 | left to right |
array_name [] |
Index the array | postfix | 1 | left to right |
structure . member |
The member of the structure | infix | 1 | left to right |
pointer -> member |
The member of the pointed-to structure | infix | 1 | left to right |
! |
Boolean negation (true <--> false) | prefix | 2 | right to left |
~ |
Bitwise negation (change every bit) | prefix | 2 | right to left |
++ |
Add one | prefix or postfix | 2 | right to left |
-- |
Subtract one | prefix or postfix | 2 | right to left |
+ |
Unary plus (does nothing) | prefix | 2 | right to left |
- |
Unary minus (negation) | prefix | 2 | right to left |
* |
Dereference (follow the pointer) | prefix | 2 | right to left |
& |
Address of (make a pointer to) | prefix | 2 | right to left |
( type ) |
Coercion, also called casting: change to the given type | prefix | 2 | right to left |
sizeof ( ) |
Size in bytes | prefix | 2 | right to left |
* |
Multiply | infix | 3 | left to right |
/ |
Divide | infix | 3 | left to right |
% |
Remainder (integer types only) | infix | 3 | left to right |
+ |
Add | infix | 4 | left to right |
- |
Subtract | infix | 4 | left to right |
<< |
Shift bits left, vacated bits are set to zero | infix | 5 | left to right |
>> |
Shift bits right, vacated bits are set to zero or to sign bit [SD] | infix | 5 | left to right |
| < | Less than | infix | 6 | left to right |
<= |
Less than or equal to | infix | 6 | left to right |
> |
Greater than | infix | 6 | left to right |
>= |
Greater than or equal to | infix | 6 | left to right |
== |
Equal to | infix | 7 | left to right |
!= |
Not equal to | infix | 7 | left to right |
& |
Bitwise AND | infix | 8 | left to right |
^ |
Bitwise exclusive OR | infix | 9 | left to right |
| |
Bitwise OR | infix | 10 | left to right |
&& |
Boolean AND | infix | 11 | left to right |
|| |
Boolean OR | infix | 12 | left to right |
cond ? expr1 : expr2
|
If condition is true then expression 1, else expression 2 | double infix | 13 | right to left |
= |
Assignment, "gets" | infix | 14 | right to left |
+= |
Addition assignment operator: a+=b is the same as a=a+b |
infix | 14 | right to left |
-= |
Subtraction assignment operator | infix | 14 | right to left |
*= |
Multiplication assignment operator | infix | 14 | right to left |
/= |
Division assignment operator | infix | 14 | right to left |
%= |
Remainder assignment operator | infix | 14 | right to left |
&= |
Bitwise AND assignment operator | infix | 14 | right to left |
^= |
Bitwise exclusive OR assignment operator | infix | 14 | right to left |
|= |
Bitwise OR assignment operator | infix | 14 | right to left |
<<= |
Left shift assignment operator | infix | 14 | right to left |
>>= |
Right shift assignment operator | infix | 14 | right to left |
, |
Evaluate in either order [SD] | infix | 15 | left to right |
Quick summary:
* / % + - ++ -- < <= == != >= >> && || ! & | ^ << >> ~ = += -= *= /= %= &= ^= |= <<= >>=Notes:
When used as a prefix, ++ adds one to its operand before using the value
of the operand in an expression. When used as a suffix, ++ uses the original
value of the operand in the enclosing expression, and adds one to the operand afterwards.
Similar remarks hold for the -- operator.
The boolean operators && and || are short-circuit
operators; if the first operand of && is false, or the first operand
of || is true, the second operand will never be evaluated. For example, in if(i < size && a[i] == 0)...,
where size is the size of the array, the array will not be accessed if i
is too large.
When numbers of different types are mixed in a single expression, shorter values are
automatically converted to longer values, and integers are automatically converted to
floating point, e.g. 7.1 + 2 gives 9.1 (the 2
is converted to 2.0 before the addition). This is called widening,
and also happens automatically when you assign a shorter value (or integer) to a longer
(or floating point) variable.
In some cases you need to coerce, or cast, a value of one type to a
value of another type. Do this by putting the desired type in parentheses before the
value, e.g. (int) (100 * pi).
Statement |
Meaning |
|---|---|
expression; |
Any expression may be used as a statement; however, unless the expression has a side
effect, the computed value is simply discarded. Example expressions that have side effects: a = b + c; |
{ statements } |
The "compound" statement, used to group several statements into one. |
if (expression) |
If the expression is true, execute the statement;
otherwise, do nothing. |
if (expression) |
If the expression is true, execute statement1;
otherwise, execute statement2. |
while (expression) |
|
do |
|
for (expr1; expr2; expr3) |
|
|
|
break; |
Exit the innermost enclosing loop or switch statement. Cannot be used outside a loop or switch statement. |
continue; |
Return to the top of the innermost enclosing loop. Cannot be used except in a loop. |
return expression; |
Evaluate the expression and return it as the value of the function. The expression must be of the correct type to be a return value of the function. |
return; |
Return from a function whose return type is void. |
label: statement ; |
Any statement may be labelled; labels are used in conjunction with the goto
statement. |
goto label; |
Branch to the statement with the given label. Except in rare cases, it is considered poor style to ever use this statement. |
Notes:
The if, while, do-while, and for
statements each control a single statement. In order to control multiple statements, use
braces to make them into a compound statement.
Each case in the switch statement can consist of multiple statements;
braces may improve readability but are not necessary.
Whichever group of statements is selected by the switch statement, the
computer will execute those statements and all remaining statements in the switch;
this is not what the programmer usually wants. A strongly recommended style is to
use break as the last statement in each group of statements, including
the last group, and to include a comment whenever the break is deliberately
(as opposed to accidentally) omitted.
The default case of a switch statement is optional. If
omitted, and no other case matches, the switch statement does nothing.
There are several predefined functions you need to know about. Some are described in the Strings and Input/Output sections below; here are some others.
The following functions require you to #include <math.h>. In
addition, you must compile your program with the -lm flag, e.g. gcc -lm myprog.c .
double sqrt(double)double sin(double)tan, cos,
acos, asin, atan.double pow(double, double)double fabs(double)
int abs(int)The following functions are in <stdlib.h>, which you don't have
to #include because C does it automatically:
int atoi(const char *)void *malloc(int)void*
pointer to it.void free(void *) int rand()rand()%n.The most important use of functions is to break up your program into separate, relatively independent chunks that you can understand on their own terms. In general, each function should perform a single, easily described operation; that operation should be put in a comment at the top of the function; and functions should be kept short (usually no more than a screenful).
There is a distinction between declaring a function (saying that you have such a function) and defining a function (writing the actual code). Defining a function automatically declares it, if you haven't done so already. A function must be declared before it is used; that is, the declaration must occur earlier in the text of your program than any call to the function.
A function declaration is called a prototype, and looks like this:
return_type function_name
( type1
name1, type2 name2, ... );
Notice that the prototype ends with a semicolon. The parameter names (the names inside the parentheses) may be omitted, but it is good practice to include them (and to ensure that they are the same as the names in the function definition). It is good practice to declare all your functions at the top of your file, immediately after your preprocessor commands.
A function definition has the same form as a prototype, but the semicolon is replaced by a function body, and the parameter names are not optional.
return_type function_name
( type1
name1, type2 name2, ... ) {
declarations ;
statements ;
}
If a function returns no value, the return type should be void. If a
function takes no parameters, the argument names should be replaced by the word void.
However, when you call a function that has no parameters, you should use empty
parentheses, (), after the function name.
Variables and parameters declared within a function are allocated space when the
function is called, and the space is released when the function returns. This means that
you cannot retain values between different calls to the same function. If you want a
single copy of a variable that is kept across function calls, preface the declaration with
the word static. (This same word is used with external variables, but has a
different meaning there.) Static variables are less useful than you might suppose, and are
very difficult to use correctly in recursive functions.
If the function returns a value, use
return expression ;
where the expression results in a value of the appropriate type. If the function returns void, use
return;
Reaching the end of the function body is equivalent to doing a return with
no value.
A function is called by writing its name followed by a pair of parentheses containing expressions to be evaluated and passed to the function. You must supply the correct number of expressions, and they must evaluate to the types expected by the function.
The expressions you supply in a function call are sometimes called arguments or actual
parameters; the variables in the head of the function are sometimes called parameters
or formal parameters. Arguments to a function are passed in by value: that
is, the arguments are evaluated and the resultant values are copied to the formal
parameters. When the function returns, the values of the formal parameters are not
copied back to the actual parameters. If you want to write a function that changes the
value of an argument, you must instead pass in the address of that variable (with &)
and treat that formal parameter as a pointer. For example, the following is a function
that adds one to its parameter:
void bump (int *n) { *n++; }
and it can be called like this:
bump (&counter);
In the description of arrays, it states that if you declare an array int a[],
the name a (by itself) is actually a pointer to the array. If you call a
function and call it with a as an actual parameter, you are passing in a pointer
to the array, not the array itself; this is called passing the argument by reference.
In the called function, you can declare the corresponding parameter as an array (and treat
it just like an array), or you can declare it as type int*, and use pointer
arithmetic on it.
Note that main is a function; when it has no arguments (or if you choose
to ignore any arguments), the word void should be put in the parentheses. You
can put arguments on the command line, and reference them as an array of strings; the
prototype is then
int main (int argc, char *argv[]);
Here argc is the number of arguments and *argv is the array
of strings.
When you write functions or declare variables that are intended to be used by other
programs, you should divide the source code up into a .c file containing the
definitions (actual code and actual storage allocation) and a .h file
containing the declarations that you want to make available to those other programs. A
typical .h file might look something like:
#define LINE_LENGTH 80
extern char *line;
void append(char *newstuff);
int chars_used(void);
void printline(void);
Strings constants are enclosed in double quotes, e.g. "This is a
string." Backslash notation for special characters can be used in strings.
Adjacent string constants separated only by whitespace are concatenated by the compiler. This is useful primarily when a string constant is too long to fit comfortably on one line.
C has no "string" data type. You can use string constants with no extra work,
but if you wish to manipulate (change) a string, you must allocate space for it yourself.
Use the char* datatype to point to the first character of the string (or any
other character in it, for that matter), and pointer arithmetic to access subsequent
characters. Strings are always terminated by a zero byte, '\0'.
To allocate storage for a string, call malloc(nchars),
where nchars is the number of characters you want (remember to add
one for the terminating zero byte). malloc returns a void* which
you must cast to a char* in order to use. For example,
char *mystring, *p;
mystring = (char *) malloc(101);
To step through a string, make a char* pointer to the first
character, and repeatedly increment that pointer until it points to the terminating zero
byte. For example,
for (p = mystring; *p != 0; p++)
printf ("%c", *p);
To examine or change the contents of a string, look at and change the string one
character at a time, by way of a char* pointer into the string, e.g.
if (*p == 'a') *p = 'A';
If you #include <string.h> you will have access to a number of
predefined useful string functions. Here are some of them; for a complete list, execute
the UNIX command "man string".
size_t strlen (const char *s)size_t
is a system-defined integer type; treat it as an int and don't worry about
it.char *strcat (char *dst, const char *src) *src to the end of the string *dst. It is
your responsibility to ensure that enough space has been allocated to *dst.char *strcpy (char *dst, const char *src) *src to the location pointed to by *dst. It
is your responsibility to ensure that enough space has been allocated to *dst.char *strchr (const char *s, int c) c (converted to a
character) in string s, or NULL if c does not occur
in s. char *strstr (const char *s1, const char *s2)
s2
in string s1, or NULL if s2 does not occur in s1.
int strcmp (const char *s1, const char *s2)
s1
is lexically less than, equal to, or greater than string s2, respectively.
C automatically provides the following I/O streams for you:
stdin -- standard input stream, nowadays usually associated with the
keyboard.stdout -- standard output stream, used for "normal" output, and
usually associated with the screen.stderr -- standard error stream, used for "error" messages, and
also usually associated with the screen.The function printf (format_string, expr1, expr2, ...)
writes the format_string to stdout, substituting the
expression values for the conversion specifications in the format string. Common
conversion specifications are given in the following table.
Spec Meaning Variations %cA character %8c %-8c %*c %-*c%dAn integer %10d %-6d %*d %-*d%eA floating point number with an exponent %12e %12.5e %.5e %-8e %*.*e%fA floating point number without an exponent %12f %12.5f %.5f %-8f %*.*ef%gWhichever of %eand%fis shorter%12g %12.5g %.5g %-8g %*.*g%ldA long integer %15ld %-12ld %*ld %-*dl%oAn octal integer (doesn't write a leading 0)%6o %-12o %*o %-*o%sA string %20s %-20s %*s %-*s%uAn unsigned integer %10u %-6u %*u %-*u%xA hexadecimal integer (doesn't write a leading 0x)%4x %-8x %*x %-*x
Variations:
printf ("val = %*.*f\n", width, precision,
val);You can write to stderr rather than stdout by using the
function fprintf (stderr, format_string, expr1, expr2, ...).
The scanf (format_string, &var1, &var2, ...)
function reads values from stdin according to the format_string,
using the same conversion specifications as printf(). Whitespace in the format_string
is ignored, but other text must be matched by corresponding text in the input stream.
Whitespace in the input stream is skipped over, except when reading characters or strings.
scanf() is convenient for reading numbers, but is difficult to use correctly
for characters and strings; consider using getc()or gets()
instead.
The function getc(stdin) (or, equivalently, getchar() ) reads
a character and returns it as an integer; you should check if it is equal to the
predefined constant EOF (end of file, i.e. nothing more could be read) before
casting it to a char. The function putc(c, stdout)
(or, equivalently, putchar(c) ) writes a character c
to stdout.
The function char *fgets(var, n, stdin) reads a
string (up to n-1 characters, or a newline, or the end of the file) from stdin
and puts it into the string pointed to by var, where var
must be of type char*. and returns a NULL result if it failed to
read anything. It is the programmer's responsibility to ensure that there is enough space
allocated for the string. The function puts(s) writes the string s
to stdout, replacing the null terminator with a newline.
When you output something, it may not be written out immediately; it may be waiting in
a buffer. To "dump the buffer" (force your output to be written), use fflush(stdout).
To read from and/or write to a file, follow these steps:
| Step | Example |
|---|---|
Declare a file_pointer variable of type FILE*. |
FILE *myfile; |
Assign to the variable the result of calling fopen(file_name, file_mode),
where file_mode is one of "r" (read), "w"
(write), or "a" (append). |
myfile = fopen ("mydata.txt", "r"); |
Use the file_pointer to perform the desired input or output. |
for (i = 0; i < N; i++) |
Call fclose(file_pointer) to close the file. |
fclose (myfile); |
You can use the following functions to access files; these each take a FILE*
variable as a parameter. The standard files stdin, stdout, and stderr
are also of type FILE* ; the only difference is that C automatically opens
and closes these files for you.
| Function | Comments |
|---|---|
int fprintf(FILE *strm, const char *format, ... ); |
Like printf(). |
int fscanf(FILE *strm, const char *format, ...); |
Like scanf(). |
int fgetc(FILE *stream); |
Gets a character as an integer, may return EOF. |
int fputc(int c, FILE *stream); |
Puts a character. |
char *fgets(char *s, int n, FILE *stream); |
Reads a line of up to n-1 characters, adds a zero byte; returns NULL
if it fails. |
int fputs(const char *s, FILE *stream); |
Writes a string. |
int fflush(FILE *stream); |
Forces the buffer to be written out. |
int ferror(FILE *stream); |
Returns zero if no error occurred. |
int feof(FILE *stream); |
Returns zero if end of file was not returned. |
When you compile a C program, it is first run through a separate program called a preprocessor before it is compiled. The C preprocessor uses different rules than the C compiler.
#.#include <filename>stdio.h, which defines printf(), scanf(), and
other I/O functions.string.h, which defines various string manipulation functions.math.h, which defines sqrt() and trignometric functions. Note:
To use math functions you must also include the -lm flag on the cc
or gcc command line, e.g. gcc -lm myprog.c .#include "filename".h file.#define name definitionname
in your program with definition. It does not replace parts of
variables, however; that is, if you define max and you have a variable named maxval,
your variable is not changed. Also, substitution does not occur within quoted strings. Note:
If your definition is an expression, it should be fully parenthesized, because it might be
used in a context where the parentheses are necessary.#define name(arg1,arg2,...) definitionname(...)
in your program with definition, where each
occurrence of an argument in the definition is replaced by the corresponding value from
the program. Caution: It is a good idea to avoid using an argument more than once
in the definition, because if an argument that causes side effects (such as n++)
is passed in, it may be executed more than once.If the compiler finds syntax errors in your program, it (usually) tells you the line number that it was on when it first realized there was a problem; the actual error might have been on the line above, or even earlier. It also tells you its best guess about what you did wrong, and it's usually right, but sometimes it's wrong and misleading.
If your program runs but produces the wrong results, the best strategy to find the
error is to think about what the program might have done to produce those results. The
next best strategy is to put in printf() statements to try to localize the
problem. The worst strategy is to change something randomly and see if it helps.
If your program crashes with a bus error or segmentation fault,
or if it seems to behave randomly, here are some things that could cause it:
string.h).& in a scanf() function call (or in any
function call where a pointer is expected).* or & where it doesn't belong.By the way, when a program crashes, it sometimes leaves a very large file named core
in your directory. This is helpful in determining why your program crashed in the same way
a black box is useful in determining why an airplane crashed: a team of experts, given
months, can get clues from it. You can't. Just throw this file away whenever it appears.