Programming for Engineers
class="bi x0 y0 w1 h1"
Aaron R. Bradley
Programming
for Engineers
A Foundational Approach to Learning
C and Matlab
Aaron R. Bradley
Dept. of Electrical, Computer,
and Energy Engineering
University of Colorado
Boulder, CO 80309
USA
ISBN 978-3-642-23302-9 e-ISBN 978-3-642-23303-6
DOI 10.1007/978-3-642-23303-6
Springer Heidelberg Dordrecht London New York
Library of Congress Control Number: 2011941363
ACM Classification (1998): B.3, B.4, B.5, D.3, E.1, E.2, G.1, G.2, I.1
© Springer-Verlag Berlin Heidelberg 2011
This work is subject to copyright. All rights are reserved, whether the whole or part of the material is
concerned, specifically the rights of translation, reprinting, reuse of illustrations, recitation, broadcasting,
reproduction on microfilm or in any other way, and storage in data banks. Duplication of this publication
or parts thereof is permitted only under the provisions of the German Copyright Law of September 9,
1965, in its current version, and permission for use must always be obtained from Springer. Violations are
liable to prosecution under the German Copyright Law.
The use of general descriptive names, registered names, trademarks, etc. in this publication does not imply,
even in the absence of a specific statement, that such names are exempt from the relevant protective laws
and regulations and therefore free for general use.
hours. I have provided many exercises with solutions and explanations to
facilitate an active approach to learning. Therefore, be active.
Finally, address confusions immediately. If you procrastinate on clear-
ing up a point of confusion, it is likely to bite you again and again.
This book introduces a subject that is wide in scope. It focuses on con-
cepts and techniques rather than listing how to use libraries and functions.
Therefore, use Internet search engines to locate references on C libraries, par-
ticularly starting with Chapter 5; the man Unix utility to read about Unix
programs; Internet search engines to learn how to use editors like emacs and
VII
VIII Preface
vim;thehelp command in gdb;andthehelp and doc commands in Matlab.
Engineers must learn new powerful tools throughout their careers, so use this
opportunity to learn how to learn.
To learn to program is to be initiated into an entirely new way of think-
ing about engineering, mathematics, and the world in general. Computation
is integral to all modern engineering disciplines. The better you are at pro-
gramming, the better you will be in your chosen field. Make the most of this
opportunity. I promise that you will not regret the effort.
To the Instructor
This book departs radically from the typical presentation of programming:
it presents pointers in the very first chapter—and thus in the first or second
lecture of a course—as part of the development of a computational model.
This model facilitates an ab initio presentation of otherwise mysterious sub-
jects: function calls, call-by-reference, arrays, the stack, and the heap. Further-
more, it allows students to practice the essential skill of memory manipulation
throughout the entire course rather than just at the end. Consequently, it is
natural to go further in this text than is typical for a one-semester course:
abstract data types and linked lists are covered in depth in Chapters 7 and
8. The computational model will also serve students in their adventures with
flated Self-Assessments, J. of Personality and Social Psychology, v. 77,
pp. 1121-1134, 1999.
The second addresses cause-and-effect in cheating and performance:
David J. Palazzo, Young-Jin Lee, Rasil Warnakulasooriya, and
David E. Pritchard, Patterns, Correlates, and Reduction of Home-
work Copying, Phys. Rev. ST Phys. Educ. Res., v. 6, n. 1, 2010.
My experience in the classroom having confirmed these studies, I admin-
ister hour-long quizzes every two to three weeks that test the material that
students ought to have learned from the text, from lectures and labs, and from
homework. Additionally, I give little weight to homework in the final grade.
Therefore, students have essentially no incentive to cheat (themselves out of
learning opportunities) on homework—and all the possible incentive to use
homework to learn the material. Students have responded well to this struc-
ture. They appreciate the frequent feedback, and a significant subset attends
office hours regularly. Fewer students fall behind. Consequently, I am able to
fit all of the material in this book into one semester. In order to motivate
students who start poorly, I announce mid-semester that the final exam grade
can trump all quiz grades. Many students seem to learn what they need to
know from the quizzes, and so many are better prepared for the final exam.
As side benefits, since enacting this teaching strategy in this and another
course, I have never had to deal with an honor code violation—which is rare for
introductory programming courses—and have not received a single complaint
about a final grade, which is rarer still.
Acknowledgments
I developed the material for this book in preparation for and while teaching
a first-year course on programming for engineering students at the University
of Colorado, Boulder, partly with the support of an NSF CAREER award.
1
The course was offered in the Department of Electrical, Computer & Energy
Engineering (ECEE) and also had students from the Department of Aerospace
June 2011
Contents
1Memory:TheStack 1
1.1 PlayingwithMemory 2
1.1.1 A First Foray into Programming . 2
1.1.2 Introduction to Pointers . . . . . 4
1.1.3 Pointers to Pointers . 6
1.1.4 How to Crash Your Program . 11
1.2 FunctionsandtheStack 13
1.2.1 Introduction to Functions . . . 13
1.2.2 A Protocol for Calling Functions . 14
1.2.3 Call-by-Value and Call-by-Reference . . 22
1.2.4 Building Fences . 25
1.3 Bits,Bytes,andWords 29
2 Control 31
2.1 Conditionals 31
2.2 Recursion 36
2.3 Loops 42
3 Arrays and Strings 47
3.1 Arrays 47
3.1.1 Introduction to Arrays . . . . . . 47
3.1.2 Looping over Arrays . 50
3.1.3 Arrays as Parameters 52
3.1.4 Further Adventures with Arrays . . 54
3.2 Strings 61
3.2.1 Strings: Arrays of chars 62
3.2.2 Programming with Strings . . . 63
3.2.3 Further Adventures with Strings . 67
XI
XII Contents
8.1 IntroductiontoLinkedLists 161
8.2 FIFOQueue:ASecondImplementation 165
8.3 PriorityQueue:ASpecification 170
8.4 PriorityQueue:AnImplementation 173
8.5 FurtherAdventures withLinkedLists 178
9 Introduction to Matlab 181
9.1 The Command-Line Interface . . . . . . 182
9.2 ProgramminginMatlab 188
9.2.1 Generating a Pure Tone . . . . . 189
9.2.2 Making Music . . 194
Contents XIII
10 Exploring ODEs with Matlab 199
10.1 Developing an ODE Describing Orbits . . 199
10.1.1 Developing the ODE . 199
10.1.2 Converting into a System of First-Order ODEs 201
10.2 Numerical Integration . . 202
10.3 Comparing Numerical Methods . . . . 205
11 Exploring Time and Frequency Domains with Matlab 215
11.1 Time and Frequency Domains . . . . . . 215
11.2 The Discrete Fourier Transform . . . . 219
11.3 De-hissing a Recording . 228
Index 231
class="bi x0 y0 w1 h1"
1
Memory: The Stack
Computation is mathematics projected onto reality: at one level an interplay
of time, space, and procedure; at another, energy. The study of computation
has yielded deep insights into the universe of the mind—revealing startling
consequences of the mathematics that humans have developed since the be-
ginning of recorded history, like the undecidability of certain questions and
Consider the following code snippet:
1 {
2 int a, b, c, d;
3 a=1;
4 b=1;
5 c=a+b;
6 d=c+b;
7 }
Line 2 declares four variables of type int, short for “integer.” This dec-
laration tells the computer to set aside four cells of memory that we shall
call a, b, c,andd, respectively. Each memory cell can be read from
and written to, and each should be interpreted as holding integer values
({ ,−2, −1, 0, 1, 2, }). A memory cell must have a location, which we ref-
erence via its address. Finally, there is no reason why four variables declared
together in the program text should not be neighbors in memory and many
reasons why they should be. We visualize the memory using a stack diagram:
int d ⊗ 1012
int c ⊗ 1008
int b ⊗ 1004
int a ⊗ 1000
As a first approximation, a program’s memory can be viewed as a contiguous
array of memory cells. We visualize memory vertically. In this case, the bottom
cell, which we refer to as a in our program, is at memory address 1000. Just
as we have declared in the program text, the memory for b is next to a (and
at a higher address). Next comes c,thend. We will discuss why the addresses
are the particular values that they are later. Each cell is annotated with its
associated variable and the type of that variable. The type indicates how to
interpret the data.
The symbol ⊗ indicates that a memory cell currently holds garbage—that
is, a meaningless value left over from the last time this particular memory was
Exercise 1.1. Consider this code snippet:
1 {
2 int a, b, c;
3 a=1;
4 a=a+a;
5 a=a+a;
6 b=a;
7 c=a+b;
8 }
Fill in the data corresponding to the final memory configuration:
int c 1008
int b 1004
int a 1000
Solution. In this code snippet, a is assigned a value multiple times: first 1
at line 3, then 2 at line 4, then 4 at line 5:
int c 8 1008
int b 4 1004
int a 4 1000
4 Chapter 1. Memory: The Stack
Exercise 1.2. Consider this code snippet:
1 {
2 int a, b, c;
3 a=1;
4 b=a+1;
5 c=b+1;
6 a=c+1;
7 }
Fill in the data corresponding to the final memory configuration:
int c 1008
1.1. Playing with Memory 5
with a. If we examine the visualization of memory above, we see that a’s ad-
dress is 1000. Therefore, &a simply evaluates to 1000, and x=&awrites the
value 1000 to x. After line 4 executes, memory looks as follows:
int * x 1000 1008
int b ⊗ 1004
int a ⊗ 1000
Now x points to or references a: x holds the address of a’s memory cell.
Their types match: x,asanint *, references an int variable; and a is indeed
an int variable. The type int * can be read as “pointer to an integer.”
Line 5 uses * differently than in line 3. In line 3, * is part of the variable
declaration: it is not being used as a verb (that is, as an operator) but as
an adjective. It describes x in line 3. In line 5, it is a verb: *x=2tells the
computer to write the value 2 to the memory cell whose address x currently
holds. Since x currently holds the value 1000, the computer writes 2 to the
memory cell located at address 1000, resulting in the following configuration:
int * x 1000 1008
int b ⊗ 1004
int a 2 1000
Finally, line 6 uses * in a manner similar but subtly different from its usage
in line 5. Here, *x is a request to read the datum at the memory cell whose
address x currently holds. This value is then written to b.Sincex references the
memory cell at address 1000, the following memory configuration is obtained:
int * x 1000 1008
int b 2 1004
int a 2 1000
Variables declared with a *,asinint * x, are traditionally called point-
ers because they “point” to a place in memory. Presentations of pointers often
draw arrows coming from a pointer variable’s memory cell to the memory cell
to which it is pointing. For example, in the memory configuration above, one
Exercise 1.4. Consider this code snippet:
1 {
2 int a, b;
3 int * x;
4 x = &b;
5 b=1;
6 a=*x+1;
7 }
Complete the stack diagram corresponding to the final memory configuration:
int * x 1008
int b 1004
int a 1000
1.1.3 Pointers to Pointers
What may now seem like an interesting diversion will be crucial in implement-
ing the sophisticated data structures of Chapter 8 and, of course, those that
you encounter subsequently. Therefore, we might as well take the full plunge
into pointers. Consider this snippet of code:
1.1. Playing with Memory 7
1 {
2 int a;
3 int * x;
4 int ** y;
5 y = &x;
6 *y = &a;
7 **y = 1;
8 }
The initial memory configuration is as follows:
int ** y ⊗ 1008
int * x ⊗ 1004
pointer assignments. Whereas *y=1would write a 1 into the memory cell
8 Chapter 1. Memory: The Stack
pointed to by y, **y = 1 writesa1intothememorycellpointedtobythe
memory cell pointed to by y. Following the addresses in the previous memory
diagram, we see that y holds address 1004. At address 1004, we find the value
1000, which is interpreted according to its int * type and thus as a pointer
to an integer. The 1 is thus written into the memory cell at address 1000,
which corresponds to a, yielding the final configuration:
int ** y 1004 1008
int * x 1000 1004
int a 1 1000
Trace through this code and its execution until you fully understand each line.
A pointer variable, or simply a “pointer,” is sometimes called a reference,
because it refers to a memory location. Applying the * operator to a pointer,
as in *x, is sometimes referred to as dereferencing it.
Exercise 1.5. Consider this code snippet:
1 {
2 int a;
3 int * x;
4 int ** y;
5 y = &x;
6 x = &a;
7 **y = 1;
8 *x = a + **y;
9 a=*x+**y;
10 }
Fill in the data corresponding to the final memory configuration:
int ** y 1008
int * x 1004
int a 1000
6 *z = x;
7 b = *y;
8 }
Line 2 compactly declares two int, a and b;twoint *’s, x and y;andone
int **, z. Fill in the data corresponding to the final memory configuration:
int ** z 1016
int * y 1012
int * x 1008
int b 1004
int a 1000
What are the types of the expressions on lines 3–7?
Exercise 1.7. Consider this code snippet:
1 {
2 int a, b, * x, * y, ** z;
3 x = &a;
4 z = &y;
5 *z = &b;
6 *x = 1;
7 *y = 1;
8 **z=a+b;
9 }
Fill in the data corresponding to the final memory configuration:
int ** z 1016
int * y 1012
int * x 1008
int b 1004
int a 1000
10 Chapter 1. Memory: The Stack
What are the types of the expressions on lines 3–8?
Solution. After line 7, the stack is configured as follows:
Notice that the memory cells corresponding to variables are ordered according
to the order of their declaration. What are the types of the expressions on lines
3–9?
Exercise 1.9. Write your own pointer-rich code snippet and draw the final
memory configuration. Trade puzzles with a few of your colleagues; check each
other’s work.