Crash Course in C
Crash Course in C
January 1995
A Crash Course in C 1
A Crash Course in C i
Contents
0 Introduction 1
1 Fundamentals 2
1.1 Example programs : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 2
1.2 Variables : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 3
1.3 Input/Output : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 4
1.4 Keywords and Operators: The C Language : : : : : : : : : : : : : : : : : : : : : : : 5
1.5 Expressions and Statements : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 9
1.6 Control Flow : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 9
1.7 The C Preprocessor : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 13
1.8 Problems : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 14
2 Functions 18
2.1 Reasons for Using Functions : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 18
2.2 Basic Structure : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 18
2.3 Return Statement : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 20
2.4 Di erence between ANSI-C and \Traditional C" : : : : : : : : : : : : : : : : : : : : 21
2.5 Object Storage Classes and Scope : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 22
2.6 Larger Programs : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 24
2.7 Macros : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 27
2.8 Problems : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 27
3 Pointers 29
3.1 Pointer De nition and Use : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 29
3.2 Pointers as Function Arguments: \Call by Value" : : : : : : : : : : : : : : : : : : : : 31
3.3 Arrays : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 32
3.4 Functions Returning Pointers : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 34
3.5 Multidimensional Arrays : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 36
3.6 Strings: : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 41
3.7 Command Line Arguments : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 41
3.8 Pointers to Functions : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 42
ii A Crash Course in C
3.9 Problems : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 42
4 Structures 43
4.1 Syntax and Operations : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 43
4.2 typedef : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 45
4.3 Array of Structures : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 45
4.4 Use with Functions : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 46
4.5 Linked Lists : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 48
4.6 union : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 49
4.7 enum : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 50
4.8 Example: Complex Numbers : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 52
4.9 Problems : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 54
5 C Libraries 55
5.1 Memory Allocation : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 55
5.2 Math Libraries : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 56
5.3 Random Variables : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 57
5.4 Input/Output : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 58
5.5 Strings : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 60
A Make Program 61
B C Style Guide 63
B.1 General Style : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 63
B.2 Layout : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 66
B.3 Coding Practice : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 66
B.4 Naming Conventions : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 67
C Answers to Problems 68
x0 A Crash Course in C 1
0 Introduction
Reasons to use C:
pointers and structures
encourages well structured control ow
modular programming is encouraged
easy to learn (C has few keywords)
portability to di erent machines
many functions are in libraries, not intrinsic parts of the language
lexical scoping for variables
References:
Brian Kernighan and Dennis Ritchie, The C Programming Language (2nd edition) (K&R)
Stephen G. Kochan, Programming in C, Programming in ANSI C (Kochan)
Al Kelley and Ira Pohl, A Book on C
American National Standard for Information Systems|Programming Language C, X3.159-
1989.
Three steps are necessary to use C:
write the program using an editor
compile (and link) it; on Unix systems, use
% cc program.c
% cc -o <name> <name>.c
This automatically runs three separate processes, using the source les <names>.c, to produce
the output:
{ preprocessor
{ compiler
{ linker
If there are no errors, this produces an executable le. The rst cc command produces the
le a.out, while the second makes the le <name>.
execute the program
% <name>
% <name> < input.file
% <name> > output.file
% <name> < input.file > output.file
Di erent systems have di erent procedures to use C. See the manual or help les for details.
2 A Crash Course in C x1.1
1 Fundamentals
1.1 Example programs
The following are simple examples to get things started. They do not do anything useful, but they
illustrate some key characteristics of C.
/* this is a comment */
main() /* function definition */
{ /* start of block */
printf("Hello world\n"); /* output; statement ends with a semicolon */
/* use '\n' in printf to get a linefeed */
} /* end of block */
A common error when using scanf() is not giving pointers as the arguments; to input a variable, use
int x;
scanf("%d", &x); /* correct */
NOT
int x;
scanf("%d", x); /* incorrect */
x1.2 A Crash Course in C 3
1.2 Variables
All variables must be declared and de ned before they can be used. Variable names can be composed of
characters, digits, and the underscore character (_), and can usually be up to 32 characters long. Vari-
able names should not begin with an underscore|these names are used by the compiler and the libraries.
Variables have speci c types and usage; basic data types:
char: a single byte, used for one character
{ can specify signed or unsigned, although signed is preferred for compatibility with int
int: integers
{ can modify with short or long
{ can specify signed or unsigned
float: single precision oating point (real) number
double: double precision oating point number
void: no type value, for pointers and functions
The speci c size of each type depends on the implementation; see <limits.h> for details. On Unix systems,
<limits.h> is usually the le /usr/include/limits.h.
int n = 10;
int n_oct = 065; /* octal */
int n_hex = 0x3d; /* hexadecimal */
long m = 10L;
unsigned int k = 304U;
unsigned long l = 3040UL;
float x1 = 143.0;
float x2 = 24.6e-3;
double y = 34.1L;
}
4 A Crash Course in C x1.3
1.3 Input/Output
Basic input/output is obtained using the standard library
Syntax: printf("control string", variable1, variable2, ) :::
scanf("control string", pointer1, pointer2, :::
)
The control string has place holders for the variables being used (see tables on page 16). For printf(),
there can also be characters in the control string. For scanf(), the pointers to the variables being inputed
must be used. Special characters are listed on table 5 on page 16.
/** using printf() and scanf() **/
main()
{
int x=10;
float y;
printf("(3) x = ");
printf("%d", x);
printf("\n"); /** same as (4) **/
/** can input several values of different types with one scanf command **/
printf("input x, y: "); scanf("%d %f", &x, &y);
printf("(6) x = %d, y = %f\n", x, y);
}
Output: (1) 10
(2) 50
(3) x = 10
(4) x = 10
input x: 40
(5) x = 40
input x, y: 20 34.5
(6) x = 20, y = 34.500000
x1.4 A Crash Course in C 5
x=5;
y = ++x; /** prefix increment **/
printf("++x: x=%d, y=%d\n", x, y);
x=5;
y = x++; /** postfix increment **/
printf("x++: x=%d, y=%d\n", x, y);
x=5;
y = --x; /** prefix decrement **/
printf("--x: x=%d, y=%d\n", x, y);
x=5;
y = x--; /** postfix decrement **/
printf("x--: x=%d, y=%d\n", x, y);
}
Output: ++x: x=6, y=6
x++: x=6, y=5
--x: x=4, y=4
x--: x=4, y=5
x1.4 A Crash Course in C 7
x = 128;
y = x / 10; /** y = 12, the remainder is dropped **/
y = x % 10; /** y = 8, which is remainder **/
x = 10;
y = !x; /** y = 0 **/
y = !(!x); /** y = 1 **/
x = 0;
y = !x; /** y = 1 **/
x = 10;
x += 2; /** x = 12 **/
x += 2; /** x = 14 **/
x = 10;
x -= 4; /** x = 6 **/
x = 10;
x *= 5; /** x = 50 **/
x = 10;
x /= 2; /** x = 5 **/
x /= 2; /** x = 2 **/
x = 2
y = (x < 5) ? 5 : 10; /** y=5 **/
x = 8
y = (x < 5) ? 5 : 10; /** y=10 **/
y = x * ++x;
printf("x = %d, y = %d\n", x, y);
z1 = x/y;
z2 = (float) x / (float) y;
printf("z1 = %6.2f, z2 = %6.2f\n", z1, z2);
}
Output: z1 = 0.00, z2 = 0.80
x1.5 A Crash Course in C 9
A statement is
a valid expression followed by a semicolon
a group of statements combined into a block by enclosing them in braces (f g). This is then treated
as a single statement.
a special statement (break, continue, do, for, goto, if, return, switch, while, and the
null statement)
A statement can be labeled, for use with goto. Since goto disrupts structured control ow, however, it is
not generally recommended.
main()
{
int x=5;
if (x > 0)
printf("x = %d\n", x);
if (x < 10)
{
printf("x = %d\n", x);
x += 10;
}
else
x -= 10;
if (x==1)
printf("one\n");
else if (x==2)
printf("two\n");
else if (x==4)
{
printf("four\n");
x /= 2;
}
else if (x==5)
printf("five\n");
else
{
printf("x = %d\n", x);
x %= 10;
}
/** 'else' matches up with last unmatched 'if' in same block level **/
if (x > 0)
if (x % 2)
printf("odd\n");
else
printf("even\n");
else
printf("negative\n");
if (!(x % 2))
{
if (!(x % 5))
x /= 10;
}
else
printf("odd\n");
}
x1.6 A Crash Course in C 11
1.6.2 Looping
while: testing at the beginning of the loop
do...while: testing at the end of the loop, after executing the loop at least once
for: almost the same as while, in a compact form
Syntax: while (exp)
statement
do
f
statement
g while (exp);
i=1;
while (i<=10)
{
printf("%d\n", i);
i++;
}
}
main() /*** print the numbers from 1 to 10 ***/
{
int i;
i=1;
do
{
printf("%d\n", i++);
} while (i<=10);
}
main() /*** print the numbers from 1 to 10 ***/
{
int i;
for (i=1 ; i<=10; i++)
printf("%d\n", i);
}
Syntax: switch(exp)
f
case (const-exp):
statement-opt
break;
case (const-exp):
statement-opt
statement-opt
break;
.
.
.
default:
statement-opt
break;
g
Here const-exp is a constant expression, and statement-opt is an optional statement. The break; after the
default: case is optional.
continue;
break;
return (exp-opt);
Here label is a statement label.
The break; statement is used inside the while, do...while, for, and switch statements to automatically
drop out of the current loop. The continue statement is used inside the loops (not switch) to jump to
the end of the loop. With while and do...while, this jumps to the next test; with for, it jumps to the
increment step, and then the test.
/** Example with 'do...while' and 'switch': waiting for a yes/no answer **/
main()
{
char ans, c;
int answer;
do
{
printf("enter y/n: "); scanf("%c", &ans);
switch (ans)
{
case 'y': case 'Y': answer = 1; break;
case 'n': case 'N': answer = 0; break;
default: answer = -1; break;
}
} while (answer == -1);
printf("answer = %d\n", answer);
}
x1.7 A Crash Course in C 13
#define MAX 10
#define TRUE 1
#define FALSE 0
After inserting the math.h header le, math subroutines can be used properly. To compile using the math
library on Unix, use
% cc -o <program> <program>.c -lm
for (i=0, x=1; i<n; i++, x*=2) /*** uses comma operator ***/
printf("log(%5d) = %8.3lf\n", x, log((double) x));
}
14 A Crash Course in C x1.8
The #if...#endif preprocessor command can be used to comment out a section of code which may have
comments within it.
/** using #if for nested comments **/
#define TRUE 1
#define FALSE 0
main()
{
int x=5;
#if FALSE /** everything until the matching #endif is commented **/
x = 304;
#endif
1.8 Problems
1. Run example programs to become familiar with using C.
2. Write a program to print all Fahrenheit and Celsius temperatures using conversion
C = (F , 32) 5=9
for 20 increments from 32 to 212. (See K&R, p. 9 if you are stuck.)
3. Input a number and print all its factors
4. Input a number and decide if it is prime
5. Change the quadratic formula program so that it also prints the complex solutions
6. Input an integer and print the value of each digit in English: 932 => nine three two
7. Count the number of characters and lines in a le (use '\n' to nd lines)
x1.8 A Crash Course in C 15
2 Functions
2.1 Reasons for Using Functions
saves repetition of common routines
functions can be used by di erent parts of the program
modularizes the program, making it easier to use:
{ write|can work on pieces independently
{ read|have to understand what the large pieces do, not each statement, hiding unnecessary detail
{ modify|changing one part should have limited e ects on other parts
{ debug|can debug the functions independently, then put everything together
{ other people can use the pieces without worrying about details
gives new variables with each call (automatic variables, lexical scoping)
allows recursive processes
main()
{
print_message();
}
x2.2 A Crash Course in C 19
A function that takes an argument. The arguments are separated by commas; the order in which they
are evaluated is unspeci ed. The value of each argument is passed to the corresponding parameter of
the function.
void print_integer(int i)
{
printf("i = %d\n", i);
}
main()
{
int n=5;
print_integer(n);
}
A function that returns a value:
int input_integer(void); /** function prototype declarations **/
main()
{
int x, y, z;
x = input_integer();
y = input_integer();
printf("the sum is %d\n", z=x+y);
}
int input_integer(void)
{
int a;
do
{
printf("input a positive integer: ");
scanf("%d", &a);
} while (a <= 0);
return a;
}
20 A Crash Course in C x2.3
int input_integer_le_n(int n)
{
int a;
do
{
printf("input a positive integer less than %d: ", n);
scanf("%d", &a);
} while (a<=0 || a>n);
return a;
}
The return statement can occur anywhere in the function, and will immediatly end that function and return
control to the function which called it. If there is no return statement, the function will continue execution
until the closing g of the function de nition, and return with an unde ned value.
The type of the expression returned should match the type of the function; C will automatically try to
convert exp to the return-type.
x2.4 A Crash Course in C 21
float max(float x, float y) /** argument types are in the definition **/
{
if (x < y)
return y;
else
return x;
}
main()
{
float x,y,z;
...
z = max(x,y); /** the function call is the same **/
...
}
float max(x,y)
float x,y; /** argument types listed after the definition **/
{
if (x < y)
return y;
else
return x;
}
22 A Crash Course in C x2.5
Also, external variables can only be de ned once, although they can be declared as often as necessary. If an
external variable is initialized during the declaration, then that also serves as a de nition of the variable.
int x; /*** definition of global variable ***/
extern int x; /*** declaration so other files can use it ***/
extern int y; /*** declaration, must be defined elsewhere ***/
extern int z=0; /*** declaration, definition, and initialization ***/
/*** can be used by other files ***/
main()
{
printf("%d", z);
}
x2.5 A Crash Course in C 23
main()
{
int m=2, n=5;
float x=10.0, y=14.1;
int count;
print_pair_i(m, n);
count = print_pair_i(m, n); printf("%d\n", count);
reset_count();
count = print_pair_f(x, y); printf("%d\n", count);
print_pair_d(15.0, 28.0);
count = print_pair_d(20.0, 30.0); printf("%d\n", count);
}
Output: (10.000000,14.100000)
1
(2,5)
(2,5)
3
(10.000000,14.100000)
1
(15.000000,28.000000)
(20.000000,30.000000)
2
main()
{
int n=1;
float x=5.0;
float A(float x)
{
return (x*x*x);
}
/*
** to compile:
** % cc -o large large_prog.c large_sub.c
**
** if large_sub.c will not been changed, can use
** % cc -c large_sub.c
** once, followed by
** % cc -o large large_prog.c large_sub.o
** whenever large_prog.c is changed
*/
x2.6 A Crash Course in C 25
/* FILE: large.h */
#include <stdio.h>
#define TRUE 1
#define FALSE 0
int num; /*** only functions in this file can access num ***/
float B(void)
{
return ((float) num);
}
float C(int n)
{
num=n;
return (n*4.0);
}
This has the following output, which shows a dependence on the argument evaluation order in printf().
Output: 125.000000, 0.000000, 4.000000
125.000000, 8.000000, 2.000000
26 A Crash Course in C x2.6
Alternatively, the les can be put together by the preprocessor. This is simpler, but it compiles all the les,
not just the unchanged ones.
/* FILE: large-2.h */
#include <stdio.h>
#define TRUE 1
#define FALSE 0
float B(void)
{
return ((float) num);
}
float C(int n)
{
num=n;
return (n*4.0);
}
/* FILE: large-2_prog.c */
#include "large-2.h"
#include "large-2_sub.c"
main()
{
int n=1;
float x=5.0;
float A(float x)
{
return (x*x*x);
}
/***
to compile:
% cc -o large large-2_prog.c
***/
x2.7 A Crash Course in C 27
2.7 Macros
Small procedures like swap() and max() can also be written as macros using #define,
#define MAX(x,y) ((x) > (y) ? (x) : (y)) /** macro for maximum **/
There are advantages to each. Since #define causes a macro substitution, code is replaced before compila-
tion. It will run faster, since it won't make a function call, but it will evaluate either x or y twice, which
may have side e ects or take extra computational e ort. MAX will work on any arithmetic type, while max()
will only work on oats. The functions dmax() and imax() are needed for double and integer values.
Macro substitutions do not happen within quoted strings or as parts of other identi ers: `#define NO 0'
does not replace `NO' in `x = NOTHING;' or `printf("NO!");.' Also, parentheses are very important:
#define RECIPROCAL_1(x) 1/(x)
#define RECIPROCAL_2(x) 1/x
main()
{
float x=8.0, y;
y = RECIPROCAL_1(x+10.0);
printf("1/%3.1f = %8.5f\n", x, y);
y = RECIPROCAL_2(x+10.0);
printf("1/%3.1f = %8.5f\n", x, y);
}
Output: 1/8.0 = 0.05556
1/8.0 = 10.12500
To continue a macro de nition onto the next line, use a `n' at the end of the current line.
2.8 Problems
8. Write a function to raise a number to an integer power, x_to_int_n(x,n)
9. Write a function to calculate factorial(n)
10. Try to write the factorial function recursively
11. Write a program to input a positive number and print all the prime numbers less than or equal to
that number, using functions like is prime() and get positive int().
28 A Crash Course in C x2.8
3 Pointers
3.1 Pointer De nition and Use
A pointer is a variable whose value is the address of some other object. This object can have any valid type:
int, oat, struct, etc. The pointer declaration syntax is
Syntax: type *ptr-name;
A pointer to an integer is declared as
int *p;
where `p' is of type `int *', pointer to an integer, and `*p' is of type integer. The type of object the
pointer references must be speci ed before a value can be obtained. The operators used with pointers are
the pointer reference/indirection (*) and address (&) operators:
main()
{
int x, *px; /* defines the pointer px */
px = &x; /* &x ==> address of x */
*px = x; /* *px ==> value px points to */
}
h212i
h208i
px: s
h204i
x:
h200i
Figure 1: Memory diagram with pointers. The memory addresses are given by h ni
/* example program */
main()
{
int x=5, y=6, *p;
p = &x; /** pointer needs to point to something **/
printf("1. x=%d, y=%d, *p=%d\n", x, y, *p);
x = 7;
printf("2. x=%d, y=%d, *p=%d\n", x, y, *p);
*p = 8;
printf("3. x=%d, y=%d, *p=%d\n", x, y, *p);
p = &y;
printf("4. x=%d, y=%d, *p=%d\n", x, y, *p);
*p += 10 * (x * *p);
printf("5. x=%d, y=%d, *p=%d\n", x, y, *p);
}
30 A Crash Course in C x3.1
p: r p: r p: r p: r p: r
y: 6 y: 6 y: 6 y: 6 y: 486
x: 5 x: 7 x: 8 x: 8 x: 8
p=&x x=7 p=8 p=&y p+=10(x p)
Figure 2: Memory diagram with pointers|the example program
Valid pointer operations:
assignment to a pointer of the same type
assigning a pointer to pointer of type (void *) and back
adding or subtracting a pointer and an integer (including increment and decrement)
subtracting or comparing two pointers which point to members of the same array
assigning or comparing to zero
/** Valid Pointer Operations **/
#define NULL 0
main()
{
int x, y;
int *px=(&x); /** can initialize an automatic pointer **/
int *py;
void *pv;
void swap_A(float *x, float *y) /** passes addresses of x and y **/
{
float tmp = *x;
*x = *y;
*y = tmp;
}
3.3 Arrays
An array is a contiguous space in memory which holds a certain number of objects of one type. The syntax
for array declarations is
Syntax: type array-name[const-size];
static type array-name[const-size] = initialization-list;
static type array-name[] = initialization-list;
where the remaining ve elements of x[10] will automatically be 0. Part of the array can be passed as an
argument by taking the address of the rst element of the required subarray (using &), so &x[6] is an array
with 4 elements.
s - 7 23 0 45 9
x[4]: 9
x[3]: 45
x[2]: 0
x[1]: 23
x[0]: 7
x: s
Figure 4: Memory diagram of arrays
x3.3 A Crash Course in C 33
#define MAX 10
static int b[MAX] = {1, 5, 645, 43, 4, 65, 5408};
main()
{
int i;
int *p, *p_max;
static int a[] = {1, 5, 645, 43, 4, 65, 5408, 4, 7, 90};
The array and pointer are closely related, in that x[i] and *(x+i) both get the i+1 element in the array,
and &x[i] and (x+i) are both pointers to the i+1 element.
There are di erences between them, however. An array name is a constant, while a pointer is a variable, so
int x[10], *px;
px = x; px++; /** valid **/
x = px; x++; /** invalid, cannot assign a new value **/
Also, de ning the pointer only allocates memory space for the address, not for any array elements, and the
pointer does not point to anything. De ning an array (x[10]) gives a pointer to a speci c place in memory
and allocates enough space to hold the array elements. To allocate space for an array declared as a pointer,
use *malloc() or *calloc(), which are declared in stdlib.h, and then free() to deallocate the space after
it is used.
34 A Crash Course in C x3.4
main()
{
int n;
float *a, *b;
free(a);
free(b);
}
main()
{
int i,n;
int A[100], *max;
max = maximum_ptr1(A,n);
printf("maximum value = %d\n", *max);
}
x3.4 A Crash Course in C 35
main()
{
int z[2][3];
printf("%d\n", x[1][2]); /** output: 12 **/
}
x[1][2]: 12
x[1][1]: 8
x[1][0]: 4
x[0][2]: 9
x[0][1]: 6
x[0][0]: 3
x[1]: s
x[0]: s
x: s
Figure 5: Box-and-pointer & memory diagrams of 2D arrays:
static int x[2][3]=ff3,6,9g,f4,8,12gg;
38 A Crash Course in C x3.5
#define MAX 5
#define LINEFEED printf("\n")
main()
{
int i, j, n = MAX;
int **A, **b, C[MAX][MAX];
A = imatrix(n, n);
for (i=0; i<MAX; i++)
for (j=0; j<MAX; j++)
{
A[i][j] = i*j;
C[i][j] = i + j;
}
Output: 0 1 2 3 4
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
0 0 0 0 0
0 1 2 3 4
0 2 4 6 8
0 3 6 9 12
0 4 8 12 16
100
100
3.6 Strings
Strings are simply character arrays, or more accurately, pointers to characters. A string literal is enclosed
within quotes, "...", and is an array with those characters and a `\0' at the end, so "hello" <==>
{'h','e','l','l','o','\0'}. The string can be de ned as
static char *p = "hello"
An example illustrating the use of pointers with the string copies one string into another:
main()
{
char *t = "hello", s[100];
void strcpy(char *, char *);
strcpy(s,t);
printf("%s\n", s); /** will print 'hello' **/
}
Since the precedence of () is higher than *, parentheses are needed around *f to get a pointer to a function.
float square(float x);
float cube(float x);
float arith(float x, float (*func)(float));
main()
{
float x, y, z;
printf("Enter x: "); scanf("%f", &x);
y = arith(x, square);
z = arith(x, cube);
printf("x = %f, x^2 = %f, x^3 = %f\n", x, y, z);
}
float square(float x)
{
return x*x;
}
float cube(float x)
{
return x*x*x;
}
3.9 Problems
11. Write a program to input two matrices, add and multiply them, and print the resulting matrices.
The matrices can be any size up to a maximum (#define MAX 5, for example). Use functions
input_matrix, print_matrix, add_matrix, multiply_matrix.
x4.0 A Crash Course in C 43
4 Structures
4.1 Syntax and Operations
A structure is a data type which puts a variety of pieces together into one object.
Syntax: struct structure-tag-opt
f
member-declarations
g structure-names-opt ;
main()
{
struct time later;
now.hour = 10;
now.minute = 30;
now.second = 4;
later = now;
printf("the later time is %d:%2d:%2d\n",
later.hour, later.minute, later.second);
}
This declares structure tag, struct time, which keeps the members, hour, minute, second, in one piece.
The variables now and later are structures of type struct time, declared the same way as integers. The
members of the structure can be any type: int, float, double, char, arrays, other structures, and
pointers to any of these. To access the members, there are two operators available (. and ->). To access the
speci ed member, use the . operator.
Valid structure operations:
assigning to or copying it as a unit
accessing its members
taking its address with &
passing it as an argument to functions, returning it by functions
{ With \Traditional C," structures can not be used as arguments or return types of functions.
Pointers to structures must be used to interact with functions. If compatibility is needed, pointers
to structures should continue to be used exclusively. Unfortunately, this may connect functions
together more than necessary.
initializing it with a list of constant member values, or by assignment for automatic structures.
{ Initialization is not allowed with \Traditional C," so a separate assignment statement should be
used.
44 A Crash Course in C x4.1
Pointers to structures are very useful, and often necessary when functions are used. For example,
struct time now, *t;
t = &now; /* identical to x=&y with numerical types */
(*t).hour = 6; /* gets the hour */
t->minutes = 30; /* gets the minutes */
The variable t is a pointer to a structure. Since the precedence of . is higher that that of *, the parentheses
are needed to get the actual structure from the pointer to it. Since this is used often, the -> operator was
made to do the same thing.
Structure members can be other structures.
struct time
{
int hour, minute, second;
} ;
struct date
{
int month, day, year;
} ;
struct dt
{
struct date d;
struct time t;
} ;
main()
{
struct dt start_class;
start_class.d.month = 1;
start_class.d.day = 5;
start_class.d.year = 93;
}
x4.2 A Crash Course in C 45
4.2 typedef
Using typedef also helps portability, especially with machine dependent data types and sizes. With typedef,
the change can be made in one place and is xed for the whole program. For example,
typedef int Length, Width, Height;
typedef struct time TIME;
TIME now, *t;
will specify the types Length, Width, Height and TIME, and now and t are de ned above. typedef is a
syntactic simpli cation to aid reading and modifying the program. It does not actually create new types.
main()
{
int i;
DATE birthdays[10], *bday;
bday = birthdays; /*** pointer <==> array name ***/
for (i=0; i<10; i++, bday++)
scanf("%d %d %d", &bday->month, &((*bday).day), &birthdays[i].year);
When bday is de ned as a pointer of type DATE (struct date), incrementing will be done properly to get
to successive structures in the array.
46 A Crash Course in C x4.4
typedef struct
{
int hour, minute, second;
} TIME;
typedef struct
{
int month, day, year;
} DATE;
main()
{
TIME now;
DATE today;
PRINT_TIME(now); LINEFEED;
PRINT_DATE(today); LINEFEED;
time_increment(&now, &today);
PRINT_TIME(now); LINEFEED;
PRINT_DATE(today); LINEFEED;
date_increment(&today);
PRINT_DATE(today); LINEFEED;
PRINT_DATE(date_increment2(today)); LINEFEED;
/** calls date_increment2 three times in macro, but today is unchanged **/
PRINT_DATE(today); LINEFEED;
}
x4.4 A Crash Course in C 47
DATE date_increment2(DATE d) /*** can also pass date one structure ***/
{
if (d.day != 31) /*** assume all months have 31 days ***/
++d.day;
else if (d.month != 12)
{
d.day = 1; d.month++;
}
else
{
d.month = 1; d.year++;
}
return d;
}
48 A Crash Course in C x4.5
Output: 12:30:15
1/ 7/93
12:30:16
1/ 7/93
1/ 8/93
1/ 9/93
1/ 8/93
struct node
{
int val;
struct node *r_branch;
struct node *l_branch;
} ;
typedef struct node * NodePtr;
main()
{
NodePtr tree, branch;
tree->r_branch->val = 3;
tree->l_branch->val = 40;
printf("%d, %d, %d\n", tree->val, tree->r_branch->val, tree->l_branch->val);
}
x4.6 A Crash Course in C 49
4.6 union
With union, di erent types of values can be stored in the same location at di erent times. Space is allocated
to accomodate the largest member data type. They are syntactically identical to structures,
Syntax: union union-tag-opt
f
member-declarations
g union-names-opt;
union-name.member
ptr-to-union->member
union union_ifd /** can store either an integer, float, or double value **/
{
int ival;
float fval;
double dval;
} ;
main()
{
union union_ifd u1;
u1.ival = 10;
printf("%d\n", u1.ival);
u1.fval = 10.34;
printf("%f\n", u1.fval);
u1.dval = 10.03454834;
printf("%.10lf\n", u1.dval);
}
It is the programmer's reponsibility to know which variable type is being stored at a given time. The code
u1.ival=10;
printf("%f\n", u1.fval);
4.7 enum
The type enum lets one specify a limited set of integer values a variable can have. For example, ags are
very common, and they can be either true or false.
Syntax: enum enum-tag-opt fenum-tagsg enum-variable-names-opt;
enum-name variable-name
The values of the enum variable are integers, but the program can be easier to read when using enum instead
of integers. Other common enumerated types are weekdays and months.
The enumerated values can be set by the compiler or set explicitly. If the compiler sets the values, it starts
at 0 and continues in order. If any value is set explicitly, then subsequent values are implicitly assigned.
enum flag_o_e {EVEN, ODD};
enum flag_o_e test1;
typedef enum flag_o_e FLAGS;
main()
{
int x;
FLAGS test2;
FLAGS if_even(int n)
{
if (n%2)
return ODD;
else
return EVEN;
}
x4.7 A Crash Course in C 51
typedef union
{
int i;
float f;
double d;
} Arith_U;
typedef enum {NONE, INT, FLOAT, DOUBLE} Arith_E;
typedef struct
{
Arith_E utype;
Arith_U u;
} Var_Storage;
main()
{
int i;
Var_Storage a[10];
int print_Var(Var_Storage x)
{
switch (x.utype)
{
case INT: printf("%d",x.u.i); break;
case FLOAT: printf("%f",x.u.f); break;
case DOUBLE: printf("%.8lf",x.u.d); break;
default: return (0); break;
}
return (1);
}
52 A Crash Course in C x4.8
main()
{
static COMPLEX z1 = {{1.0, 2.0}, {0.0, 0.0}};
static COMPLEX z[MAX] = { {{1.0, 1.0}, {0.0, 0.0}},
{{2.0, -1.0}, {0.0, 0.0}} };
rect_to_polar(&z1);
rect_to_polar(z);
rect_to_polar(z+1);
complex_print(z1, BOTH);
complex_print(*z, BOTH);
complex_print(*(z+1), BOTH);
z[2] = z1;
struct rect
{
double a, b;
};
struct polar
{
double r, theta;
};
struct complex
{
struct rect r;
struct polar p;
} ;
typedef struct complex COMPLEX;
4.9 Problems
12. Write the functions polar_to_rect, complex_multiply, and complex_input to be used with the
answer to question 11.
x5.0 A Crash Course in C 55
5 C Libraries
The standard C libraries include functions for
memory allocation
math functions
random variables
input/output operations
le manipulations
string manipulations
other functions (see K&R, Appendix B)
5.1 Memory Allocation
To have variable array sizes, dynamic memory allocation can be used.
#include <stdlib.h>
in ANSI C, size_t is the size of a character. The (sizeof) operator returns the size of an object in units
of size_t. In addition, the type of the pointer returned by malloc and calloc has to be cast as needed.
For example,
#include <stdlib.h>
main()
{
int i, n;
double *A, *a;
scanf("%d", &n);
A = (double *) malloc(n * sizeof (double));
main()
{
double x,y,z,theta;
z = sqrt(x);
z = sin(theta); /*** theta is in radians ***/
z = asin(x);
z = atan(x);
z = atan2(y, x); /*** atan(y/x) ***/
z = exp(x); /*** e^x ***/
z = log(x); /*** ln(x) [natural log] ***/
z = pow(x, y); /*** x^y ***/
}
#include <math.h>
main()
{
double x, y, theta;
scanf("%lf", &x);
printf("sqrt(%f) = %f\n", x, sqrt(x));
printf("sin(0.6) = %f\n", sin(0.6));
printf("atan(10) = %lf\n", atan(10.0));
printf("atan(10/20) = %lf\n", atan2(10.0, 20.0));
printf("exp(10) = %lf\n", exp(10.0));
printf("log(10) = %lf\n", log(10.0));
printf("log_10(10) = %lf\n", log10(10.0));
printf("10^1.3 = %lf\n", pow(10.0, 1.3));
}
Output: sqrt(10.000000) = 3.162278
sin(0.6) = 0.564642
atan(10) = 1.471128
atan(10/20) = 0.463648
exp(10) = 22026.465795
log(10) = 2.302585
log_10(10) = 1.000000
10^1.3 = 19.952623
When compiling, is must be speci ed that the math libraries are being used. For example, on Unix systems,
use
% cc -o <program> <program>.c -lm
x5.3 A Crash Course in C 57
The function rand() will return a value between 0 and RAND MAX, where RAND MAX is de ned in <stdlib.h>
and is at least 32767. The function srand() is used to seed the random number generator. Many systems
have better random number generators, and C can usually access them, although this would then not be
very portable. A good practice is to write a function or macro which returns a random number, and have
this call the system-speci c routines.
#include <stdlib.h>
main()
{
int i, n, seed;
double *x;
5.4 Input/Output
The conversions for printf() and scanf() are described in tables 3 and 4. In addition, I/O includes
character output, sscanf(), and le manipulation.
#include <stdio.h>
int i;
char c, s[], file_name[], access_mode[];
FILE *fp;
fp = fopen(file_name, access_mode);
fflush(fp); /*** flush the buffers ***/
fclose(fp);
c=getchar();
c=getc(fp);
gets(s);
fgets(s,i,fp); *** first i characters or till newline ***/
scanf(format, &arg1, ...) /*** formatted ***/
fscanf(fp, format, &arg1, ...);
sscanf(s, format, &arg1, ...);
x5.4 A Crash Course in C 59
main()
{
int i, n, *x;
char file_name[FILENAME_MAX];
FILE *fp;
5.5 Strings
A variety of string functions are available.
#include <string.h>
int i;
size_t n;
char *s, *s1, *s2, *to, *from;;
s = strcat(s1, s2);
s = strchr(s, char c);
i = strcmp(s1, s2); /*** s1=s2 ? 0 : (s1>s2 ? 1 : -1) ***/
s = strcpy(to, from); /*** returns *to ***/
n = strlen(s);
s = strstr(s1, s2); /*** is s2 in s1? ***/
s = strncat(s1, s2, int n); /*** only use first n characters ***/
i = strncmp(s1, s2, int n);
s = strncpy(to, from, int n);
#include <string.h>
#include <stdlib.h>
main()
{
char *s, *ct = "hello";
s = (char *) malloc(100 * sizeof(char));
strcpy(s, ct);
printf("%s\n", s);
if (strcmp(s, ct) == 0)
printf("strings equal\n");
else
printf("\"%s\" and \"%s\" differ\n", s, ct);
}
#include <stdio.h>
#include <stdlib.h>
main()
{
int i, j;
float x;
char *s1 = "10 20 15.5", *s2;
s2 = (char *) malloc(100 * sizeof(char));
A Make Program
The make function is used to simplify the compilation process. It has three main features:
target speci cations with dependencies,
command lines to be executed, and
assignment of strings to variables
The target is the le to be produced, either an executable le or an object le. The dependency list speci es
the les on which the target depends, so if any of the dependency les has been modi ed since the target
le was created, make will create a new target le. The command lines specify how the target is supposed
to be made. Although this is primarily using the cc command, other commands can also be executed.
Syntax: # comments
var = string value
$(var) # uses variable value
target : dependencies
TAB command-lines
The following commands run make:
% make -k
% make -k <target-name>
When calling make, the -k argument indicates that all speci ed les should be compiled, even if there is an
error compiling one le. Otherwise, make will stop when there is a compile error in any le.
# a makefile for any simple, one file program, with no dependencies
$(PROGS) : $(PROGS).c
$(CC) -o $(PROGS) $(PROGS).c
Output: % make program
/bin/cc -O program.c -o program
62 A Crash Course in C xA
% make -k
/bin/cc -O -c large_prog.c
/bin/cc -O -c large_sub.c
/bin/cc -o large large_prog.o large_sub.o
% make -k large_prog.o
/bin/cc -O -c large_prog.c
% make clean
rm large_prog.o large_sub.o
xB.0 A Crash Course in C 63
B C Style Guide
When writing C code, especially when other people will use or modify the code, it is useful to adhere to a
consistent set of coding guidelines. The following is not the only acceptable style, but rather an example of
a fairly conventional style guide.
statement1; /* OK */
statement2;
int func(int arg)
{ /* no indentation on the first set of braces */
/* around a procedure */
switch (...)
{
case xxx: /* case labels are indented clearly mark the */
statement; /* places where a 'break' statement is */
/*fall thru*/ /* expected but missing */
case yyy:
statement;
break;
default:
statement;
break; /* should have a break statement even at the end */
} /* of the default case */
if (...) /* BETTER */
statement;
else if (...)
statement;
else if (...)
statement;
xB.1 A Crash Course in C 65
switch (...) /* OK */
{
case xxx:
statement;
break;
case yyy:
statement;
break;
}
if (...) /* OK */
{
statement1;
statement2;
}
else
{
statement1;
statement2;
}
if (...) /* OK */
statement;
else if (...)
statement;
else if (...)
statement;
B.2 Layout
Avoid using the TAB character in a source le. Use spaces instead. This is because there is no
standard governing how TAB's are expanded. Thus, the same le may look very di erently from one
editor to another.
Avoid having any text past column 78.
C Answers to Problems
/** "A Crash Course in C", day 1, problem 2: print fahrenheit
** and celcius temperatures for 32-212 F in steps of 20 F **/
#define FREEZE 32
#define BOIL 212
#define STEP 20
main()
{
int f;
for (f=FREEZE; f<=BOIL; f+=STEP)
printf("F = %3d, C = %5.1f\n",f,(f-32.0)*5.0/9.0);
}
/** "A Crash Course in C," problem 3:
** input a number and print all its factors **/
#include <stdio.h>
main()
{
int i,n;
main()
{
int i,n, nmax, prime_flag=TRUE;
if (prime_flag)
printf("%6d is prime\n", n);
else
printf("%6d is not prime\n", n);
}
/** "A Crash Course in C," problem 5
** program to calculate x using the quadratic formula
**/
#include <math.h>
main()
{
float a, b, c, d, x1, x2;
printf("input a,b,c: ");
scanf("%f %f %f",&a, &b, &c);
d = b*b - 4.0*a*c;
if (d >= 0) /*** check if solution will be real or complex ***/
{
x1 = (-b+sqrt(d)) / (2.0*a);
/*** need parentheses for proper order ***/
x2 = (-b-sqrt(d)) / (2.0*a);
/*** use sqrt() from the math library ***/
printf("x = %f, %f\n",x1,x2);
}
else
{
x1 = -b/(2.0*a);
x2 = sqrt(-d)/(2.0*a);
printf("x = %f + %fi, %f - %fi\n", x1, x2, x1, x2);
}
}
70 A Crash Course in C xC
main()
{
int n, pow_ten;
printf("input an integer: "); scanf("%d",&n);
do {
pow_ten=1;
while (n / pow_ten)
pow_ten *= 10;
main()
{
char c;
int characters, lines;
main()
{
int n;
float x;
printf("input x, n: ");
scanf("%f %d", &x, &n);
printf("%f^%2d = %f\n", x, n, x_to_int_n(x,n));
}
main()
{
int n;
printf("input n: ");
scanf("%d", &n);
printf("factorial(%d) = %d\n", n, factorial(n));
printf("factorial(%d) = %d\n", n, factorial_r(n));
}
int factorial(int n)
{
int fact=1;
for ( ; n>1; n--)
fact *= n;
return fact;
}
int factorial_r(int n)
{
if (n>1)
return n*factorial_r(n-1);
else
return 1;
}
72 A Crash Course in C xC
#include <math.h>
main()
{
int n,i;
while (n=get_positive_int())
for (i=2; i<=n; i++)
if (is_prime(i))
printf("%d is prime\n", i);
}
int is_prime(int n)
{
int i, max;
max = (int) sqrt((double) n);
int get_positive_int(void)
{
int n;
do
{
printf("input a positive number, 0 to quit: ");
scanf("%d", &n);
} while (n < 0);
return n;
}
xC A Crash Course in C 73
#define MAX 5
main()
{
int n;
float A[MAX][MAX], B[MAX][MAX], C[MAX][MAX];
COMPLEX complex_input(void)
{
COMPLEX z;
int ans;
double x,y;
printf("input (0,a,b) or (1,r,theta): ");
scanf("%d %lf %lf",&ans, &x, &y);
if (ans == 1) {
z.p.r = x; z.p.theta = y;
polar_to_rect(&z);
}
else if (ans == 0) {
z.r.a = x; z.r.b = y;
rect_to_polar(&z);
}
else {
printf("invalid coordinate system\n");
z.r.a = 0.0; z.r.b = 0.0; z.p.r = 0.0; z.p.theta = 0.0;
}
return z;
}