Upload
others
View
1
Download
0
Embed Size (px)
Citation preview
APS 105Fall 2008
Lecture Notes
1 Introduction
1.1 Welcome
• Welcome to engineering at UofT!A great choice: top engineering program in Canada, at the best univ in Canada.
You are working towards a degree that is very highly regarded, in industry andacademia, in Canada and abroad.
• University is a new and exciting time in your life – many intellectual, social, and extracur-ricular opportunities. Soak it up and enjoy it!
• Engineering at UofT is a challenge. University is a lot different than high school, as you nowhave total independence and responsibility for your own success. You will need to workhard to do well here!
1.2 Instructor
• My name is Jason AndersonI’m a prof in the Computer Engineering Group
Research area: computer hardware design, semiconductor chips
• Experience10 yrs at Xilinx – a semiconductor chip company with HQ in San Jose, CA
5 yrs in Silicon Valley (Calif), 5 yrs in TorontoAdjunct prof at UofT from 2005-2008
Taught a grad course on how to design semiconductor chips.Full-time prof starting Aug 2008
1.3 How to find me
• Refer them to info sheet
• What to do if office hours are not suitable
• Encourage them to use me as a resource
1.4 Lectures
• Times and locations in the course handout.
1
1.5 Tutorials
• One per week
• Run by TAs
• TA’s will have material to present but questions are welcome
1.6 Labs
• A two-hour period is assigned each week
• TAs will be available for help and marking in the labs during those time slots
• Mandatory attendance.
• Necessary that they submit the labs on timeProbably no exceptions — unless system goes down, building on fire, etc.
• Can do labs from home by connecting to ECFIf they have not done so before, they should try to get connected now
1.7 Evaluation
• Quizzes — 12%Six quizzesGiven in tutorialsQuestions in quiz will be based on lectures of previous week
(or previous two weeks if no quiz in previous week)
• Labs — 13%A total of eight – all countMust run on ecf — no exceptionsSome marks for functionality, some marks for style.I will explain what is required for style as we proceed
• Midterm test — 25%Held on October 28 at noon for 2 hours.
• Final exam — 50%SummativeEmphasis on latter half of course
• Problems with labs, quizzes, testwhat to do if you miss something
form available on course websitewhat to do if you are unhappy with your mark on a piece of work
form available on course website
2
what to do if you need special considerationform available on course website
1.8 Getting help
• Refer them to handout — discuss briefly
• Encourage them to form study groupsLearn the name, phone number, and email address of a neighbour
Give them time for this
• Contrary to what they may have heard, we DO care about our studentsWe are available and eager to helpTake advantage of tutorials, office hours
• Other supportCounselling and learning skills services offers
help with academic skillspersonal counsellingwebsite: www.calss.utoronto.ca
• First-year office on the main floor of Galbraith Building.
• Encourage them to get help quickly if they are in any kind of trouble
• For those having difficultyDon’t let things get out of control
Get help fast
• Ask questions in classDon’t worry about looking foolish
• If you see something on the board that is confusing, askI do make mistakes — I appreciate having them corrected
• If questions are slowing things down too much I may ask you to see me later
• Whatever works (and does not involve cheating)
1.9 Academic integrity
• Infractions are treated very seriously
• You may get away with cheating but, if you don’t, very bad things can happen to you
• Consequences can be very severe — far worse than a poor mark
• See Engineering Calendar pp 87 for details of consequences
3
1.10 In-class rules
• No talking to fellow students
• Be on timeClass starts 10 mins after hour; ends at hour.
Late arrivals are distracting
• Early departuresInform me ahead of time and sit in a location that minimizes disturbance.
• Food and drink – not allowed.
• No cellphones and other noisemakers.
• Exams are related to lecture content: pay attention!
1.11 Using the course website
• Course website is within the Blackboard framework, accessible using your UTORid throughthe University of Toronto Portal: http://portal.utoronto.ca
1.12 About this Course
• By December, you will know Computer Programming!!Getting a computer to DO what YOU want it to.Examples of programs that you likely already know:
Word processors, IE, image re-sizer, Windows itself!, many programs within Facebook(consider the NEWSFEED)
• Programming is expression – part “science” and part “art”.Consider writing an essay or explaining a concept in words:
MANY ways to convey same/similar ideas.Likewise, a program that does some thing X can be written in MANY different ways.Creativity, style, elegance, logic, conciseness are ALL relevant to programming.
• While programming is KEY for ECE, ALL types of engineers use computers and MANYneed to program them.
How many here are “Track one”?
• Great skill for your career.
1.13 Computer System
• Draw a CPU with the memory and the I/O devices.
• Explain that the CPU, mainly, has a control unit and an ALU.
• Example CPUs: Intel Pentium, Xeon; ARM CPU in iPhone, iPod Touch (low-power embed-ded).
4
• CPU – control unit: fetch, decode, execute
• Arithmetic Logic Unit (ALU): execution unit
• Main memory: addresses, cells (each one byte)
• I/O devices: disks – non-volatile storage, mouse, keyboard, iPhone screen.
1.14 Getting started with C
• “C” is the name of a popular programming languageInvented in Bell Labs (in 1970s); many features taken from earlier language called “B”.C is widely used in industry!Once you know one language, you can learn others easily.
• Another lang is C++; C++ is an extension of C.
• TextbookAn Introduction to Computer Science Using C by John Carter
Published by McGraw Hill-Ryerson.Copies in bookstore and basement of Sandford Fleming Building.Read it!
• Jumping in with a first program!traditionally, writing Hello, world
• #include <stdio.h>
// This program prints: Hello, world
int main (void){printf("Hello, world\n");return 0;
}
1.15 Analyzing the features of the first program
• #include <stdio.h>gives program info it needs to use standard I/O functions
• commentsnote alternative forms
• main functionexplain header line
5
• printfsends output to standard system output device — the screen\n causes jump to nextline
• whitespace and use of indentation
• printing very long stringscan close quotes and then start a new quoted group on a new linecompiler will assemble strings into one long string
• escape sequenceshow do we print "?
use \" — an escape sequenceexplain
to print \, use \\
• explain return statement
1.16 Developing C programs
• C compilers: gccgcc is a “compiler”.Computers deal only with 0s and 1s (bits).A compiler is a special type of program that converts another program in a language like
C into the 0s and 1s that the computer can understand.Actually, how to build better compilers is a still research problem in itself!
• Editors to edit source code: emacs, vi, pico
• Integrated Development Environment (IDE)
• Debuggers
• The program development cycle: edit – compile – execute
• gcc -o hello hello.c
6
2 Creating and Printing Basic Types
2.1 Introduction
• Think about how a human learns a new language.
• First, they learn some words.
• And, it takes a while before they combine words into useful sentences.
• And then, even when someone can form good sentences, it takes a while before they canreally speak eloquently.
• Likewise, we have to learn a few “basics” about C, before we can write really useful pro-grams.
• And also likewise, it’ll take some time before you can write programs that would be called“elegant”.
Note here that elegant doesn’t mean complicated or hard-to-follow; elegant means con-cise, simple, and clear.
2.2 Basic storage ideas
• Notion of type:English, French, Spanish all use the same alphabet.Consider the word “pour” with same spelling in French and English, but different mean-
ings and maybe meaningless in Italian.We need to know whether we’re using Spanish, English, or French to get the right
interpretation!
• All information in a compter made up of “bits” – bit: capable of being in one of two states: 0or 1
byte: 8 bits — 28 = 256 possible states
• We store data of various kinds as patterns of bitsThe same pattern of bits might represent a variety of things
e.g. , a number, some text, part of a picture, part of a song
• In writing a program, we may, for example, need an integer.We tell C to reserve space for an integer.The bit pattern in that space will be interpreted as an integer.
• On another occasion, the same bit pattern could mean a letter or a colour.We get whatever interpretation type we request in C.
• spend some time on thistry to make sure that they understand the concept
7
2.3 Integer types
• Examples of integers
• Various sizes of integers: short, int, long, long long, unsigned int, . . .Each of these may be able to represent different sizes of integers. We will be using intalmost all the time.
• Use of l or L for long constants: 2l, 3L.
• Range of int integer: −231 → 231 − 1
• No exam questions on integer types except int.
2.4 Floating point types
• Examples of floating point constants as normal decimals
• Examples — include use of e or E notationsimilar to scientific notation
• Floating point values are stored as two partsdigits (mantissa) and exponent are stored separatelynot whole story — values are stored in binary rather than decimal formwe don’t need to know the whole story
• C has a variety of floating point numbersWe will only be using float and doubleIn fact, virtually all the time we will use double
• Use of f or F for float constantse.g. , 2.7f -3F 0.73e3F
• No exam questions on floating point types except double.
2.5 Characters
• examples’A’ ’$’ ’\\’ ’\n’ ’"’ ’\’’
• strings vs. characters
• ’0’ vs. ’\0’
2.6 Identifiers
• Purpose — to give names to items.
• rulesAny number of charactersUpper or lower case letters plus digits plus _First character cannot be a digit
8
• Some identifiers reserved by the language — called reserved words (pp. 23 of text):e.g. , int, double, if, do
• Conventions (not rules)use of lower-upper
e.g. , valueAtStartuse of underscore as in value_at_start— I won’t use thisupper case for constants as in PI
• Be sensible about identifiersnot too shortnot too long
• Be careful to avoid confusion0 and O1, l, and I
2.7 Declaring variables
• general form:<type> <identifier list>;
• examples
int age; // in yearsfloat mass; // in kg - to nearest gdouble a,b,c; // sides of a trianglechar sexCode; // M or F
• what does a declaration do?explainno initialization (explain term) can be expected
2.8 Assigning values to variables
• Meaning of an assignment statement — contrast with equality
• Can be done as soon as the variable is declarede.g. , int i = 0;
int width = 5, length = 8;
• Or at any time after thate.g. , int i; . . .i = 3;
• conversionsfloating point to integer — lose fraction
e.g. , int i = 2.7;⇒ 2double to float — may lose digits
9
e.g. , float f = 1.23456789;⇒ 1.2345 (possibly)longer integer to shorter integer — may lead to nonsenselonger floating point to shorter FP — may lose precisioninteger to character – may lead to nonsenseanything to bool — non-zero: true; zero: falsebool to integer — true: 1; false: 0
2.9 Printing values of variables
• Use of printfdevelop with examples: conversion specifications in control string.
• Printing integers as a decimal (base 10) value%d — leaves just the right amount of space%4d — leaves at least four spaces (more if necessary)
Example:
int numInAlpha = 26;printf("There are %d letters in the alphabet.\n", numInAlpha);
You will see:
There are 26 letters in the alphabet.
• floats and doublesfloat value converted to double for printing%f — six digits after the decimal%.2f — two digits after the decimal%6.1f — minimum field width of six characters, one after the decimal point%e — format is: ±x.xxxxxxe±nnThere is no %lf, but there is %ld
• char values%c — printed in just one space
• printing the % character (rather than as a control string)use %%
10
3 Reading Values, Constants, and Arithmetic
3.1 Reading numerical values using scanf
• discuss concept of “input”from where?to where?
• develop ideas with examples of use of scanf
• to read an integer into the variable agescanf("%d",&age);lots of time explaining features of this statementthe & means “the memory location of variable age”
• to read a double into the variable x, usescanf("%lf",&x);
3.2 Reading multiple values
• values to be read can be separated by whitespaceblanks, newlines, tabs
• e.g. , scanf("%d%d%d",&i,&j,&k);
• show some possible arrangements of inputall on same lineon different lines
• input cannot contain anything other than integers and whitespacee.g. , 5.0 7 -8 would not be read as three integers
3.3 Consuming whitespace and other items
• in reading numeric values of any typescanf consumes leading whitespace, but not trailing whitespace
• can skip characters by including them in control stringe.g. , if input has form nnn-nnnn
use scanf("%d-%d",&first,&second);
3.4 Reading char values
• in reading char values, scanf does not skip whitespace
• use an example to illustrate
11
int age;char sex;printf("Please give your age and sex (M/F)\n");scanf("%d%c",&age,&sex);
look a results of various responses18 F
gives age = 18, sex = ’ ’18F
gives age = 18, sex = ’\n’
3.5 Constants
• literal constants vs. named constants
• why use named constants?clarityease of revisionavoidance of errors
• identifiers of constantsConvention: use of upper case letters
• how do we create them?use of const attribute
e.g. const double PI = 3.141592653589793;use of #define
e.g. #define PI 3.141592653589793Every instance of PI in program is replaced with 3.145...note absence of = and ; in #defineWatch out!: no comments on the same line
• discuss concept of magic numbersnote consequences of using them on assignments
3.6 Tips of Programming Style
• Use the style of indentation that the textbook usesit will help the TA markingsome labs offer marks for style
• Make sure you put semi-colons at the end of each statement
• Examine the first error message, recompile after fixing it
• Syntax errors (caught by compiler) vs. logical errors (wrong program functionality).
(End of Chapter 1)
12
3.7 Basic arithmetic operations
• four basic operators+ - * / ( )usual precedence rulesdo not use square or brace brackets for math
• use of / with integers and floating point values
• one more operator: %implements remainder; arguments must be ints: m % ntakes ABS(m) % ABS(n); result takes the sign of mexplain and do a few examples with %precedence is the same as * /
• if types of operands are mixed, wider type is contagiousfloat point is contagious.
9 + 6.3 → doubledo some examples
• division by zero (including %)result is compiler dependent
• overflow and underflow are possible.
3.8 Calculations involving char values
• All computer data made up of 0s and 1s.When your computer gets sequence 0s/1s over internet:
How does it know to print “A” or “B” or whatever?Each letter has an encoding (ASCII).
• values of type char are promoted to int before any calculations
• e.g. ’A’ + 1encoding of ’A’ is 0100 0001to convert this to an int, code is read as a base 2 valueexplain briefly: 010000012 = 1 × 26 + 1 × 20 = 64 + 1 = 65thus ’A’ + 1 gives 65 + 1 = 66if we assign result to a char, result is ’B’
3.9 Increment and decrement operators
• brieflyexamples of both prefix and postfix formsHigher precedence than other math operators.
• don’t combine with other operators(or read Section 2.3 very carefully before doing so)
13
perhaps one example (result: 20)i = 3;j = 5;k = ++i * j--;
• Do NOT do similar things as the following problem:what is the value of i and j after execution of the following (i = 5, j = 15):
int i = 3;int j = 2*i++ + 3*i++;
Watch out!: Problem here is don’t know which operand of + will be evaluated first.
14
4 Mathematics (cont.) and Choosing Alternatives
4.1 Increment and decrement operators (cont.)
• look at problem from last day
• note that different compilers may give different results
4.2 Assigning expressions to variables
• note sequence: evaluation and then assignmentlook at
i = 5;i = i + 1;
• multiple assignmentsapplied from right to lefti = j = k + 1→ i = (j = (k + 1))
• other assignment operators: = += -= *= /= %=brieflyexamples
int i = 3, j = 5;i += j;i *= j + 2;
• Actual assignment process is the side effect of assignment operators
4.3 Mathematical functions
• we can find square roots, sines, ...
• to do so, we must use#include <math.h> in programwhen compiling with gcc, use -lm
• these functions have double arguments and return double values
• a partial list
15
Method Value Returned
sqrt(x)√
x
pow(x,y) xy
log(x) ln x
exp(x) ex
fabs(x) |x|fmax(x,y) maximum of argumentsfmin(x,y) minimum of argumentsfloor(x) largest integer ≤ x (as a double)ceil(x) smallest integer ≥ x (as a double)sin(x) sin x (in radians)cos(x) cos x
4.4 rand
• function rand takes no argumentreturns a pseudo-random non-negative integer value less than some large valuelarge value has identifier RAND_MAX
• need the directive #include <stdlib.h> to use rand
• show (step by step) how to obtain an integer from 1 to 6rand()%6 + 1
• this may not produce random behaviour if last bits have some patternbut probably OK
• show how to obtain an even number from 2 to 100: (rand() % 50 + 1) * 2
• use of srand to obtain an initial value (a seed)seed is an int
4.5 Casts
• occasionally we need to change the type of some value
• C gives us the cast to do this
• form is (<type>)<expression>
• discuss precedencePrecedence is higher than math ops, except ++ and --examples
(int) 5.7 + 8.9(int) 5.7 + (int)8.9(int) (5.7 + 8.9)
16
4.6 Things to watch for
• double x, y, z;...z = (int)x*y;
x is cast to integer before the multiply.
• double z, p, q, r;...z = p/q*r;
You get (p/q)*r and NOT p/(q*r)
• (3/4)*8
You get 0 and not 6! Ask them: how to get 6? (typecast)
4.7 Choosing between alternatives
• flexibility of programs is produced by their ability to take different actionswhen faced with different conditions
• in early versions of Cif value of an expression was zero, that was falseany other value was true
• C99 permits the use of variables and expressions of type boolvalues true or false
• to use this feature, we need the directive#include <stdbool.h>
• two approaches are compatible as C treats false as zero and true as one
• we can create and use variables of type bool
#include <stdio.h>#include <stdbool.h>
int main (void){bool x = false;bool y = true;printf("x: %d y: %d\n",x,y);return 0;
}
• program will printx: 0 y: 1
17
4.8 Relational expressions
• decisions often based on comparisons using relational expressionsexamples: x < 0
height > width
• concept of a relational expression having a valuetrue or false
2 < 5 has the value 1-6.3 > 1.75 has the value 0
• list of relational operators< <= > >= == !=
no spaces between tokensWatch out: == is not the same as = (VERY common error in C programming).
emphasize difference between x = 0 and x == 0
• can mix types in relational expressionse.g. can compare an int to a double
• can mix arithmetic operators and relational operatorsarithmetic operators have higher precedencegive an example
4.9 Comparing characters
• encoding (usually ASCII) determines order
• blank is very low — lower than any printable character
• usually we will be dealing with digits and letters’0’ < ’1’ < ... < ’9’’A’ < ’B’ < ... < ’Z’’a’ < ’b’ < ... < ’z’Called a “collating sequence”
• (to summarize)The digits are sequential with 0 < 1 < 2 < ...< 9Upper case letters are sequential with A < B < C < ...< ZLower case letters are sequential with a < b < c < ...< zA blank precedes any digit or letter.All digits precede all letters.All upper case letters precede all lower case letters
• note that ’0’ == 0 is falseexplain
• other characters are scattered aroundthey don’t need to know details
18
5 Control Structures for Making Decisions (cont.)
5.1 if statements for choosing between two alternatives
• start with an example — printing square rootsprint square roots of negative numbers with ie.g.
√−4 = 2i
if (x < 0)printf("%fi\n",sqrt(-x));
elseprintf("%f\n",sqrt(x));
• general form
if (<expression>)<statement>
else<statement>
• noteindentation — for readabilityparenthesessemi-colons
5.2 if statements without else clauses
• for choosing to perform an action only if some condition is true
• if (<expression>)<statement>
• do an example
/* make result positive */if (result < 0)result *= -1;
/* how about printf("%d", result = -result);? */
• Often represented using flow charts (show them an example).
5.3 Compound Statements or Blocks
• use of {..} to create a block
• do an example
19
if (result < 0){result *= -1;printf("Negative result made positive\n");
}
• note indentation style — and alternatives
5.4 A common error
• be careful not to write things like the following:
if (result < 0);result *= -1;
• the ; following the condition is interpreted as a statementan empty statement
• fragment of code is parsed by compiler as:
if (result < 0);
result *= -1;
• thus, any value of result will have its sign reversedprobably not what we wanted
5.5 Boolean operators
• ! (not) && (and) || (or)
• Can override precedence using parentheses.
• A B A && B A || Bfalse false false falsefalse true false true... etc.Also show them !A.
• order of evaluationprecedence: !, &&, ||left to right for same operatore.g. !(2.5 || 0) && 6.1 (answer: 0)
• See precedence table on page 100 of book (for all operators covered thus far).
20
5.6 Properties of boolean expressions
• lazy evaluation<e1> && <e2>
here <e2> is not examined if <e1> is false<e1> || <e2>
here <e2> is not examined if <e1> is true
• why is lazy evaluation useful?an example — testing if x/y < 10
must guard against the possibility that y = 0if (y != 0 && x/y < 10)
• De Morgan’s lawsConsider the statement S1: Engineers are happy AND smart.For S1 to be true, both parts must be true: we’re happy AND we’re smart!Consider its negation, !S1: It’s not the case that engineers are happy and smart.If !S1, then either engineers are either NOT happy, or engineers are NOT smart.!S1 = !(Engineers are happy) OR !(Engineers are smart).(!p) || (!q) ≡ !(p && q)
Consider statement S2: I like coffee OR tea.Consider !S2: I don’t like (coffee OR tea.)So, !S2 means: (I don’t like coffee) AND (I don’t like tea.)(!p) && (!q) ≡ !(p || q)
lots of time explaining these
5.7 Nested if statements
• develop an exampleassign to variable largest the largest of a, b, cdiscuss strategy first
5.8 Dangling else problem
• Show two pieces of code
if (p) if (p)/* p true */ /* ??? */if (q) if (q)/* ??? */ /* ??? */
else else/* ??? */ /* ??? */
• Get them to fill in truth values in comments
• once they see the problem, look at ways to solve it
21
5.9 Indentation style with many nesting levels
• if ( )<statement>
else if ( )<statement>
else if ( )<statement>
.
.else<statement>
5.10 switch statements
• Discuss briefly ??? janders: we may perhaps consider omitting switch statements.
• do an examplenote use of break; after last casenote use of default
• For more details, see Section 3.5
• switch(score) // score must be an integer{case 3: grade = ’A’;break;case 2: grade = ’B’;break;case 1:case 0: grade = ’C’; //break;default: grade = ’F’;break;}
5.11 Conditional operator/expression
• discuss brieflydo an example — assigning to a variable the larger of two values
larger = a > b ? a : b;
• Evaluation: from right to left (show signum() example in textbook, p. 114)
• Called a ternary operator.
• largest = (x >= y) ? (x >= z ? x : z) : (y >= z ? y : z);
22
5.12 Debugging notes
• 4 < 2 <= 8 -> 1
• Go from left-to-right in the evaluation.
23
6 Repetition
6.1 Introduction to repetition
• two kinds of repetitive actions (loops)counted and conditional
• examples — from cookingstir for 300 strokesstir as long as there are lumps
6.2 while statements
• general form:while (<expression>)<statement>
• effect — explain slowly and carefully — compare to if
• an example — develop slowlya loop to read integers until zero is read and print the sum of values
sum = 0;scanf("%d",&n);while (n != 0){
sum = sum + n;scanf("%d",&n);
}printf("The sum is %d\n",sum);
• note initialization before loop to make condition meaningful first time
• note the use of while (n) is the same as while (n != 0)
• note the use of sentinel value to halt the loop
• note also that<expression> must be meaningful before we enter the loop<expression> must be true if we are to perform the body of the loop the first timesomething in loop must make <expression> false if we do not want an infinite loopvalue of <expression> after exiting loop must be false
• a second example — develop slowlya loop to sum a set of values and find their average
int total = 0, count = 0, next = 0;scanf("%d", &next);while (next >= 0){
24
total += next;count ++;scanf("%d", &next);
}if (count > 0){
printf ("Average for %d students is %d\n",count, rint((double) total / count);
}else
printf ("No marks submitted.");
6.3 do statements
• recall processing of an indeterminate number of studentsas well as “while there are students, keep processing”,we can also have “keep processing as long as there are students”
• note difference — in second case, we must process at least one student
• for first loop, C haswhile (<expression>)
<statement>
• for second loop, C hasdo
<statement>while (<expression>);
• almost like while but now<expression> is not evaluated until we reach the end of the loop
• an example:a loop to force a user to enter a number from one to ten
do{printf("Give a number from one to ten\n");scanf("%d",&n);
}while (n < 1 || n > 10); // this is what we DON’T want
• noteuse of semi-colon at enduse of parenthesesloop must be executed at least once (unlike while)
25
6.4 for statements
• recall common structure with a while statement:
<initialization>;while (<condition>){<statement(s)><alteration>;
}
• this can be written more concisely as:
for (<intialization>;<condition>;<alteration>)<statement>
• an example: printing a table of squares from one to tenfor (n = 1; n <= 10; n++)printf(n + "%d squared is %d\n",n,n*n);
• we can write this in formfor (int n = 1; n <= 10; n++)printf("%d squared is %d\n",n,n*n);
• in the second case, n is only defined in the for statementif we tried to print it outside the for, we would get an errorexplain, informally, idea of scope of a variable
• older versions of C do not permit declarations within for statements
26
7 Repetition (cont.)
7.1 Notes on programming style
• from now on, labs will be marked for style as well as for correctness // ??? janders: need toconsult with instructors
• for now, features of good style aregood identifiersintroductory comment in the program with
titleauthordateoverview of function of program
occasional comments toclarify codeintroduce a section of code
• program efficiency is not that importantonly a problem if program is grossly inefficient
• no goto, no break (except in switch statements), no cin, no cout
• later, we will be seeing more aspects of good style
7.2 Variations on for loops
• recall general form:for (<exp1>; <exp2>; <exp3>)
<statement>
<exp1> is executed once, at beginning<exp2> is boolean, must be true for <statement> to be executed<exp3> is executed after <statement>
• very flexible
• first and/or third expressions can be empty:an example
int n = 1;..for (; n <= 10; n++)printf(...);
another example
n = 1;for(;n <= 10;)
27
{printf(...);n++;
}
• if second expression is empty, it is taken to be truee.g. for (;;)
creates an infinite loop
• expressions can be complex:for (n = 1; n < 11; printf(...),n++);
• notesemi-colon on next line (for visibility)use of comma expressions
(only valid in first and third part of for statement headers)
• another example:for (m = 1, n = 10; m < n; printf("%d\n",m*n),m++,n--);
show output
7.3 Choosing a loop structure
• recommendations:normally,
keep things simpleuse while or do with conditional loopsuse for with counted loops
• go briefly through the ideas of §4.5 in the text
• Rules of thumb:If number of repetitions is known, use a forIf want to test condition before entering loop, use a whileIf one loop iter is OK before testing condition, use a doSometimes, it’s a matter of personal preference.
Suggest looping situations and try to find most natural structure
7.4 Loops that combine counting and conditional elements
• explain general ideae.g. process 100 items (or quit if done before that)
• note that for is often used for partially conditional loopsprobably the best solution
28
• e.g. perform an action MAX times, unless something special happens
bool done = false;..for (int i = 1; i <= MAX && !done; i++){..if ( .. )done = true; // something special happened
}
7.5 Nesting loops
• just as we can nest if statements inside other if statements,we can nest loop statements inside other loop statements
• a very simple example, printing a rectangle of asterisksbest to nest a for inside another for
• develop another example, again using nested for statementsprint a triangular pattern containing n rows of numbers from 1 to n
e.g. if n is 5, print112123123412345
• Solution:
for (int row = 1; row <= 5; row ++){for (int i = 1; i <= row; i ++)printf("%d", i);
printf("\n");}
• develop code to print a triangle of stars like the following
****... *..
******
• Solution:
29
for (int row = 1; row <= n; row ++){for (int i = 1; i <= n - row + 1; i ++)
printf("*");printf("\n");
}
• develop code to print a triangle of stars like the following
******..
*...****
• here is one possible solution to the last problem
for (int row = 1; row <= n; row++){for (int col = 1; col <= n; col++)if (row + col <= n)
printf(" ");else
printf("*");printf("\n");
}
• develop a program fragment thatfirst forces a user to supply a single digitthen reads an integer and counts the number of occurrences of the digit in the number
int digit, n, count, lastDigit;do{printf("Please give a digit - 0 to 9: ");scanf("%d",&digit);
}while (digit < 0 || digit > 9);
count = 0;printf("Please give an integer: ");scanf("%d",&n);do{lastDigit = n%10;if (lastDigit == digit)count++;
30
n /= 10;}while (n != 0);
31
8 Functions
8.1 Introduction to functions
• as problems get larger, they get much harder to solve
• modularity is a useful response to thisexplain modularity
e.g. input/processing/output
• why is it a good idea?allows us to think about one part of a large problem (more or less) in isolation
break down a large problem into pieces that can be solved reasonably (divide-and-conquer)
many people can work on various parts of the problemsome parts may be identical (or at least very similar) so . . .modules from other programs might be useful — “plug them in”structure is lost if segments are too largemay be easy to test each small module
this may give some hope that the entire package may work
8.2 Function basics
• in C, the basic modular unit is the function
• many pre-defined functions are available in virtually all programming languageswe have, for example, in C, already seen
main functionmath functionsI/O functions
• functions can be divided into two typescommands that carry out some process and then simply quit when done
e.g. , sort a list of numbersqueries that evaluate something and return that value to the user
e.g. , given a value, find its square rootx = sqrt(y);
• some languages differentiate between two typesuse terms like
procedure, subroutine for commandfunction for query
not C — both types called functions
8.3 Defining commands
• a very simple examplea command that skips lines (by printing a blank line)
32
• develop the following code to define our command:
void skipLine (void){printf("\n");
}
• the function skipLine can now be used in a program
8.4 Program organization
• where do we put the definition of a function?we could put it at the beginning of a program
• as an example, to use skipLine in a program, we could write
#include <stdio.h>
void skipLine (void){printf(’\n’);
}
int main (void){..skipLine();..skipLine();.
}
• note use of parentheses in calls — to indicate that skipLine is a function
• could put main firstif we did, then, when program came to skipLine command
it would not know what it meant (because it had not yet seen its definition)to overcome this, we can tell main what it needs to know about skipLine
it takes no argument and it returns no valueto do this, we can write a declaration of the function in maindeclaration takes the form
void printLine(void);note use of semi-colon
declaration is known as a function prototyeContrast the difference between function declaration and definition
33
• we can put the prototype at the start of the programOr, we can also put the prototype inside a function, prior to the call.
• show outline of program with this ordering
#include <stdio.h>
void skipLine (void);
int main (void){..skipLine();..skipLine();.
}
void skipLine (void){printf(’\n’);
}
• however we arrange our function definitions, program execution always starts with main
8.5 Adding flexibility with parameters
• skipLine always skips one linea more useful method would allow us to vary number of lines skipped
• the following method does what we want
void skipLines (int n){for (int i = 1; i <= n; i++)printf("\n");
}
• the variable n in the header is called a parameter
• to call or invoke skipLines, we could write (in main, say)int i = 3;skipLines(i+2);
i+2 is an argument
• when we call a function, the following occurs:argument(s) is/are evaluated
34
control passes to the functionparameter(s) are automatically assigned value(s) of argument(s)called function is executedcontrol passes back to the calling function
• this form of argument-parameter correspondence is known as call by valueexplain why
• some programming languages have other formsC only has call by value
• parameters are known throughout the function but not outsidesince they are not known outside the function,
their identifiers can be used outside — for other variables
• develop the following example of parameter passing
• both the calling and the called function use a variable called nin main
int n = 7;result = fun(n);
method funint fun (int n){n = n/2;return n;
}
trace values of both variables
35
9 Functions (cont.)
9.1 Defining queries
• develop a simple example — a query to find the value of n!
int factorial (int n){int product = 1;for (int i = 1; i <= n; i++)product *= i;
return product;}
• be sure they understand the meaning of return product;
• to call this (from main perhaps), we could writeint n = 3;int result = factorial(n+2);
• go through calling process again
9.2 A closer look at parameter passing
• automatic correspondenceif more than one parameter, correspondence is determined by ordertypes of arguments and parameters need not match exactly
they only need to be assignment compatibleSo, you can pass a short or a char to a parameter that expects an int.
• as an example, suppose we were to write a function to determine powers of numbersthe header of such a function might have the form
double power (double x, int n)to call such a function, we might write
value = power(1.5,2);could also write
value = power(15,2);value of 15 is promoted to double (as 15.0) before assignment
could also write writevalue = power(1.5,2.5);
2.5 would be assigned to the int parameter n (as 2)
9.3 Use of return
• definitions of queries (functions that return a value) must contain a statement of the formreturn<expression>;
• multiple return statements can appear in function definitions
• as an example, develop a function that returns the larger of two integers
36
int larger (int m, int n){if (m > n)return m;
elsereturn n;
}
• this is often seen as bad stylewhy? explain — compare to break
we will usually follow this style rule — occasional exceptions
• rewrite larger with only one return statementint larger (int m, int n){int big = m;if (n > m)big = n;
return big;}
or
int larger (int m, int n){return m>n?m:n;
}
• for commands, as we have seen, no return is necessary
• in commands, we can have return if we choose to do so
• as an example, developvoid skipLines (int n){if (n < 1) // nothing to doreturn;
for (int i = 1; i <= n; i++)printf("\n");
return; // can be omitted}
9.4 Functions that return bool values
• brieflyidentifiers are normally of the form is<Something>
e.g. , isPerfectSquarea function to return true iff an int is a perfect square
37
• to use such a function, we might writeif (isPerfectSquare(n))
• easier for somebody reading our program to understand what we are doing
• develop definition of function
bool isPerfectSquare (int n){if ((int)sqrt(n)*(int)sqrt(n) == n)return true;
elsereturn false;
}
• note use of multiple return statements in function
• could replace this with something like
bool isPerfectSquare (int n){bool result = false;if ((int)sqrt(n)*(int)sqrt(n) == n)result = true;
return result;}
• a more concise solution:
bool isPerfectSquare (int n){return (int)sqrt(n)*(int)sqrt(n) == n;
}
• spend some time explaining this
38
10 Pointers and Functions
10.1 A problem with parameter passing
• consider the following function to swap two values(perhaps useful in sorting)
• void swap (int i, int j){int temp = i;i = j;j = temp;
}
• analyze operation to see why the function fails to swap values
• use diagrams — emphasize call by value
• we need some new tools to solve this problemnew tools involve pointers
10.2 Creating and using pointer variables
• Consider a sign in a cafe that says: “Restrooms are on your left.”That sign is itself an object. It’s not the restroom itself, but it tells us where the restroom is.
It “points” us to the restroom (a specific type of room.)
• Another way to think about it: Consider a room of a certain size, with certain contents.A pointer is like a key to the room.We can get into the room using the key.
• Think of the computer’s memory as being a very long straight street, like Yonge Street.A pointer is like a particular address on Yonge Street, e.g. , 887 Yonge Street
• A pointer variable holds a memory address.
• It points to somewhere in memory.
• int *p; is a declaration of a pointer variable.p points to someplace in memory where an integer resides.
Note that it points to a specific type.Initially, it’s not pointing anywhere.
• int m = 3;int *p = &m;// draw a figure for them with p pointing to m.
p points to the memory location where integer m is stored.
39
• We use the dereferencing operator * to get to what’s at an address pointed to.
• & and * are complementary:& gives the address.
* gives us what’s at an address.
• double x,y;double *a, &b;
x = 3.6;y = 6.7;a = &x;b = &y;
// at this point, draw a figure for them, as in page 184 of the book
*a = 1.0;
*b = *a + 1.0;
// at this point, draw a figure for them, again, as in page 184 of book.
// now x contains 1.0// y contains 2.0;// could alternatively write as:
x = 1.0;y = x + 1.0;
• So, what’s the use of pointers?Now we can re-write the swap function // shown below
10.3 A correct version of a swapping function
• develop the following slowly
• void swap (int *p, int *q){int temp = *p;
*p = *q;
*q = temp;}
• a call to swap might take the form:int i = 5, j = 7;swap(&i,&j);
40
11 Pointers (cont.) and Scope
11.1 Functions that return pointers
• develop an examplea function that takes the addresses of two double variables
and returns the address of the larger
• call to function might have the formdouble x = 2.6, y = 3.4, *p;p = largeLoc(&x,&y);
• develop code — lots of time explainingdouble *largeLoc (double *a, double *b){return *a >= *b ? a : b;
}
11.2 Scope of internal identifiers
• scope of an identifier is the range in which it is recognized
• an internal identifier is one that is declared inside a function definition
• recall from previous work that, in a statement likefor (int i = 1; ... ; ...)the variable i is only known inside the fori.e. the scope of i is the for
• the scope of a parameter is its entire function
• the scope of any variable declared within a functionstarts at the point of declarationends at the end of the block in which the variable was declared
a block starts with { and ends with }
• give examples of variables declared within sub-blocks of functions
• note that we can re-use identifiers if we are out of their scopeuse examples to illustrate this
• can have scopes overlapping
int i = 1;printf("i = %d\n",i);{int i = 2;printf("i = %d\n",i);
}printf("i = %d\n",i);
41
• output is
i = 1i = 2i = 1
• overlapping is not recommendedleads to errors
11.3 Scope of external identifiers
• identifiers declared outside any function are known as external identifiers
• function identifiers are example of external identifiers
• can also define variables outside any functione.g. , int sum; can be written outside any function
this defines the identifier, reserves space, and initializes it to zero
• to use such an external identifier within a functionwe can make a declaration inside a function
extern int sum; // ??? janders: should we cover this?
• declaration within function is not not required if definition precedes uselike function definitions
• external identifiers that precede all function defintions are called global
11.4 Putting the pieces together
• Recall idea of using functions to produce modularitythink about the problem as consisting of smaller pieces
• Explain strategy of top-down design brieflyDecomposing a problem into a set of smaller problems
• To begin to solve a large problemwe might try to describe the process using pseudo-code
explain briefly
• perhaps think of each of smaller pieces as being made up of even smaller ones
• continue this process until we have nice, easy to contemplate pieceswrite these as functions, then combine them
• Explain Goldbach’s Conjecture brieflyCan any even number greater than 2 be expressed as the sum of two prime numbers?
42
• Start top-down design for solution to problem of testing conjecture:Pieces:
Receive an input number to check.Develop a function that, for a given prime, returns the next higher prime.Develop a function that tests if a number is prime.
• Refer them to Section 5.7 in the text for details
43
12 Arrays
12.1 Introduction to Arrays
• Idea of a group name for a collection of items of the same type (any type)
• Here you will really see power of programming for efficient large-scale data processing!!
• e.g. , marks on assignments
Asst 1 2 6
Mark 85 92 73
• We could create separate variables for each mark: int mark1, mark2, mark3;However, that’s not very efficient.
• math analogy: x1, x2, . . . , xn
• terminology:index (rather than subscript) (plural: indices)component or element
12.2 Creating arrays in C
• index starts at 0 — no choice
• e.g. , an array to store 6 marks would have components calledmarks[0], marks[1], ... , marks[5]
• to create an array for our six marks, we could writeint marks[6];
• after this we have, pictorially
0 1 2 3 4 5marks
• note that elements of the array have no value shownjust as we have seen previously, C does not initialize these cells
12.3 Declaration with initialization
• C has an alternative form of array declarationit allows us to initialize an array with any values that we like
• e.g. , to create an array with the first ten primesint primes[] = {2,3,5,7,11,13,17,19,23,29};
• notice that the size of the array is not statedC knows that the array length is 10 because there are 10 values in brackets
44
• we can specify the length of the array when we use initializersif specified length is greater than the number of initializers
C initializes the remaining cells to zeroif specified length is less than the number of initializers
C treats this as an error
• examplesint list[6] = {1, 2, 3};
is equivalent toint list[6] = {1, 2, 3, 0, 0, 0};
int quantity[5] = {0};is equivalent toint quantity[5] = {0, 0, 0, 0, 0};
double mass[3] = {2.1, 1.5, 3.2, 8.8};is illegal
12.4 Adjusting array indices
• C’s arrays are always indexed from zerosometimes this is not convenient
• e.g. , to store the values of a sequence with terms t1, t2, . . . , tn
• we could use an array of length n but then ti would be stored in the location with index i-1
• as an alternative (that we favour)declare the array to be of size n + 1 then store ti at location ithe location having index zero is unused.
• e.g. , to store the sequence with termst1 = 1
2, t2 = 1
4, . . . , t5 = 1
32
no t0 term
we could create and initialize such an array by writingdouble terms[] = {0.0,0.5,0.25,0.125,0.0625,0.03125};element with index zero unused.
12.5 Operating with arrays
• suppose we have an array declared by:double list[MAX];
• setting the elements of an array to one
for (i = 0; i < MAX; i++)list[i] = 1.0;
• note: i < MAX is preferable to i <= MAX - 1
• summing the components of an array
45
sum = 0;for (i = 0; i < MAX; i++)sum += marks[i];
• reversing the elements of an arraydevelop the following slowly
for (low = 0, high = MAX - 1; low < high; low++, high--){temp = list[low];list[low] = list[high];list[high] = temp;
}
• if we attempt to use an index value that is out of the range of an arrayC does not give an error messageresults, however, are likely to be unexpected and unpleasant
12.6 Meaning of an array identifier
• array identifiers in C behave in ways that we have not seen before
• to illustrate, suppose we make the declarationint x[] = {3,7,2,4,5};
• we can illustrate the result as follows:
3 7 2 4 5
x[0]x[1]x[2]x[3]x[4]
• space in memory has been allocated for cells with identifiers x[0], x[1], . . . , x[4]but no memory has been allocated to the identifier x itself
• if we were to write a statement likex = 7; // wrong!the C compiler would reject this as an error
• there are, however, ways that we can use array identifiers in our programsan array identifier is interpreted as the address of the first cell in the array
• if x is an array identifier, then the meaning that C attaches to x is &x[0]a pointer to x[0]
• thus *x has the meaning *&x[0] or simply x[0]
46
12.7 Array identifiers as arguments
• array identifier as a pointer to an array is useful with array parameters
• e.g. , suppose we want to define a function f that returns a double and has a single intarray parameter
header might take the formdouble f (int list[])
• to call this function with an array x as argument, we might writeresult = f(x);
the value of &x[0] would then be assigned to the parameter list
47
13 Arrays (cont.)
13.1 Arrays as parameters (cont.)
• recall ideas of last day on passing an array identifier as an argument
• since the value passed to an array parameter is the address of the first cell of the argumenta function having an array parameter knows the location of the argument array
it can, therefore, alter the contents of that array
• e.g. , the function swap will switch the values of two elements in an array of double values.
void swap (double list[], int i, int j){double temp = list[i];list[i] = list[j];list[j] = temp;
}
• to show the effect of swap, suppose we have an array masses shown below.
masses 7.3 9.1 3.3 4.7 6.0
0 1 2 3 4
use numerical values for addresses
• if we then write the statementswap(masses,1,4);
the values at masses[1] and masses[4] will be switched.
masses 7.3 6.0 3.3 4.7 9.1
0 1 2 3 4
13.2 Array sizes in parameter lists
• in function headings in previous examples, we did not specify array sizeswe could have put a value inside the square bracketsbut the compiler would ignore whatever we put there
• why?value passed to the parameter is the address of the first cell of an arrayit contains no information about the size of the argument array
• if a function needs to know the size of an array, we can use a separate parameter
• e.g. , the function sum finds and returns the sum of the elements of a double array
48
double sum (double list[], int listLength){double total = 0;for (int i = 0; i < listLength; i++)sum += list[i];
return total;}
13.3 Arrays and pointers
• In C, there is a very close connection between arrays and pointerswe have already seen that an array identifier is a pointer to the first cell of an arraylots of other connections
• to examine connections, suppose we have an array declaration:int x[] = {3,7,2,4,5};
3 7 2 4 5
x[0]x[1]x[2]x[3]x[4]
• now create and initialize two pointers by writingint *p = x;int *q = &x[3];
p
?
q
?
3 7 2 4 5
x[0]x[1]x[2]x[3]x[4]
• now
*p is a synonym for x[0]
*q is a synonym for x[3]
• we can perform some arithmetic operations on pointerspointer arithmetic is restricted to:
<pointer> + < integer> // result is a pointer<pointer> − < integer> // result is a pointer<pointer> − < pointer> // result is an integer
• in evaluating expressions involving pointers, C scales resultsunit that C uses is the size of the item to which the pointer refers
49
e.g. , if p is a pointer to an int, then p+1 refers to the next int cell after pif an int occupies four bytes, then p+1 would add four to passign sample values to addresses of x to illustrate examples
• for difference between two pointers, C again scales the resulte.g. , in the array shown, q - p + 1 has the value 4
the number of int cells from p to q inclusivean expression p - q is only valid if p and q point to the same array
(or possibly one cell past the end of the array) and difference is not negative
• if p and q point to the elements of the same array,relational expressions (using ==, !=, <, >, <=, and >=) work correctly on p and q
if p and q do not refer to the same array (or possibly one cell past the end of the array)the behaviour of pointer arithmetic is undefined
• cannot normally assign an integer to a pointer nor compare a pointer to an integerone exception is the value zeroC has a named constant NULL with the value zero
usually use NULL in assignments and comparisons between pointers and zeroC guarantees that any valid address will not have the value zero
a pointer with the value NULL is guaranteed to be pointing to nothingsymbolically, we show that a pointer p has the value NULL as follows:
p
• do some examples like the following for the array x and pointers p and q shown previouslyp+1 is a pointer to x[1]p+2 is a pointer to x[2]q-- is a pointer to x[2]q-p has the value 3p-q is undefinedp < q is truep == NULL is false
• we can make references to cells of an array list in various ways:
*(list+2) is a synonym for list[2]list+3 is a synonym for &list[3]
*(list++) is a synonym for list[1]
• can often choose to use array notation or pointer notatione.g. , to read the elements of an array of double values:
void read (double list[], int size){
50
for (int i = 0; i < size; i++)scanf("%lf",&list[i]);
}
void read (double *p; int size){for (int i = 0; i < size; i++)scanf("%lf",p+i);
}
• a swap function using pointersdevelop the following
void swap (double *p, int i , int j){int temp = *(p+i);
*(p+i) = *(p+j);
*(p+j) = temp;}
51
14 Dynamic Array Allocation and 2D Arrays
14.1 Introducing malloc and free
• We now know that pointers and arrays are closely related.
An array identifier is a pointer to the first array element.
• Two ways of specifying arrays as function parameters:
double getAverageGrade (double classGrades[]) { ... } ordouble getAverageGrade (double *classGrades) { ... }
We can use either form interchangeably!
• So far, the sizes of our arrays were specified in the program.
e.g. , double listOfMarks[100];
• However, there are situations where we don’t know how big the array needs to be until theprogram is running.
e.g. , Say the number of students in the class is input from scanf(...)We may know there will never be more than 10000 students, so one option is to always
(conservatively) create arrays of the maximum possible size.e.g. , double listOfMarks[10000];
⇒ uses up memory quickly and unnecessarily!!
• C allows us to dynamically create an array while the program is running (AKA, at run-time).
• We use a special function malloc(...) to reserve memory space for an array at run-time.
malloc means “Memory ALLOCation”.
• We use a special function free(...) to let go of the space, when we don’t need the arrayanymore.
This is different from what we’ve seen so far; before, we didn’t have to worry aboutreleasing memory.
int main (void) {
int numStudents;
printf("Enter number of students in the class?\n");scanf("%d", &numStudents);
double *listOfMarks;
52
// reserve memory for an array to hold the student markslistOfMarks = (double *)malloc(numStudents * sizeof(double));
... // other things happen
free(listOfMarks); // let go of the memory we reserved.
}
• e.g. , say numStudents is 100 and storing a double uses 8 bytes, then malloc will reserve100*8 = 800 bytes of memory and return a pointer to the reserved memory.
• More examples:
int numberOfRecords = 66;int familyNameLength = 100;
char *familyNames = (char *)malloc(familyNameLength*sizeof(char));int *agesOfParticipants = (int *)malloc(numberOfRecords*sizeof(int));
• Watch out!: The entries in such arrays are not initialized by malloc.
• For now, just comment on why free(...) is needed and consequences of not using it.
• Refer them to Section 10.2 of text.
14.2 Two-dimensional arrays
• conceptit is often useful to be able to store data in a tabular form
• we can easily create such a structure in C#define ROWS 3#define COLS 6
int table[ROWS][COLS];
• can think of this as 3 rows, 6 columns
• note that cells are not initialized
• draw diagram
53
0 1 2 3 4 5012
rows
columns
54
15 Arrays of Higher Dimensions
15.1 Initialization of 2D Arrays
• can initialize arrays in declarations (as we did with one-dimensional arrays)
• int stuff[3][4] = {{9,4,5,7},{6,2,3,8},{7,1,0,4}
};
• note: semi-colon, commas
• can omit inner brace bracketscan write all values on one line
• if we do not initialize in declaration, we can use nested for statements
for (int row = 0; row < ROWS; row++)for (int col = 0; col < COLS; col++)table[row][col] = 0;
15.2 Storage of 2-D arrays
• we think of these arrays as rectangular
• actually stored linearly — in row major ordere.g. , for the array table
0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5
0 0 0 0 0 0 1 1 1 1 1 1 2 2 2 2 2 2table
rows
columns
• develop formula for locating element table[i][j]
&table[i][j]= &table[0][0]+ sizeof(int)(i× COLS + j)
15.3 Higher dimensional arrays (cont.)
• no problem
• think of 2D as a rectangular table with rows and cols3D — book containing pages of tables
indices are [page][row][col]4D — a set of books of pages of tables
indices are [volume][page][row][col]etc.
55
15.4 Multi-dimensional arrays as parameters
• All dimensions except (possibly) first must be specified
• e.g. , double f (double table[][COLS])
• need COLS to be able to locate element table[i][j]
15.5 Dynamic Allocation of Two-Dimensional Arrays
• Can also use dynamic allocation for 2D arrays.
• e.g. , allocate a 100 X 100 matrix of integers
int **matrix;
// allocate the first dimension (rows)matrix = (int **)malloc(100*sizeof(int *));
for (int i = 0; i < 100; i++){
// allocate the second dimension (columns)matrix[i] = (int *)malloc(100*sizeof(int);
}
... // other things happen
for (int i = 0; i < 100; i++)free(matrix[i]); // let go of the columns
free(matrix); // let go of the rows
• As before, no initialization is done by malloc.
• Can pass a 2D array to a function like this: void foo (int **matrix)
56
16 Strings
16.1 Review of strings
• so far, we have seen string constants (literals)e.g. , "Hello, world"
• in C, strings are stored as arrays of charactersterminated by the null character ’\0’Inside the computer, the null character is represented as zero.
• e.g. , the string "Hello" would be stored as the 6 character array
’H’ ’e’ ’l’ ’l’ ’o’ ’\0’
• the empty string "", would be stored as a one-element array
’\0’
16.2 String literals and characters
• be careful not to confuse strings and characters
• e.g. , consider ’$’ and "$"first is a single character, second is an array of two characters: ’$’ and ’\0’
• note thatprintf("\n"); // is valid (it prints a newline character)printf(’\n’); // is not valid
16.3 String variables
• an array of characters terminated by ’\0’
• to declare a string, use something like#define LENGTH 20char s[LENGTH+1];
explain use of +1
• actual length of string does not need to be equal to space allocatedthis is only the maximumcan store shorter strings
• can initialize strings in declarationse.g. , char s[] = "An example"
show result
57
• can provide a length when initializinge.g. , char t[8] = "Junk";
show result — padding with ’\0’if length is too small, this is illegal
16.4 Character arrays vs. character pointers
• consider the following declarations:char s[] = "An example";char *t = "An example";
• draw diagrams to illustrate results
• in the character version, we can alter the values of the individual characterss is an array that can be manipulated like any other array
in the pointer version, an attempt to alter a character may cause a compilation errorwhy? — because C takes t to be a pointer to a string constant
it may not take kindly to any attempt to alter that constant
• in the pointer version, t is a variable that can be assigned to point to a different charactere.g. , we can write t = "Another string";
for the array version, we cannot write s = "new string";as that is an attempt to alter an entire array
16.5 Accessing the characters in a string
• since strings are arrays of characters, we can use array techniques to access characters
• e.g. , count the number of blanks in a string s
int blankCount = 0;for (int i = 0; s[i] != ’\0’; i++)if (s[i] == ’ ’)blankCount++;
• note use of ’\0’ rather than length to find end of string
16.6 Writing strings
• can use printf to print a stringbasic conversion specification is %s
• e.g. , string sample = "An example"printf("Result: %s\n",sample);will print Result: An example
• can use modifications to %s to control printinge.g. , printf("Result: %.5s\n",sample);
will print Result: An ex(prints the first 5 characters)
58
16.7 Reading strings
• can use scanfe.g. , scanf("%s",s);
no ampersand — why?scanf skips leading white space, reads characters until it hits white space, adds a ’\0’
• can use getse.g. , gets(s);
Only takes a single argument.gets does not skip white space, reads until it hits end of line, adds a ’\0’
• can read character by character using getcharcall to function has form getchar()returns the next character from the input
• write a loop to read a stringbe sure they understand various features
char c;int i = 0;while (i < LENGTH && (c = getchar()) != ’\n’)
s[i++] = c;s[i] = ’\0’;
59
17 Strings (cont.)
17.1 Printing and pointer arithmetic
• suppose we have char *p = "Sample";
• examine output for each of the followingprintf("%s\n",p); prints Sampleprintf("%s\n",p+2); prints mpleprintf("%c\n",*p); prints Sprintf("%c\n",*(p+2)); prints mprintf("%c\n",*p+2); prints U
17.2 Introduction to the string library
• C has a number of functions for manipulating stringsto use most of them, write:
#include <string.h>
17.3 Determining the length of a string
• the function size_t strlen (const char *p)takes one string argumentreturns an integer: the length of the argument
type of integer returned (size_t) is an unsigned integer value
• i.e. it returns the number of characters up to ’\0’
• examples
• we could write our own version of this functiondevelop the following:int stringLength (const char *p){int i = 0;while (*(p+i) != ’\0’)i++;
return i;}
• we can simplify this to some extentdevelop the followingint stringLength (const char *p){int i = 0;while (*(p+i))i++;
return i;}
60
• we can write a pure pointer versiondevelop the following
int stringLength (const char *p){const char *q = p;while (*q)q++;
return q-p;}
17.4 Copying a string
• the function char *strcpy (char *dest, const char *source)copies characters from source to dest
like an assignment statement, destination is on the leftstops when it copies ’\0’returns a pointer to the destination stringreturn value is usually discardedWatch out: you must have enough space in the destination string!
• to be continued next day
61
18 Strings (cont.)
• last day, we looked at the function strcpy that copied one string to another
• we can write our own version of this functionstart by developing the following
void stringCopy (char *p, const char *q){while (*q != ’\0’){
*p = *q;p++;q++;
}
*p = ’\0’;}
• then simplify this to
void stringCopy (char *p, const char *q){while ((*p = *q) != ’\0’){p++;q++;
}
*p = ’\0’;}
• then simplify this to
void stringCopy (char *p, const char *q){while ((*p++ = *q++) != ’\0’);
}
• finally simplify this to
void stringCopy (char *p, const char *q){while (*p++ = *q++);
}
18.1 Concatenating two strings
• the function strcathas headerchar *strcat (char *dest, const char *source)
62
• it concatenates a copy of source onto the end of destthe ’\0’ in dest will be overwrittena ’\0’ will be written at the end of the new stringreturn value is usually discarded
• it is the programmer’s responsibility to make sure that there is space for the new stringe.g. ,
char s[4] = "Oh";char t[] = "No";strcat(s,t); // Wrong
explain problem
18.2 Comparing strings
• the function int strcmp (const char *p, const char *q) compares two strings
• it returnsa negative value if first string precedes secondzero if strings are identicala positive value if first string follows second
• function uses lexicographic orderingbased on encoding of characters
dictionary order if all upper case letters or all lower case lettersall upper case letters precede all lower case letters (in ASCII and Unicode)blank precedes all letters"sam" precedes "same"
• typical usage: if (strcmp(a,b) < 0)// a precedes b
18.3 Some other string functions (briefly)
• int atoi (const char *s)returns an integer using leading characters of sbehaviour is undefined if no valid charactersto use it, need #include <stdlib.h>
• double atof (const char *s)returns a double using leading characters of sbehaviour is undefined if no valid charactersto use it, need #include <stdlib.h>
• char *strchr (const char *s, int c)returns a pointer to the first occurrence of the character c in sreturns a null pointer if c is not foundbrief note on use of int for a character
63
• char *strstr (const char *s1, const char *s2)returns a pointer to the first occurrence of s2 in s1if s2 is not found in s1, function returns NULL
• there are others but they are not our concern
64
19 Strings (cont.) and Recursion
19.1 Arrays of strings
• suppose we want to have an array of the names of the months of the year
• we could write char months[][9] = {"January", "February", ... , "December"};show result — a rectangular array
spaces are padded with ’\0’ as necessary
• as an alternative, we can create an array of pointers, each pointing to a stringwe could do this by writing char *months[12];
result is an array of pointers (of type char *)we could initialize the array by writing
months[0] = "January";months[1] = "February";etc.
• could also have done initialization in declarationchar *months[] = {"January", ... , "December"};
• draw diagram — no space wasted in stringsalthough extra space required for pointers
19.2 Command line arguments
• in C the main function has two forms — either zero or two parameterswe can write the header of main as follows:
int main (int argc, char *argv[])argument count and argument vector
• as an example, if we have an executable file called stuff, we can writestuff foo bar
now argc is set to 3, the number of arguments (including the file name)and argv is an array of pointers to strings
elements of the array areargv[0] = "stuff"argv[1] = "foo"argv[2] = "bar"argv[3] = NULL
• draw a diagram
65
argv
argv[0]
argv[1]
argv[2]
argv[3]
- "stuff"
-"foo"
-"bar"
• frequently we use command line arguments in error checkinge.g. , if stuff requires two other arguments, we could write
int main (int argc, char *argv[]){
if (argc != 3){printf("Usage: stuff <infile> <outfile>\n");exit(0);
}
• develop a program that prints its command line arguments
int main (char argc, char *argv[]){int i;for (i = 0; i < argc; i++){
printf("%s",argv[i]);if (i < argc - 1)printf(" ");
elseprintf("\n");
}return 0;
}
• perhaps note that argv can be treated as a pointer to an array of pointersthe identifer argv represents &argv[0]then see what happens if we replace printf("%s",argv[i]);with
printf("%s",*argv + i); will print: stuff tuff uffprintf("%s",*(argv + i)); will print: stuff foo barprintf("%s",*(argv + i) + i); will print: stuff oo rprintf("%c",*(*(argv + i) + i)); will print: s o r
19.3 Recursion
• introduce recursion by examining expression evaluation — BEDMAShave them develop algorithm by explaining meaning of acronym
66
try to get them to see the recursive aspect of the algorithm
• essential features of any recursive processprocess is defined in terms of a “simpler” version of itselfmust be some simple case that stops the recursion
a base case or simple or terminating caseeach step takes us closer to the base case.
19.4 Recursion in everyday processes
• consider problem of walking across roomone step at a time
• old way of thinking: a loopkeep taking steps until we reach the wall
• new way of thinkingto WALK ACROSS A ROOM
if we are at the far wallwe are done // simple case
elsetake one stepWALK ACROSS THE REST OF THE ROOM
• Another example – say we have a huge chunk of cake we want to cut into pieces that are nobigger than 100 grams
CUT THE CAKE(CHUNK)if CHUNK <= 100 grams
this CHUNK is small enough.else
Cut CHUNK down the middle into 2 pieces, a LEFT CHUNK and a RIGHT CHUNKCUT THE CAKE(LEFT CHUNK)CUT THE CAKE(RIGHT CHUNK)
19.5 Recursively defined functions
• defining and evaluating a term
• consider an example something like
f(n) =
{
2f(n − 1) + 1 n > 0
3 n = 0
analogy with phoning and putting people on hold
67
• note inefficiency of recursion with functionsrecursive statement of function definition may be very simplerecursive implementation is very inefficient
recursion should not be used for this purpose
• as we shall see later, there are situations thathave the simplicity of recursionare still efficient
68
20 Recursion (cont.)
20.1 Implementing recursion in C
• computing values of
f(n) =
{
2f(n − 1) + 1 n > 0
3 n = 0
• develop following functionassuming valid argument values
int f (int n){int value;if (n == 0)value = 3;
elsevalue = 2*f(n-1) + 1;
return value;}
20.2 Another example — n!
• recall non-recursive definitionsuggest computation using a loop
• show how to form recursive definition — with base of 0! = 1
• develop following code
int factorial (int n){int value;if (n < 0){printf("Invalid argument to factorial - 0 returned\n");value = 0;
}else if (n == 0)value = 1;
elsevalue = n * factorial(n-1);
return value;}
• note that we could also write the definition as:
69
int factorial (int n){if (n < 0){printf("Invalid argument to factorial - 0 returned\n");return 0;
}if (n == 0)return 1;
return n * factorial(n-1);}
• chat briefly about merits of each form
20.3 Towers of Hanoi
• show problem with something visual (mixing bowls work well)
• develop algorithm and then show code
void moveTower (int height,int start,int finish){if (height == 1)printf("%d ---> %d\n",start,finish);
else{int other = 6 - (start + finish); // explain!moveTower(height-1,start,other);printf("%d ---> %d\n",start,finish);moveTower(height-1,other,finish);
}}
• look at timing brieflyAn Ancient Lengend: Monks near Hanoi came across 64 disks mounted on one of three
needles.universe is to end when monks finish their task
show that one move per second gives about 5.8 × 1011 yearscompare to time since big bang — about 1.4 × 1010 years
• note that algorithm is exponential — such algorithms are totally impractical
70
21 Recursion (cont.)
21.1 Printing patterns recursively
• e.g. , printing a row of stars
void printRow (int n){if (n < 1) // simple case could also be n == 1 - discussprintf("\n");
else{printf("*");printRow(n-1);
}}
• e.g. , printing a triangle of stars of the form
***************
• develop ideahave them think about details of a C function
• develop code for function to print the trianglenote that base case (n == 0) requires that we do nothing
void printTriangle(int n){if (n > 0){printRow(n);printTriangle(n-1);
}}
• perhaps also look at problem of printing an inverted triangle
***************
• show how we can adapt previous function
71
Develop the following solutions slowly:
#include <stdio.h>
void printRow(int n){if (n == 1){printf("*\n");return;
}
printf("*");printRow(n - 1);
}
void printTriangle(int n){if (n == 0) return;printTriangle(n - 1);printRow(n);
}
void printPattern(int n){if (n == 0) return;printRow(n);printPattern(n - 1);printRow(n);
}
int main(void){printRow(5);printf("-\n");printTriangle(5);printf("-\n");printPattern(5);
}
21.2 Recursion with strings
• can think of a string as a character followed by a string(or a character preceded by a string)(or two characters enclosing a string)
• by thinking in these ways, we can develop recursive algorithms
72
• as an example, consider the problem of determining whether or not a string is a palindromeoutline an algorithm for this
• start with analysis of a given palindrome – step by step"racecar""aceca""cec""e"
• then develop recursive function to test for palindromes
bool isPalindromeHelper(char *s, int low, int high){bool result;if (high - low <= 0)result = true;
else if (*(s+low) != *(s+high))result = false;
elseresult = isPalindromeHelper(s,low+1,high-1);
return result;}
• note inconvenience of having to give three arguments in call
• develop develop non-recursive function
bool isPalindrome(char *s){return isPalindromeHelper(s,0,strlen(s)-1);
}
• finally, convert recursive form to a helper function with headerbool isPalindromeHelper(char *s, int low, int high)and recursive call to itself
73
22 Recursion (cont.)
22.1 Euclid’s algorithm for gcd’s
• a classic example of recursion
• develop basis of algorithm with classto find gcd(m,n)
let gcd be g
then m = ga, n = gb
g will also be a factor of m − n = ga − gb
• do an example: gcd(20, 8)
• formalize algorithm
gcd(m,n) =
m if m = n
gcd(n,m) if m < n
gcd(n,m − n) if m > n
• show how rules are applied to determination of gcd(8, 20)
• develop code
int gcd(int m, int n){if (m == n)return m;
if (m < n)return gcd(n,m);
return gcd(n,m-n);}
22.2 Determining powers efficiently
• examine problem of determining xn efficiently
• start by looking at problem of minimizing number of multiplications to find xn
e.g. , x8, x20, . . .
• try to get them to see that
xn =
(
xn
2
)2
if n is even(
xn−1
2
)2
× x if n is odd
• base casesn = 1n = 0
74
• note that we can add in negative integral exponents using x−n =1
xn
• then develop C code
double power (double x, int n){if (x == 0)if (n == 0){
printf("Invalid arguments to power - zero returned\n");return 0.0;
}else
return 0.0;if (n < 0)return 1.0/power(x,-n);
if (n == 0)return 1.0;
double temp;if (n % 2 == 0){// n is an even positive valuetemp = power(x,n/2);return temp * temp; // spend some time explaining this
}else{// n is an odd positive valuetemp = power(x,(n-1)/2)return x * temp * temp;
}}
22.3 Ackermann’s function
• brief introduction – grows faster than any exponential function.Discovered in 1920s – has significance in computability theory.
• definition
a(m,n) =
n + 1 if m = 0
a(m − 1, 1) if m > 0 and n = 0
a(m − 1, a(m,n − 1)) otherwise
• work through the evaluation of a few valuesa(0, 4) = 5a(1, 1) = 3a(2, 1) = 5
75
22.4 Maze Routing Example
• Mention briefly; refer them to book Chapter 8.
• Want to find way out of a maze, from a specific starting point, with blockages here and there.
• Can solve using recursion; basic idea is as follows:
• FIND WAY OUT OF MAZE(STARTING POINT)If we are at the exit, we’re done!Take a step West, if possible (not blocked), and use new position as “starting point” (re-
curse).Else take a step East, if possible, and use new position as “starting point” (recurse)....
• Bookkeeping to ensure we don’t revisit the same portions of maze multiple times!
76
23 Searching
23.1 Intro to searching
• problemgiven a list of values, each of which has a key (usually unique)we want to search for an item with a particular key
• in practice, we will usually be dealing with objects in which one field is the keyfor our purposes, we will simply search an array of values called list for item
• after searching for an item, we may want to do a variety of things with italter itprint itdelete itetc.
• to make the functions that we create reasonably flexible,we will simply have them return the index in the list of the itemreturn an impossible index value (−1) if we fail to find the item
23.2 Sequential search (linear search)
• explain algorithm
• develop basic C version
int seqSearch (double list[], int listLength, double item){int location = -1;for (int i = 0; i < listLength; i++)if (list[i] == item)
location = i;return location;
}
• how can we improve this?
• develop improved version
int seqSearch (double list[], int listLength, double item){int location = -1;bool found = false;for (int i = 0; i < listLength && !found; i++)if (item == list[i]){
location = i;found = true;
77
}return location;
}
• also look at and discuss shorter version
int seqSearch (double list[], int listLength, double item){for (int i = 0; i < listLength; i++)if (item == list[i])
return i;return -1;
}
23.3 Binary search
• if a list is sorted, we can take advantage of this in our searching
• lead up to idea of binary searcheach time we can eliminate half the remaining items
in fact, more than half — can eliminate middle item as well as one half
• do an examplepart 1 — item in listpart 2 — item not in list
Say we have this list: 1 5 7 8 10 12 17We want to search list for 5.Can first check middle element, 8, and see if:
It is the # we’re looking for → we’re done!It is > 5→ we only need to look in bottom-half of list!It is < 5→ we only need to look in top-half of the list
We can iterate this action repeatedly, each time cutting away 1/2 of the list.
• how do we stop the search?if successful, no problemif we fail, how do we know?
bottom and top pointers close in on each otheronce we get down to one, if we fail there, pointers cross over
23.4 Implementation of binary search
• develop code slowly, referring to example
int binSearch (double list[], int listLength, double item){int low = 0;
78
int high = listLength - 1;int location = -1;bool found = false;
while (low <= high && !found){middle = (low + high)/2;if (item == list[middle]){
location = middle;found = true;
}else if (item < list[middle])
high = middle - 1;else
low = middle + 1;}return location;
}
79
24 Searching (cont.) and Structures
24.1 Recursive binary search
• in recursive form, think of each copy of the function working on part of the problem
• new header:int binSearch (double list[], double item, int low, int high)
• develop code
int binSearch (double list[], double item, int low, int high){int location;if (high < low) // failure - item not in listlocation = -1;
else{int middle = (low + high)/2;if (item == list[middle]) // success
location = middle;else if (item < list[middle]) // try bottom half
location = binSearch(item,list,low,middle-1);else // try top half
location = binSearch(item,list,middle+1,high);}return location;
}
• note that it is a nuisance to use this functionwe can use a helper function to simplify life for a useruser’s call might take the form
position = binSearch(values,valuesLength,item);
• function called by user has form
int binSearch (double list[], int listLength, double item){return binSearchHelp(item,list,0,listLength-1);
}
• rename recursive function as binSearchHelp
24.2 Structures
• a collection of related itemscan be of different types
e.g. student records
80
• to define a structure, we can use the formstruct{
variable declarations} <identifier list>;
• an examplestruct{int itemNumber, quantity;char size;double price;
}x,y;this creates two variables, x and y with the defined structure
• if we wish to create an identifier that can be used to declare structures elsewhere,we can use an identifier called a tag to name the structurestruct<tag>
{<variable declarations>
};
• an examplestruct date{int year, month, day;
};
• such a definition of a structure does not declare anythingto do so, we can write a declaration as follows:
struct date today, momBirthday;we must use the word struct — cannot simply say date today;
• items in the structure are called memberssometimes fields, components
• can combine definitions and declarationsstruct date{int year, month, day;
}today, momBirthday;defines a structure and declares two variables of that type
• can shorten declarations using typedefe.g. typedef struct date Date;
this sets Date as a synonym for struct datecan now make declarations:
Date anniversary;note convention for typedef identifiers: upper-lower
81
• other examples of use of typedeftypedef double Real;typedef char * CharPointer;
• can do typedef at point of definition of structtypedef struct date{int year, month, day;
} Date;
• if using a typedef, we may not need a tagbut, as we shall see later, we often need both the tag and the typedef synonym
• we can initialize members of a structure while declaringe.g. struct date confederation = {1867,7,1};
if some fields are omitted, they are set to zero
24.3 References to members of structures
• use dot notatione.g. today.year = 2004;
• can have pointers to structurese.g. a pointer to a Date structure called today
Date today = {2007,3,28};Date *p;p = &today;
draw diagram
• to set year to 2004, we can write:(*p).year = 2004;
note need for parentheses
• We need to do this very often, so C has a special short-hand notation:p->year = 2004;read as “p’s year”
82
25 Dynamic Memory Allocation and Linked Lists
25.1 Practice with dynamic memory allocation
• Recall malloc from our work with arrays.
• Can use malloc with structures that we define ourselves:malloc is not solely limited to already-defined types like int, doubleDate *q = (Date *) malloc(sizeof(Date));draw a diagramthen q->day = 28; sets the day field to 28
• Could write a function that allocates memory space for an int and returns a pointer to thatmemory space:
#include <stdio.h>#include <stdlib.h>typedef int *IntPointer;
IntPointer newInt (void){Intpointer p = (IntPointer)malloc(sizeof(int));if (p == NULL)printf("\nError - Insufficient memory\n");
return p;}
int main (void){IntPointer p,q;p = newInt();q = newInt();
*p = 3;
*q = 4;printf("%d %d %d\n",*p,*q,*p+*q);
*p *= *q;printf("%d\n,*p);free(q); // don’t forget to avoid ‘‘memory leaks’’q = p;printf("%d\n",*q);free(p);return 0;
}
83
25.2 Linear lists
• often it is useful to separate the problems ofwhat we want to dohow we are going to do it
• as an example, we often want to work with a linear lista finite sequence of nodes together with certain operations
a node is an undefined term — some collection of datapossible operations
start a new, empty listinsert a new item into the listdelete an item with a given valuesearch for an item in the listprint the listetc.
• the concept of a linear list is an example of an abstract data type or ADT
• nothing in the ADT to talk about implementationsimply a collection of data and abstract functions to manipulate the data
• to implement such an ADT, we could useindividual cellsarraysother structures — as we shall see shortly
25.3 Introduction to linked lists
• we have seen that we can create linear lists using arrays
• a problem with such an implementationinsertions and deletions require a great deal of data movement
• a solution to this is to use linked allocation
• draw a diagram showing a linked list of nodes
• show insertion, deletion pictorially
25.4 Implementation of linked lists
• suppose that the items to be stored in the list are integers
• each node of the list will contain two fieldsinfo — an information fieldlink — a pointer to the next node
• we can create a structure to define these items
84
typedef struct node{int info;struct node *link;
} Node;
• add NodePointer to typedefeither after original typedef
typedef Node *NodePointer;or as part of original typedef
} Node, *NodePointer;
25.5 Creating nodes for a linked list
• if we want to create a linked list, we need to be able to create a single node
• develop a function to:allocate memory for a nodeplace values into its membersreturn a pointer to this node
NodePointer newNode (int i, NodePointer np){NodePointer p = (NodePointer)malloc(sizeof(Node));if (p == NULL)printf("\nError - out of memory\n");
else{p->info = i;p->link = np;
}return p;
}
85
26 Linked Lists (cont.)
26.1 Building a linked list — an elementary approach
• recall from last day a function to create a new nodeNodePointer newNode (int i, NodePointer np)
• to begin creating a list, we could write, in our main function, for example,NodePointer head1 = newNode(7,NULL);to give us a new element containing 7 in its info field
• illustrate result
• if we want to build a list. we could do so by writinghead1->link = newNode(4,NULL);
• show diagram
• we could continue withhead1->link->link = newNode(8,NULL);
• show new diagram
• againhead1->link->link->link = newNode(2,NULL);
• add this diagram
• this, clearly, gets silly
• we need some other solution
26.2 Avoiding excessive link references
• one solution to this problem:try to build the list at the head, rather than at the tail
• develop an example — with lots of diagrams
• start withNode head2 = newNode(8,NULL);
• then add a node in front of thishead2 = newNode(5,head2);lots of time explaining this
• then add a third nodehead2 = newNode(2,head2);
86
26.3 Inserting into the front of linked list
• Function that accepts pointer to the linked list and returns a pointer to the new head of thelist.
Node* insertAtFront(int item, Node* head){return newNode(item, head);
}
// usage ... for example in main(...)
node* headOfList = NULL;headOfList = insertAtFront(3, headOfList);headOfList = insertAtFront(5, headOfList);headOfList = insertAtFront(7, headOfList);
• Draw a diagram to illustrate it.
26.4 Moving along a linked list
• suppose we want a function that prints the items in a linked list
• suppose we have previously created a linked list with an arbitrary number of nodesthe pointer head points to the first node in the list
• show diagram
• develop the following (carefully and slowly)
void printList (NodePointer head){NodePointer current = head;while (current != NULL){printf("%d\n",current.info);current = current->link;
}}
26.5 Deletion of first item in a list
• draw diagrams: before and after
• develop following (incorrect) code
void deleteFirst (NodePointer head){
87
if (head == NULL)printf("\nError - attempt to delete from empty list\n");
else{NodePointer temp = head;head = head->link;free(temp);
}}
• then note problem with parameter being passed by value
• develop correct code
void deleteFirst (NodePointer *headPointer){if (*headPointer == NULL)printf("\nError - attempt to delete from empty list\n");
else{NodePointer temp = *headPointer;
*headPointer = (*headPointer)->link;free(temp);
}}
info
linkNodePointer *orNode **
NodePointer orNode *
• An alternative to avoid pointers-to-pointers is to have the function return the “new” head ofthe list.
NodePointer deleteFirst(NodePointer head) // no pointers-to-pointers{if (head == NULL)printf("\nError - attempt to delete from empty list\n");
else{NodePointer temp = head->link;free(head);return temp; // return a NEW head for the linked list
}}
• How to use this function:
88
NodePointer head;... // build-up the linked list and... // say that head is a pointer to a populated (non-empty) linked list....head = deleteFirst(head); // head is re-assigned to its successor node
89
27 Practice with Linked Lists
27.1 Searching for an element in a list
a function to determine whether or not an item is in a list
• bool contains (NodePointer head, int item){Nodepointer current = head;bool found = false;while (current != NULL && !found)if (current->info == item)
found = true;else
current = current->link;return found;
}
27.2 Deleting an entire list
• use diagram of list to show required change for list deletion
• develop code
void deleteAll (NodePointer *headPointer){while (*headPointer != NULL){NodePointer temp = *headPointer;
*headPointer = (*headPointer)->link;free(temp);
}}
• Alternative style uses no pointers-to-pointers
void deleteAll(NodePointer head){while (head != NULL){
NodePointer temp = head;head = head->link;free(temp);
}}
• After calling this alternative implementation, don’t forget to set the head pointer to NULL.
90
27.3 Insertion into the tail of a linked list
• we can adapt the traversal technique for printing a list to many situations
• as an example, a function to insert a new node as the last node of a list
• develop the following:
void insertAtTail (NodePointer *headPointer, int item){if (*headPointer == NULL)
*headPointer = newNode(item,NULL);else{NodePointer current = *headPointer;while (current->link != NULL)
current = current->link;current->link = newNode(item,NULL);
}}
• note that we control the loop using current->link != NULLbefore we used current != NULLwhy the change?
• Alternative implementation returns a new head pointer (which may be the same as the oldhead pointer! ask them when?)
NodePointer insertAtTail(NodePointer head, int item){if (head == NULL)return newNode(item, NULL);
else{
NodePointer current = head;for (; current->link != NULL; current = current->link)
;current->link = newNode(item, NULL);return head;
}}
27.4 Deletion of last item in a list
• draw diagrams
• spend lots of time showing that traversal must stop at second last node
91
• note that there are now two special casesempty listlist with a single node
• develop code
void deleteLast (NodePointer *headPointer){if (*headPointer == NULL)printf("\nerror - attempt to delete from empty list\n");
else if (*headPointer->link == NULL){free(*headPointer);
*headPointer = NULL;}else{NodePointer current = head;while (current->link->link != NULL)
current = current->link;free(current->link);current->link = NULL;
}}
• Alternative returns a new head:
NodePointer deleteLast (NodePointer head){if (head == NULL)printf("\nerror - attempt to delete from empty list\n");
else if (head->link == NULL){ // deleting the last guy in the listfree(head);return NULL;
}else{NodePointer current = head;while (current->link->link != NULL)
current = current->link;free(current->link);current->link = NULL;return head; // head isn’t changed in this case
}}
92
27.5 Insertion into an ordered list
• draw diagrams: before and after
• show need to look ahead in comparisonscould use temp->link->link approach as in tail deletion
• as an alternative, use two references that traverse the list in tandemcurrent and previous
• draw diagrams showing previous and current on either side of gapeasy to change links once we have this situation
• sketch processnote that lists with zero nodes or one node may be special cases
• if there is time, develop the following
void insert (NodePointer *headPointer, int item){Node current, previous;bool found = false;current = *headPointer;while (!found && current != NULL)if (item < current->info)
found = true;else{
previous = current;current = current->link;
}NodePointer newOne = newNode(item,current);if (current == *headPointer)
*headPointer = newOne;elseprevious->link = newOne;
}
• Again, an alternative returns a new head...
Node *insert(Node* head, int item){
Node* current = head;if (item < current->item) {return newNode(item, head); // a new head to the list
}else {// need to find the right spot to insert// use a different style to spice things ...
93
bool foundSpot = false;while (!foundSpot){
if (current->link && (item < current->link->item)foundSpot = true;
else if (!current->link)foundSpot = true;
elsecurrent = current->link;
}current->link = newNode(item, current->link);return head;
}}
94
28 Linked lists and Recursion
28.1 Recursive structure of a linked list
• we can think of a linked list recursively as beingeither emptyor composed of two parts:
the first node — the headthe other nodes — the tail
• show them a diagram
head
3info
link
9info
link
2info
link
- - - p p p
The tail
• thinking in this way, we can develop recursive algorithms to process a listsimple case:
the empty listnon-simple case:
take care of the headprocess the tail recursively
28.2 Printing a linked list recursively
• for the simple case here, we have nothing to do
• otherwise, weprint the head’s infodo the tail recursively
• develop the following
void printList (NodePointer head){if (head != NULL){printf("%d\n",head->info);printList(head->link);
}}
• we could then call this by writing
95
NodePointer myListHead;.. // list gets built and other things happen.
printList(myListHead);
28.3 Deleting a linked list recursively
•void deleteList(NodePointer head) {if (head != NULL) {
NodePointer next = head->link;free(head);deleteList(next);
}}
• We can call this function as follows:
• NodePointer myListHead;.. // list gets built and other things happen.
deleteList(myListHead);myListHead = NULL;
28.4 Searching for an item in a list
• a boolean function that returns true iff an item is in a list
• bool contains (NodePointer head, int item){bool result;if (head == NULL)result = false;
else if (head->info == item)result = true;
elseresult = contains(head->link,item);
return result;}
28.5 Comparing two lists to see if they are identical
• a boolean function that will return true iff two lists containexactly the same items in exactly the same order
96
• bool identical (NodePointer head1, NodePointer head2){bool result;if (head1 == NULL && head2 == NULL)result = true;
else if (head1 == NULL || head2 == NULL)result = false;
else if (head1->info != head2->info)result = false;
elseresult = identical(head1->link,head2->link);
return result;}
28.6 Insertion into an ordered list
• develop the following, slowly and carefully
• void insert (NodePointer *headPointer, int item){if (*headPointer == NULL || item < (*headPointer)->info)
*headPointer = newNode(item,*headPointer);elseinsert(&((*headPointer)->link),item);
}
• (Simpler?) recursive alternative uses a “helper function”:
void insert(NodePointer* headPointer, int item){if (*headPointer == NULL) // list is empty
*headPointer = newNode(item, NULL);else if (item < (*headPointer)->info) // new front of the list
*headPointer = newNode(item, (*headPointer)->link);elseinsert_helper(*headPointer, (*headPointer)->link, item);
}
void insert_helper(NodePointer prev, NodePointer curr, int item){ // no pointers to pointers on the function signature
if ((curr == NULL) || (item < curr->info)){ // found the insertion spotprev->link = newNode(item, curr);
}
97
else // move alonginsert_helper(curr, curr->link, item);
}
98
29 Sorting
29.1 Introduction to Sorting
• Sorting is used all over the place in computingiPod sorts your songs by title or by artistExcel can sort your spreadsheet data by values in a columnNotion of alphabetical orderTelephone book sorted by last name
• chat briefly about variety of sorting techniquesfairly vague discussion
• usually sorting data on some keypossibly SIN, etc.we will simply be sorting elements in an array
• we will be examining four or five sorting algorithmssometimes very different approaches to problem
29.2 Selection sort
• discuss idea and give an exampleFind the largest element in an array, put it at the end.Find the next-largest element in the array, put it in the next-to-last spotand so on....
• develop code for selection sort slowlystart with code for one pass
then wrap this in an outer loop
void selectSort (double list[], int listLength){int top, largeLoc, i;
for (top = listLength - 1; top > 0; top--){// find largest from 0 to toplargeLoc = 0;for (i = 1; i <= top; i++)
if (list[i] > list[largeLoc])largeLoc = i;
// put largest at topdouble temp = list[top];list[top] = list[largeLoc];list[largeLoc] = temp;
99
}}
• note possible variationcould start by putting smallest in first locationseen in some texts
• sort is easily adapted to finding top ten, bottom three, etc.
29.3 Insertion sort
• discuss algorithm informally and give an exampleFirst sort the first two items in the list (maybe just a swap).Next, take the third item, and put it in the right place within the first three items.
We may have to shift things to make space for it.Next, take the fourth item, and put it in the right place within the first four items.and so on...
• point out tricky bitinsert when we find a smaller value or when we get to front of list
• note that it may take a lot of time to execute algorithm if list gets long
int top, i;
for (top = 1; top < listLength; top++){double item = list[top];int i = top;while (i > 0 && item < list[i-1]){list[i] = list[i-1]; // shift data to the right to make spacei--;
}list[i] = item;
}
100
30 Sorting (cont.)
30.1 Bubble sort
• analogy of children ordering themselves by height in a lineif each child is happy with immediate neighbours, entire line is ordered
• discuss algorithm and give an example
• note problem with small values taking many passes to get to final locationcocktail shaker sort helps to some extent
discuss it briefly
• generally, bubble sort is very slow — don’t use it
int top, i;for (top = listLength - 1; top > 0; top--) // going downfor (i = 0; i < top; i++) // walking upif (list[i] > list[i+1]) // big item ‘‘bubbles up’’
{temp = list[i];list[i] = list[i+1];list[i+1] = temp;
}
• Optimization: if no moves within one outer-loop iteration, can bail out, as list must be sorted.
30.2 Quicksort
• discuss algorithm and illustrate it with cardsmake sure that they understand the idea of partitioning about a pivot element, KIn the first step: we are going to move K into its right and FINAL position and it will not
be moved again!Items to its left are unsorted, but they are all < K.Likewise, items to its right are unsorted by > K.
Kitems < K items > K
• once we have partitioned the list, we apply the partitioning to the sublists
• usually implement quicksort recursively as:non-recursive partition of a sublistrecursive call to quicksort left sublistrecursive call to quicksort right sublist
101
• Algorithm example action (pp. 345 of text)
• simple case is a sublist with fewer than two itemsin simple case, nothing to do
• develop the following code
void quickSort (double list[], int low, int high){if (low < high){double pivot = list[low];int left = low;int right = high;
while (left < right){
while (list[right] >= pivot && left < right)right--;
list[left] = list[right];
while (list[left] <= pivot && left < right)left++;
list[right] = list[left];}list[left] = pivot; // or list[right] - same spot
quickSort(list,low,left-1);quickSort(list,right+1,high);
102
}}
• make recursive form of function a helper functionwith extra parameters for bounds
• user calls the following function
void quickSort (double list[], int listLength){quickSortHelp(list,0,listLength-1);
}
• helper function then works recursively, calling itself as necessary
• note that recursion is really helpful herekeeps track of bounds of sub-lists without extra work on our part
30.3 A problem with quicksort (and a solution)
• if we want the sort to work efficiently,the sublists should be of (approximately) equal size(most of the time)
• if we always choose leftmost item as pivot, we may get lopsided lists
• one solution is to look at leftmost item, middle item, rightmost itemchoose median of these as pivot
(swapping if necessary to get it to left end of sublist)then proceed as before
103