Copyright (C) 1997 Rich Neidinger, John Swallow, and Todd Will.  Free for
distribution to college and university instructors for personal,
non-commercial use.  If these notebooks are used in a course, the authors
request $20 per student.

26. The C Language

Last revision:  December 3 1996

This section introduces a subset of the C language and explores its
similarities and differences with Mathematica.

A Quick Tour of the C Language

The C language is a computer programming language widely used by
professional programmers, and for that reason we believe that students
should have some exposure to the language.  While structuring an
introductory computing class around C is possible, it poses pedagogical
burdens which we did not wish to assume, one of the most important being
that it initially takes students longer to write programs in C than in
Mathematica, and another being that Mathematica contains many more built-in
functions which C, in its original state, does not support.  However, C
shares so many similarities to certain aspects of Mathematica that we can
introduce C by highlighting these similarities.  This section is by no
means intended as a tutorial which will result in the reader's immediately
being able to write perfect C code; instead, it is meant to serve as a
reader's guide to literature in C.  The student who wishes to program
professionally should take at least a second course in programming
structured around C or some other common language.

Data Types, Declarations, and Definitions

C is a functional language, just like Mathematica, which means that it is
primarily structured around variables and functions which act upon them.
Unlike Mathematica, however, C requires that every variable and function
have a data type, and these types cannot change over the course of the
program.  For instance, if "i" is an integer, it must always denote an
integer, and if an approximate number is assigned to it, "i" will hold only
the integer portion.  What we mean when we say "the data type of a
function" is really the data type of the return value, and if a function
does not return a value, its data type (or "return type", as we will use
later) must defined as void.

What data types does C support, other than "void" for functions with no
return value?  Here is a partial list:  "char" (values must be single
characters); "int" (values must be machine-precision integers, typically
ranging in value from -32767 to +32767); "long" (values are integers which
take up several bytes, so typically ranging from -2147483647 to
2147483647); "float" (values are machine-size approximate numbers,
typically ranging from -10^37 to 10^37, with up to 6 significant digits);
"double" (values are approximate numbers allowed more bytes than floats, so
with a wider range of values and with more significant digits); and arrays
of any of these types.

Note that C does not support lists or strings as separate data types.
Instead, C programmers must keep arrays of integers or characters and must
worry about the lengths of these arrays themselves.  While Mathematica
allows lists of arbitrary length and numbers of arbitrary size, C instead
restricts the values to machine-precision numbers.  In C, to use huge
integers, it is necessary to store them in pieces and manipulate their
separate parts (digits, say) separately.  C is thus a more primitive
language than Mathematica.   However, one can write packages so that C can
use arbitrary-length lists and numbers, if one desires, and C's chief
advantages over Mathematica include its versatility and its compiled,
rather than interpreted, implementation.

Declaring Variables and Functions; Arrays

Again, every variable and function in C must have its type declared.  The
syntax for declaring variables and functions is to write, on a separate
line, the data type name, followed by a space, followed by the names of the
variables and functions which have that type.  Function names must be
suffixed with "()", which indicates that the name refers to a function, not
a variable, and if the function takes any arguments, they must be included
between the parentheses, separated by commas, each preceded by its data
type.  In order to declare a variable to be an array of elements of a
certain type, the variable name must be suffixed with "[number]", where
"number" is an integer, in which case an array of size "number" will be
declared.  Finally, all C lines must end with a semicolon.  Here are some
examples:

In this example we have three integer variables defined, "a", "b", and "c";
two functions which return float values, "sin" and "myFunc", the first of
which takes no arguments and the second of which takes one argument of type
float; and finally an array of 30 characters, "str".

Arrays in C deserve special mention, because in C the first array element
is referenced with "[0]", and the last element (in an array with "n"
elements) "[n-1]".  Hence, the values in a three-element array "a" are
"a[0]", "a[1]", and "a[2]".  Also, arrays with more than one dimension are
declared simply by suffixing more "[number]" components:  "int a[10][10]"
declares a 10 by 10 array of integers.

Several syntactical differences with Mathematica are immediately apparent.
First, Mathematica suffixes functions with square brackets which enclose
the arguments, if any; C instead uses parentheses.  Also, Mathematica uses
double brackets to denote an array, but C uses single square brackets.
Finally, Mathematica does not permit the declaration of an array without
constructing it, as with a "Table[ ]".

Defining Variables and Functions; Return Statements; Local, Global

