Program and Programming Style: The Practice of Programming
Program and Programming Style: The Practice of Programming
Programming Style
1
Program and Programming Style
2
Goals of this Lecture
• Why?
• A large program that is well styled is easier to maintain
(and more likely to be correct) than a large program that
is poorly styled
• A power programmer knows the qualities of a well styled
program, and how to go about developing one
3
Overview
• Program style: What are the qualities of a good
program?
• Well structured
• Uses common idioms
• Uses descriptive names
• Contains proper comments
• Modular
5
Program Style
• Who reads your code?
• Compiler
• Other programmers
• Which of them cares about style?
typedef struct{double x,y,z}vec;vec U,black,amb={.02,.02,.02};struct sphere{
vec cen,color;double rad,kd,ks,kt,kl,ir}*s,*best,sph[]={0.,6.,.5,1.,1.,1.,.9,
.05,.2,.85,0.,1.7,-1.,8.,-.5,1.,.5,.2,1.,.7,.3,0.,.05,1.2,1.,8.,-.5,.1,.8,.8,
1.,.3,.7,0.,0.,1.2,3.,-6.,15.,1.,.8,1.,7.,0.,0.,0.,.6,1.5,-3.,-3.,12.,.8,1.,
1.,5.,0.,0.,0.,.5,1.5,};yx;double u,b,tmin,sqrt(),tan();double vdot(A,B)vec A
,B;{return A.x*B.x+A.y*B.y+A.z*B.z;}vec vcomb(a,A,B)double a;vec A,B;{B.x+=a*
A.x;B.y+=a*A.y;B.z+=a*A.z;return B;}vec vunit(A)vec A;{return vcomb(1./sqrt(
vdot(A,A)),A,black);}struct sphere*intersect(P,D)vec P,D;{best=0;tmin=1e30;s=
sph+5;while(s--sph)b=vdot(D,U=vcomb(-1.,P,s-cen)),u=b*b-vdot(U,U)+s-rad*s -
rad,u=u0?sqrt(u):1e31,u=b-u1e-7?b-u:b+u,tmin=u=1e-7&&u<tmin?best=s,u:
tmin;return best;}vec trace(level,P,D)vec P,D;{double d,eta,e;vec N,color;
struct sphere*s,*l;if(!level--)return black;if(s=intersect(P,D));else return
amb;color=amb;eta=s-ir;d= -vdot(D,N=vunit(vcomb(-1.,P=vcomb(tmin,D,P),s-cen
)));if(d<0)N=vcomb(-1.,N,black),eta=1/eta,d= -d;l=sph+5;while(l--sph)if((e=l -
kl*vdot(N,U=vunit(vcomb(-1.,P,l-cen))))0&&intersect(P,U)==l)color=vcomb(e ,l-
color,color);U=s-color;color.x*=U.x;color.y*=U.y;color.z*=U.z;e=1-eta* eta*(1-
d*d);return vcomb(s-kt,e0?trace(level,P,vcomb(eta,D,vcomb(eta*d-sqrt
(e),N,black))):black,vcomb(s-ks,trace(level,P,vcomb(2*d,N,D)),vcomb(s-kd,
color,vcomb(s-kl,U,black))));}main(){printf("%d %d\n",32,32);while(yx<32*32)
U.x=yx%32-32/2,U.z=32/2-yx++/32,U.y=32/2/tan(25/114.5915590261),U=vcomb(255.,
trace(3,black,vunit(U)),black),printf("%.0f %.0f %.0f\n",U);}
7
Program Style
• Why does program style matter?
• Bugs often caused by programmer’s misunderstanding
• What does this variable do?
• How is this function called?
• Good code = human readable code
8
Structure: Spacing
• Use readable/consistent spacing
• Example: Assign each array element a[j] to the value j.
• Bad code
for (j=0;j<100;j++) a[j]=j;
• Good code
for (j=0; j<100; j++)
a[j] = j;
9
Structure: Indentation (cont.)
• Use readable/consistent indentation
• Example: Checking for leap year (does Feb 29 exist?)
if (month == FEB) { if (month == FEB) {
if (year % 4 == 0) if (year % 4 == 0) {
if (day > 29) if (day > 29)
legal = FALSE; legal = FALSE;
else }
if (day > 28) else {
legal = FALSE; if (day > 28)
} legal = FALSE;
}
Wrong code }
(else matches “if day > 29”)
Right code
10
Structure: Indentation (cont.)
• Use “else-if” for multi-way decision structures
• Example: Comparison step in a binary search. v
• Bad code low=0
if (x < v[mid]) 2
high = mid – 1; 4
else
if (x > v[mid])
5
low = mid + 1;
mid=3 7
else
return mid; 8
• Good code 10
high=6
if (x < v[mid]) 17
high = mid – 1;
else if (x > v[mid])
low = mid + 1;
else x
return mid; 10
11
Structure: “Paragraphs”
• Use blank lines to divide the code into key parts
#include <stdio.h>
#include <stdlib.h>
int main(void)
/* Read a circle's radius from stdin, and compute and write its
diameter and circumference to stdout. Return 0 if successful. */
{
const double PI = 3.14159;
int radius;
int diam;
double circum;
diam = 2 * radius;
circum = PI * (double)diam;
return 0;
}
13
Structure: Expressions
• Use natural form of expressions
• Example: Check if integer n satisfies j < n < k
• Bad code
• Good code
14
Structure: Expressions (cont.)
• Parenthesize to resolve ambiguity
• Example: Check if integer n satisfies j < n < k
• Moderately bad code
15
Structure: Expressions (cont.)
• Parenthesize to resolve ambiguity (cont.)
• Example: read and print character until the end-of-file.
• Right code
• Good code
if ((c == 'J') || (c == 'F') ||
(c == 'M') || (c == 'A') ||
(c == 'S') || (c == 'O') ||
(c == 'N') || (c == 'D'))
i = 0;
while (i <= n-1)
array[i++] = 1.0;
• Good code
19
Comments
• Master the language and its idioms
• Let the code speak for itself
• And then…
20
Comments (cont.)
• Comment sections (“paragraphs”) of code, not lines of code
#include <stdio.h>
#include <stdlib.h>
int main(void)
/* Read a circle's radius from stdin, and compute and write its
diameter and circumference to stdout. Return 0 if successful. */
{
const double PI = 3.14159;
int radius;
int diam;
double circum;
return 0;
}
22
Function Comments
• Describe what a caller needs to know to call the
function properly
• Describe what the function does, not how it works
• Code itself should be readable enough to reveal how it
works…
• If not, compose “paragraph” comments within definition
/* decomment.c */
int main(void) {
…
}
24
Function Comments (cont.)
• Good function comment
/* decomment.c */
int main(void) {
…
}
25
Modularity
• Big programs are harder to write than small ones
• “You can build a dog house out of anything.” – Alan Kay
• “A dog house can be built without any particular design, using
whatever materials are at hand. A house for humans, on the other
hand, is too complex to just throw together.” – K. N. King
27
Bottom-Up Design
• Bottom-up design
• Design one part of the product in detail
• Design another part of the product in detail
• Repeat until finished
28
Bottom-Up Design in Pgmming
29
Top-Down Design
• Top-down design
• Design entire product with minimal detail
• Successively refine until finished
30
Top-Down Design in Pgmming
31
Top-Down Design in Reality
1 1’ 1’ 1’’
2 Oops 2’ 3 2’ 3 2’’ 3’
4 Oops 4’ 5 …
32
Example: Text Formatting
• Goals of the example
• Illustrate good program and programming style, esp. function-level
modularity and top-down design
• Illustrate how to go from problem statement to code
• Review and illustrate C constructs
O
U Tune every heart and every voice. Bid every bank
withdrawal. Let's all with our accounts rejoice.
T In funding Old Nassau. In funding Old Nassau we
P spend more money every year. Our banks shall give,
while we shall live. We're funding Old Nassau.
U
T
34
Thinking About the Problem
• I need a notion of “word”
• Sequence of characters with no white space, tab, newline, or EOF
• All characters in a word must be printed on the same line
• I need to be able to read and print words
• Read characters from stdin till white space, tab, newline, or EOF
• Print characters to stdout followed by white space(s) or newline
• I need to deal with poorly-formatted input
• I need to remove extra white spaces, tabs, and newlines in input
• Unfortunately, I can’t print the words as they are read
• I don’t know # of white spaces needed till I read the future words
• Need to buffer the words until I can safely print an entire line
• But, how much space should I add between words?
• Need at least one space between adjacent words on a line
• Can add extra spaces evenly to fill up an entire line
35
Writing the Program
• Key constructs
• Word
• Line
• Next steps
• Write pseudocode for main()
• Successively refine
38
Reading a Word (cont.)
• The ReadWord() function seems easy enough to design. So let’s flesh
it out…
int ReadWord(char *word) {
int ch, pos = 0;
strcat(line, word);
(*lineLen) += strlen(word);
}
42
Printing the Last Line
…
int main(void) {
• Again, back to main().
char word[MAX_WORD_LEN + 1]; What do <No more
int wordLen; words> and <Print line
char line[MAX_LINE_LEN + 1];
int lineLen = 0; with no justification>
<Clear line buffer> mean? Those jobs seem
for (;;) {
wordLen = ReadWord(word);
easy enough that we
need not define
/* If no more words, print line
with no justification. */
additional functions…
if ((wordLen == 0) && (lineLen > 0)) {
puts(line);
return 0;
}
if (<Word doesn’t fit on this line>) {
<Print line with justification>
<Clear line buffer>
}
AddWord(word, line, &lineLen);
}
return 0;
}
43
Deciding When to Print
…
int main(void) {
• What does <Word
char word[MAX_WORD_LEN + 1]; doesn’t fit on this
int wordLen; line> mean? That’s
char line[MAX_LINE_LEN + 1];
int lineLen = 0; somewhat tricky,
<Clear line buffer> but involves little
for (;;) {
wordLen = ReadWord(word); code…
/* If no more words, print line
with no justification. */
if ((wordLen == 0) && (lineLen > 0)) {
puts(line);
return 0;
}
/* If word doesn't fit on this line, then… */
if ((wordLen + 1 + lineLen) > MAX_LINE_LEN) {
<Print line with justification>
<Clear line buffer>
}
AddWord(word, line, &lineLen);
}
return 0;
} 44
Printing with Justification
• Now, to the heart of the program. What does <Print line with
justification> mean? Certainly that job demands a distinct function.
Moreover, it’s clear that the function must know how many words are in
the given line. So let’s change main() accordingly…
…
int main(void) {
…
int numWords = 0;
<Clear line>
for (;;) {
…
/* If word doesn't fit on this line, then… */
if ((wordLen + 1 + lineLen) > MAX_LINE_LEN) {
WriteLine(line, lineLen, numWords);
<Clear line>
}
46
Printing with Justification (cont.)
void WriteLine(const char *line, int lineLen, int numWords)
{
• Let’s go
int extraSpaces, spacesToInsert, i, j; ahead and
complete
/* Compute number of excess spaces for line. */
extraSpaces = MAX_LINE_LEN - lineLen; WriteLine()
…
for (i = 0; i < lineLen; i++) {
if (line[i] != ' ')
putchar(line[i]);
else { The number
/* Compute additional spaces to insert. */ of gaps
spacesToInsert = extraSpaces / (numWords - 1);
49
Summary: Program Style
• Convey program structure
• Use spacing, indentation, parentheses
• Use idioms
• Choose descriptive names
• Choose variable and function names to enhance readability
• Use consistent naming conventions
• Compose proper comments
• Function-level comments are especially important, are for the
potential caller, and should describe what the function does, not how
it works
• Use modularity
• Divide programs into modules
• This lecture: function-level modularity
• Soon: file-level modularity
50
Summary: Programming Style
51
Appendix: The “justify” Program
#include <stdio.h>
#include <string.h>
52
Appendix: The “justify” Program
int ReadWord(char *word) {
/* Clear the given line. That is, clear line, and set *lineLen
and *numWords to 0. */
line[0] = '\0';
*lineLen = 0;
*numWords = 0;
}
/* Append word to line, making sure that the words within line are
separated with spaces. Update *lineLen to indicate the
new line length. */
int main(void) {
/* Read words from stdin, and write the words in justified format
to stdout. */
/* Simplifying assumptions:
Each word ends with a space, tab, newline, or end-of-file.
No word is longer than MAX_WORD_LEN characters. */
56
Appendix: The “justify” Program
for (;;) {
wordLen = ReadWord(word);
57