(*^
::[ Information =
"This is a Mathematica Notebook file. It contains ASCII text, and can be
transferred by email, ftp, or other text-file transfer utility. It should
be read or edited using a copy of Mathematica or MathReader. If you
received this as email, use your mail application or copy/paste to save
everything from the line containing (*^ down to the line containing ^*)
into a plain text file. On some systems you may have to give the file a
name ending with ".ma" to allow Mathematica to recognize it as a Notebook.
The line below identifies what version of Mathematica created this file,
but it can be opened using any other version as well.";
FrontEndVersion = "Macintosh Mathematica Notebook Front End Version 2.2";
MacintoshStandardFontEncoding;
fontset = title, inactive, noPageBreakBelow, nohscroll, preserveAspect,
groupLikeTitle, center, M7, bold, e8, 24, "Times";
fontset = subtitle, inactive, noPageBreakBelow, nohscroll, preserveAspect,
groupLikeTitle, center, M7, bold, e6, 18, "Times";
fontset = subsubtitle, inactive, noPageBreakBelow, nohscroll,
preserveAspect, groupLikeTitle, center, M7, italic, e6, 14, "Times";
fontset = section, inactive, noPageBreakBelow, nohscroll, preserveAspect,
groupLikeSection, grayBox, M22, bold, a20, 18, "Times";
fontset = subsection, inactive, noPageBreakBelow, nohscroll,
preserveAspect, groupLikeSection, blackBox, M19, bold, a15, 14, "Times";
fontset = subsubsection, inactive, noPageBreakBelow, nohscroll,
preserveAspect, groupLikeSection, whiteBox, M18, bold, a12, 12, "Times";
fontset = text, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7,
12, "Times";
fontset = smalltext, inactive, nohscroll, noKeepOnOnePage, preserveAspect,
M7, 10, "Times";
fontset = input, noPageBreakInGroup, preserveAspect, groupLikeInput, M42,
N23, bold, B65535, L-5, 12, "Courier";
fontset = output, output, inactive, noPageBreakInGroup, preserveAspect,
groupLikeOutput, M42, N23, L-5, 12, "Courier";
fontset = message, inactive, noPageBreakInGroup, preserveAspect,
groupLikeOutput, M42, N23, R65535, L-5, 12, "Courier";
fontset = print, inactive, noPageBreakInGroup, preserveAspect,
groupLikeOutput, M42, N23, L-5, 12, "Courier";
fontset = info, inactive, noPageBreakInGroup, preserveAspect,
groupLikeOutput, M42, N23, B65535, L-5, 12, "Courier";
fontset = postscript, PostScript, formatAsPostScript, output, inactive,
noPageBreakInGroup, preserveAspect, groupLikeGraphics, M7, l34, w282, h287,
12, "Courier";
fontset = name, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7,
italic, 10, "Geneva";
fontset = header, inactive, noKeepOnOnePage, preserveAspect, M7, 12, "Times";
fontset = leftheader, inactive, L2, 12, "Times";
fontset = footer, inactive, noKeepOnOnePage, preserveAspect, center, M7,
12, "Times";
fontset = leftfooter, inactive, L2, 12, "Times";
fontset = help, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7,
10, "Times";
fontset = clipboard, inactive, nohscroll, noKeepOnOnePage, preserveAspect,
M7, 12, "Times";
fontset = completions, inactive, nohscroll, noKeepOnOnePage,
preserveAspect, M7, 12, "Times";
fontset = special1, inactive, nohscroll, noKeepOnOnePage, preserveAspect,
M7, 12, "Times";
fontset = special2, inactive, nohscroll, noKeepOnOnePage, preserveAspect,
M7, 12, "Times";
fontset = special3, inactive, nohscroll, noKeepOnOnePage, preserveAspect,
M7, 12, "Times";
fontset = special4, inactive, nohscroll, noKeepOnOnePage, preserveAspect,
M7, 12, "Times";
fontset = special5, inactive, nohscroll, noKeepOnOnePage, preserveAspect,
M7, 12, "Times";
currentKernel;
]
:[font = smalltext; inactive; preserveAspect]
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.
:[font = title; inactive; preserveAspect]
26. The C Language
:[font = smalltext; inactive; preserveAspect]
Last revision: December 3 1996
:[font = text; inactive; preserveAspect]
This section introduces a subset of the C language and explores its
similarities and differences with Mathematica.
:[font = section; inactive; Cclosed; preserveAspect; startGroup]
A Quick Tour of the C Language
:[font = text; inactive; preserveAspect]
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.
:[font = subsection; inactive; Cclosed; preserveAspect; startGroup]
Data Types, Declarations, and Definitions
:[font = text; inactive; preserveAspect]
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.
;[s]
7:0,0;7,1;18,0;193,1;198,0;675,1;679,0;683,-1;
2:4,13,9,Times,0,12,0,0,0;3,13,9,Times,2,12,0,0,0;
:[font = text; inactive; preserveAspect]
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.
:[font = text; inactive; preserveAspect]
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.
;[s]
3:0,0;17,1;21,0;757,-1;
2:2,13,9,Times,0,12,0,0,0;1,13,9,Times,2,12,0,0,0;
:[font = subsubsection; inactive; Cclosed; preserveAspect; startGroup]
Declaring Variables and Functions; Arrays
:[font = text; inactive; preserveAspect]
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:
:[font = print; inactive; preserveAspect]
int a,b,c;
float sin(),myFunc(float b);
char str[30];
:[font = text; inactive; preserveAspect]
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".
:[font = text; inactive; preserveAspect]
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.
:[font = text; inactive; preserveAspect; endGroup]
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[ ]".
:[font = subsubsection; inactive; Cclosed; preserveAspect; startGroup]
Defining Variables and Functions; Return Statements; Local, Global
:[font = text; inactive; preserveAspect]
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.
;[s]
3:0,0;752,1;755,0;830,-1;
2:2,13,9,Times,0,12,0,0,0;1,13,9,Times,2,12,0,0,0;
:[font = text; inactive; preserveAspect]
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.)
:[font = print; inactive; preserveAspect]
i = 4;
int myFunc(int a, int b) {
int c;
c = 2*a + b;
return c;
}
:[font = text; inactive; preserveAspect]
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.
;[s]
5:0,0;102,1;116,0;172,1;189,0;267,-1;
2:3,13,9,Times,0,12,0,0,0;2,13,9,Times,2,12,0,0,0;
:[font = text; inactive; preserveAspect]
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
:[font = print; inactive; preserveAspect]
int myFunc2(int a);
int myFunc2(int a) {
return 1;
return a;
}
:[font = text; inactive; preserveAspect; endGroup; endGroup]
a "1" will always be returned, and the statement "return a" would never be
executed.
:[font = subsection; inactive; Cclosed; preserveAspect; startGroup]
Control Structures
:[font = text; inactive; preserveAspect]
C's control structures are also very similar to Mathematica's. We'll
sample the most important ones here.
:[font = subsubsection; inactive; Cclosed; preserveAspect; startGroup]
If
:[font = text; inactive; preserveAspect]
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,
:[font = print; inactive; preserveAspect]
if (a==1) b = 2;
b = 3;
if (a==2) { b = 3; c = 4; }
:[font = text; inactive; preserveAspect]
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.
:[font = text; inactive; preserveAspect]
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!):
:[font = print; inactive; preserveAspect; endGroup]
int myFac(int i);
int myFac(int i) {
if (i==1) return 1;
else return i*myFac(i-1);
}
:[font = subsubsection; inactive; Cclosed; preserveAspect; startGroup]
Switch, Break
:[font = text; inactive; preserveAspect]
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.
:[font = print; inactive; preserveAspect]
void commentOnGrade(char c);
void commentOnGrade(char c){
switch (c) {
case 'A' : { printf("Excellent!\n"); break;}
case 'B' : { printf("Good!\n"); break;}
case 'C' : { printf("Fair.\n"); break;}
case 'D' : { printf("Disappointing\n"); break;}
case 'F' : { printf("!\n"); break;}
}
}
:[font = text; inactive; preserveAspect; endGroup]
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.
:[font = subsubsection; inactive; Cclosed; preserveAspect; startGroup]
For
:[font = text; inactive; preserveAspect]
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.
:[font = print; inactive; preserveAspect]
int i,j;
j = 0;
for (i=1; i<10; i++)
j = j + i;
:[font = text; inactive; preserveAspect; endGroup]
As might be expected, this section of code adds up the numbers from 1 to 9.
:[font = subsubsection; inactive; Cclosed; preserveAspect; startGroup]
While
:[font = text; inactive; preserveAspect]
C's While statement is also very similar to Mathematica's, having syntax
"while (boolean-expression) statement;". An example is then
:[font = print; inactive; preserveAspect; endGroup]
int countDigits(int a);
int countDigits(int a) {
int b,c;
b = 1;
c = 10;
while (c",
"<=", ">=", "++", "--", "+=", "-=", "*=", "/=", "||", "&&", """ (quotation
mark to mark beginning or ending of a string), and parentheses to show
precedence in an expression.
:[font = text; inactive; preserveAspect; endGroup; endGroup]
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 " or
"#include "filename" " statements.
:[font = section; inactive; Cclosed; preserveAspect; startGroup]
Reading Examples
:[font = text; inactive; preserveAspect]
In this section we will present entire C programs and comment on their
functionality.
:[font = subsection; inactive; Cclosed; preserveAspect; startGroup]
1: primeTester
:[font = text; inactive; preserveAspect]
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.
:[font = print; inactive; preserveAspect]
void main() {
int a,b,c,d;
printf("Please enter an integer.\n");
scanf("%d",&a);
b = sqrt(a);
d = 0;
for (c=2; c<=b; c++)
if (((a/c)*c)==a) d = 1; /* evenly divides! */
if (d==1)
printf("Not prime!\n");
else
printf("Prime!\n");
}
:[font = text; inactive; preserveAspect; endGroup]
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.
:[font = subsection; inactive; Cclosed; preserveAspect; startGroup]
2: factorialComputer
:[font = text; inactive; preserveAspect]
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.
:[font = print; inactive; preserveAspect]
#include
int fac(int a);
int fac(int a) {
if (a<=1) return 1;
else return a*fac(a-1);
}
void main() {
FILE *fp;
int a;
fp = fopen("myFile","w");
for (a=1; a<=7; a++)
fprintf(fp,"%d\n",fac(a));
fclose(fp);
}
:[font = text; inactive; preserveAspect; endGroup]
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.
:[font = subsection; inactive; Cclosed; preserveAspect; startGroup]
3: grades
:[font = text; inactive; preserveAspect]
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.
:[font = print; inactive; preserveAspect]
#include
float grades[100]; /* global variable to hold up to 100
grades */
int numGrades; /* global variable to indicate how many
grades actually stored */
void addGrade(float g),deleteGrade(float g);
void listGrades(),gradeInit(),printMenu();
float findAverage();
void gradeInit() {
int i;
for (i=0; i<100; i++)
grades[i] = 0.0; /* unnecessary but nice to
clear array */
numGrades = 0;
}
void addGrade(float g){
if (numGrades>=100)
printf("Full of grades! No more allowed!\n");
else {
grades[numGrades] = g;
numGrades++;
}
}
void deleteGrade(float g){
int a,b,c;
b = -1; /* -1 is a flag for 'not found' */
for (a=0; a<100; a++)
if (b==-1) /* if not found, try */
if (grades[a]==g) b=a; /* b has the index of g */
if (b==-1)
printf("Grade %f not found!\n",g);
else {
for (c=b; c
float grades[100]; /* global variable to hold up to 100
grades */
int numGrades; /* global variable to indicate how many
grades actually stored */
void addGrade(float g),deleteGrade(float g);
void listGrades(),gradeInit(),printMenu();
float findAverage();
:[font = text; inactive; preserveAspect]
The function "gradeInit()" sets "numGrades" to 0 and zeros out the array
"grades".
:[font = print; inactive; preserveAspect]
void gradeInit() {
int i;
for (i=0; i<100; i++)
grades[i] = 0.0; /* unnecessary but nice to
clear array */
numGrades = 0;
}
:[font = text; inactive; preserveAspect]
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.
:[font = print; inactive; preserveAspect]
void addGrade(float g){
if (numGrades>=100)
printf("Full of grades! No more allowed!\n");
else {
grades[numGrades] = g;
numGrades++;
}
}
:[font = text; inactive; preserveAspect]
"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'.
:[font = print; inactive; preserveAspect]
void deleteGrade(float g){
int a,b,c;
b = -1; /* -1 is a flag for 'not found' */
for (a=0; a<100; a++)
if (b==-1) /* if not found, try */
if (grades[a]==g) b=a; /* b has the index of g */
if (b==-1)
printf("Grade %f not found!\n",g);
else {
for (c=b; c