In C, just as in Mathematica, variables are defined or modified with
assignment statements, as in "i=3;".  Functions are defined similarly to
Mathematica, as follows.  The return type of the function is specified
first, followed by the name of the function, followed by a parenthesized,
comma-separated sequence of argument names, each preceded by the
appropriate data type, followed by a curly-brace-enclosed set of statements
inside the function, called the "function block".  The statements inside a
C "function block" are similar to Mathematica statements, as we will see,
later; however, we point out now that the return value must be contained in
a statement "return x", where "x" is the value the function wishes to
return---the return value is not simply the value of the last statement
executed, as it is in Mathematica.

Here is an example of definitions of a variable "i" and a function
"myFunc", which multiplies its first argument, an integer, by 2 and adds
the second argument, returning the result.  (The variable definition here
has nothing to do with the function definition but is provided only as an
example.)

Notice that a separate variable was defined inside the function block.
This variable, "c", will be a local variable in C because it is declared
inside the function block.  Global variables, on the other hand, are those
variables declared outside any function block.

One difference with Mathematica is that, in C, when a return statement is
encountered, the function immediately stops and returns the value; no
succeeding statements will be executed.  For instance, in the function

a "1" will always be returned, and the statement "return a" would never be
executed.

Control Structures

C's control structures are also very similar to Mathematica's.  We'll
sample the most important ones here.

If

C's "If" statement has the following syntax:  "if (boolean-expression)
statement;", and the statement is executed only if the boolean condition is
true.  When several statements are to be executed, they should be listed,
separated by semicolons as usual, with the entire group surrounded by curly
braces to form a block.  For example,

causes "b=2" to be executed only if "a" is 1, after which "b" is set equal
to 3, and then, if "a" is 2, then "b" is set to 3 and "c" to 4.

If we wish to have other statements executed if the boolean value is false,
the syntax is "if (boolean-expression) statement; else statement;", where
again a statement can be replaced by a curly-brace-enclosed block.  Hence
we could have the following recursive function to compute factorials
(notice that the function is declared before it it defined!):

Switch, Break

C's switch statement has the following standard syntax:  "switch (variable)
{ case value: statement; case value: statement; ....}", where as many "case
value: statement;" structures many be repeated as necessary.  The value of
the variable will be checked, the program will jump to the statement
following "case value" with the same value, and will then continue down
through the rest of the statements until a "break;" statement is
encountered, in which case the switch statement will terminate.  As usual,
one may substitute a block of statements enclosed by curly braces for a
"statement" in the syntax expression.  Here's one example.

Note that without the "break" statements, each statement after one jumped
to by the case would have been executed, so that "commentOnGrade('A')"
would have caused all five print statements to be executed.  Notice also
that single characters are surrounded by single quotes---in essence, they
are separate from strings---and the "printf" command behaves much like
Mathematica's "Print[ ]" command.  Finally, notice that there is no
"return" statement, since the function has a "void" return value.

For

C's For statement is very similar to Mathematica's; the only difference is
that the first three statements in Mathematica's For command are separated
by commas and enclosed by parentheses, and the fourth statement simply
follows the parentheses, as in "for (initialization-statement;
boolean-expression; increment-statement) execution-statement;".  Here is an
example.

As might be expected, this section of code adds up the numbers from 1 to 9.

While

C's While statement is also very similar to Mathematica's, having syntax
"while (boolean-expression) statement;".  An example is then

Do...While

C's Do statement, however, differs from Mathematica's, because C's Do
statement is simply a While statement with the boolean test at the end
instead of the beginning.  In other words, the execution is the same as a
While loop except that the loop is executed once before the boolean test is
checked.  C's Do statement, therefore, does not permit the use of
iterators.  Here is an example which counts the number of zeros in an array
which is a global variable.

main()

When one runs a C program, the first function executed is always the
"main()" function.  Hence, every C program must have a "main" function
defined somewhere, which marks the entry point into the program.  "main()"
typically has void return type.

File Access Basics; Reading, Writing; Standard Input, Output

C uses streams for file management, just like Mathematica.  For reasons we
won't go into here, a stream variable must be preceded by an asterisk in
its declaration:

Apart from that peculiar detail, however, the open, close, and
string-printing functions are quite similar:

In order to read or write variables, however, C must be told what sort of
format the values will be in.  For reading from a file, "fscanf" (which
stands for "file-scan-formatted") must first be told the stream variable
("fp" above), followed by a string with symbols indicating what is to be
read in---"%d" means an integer, "%f" an approximate number, "%c" a
character, and so forth---followed by the variable names to store the
values in, each preceded by an ampersand ("&").  For writing to a file,
"fprintf" (which stands for "file-print-formatted") must be told the stream
variable ("fp") above, followed by a string with symbols indicating what it
to be printed---characters interspersed with "%d" for integral output, "%f"
for approximate numeric output, "%c" for single-character output, and so
on---followed by the variable names whose values need to be written out.
These strings are the "formatting" of the input and the output referred to
in the names of the functions.  Here are a couple of examples:

