A Concise Introduction to C
       See also Dave's C Oneliners

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].

Quick links:
   Names    Expressions
   Comments    Statement types
   Basic datatypes    Functions
   Constructed types         Defining your own functions
   Declarations    Strings
        Arrays and pointers    Input/Output
        Structs    Reading and writing files
        Declaring types with typedef       Preprocessor commands
        extern declarations    Problems

Names

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:

auto double int struct
break else long switch
case enum register typedef
char extern return union
const float short unsigned
continue for signed void
default goto sizeof volatile
do if static while

Comments

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:

 

Basic datatypes

int
An integer. Typically [SD] represented as a 16-bit quantity, with values in the range -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 int
An integer. Typically [SD] represented as a 32-bit quantity, with values in the (approximate) range plus or minus two billion. Long int constants are written with a final L (preferably uppercase), e.g. 0L, 100L, 12345678L.
 
short  or  short int
An integer. Typically [SD] the same as an int, but occasionally represented with fewer bits.
 
char
A character, usually [SD] represented as an 8-bit quantity. Most common characters can be represented by enclosing them in single quotes: 'a', '5'. Other common characters can be represented by "escaping" them with a backslash:
\a alert (bell)       \r carriage return       \' single quote
\b backspace \t horizontal tab \" double quote
\f form feed \v vertical tab \0 null character
\n newline \\ 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.

double
A floating-point number; that is, a number containing a decimal point, an exponent, or both. Examples: 3.1416, 1e12, -6.69E-24. The e or E stands for "times 10 to the power".
 
float
A floating-point number that may [SD] use fewer bits (thus being less precise or having a smaller range of legal exponents, or both) than a double. Constants are suffixed with f or F, e.g. 1e12f.
 
long double
A floating-point number that may [SD] use more bits (thus being more precise or having a larger range of legal exponents, or both) than a double. Constants are suffixed with l or L, e.g. 1e12L.
 
string
C does not have a string data type as such, but it does have string constants. A string constant consists of zero or more characters surrounded by double quotes; characters in a string may use the same backslash notation, e.g. "\"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.
 
boolean
C does not have a boolean ("true" or "false") data type as such. Instead, a variable or expression of any data type that evaluates to zero is usually considered to be "false," and any nonzero value is considered to be "true."
 

Constructed types

type*
A pointer to a value of the given type. For example, a 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[]
A array of values of the given type. For example, an int[] is an array of integers, while a double[][] is an array of arrays of double.
 
struct name {type1 name1; type2 name2; ...}
A structure (whose name is 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, ...)
A function that takes expressions of type1, type2, ... as arguments and returns a typeR result.

 

Declarations

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.

Arrays and pointers

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.

Structs

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.

Declaring types with typedef

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).

extern declarations

 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].

 

Expressions

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 types

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;
  i++;
  printf ("r = %d\n", r);
statements } The "compound" statement, used to group several statements into one.
if (expression)
  statement;
If the expression is true, execute the statement; otherwise, do nothing.
if (expression)
  statement1;
else
  statement2;
If the expression is true, execute statement1; otherwise, execute statement2.
while (expression)
  statement;

do
  statement
while (expression);

for (expr1expr2expr3)
  statement;

switch (expression) {

  case value1 : statements1;

  case value2 : statements2;

  ...

  default : statementsN;

}

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.

 

Functions

 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)
Returns the square root of the input argument.
 
double sin(double)
Returns the sine of the input argument. Related functions are tan, cos, acos, asin, atan.
 
double pow(double, double)
Returns the first argument raised to the power of the second argument.
 
double fabs(double)
int abs(int)
Returns the absolute value of the input argument.

The following functions are in <stdlib.h>, which you don't have to #include because C does it automatically:

int atoi(const char *)
Converts a string to an integer.
 
void *malloc(int)
Allocate the specified number of bytes of storage, and return a void* pointer to it.
 
void free(void *)
Release the storage pointed to by the argument (which may be any type of pointer).
 
int rand()
Return a random integer in the range 0 to the maximum int size. Hint: to get a random number in the range 0 to n-1 inclusive, use rand()%n.

Defining your own functions

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

 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)
Returns the length of the string, not including the terminating null (zero) character. (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)
Appends the string *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)
Copies the string *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)
Finds and returns a pointer to the first occurrance of 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)
Finds and returns a pointer to the beginning of the first occurrence of string s2 in string s1, or NULL if s2 does not occur in s1.
 
int strcmp (const char *s1, const char *s2)
Returns a negative, zero, or positive result depending on whether string s1 is lexically less than, equal to, or greater than string s2, respectively.
 

 

Input/Output

C automatically provides the following I/O streams for you:

The function printf (format_stringexpr1expr2, ...) 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
%c A character %8c  %-8c  %*c  %-*c
%d An integer %10d  %-6d  %*d  %-*d
%e A floating point number with an exponent %12e  %12.5e  %.5e  %-8e  %*.*e
%f A floating point number without an exponent %12f  %12.5f  %.5f  %-8f  %*.*ef
%g Whichever of %e and %f is shorter %12g  %12.5g  %.5g  %-8g  %*.*g
%ld A long integer %15ld  %-12ld  %*ld  %-*dl
%o An octal integer (doesn't write a leading 0) %6o  %-12o  %*o  %-*o
%s A string %20s  %-20s  %*s  %-*s
%u An unsigned integer %10u  %-6u  %*u  %-*u
%x A hexadecimal integer (doesn't write a leading 0x) %4x  %-8x  %*x  %-*x

Variations:

You can write to stderr rather than stdout by using the function fprintf (stderr, format_stringexpr1expr2, ...).

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).

Reading and writing files

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_namefile_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++)
  fscanf(myfile, "%d", &a[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.

 

Preprocessor commands

 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>
This command inserts the contents of the specified system file at this point in the program. Important system files to know about are
#include "filename"
This command inserts the contents of your specified file at this point in the program. Usually this will be a .h file.
 
#define name definition
This causes the preprocessor to replace every succeeding occurrence of name 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,...) definition
This causes the preprocessor to replace every succeeding occurrence of name(...) 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.
 

Problems

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:

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.