The code above prints a single line with the numeric value of "i" after the
string "The answer is ".

Here, three characters are read from the file and placed in variables "c1",
"c2", and "c3", respectively.

Finally, two files are always associated to a C program, "stdin" and
"stdout".  The former, "stdin", is the "standard input" file, which
typically means input from the keyboard.  The latter, "stdout", is the
"standard output" file, typically meaning the console screen.  These two
stream names "stdin" and "stdout" can be used with "fscanf" and "fprintf",
or they can be omitted if one uses the functions "printf" and
"scanf"---"printf" writes to the "standard output" file, while "scanf"
reads from the "standard input" file.

Comments, Operators, Libraries

In C comments are enclosed not by "(*" and "*)" as in Mathematica, but by
"/*" and "*/".

Many of the operators of C and Mathematica are identical.  Here are the
most important:  "!" (not), "+", "-", "*", "/", "=", "==", "!=", "<", ">",
"<=", ">=", "++", "--", "+=", "-=", "*=", "/=", "||", "&&", """ (quotation
mark to mark beginning or ending of a string), and parentheses to show
precedence in an expression.

Finally, just as Mathematica has separate packages which can be loaded to
permit greater functionality, C programs can include functions from other
libraries which add to the functions the program can use.  These are
usually indicated at the top of the program with "#include <filename>" or
"#include "filename" " statements.

Reading Examples

In this section we will present entire C programs and comment on their
functionality.

1: primeTester

C does not have a prime-tester function like Mathematica's "PrimeQ".  Here
we present a program which would allow a user to enter a machine-size
integer and have its primality determined.  We use the fact that if an
integer has no divisor smaller than its square root, it must be prime.
Note that when one divides two integers in C, the result is the integer
quotient---the remainder is thrown away.

Here no "#include" statements were necessary, since we did not use any
non-standard C functions. The program writes out the query line, reads in a
number from the keyboard, and sets "b" to be its square root (rounded to
the next lowest integer, since the result is placed in "b", an integer).
Then, one at a time, it decides if any of the numbers between 2 and "b"
evenly divide "a", by taking the integer quotient, multiplying back by "c",
and seeing if the result equals "a", which would only occur if "c" evenly
divided "a".  If one does evenly divide, then a flag "d" is set to "1",
indicating that the number is not prime.  A message indicating the
primality is finally written out to the screen.

2: factorialComputer

Here we present a program which writes out "n" factorial, as "n" runs from
1 to 7, to a file "myFile", one number to a line.

Here we needed to include the standard input/output function library,
"stdio.h".  Note that we could not have increased the number of factorials
to 8 without changing the data types of the factorial function and its
arguments, since 8! cannot be stored in a machine-size integer.

3: grades

We end with a version of the "Grades`" package defined in a previous
section, converted to be a C program.  In order to implement the range of
choices permitted by the package, we introduce a menu function which writes
a list of options to the screen, one of which the user must indicate by
entering appropriate data from the keyboard.

Let's look through this C program piece by piece.  The matter at the top
reads in the appropriate input/output libraries of commands and declares
several functions and data.

The function "gradeInit()" sets "numGrades" to 0 and zeros out the array
"grades".

The function "addGrade()" takes an argument, and, assuming there is room in
the array "grades" to add an additional grade to it, does so, incrementing
"numGrades" in the process.

"deleteGrade()" must do more work.  First it looks through the array,
attempting to find a match with the given argument.  If it does not find
one, it complains to the operator; otherwise, it eliminates the grade by
copying everything in the array left one position, beginning with the grade
to be deleted.  Hence, if the original array contained '1,2,3,4,5', and '3'
was deleted, then the '4' would be copies to the place of '3', the '5' to
the place of '4', resulting in '1,2,4,5'.

"listGrades()" and "findAverage()" are fairly self-explanatory.
"findAverage" must check "numGrades" to insure that it does not divide by
zero, and it returns the average as its return value.

Finally, we have below the portion of the program which implements the
outer loop.  "main()" declares some variables, initializes the grades, and
has an outer "do...while" loop based on the user's command, a character in
the variable "c".  The first "do" loop inside loops until a valid character
is entered from the keyboard.  Note that in C the input stream contains the
return button character, which we must take out of the stream in order to
process correctly the remaining characters.  (Otherwise the return
character would be read in as the next command, an illegal one, and we
would then get the menu printed again.)  If the command requires a grade,
one is read in, and finally a switch statement controls the path of
execution.