Prentice - Hall.the.c.puzzle - book.1982.SCAN DARKCROWN

Download as pdf or txt
Download as pdf or txt
You are on page 1of 196

UNIV.

OF COLORADO AT COLORADO SPRINGS

"33280 00445 4699


iW

PUZZLE
BOOK
Puzzles for the € Programming Language
QA ALAN R. FEUER
76. 73
«Cis
F48
1982
PRENTICE-HALL SOFTWARE SERIES
Digitized by the Internet Archive
in 2021 with funding from
Kahle/Austin Foundation

https://archive.org/details/cpuzzlebookO000feue_w2u4
QA /6.73.Clo F486 1382
Feuer, Alan R.
ny THD book

THE C PUZZLE BOOK

DATE DUE

ee ee
Eee as
ah ae
a eee
i sia a

Demco, Inc. 38-293


PRENTICE-HALL SOFTWARE SERIES

Brian W. Kernighan, advisor


THE C PUZZLE BOOK

Alan R. Feuer
Bell Laboratories
Murray Hill, New Jersey

PRENTICE-HALL, INC.,
Englewood Cliffs, NJ 07632
Library of Congress Cataloging in Publication Data
Feuer, Alan.
The C puzzle book.
(Prentice-Hall software series)
Includes index.
1. C (Computer program language) 2. UNIX (Computer
system) I. Title. Il. Series.
QA76.73.C15F48 001.64'24 82-5302
ISBN 0-13-109934-5 AACR2
ISBN 0-13-109926-4 (pbk.)

Editorial/production supervision: Nancy Milnamow


Cover design: Ray Lundgren
Manufacturing buyer: Gordon Osbourne

© 1982 by Bell Laboratories, Incorporated

All rights reserved. No part of this book


may be reproduced in any form or
by any means without permission in writing
from the publisher.

Printed in the United States of America

LOG 95 8) 7 Gr a 4 SZ

UNIVERSITY OF COLORADO
COLORADO SPRINGS

AUL 27 2009
We

KRAEMER FAMILY
LIBRARY

Tsen O=-L3=,049S8=5
ISBN 0-13-1099%eb-4 f{pbk-}

Prentice-Hall International, Inc., London


Prentice-Hall of Australia Pty. Limited, Sydney
Prentice-Hall of Canada, Ltd., Toronto
Prentice-Hall of India Private Limited, New Delhi
Prentice-Hall of Japan, Inc., Tokyo
Prentice-Hall of Southeast Asia Pte. Ltd., Singapore
Whitehall Books Limited, Wellington, New Zealand
CONTENTS

LEE ACE eens teens secctensnicol Sea cse wise COME ae eC c om oisdesetenaey esas page vii

PUZZLES

LOT8YS) 9) cc oceoobnace cote cache aaa een Soe emacaascd sadbrataG nadca coun pgocahictsnntee page 1

1. Basic Arithmetic Operators 3


2. Assignment Operators 5
3. Logic and Increment Operators 7
4. Bitwise Operators 9
5. Relational and Conditional Operators 11
6. Operator Precedence and Evaluation 13
IBASICMIDY DCS Sree ccc coca cag cn ceccses ores ters sfeees coe ecet oak dnc eeapis eet -wovessussers page 15
1. Character, String, and Integer Types 17

2. Integer and Floating Point Casts 19


3. More Casts 21
Included thilestrcccscsimse-.sstsatees
seenesosanrs ceceee reece meenemer sveasceceseeeaces page 23
On trolpRlow a irrccsvesecen seis ct ens cu ciateaceticsack tenuas ues daseasee seus euwestncsteeeceene page 25

1. if Statement 27
2. while and for Statements 29
3. Statement Nesting 31
4. switch, break, and continue Statements 33

Program min geStylowe ccccsetestetoedetavsetaeteneseeserseswas


oescesecece tess smeoatoeepage 35
1. Choose the Right Condition 37
2. Choose the Right Construct 39
StorapeGlassestes nme acacomeccceecnecsccecectunenccnsmectaeemuprensuenseedceter page 41
1. Blocks 43
Functions 45
More Functions 47
as
OeFiles 49
vi CONTENTS

rer page 51
Miekseawrons: niaccennees
Pointers and ‘Atrays::.c,.csccces-wstsstevsvarccoruvesirsacce
1. Simple Pointer and Array 53
2. Array of Pointers 55
3. Multidimensional Array 57

4. Pointer Stew 59
Str Gturesi ccs creo cane atvc eres baat taec eure wieecnaeaicese coneutoney eaese he tae erage page 61
1. Simple Structure, Nested Structure 63

2. Array of Structures 65
3. Array of Pointers to Structures 67
PRE PROCOSSOT vsccccecacecsnasrpeaaesiy
veetieoncai satheoasnthecaar aia: oaposadauateneveneees page 69

1. The Preprocessor Doesn’t Know C 71


2. Caution Pays 73

SOLUTIONS

OP ETATOTS Msaeccs vee cer cocvastteaw-wanieese<ncses


asa avstrae naaes avant tirvegan tarsaeeedpage 77

BaSiGel VpeSouucccesentocccrescvetevevsaeceactuvteosin
toc eestrs etree waycigeeetagVariaeeNes page 97
ASOMIT OLVELOW ssccc cecurenceugeret te at cence cay heat amen eevecenesers sera ceeee ee rate page 105
RRO SCAT Dut1G cet ovate terri ie occeviestass acer eenceneeemtoneemercera page 117
DSLOTARE CLASSESr vunsie cece gaonuterdenetacearertee
ceric otace. teasers Sen eater page 123
Pointers And ATraVS: ox, Mavtecatwe cevenansthissatsnadesgnceaeateroue
ehennen uate ances page 129
PSELTICE ECS 2rryc5 cmitreceu deeds oweaecsane tony vos trer ent ere ca coe gseredear rane a aeeontes page 141
PEC DROCCRSOL wc, crewed <agxve evetaesancie sentegeer crane rman orteemvcenesMesteecae
rene page 158

APPENDICES

Te Precedence: Ta Dlenr.ceccsesvncsessecn,
chine touereeneon oeeetteoemee eects page 165
2a AOPETACOL SoUMUIMLALY, “lOlC mertvcverres vcsnies een ereueme teenie ecneenet page 167
Pe PEL PRROUM csnivcocavieriscndGels) cocuancansuctnrveneyeaeedel tediscan Adee area page 171
H.,. TEypee Five tary Bart cisccavasisaasziden
seOoraenesha eevenna nee tees page 173
PREFACE

C is not a large language. Measured by the weight of its reference manual, C could even be
classified as small. The small size reflects a lack of confining rules rather than a lack of power.
Users of C learn early to appreciate the elegance of expression afforded by its clear design.

Such elegance might seem needlessly arcane for new C programmers. The lack of restrictions
means that C programs can be and are written with full-bodied expressions that may appear as
printing errors to the novice. The cohesiveness of C often admits clear, but terse, ways to
express common programming tasks.

Thepreseason Cabal e one is to understand the language syntax, at least


to the point where the translator no longer complains of meaningless constructions. Step two is
to know what meaning the translator will ascribe to properly formed constructions. And step
three is to develop a programming style fitting for the language; it is the art of writing clear,
concise, and correct programs.

The puesin this book ar designedto help the throughthe


render secondstepThey will
challenge the reader’s mastery of the basic rules of C and lead the reader into seldom reached
corners, beyond reasonable limits, and past a few open pits. (Yes, C, as all real languages, has
its share of obscurities that are learned by experience.)

Thepuzzles should notbereadassamples ofgoodcoding;inde, some of the code is


a ; expected. Often the same qualities that make a program poor make
a puzzle interesting:
e ambiguity of expression, requiring a rule book to interpret;
e complexity of structure, data and program structure not easily kept in one’s head;
e obscurity of usage, using concepts in nonstandard ways.

C is still an evolving language. Depending upon the vintage of your local compiler, some of
the features explored here may not be implemented and some of the implemented features may
not be explored here. Fortunately, the evolution of C has proceeded uniformly, so it is very
unlikely that your compiler will have a feature implemented in a different way than described
here.

HOW TO USE THIS BOOK

book is divide sections with one major topic per section. Each section comprises C
programs that explore different aspects of the section topic. The programs are sprinkled with
print statements. The primary task is to discover what each program prints. All of the

Vii
viii PREFACE

programs are independent of one another, though the later puzzles assume that you understand
the properties of C illustrated in earlier puzzles.
The output for each program is given on the page following the text of the program. Each of
the programs was run from the text under the UNIXt Operating System on Digital Equipment
Corporation PDP 11/70 and VAX 11/780 computers. For the few cases where the output is
different on the two machines, output is given from both.

The larger portion of the book is devoted to step-by-step derivations of the puzzle solutions.
Many of the derivations are accompanied by tips and caveats for programming in C.

A typical scenario for using the puzzles might go like this:


e Read about a topic in the language textbook.
e For each program in the puzzle book section on the topic
— Work the puzzles of the program.
— Compare your answers to the program output.
— Read the solution derivations.

ACKNOWLEDGEMENTS

The first C puzzles were developed for an introductory C programming course that I taught at
Bell Laboratories. The encouraging response from students led me to hone the puzzles and
embellish the solutions. A number of my friends and colleagues have given valuable
comments and corrections to various drafts of this book. They are Al Boysen, Jr., Jeannette
Feuer, Brian Kernighan, John Linderman, David Nowitz, Elaine Piskorik, Bill Roome, Keith
Vollherbst, and Charles Wetherell. Finally, I am grateful for the fruitful environment and
generous support provided me by Bell Laboratories.

Alan Feuer

+ UNIX is a trademark of Bell Laboratories.


THE C PUZZLE BOOK
pehevtg V4 ex ™
>
on,
OZ
ZA Ss
Operators

1. Basic Arithmetic Operators


Assignment Operators
Logic and Increment Operators
Bitwise Operators
Relational and Conditional Operators
Rep
SA
RS Operator Precedence and Evaluation

C programs are built from statements, statements from expressions, and


expressions from operators and operands. C is unusually rich in operators; see
the operator summary of Appendix 2 if you need convincing. Because of this
richness, the rules that determine how operators apply to operands play a
central role in the understanding of expressions. The rules, known as
precedence and associativity, are summarized in the precedence table of
Appendix 1. Use the table to solve the problems in this section.
if
PUZZLES 3

Operators 1: Basic Arithmetic Operators

What does the following program print?

main()
{
sis S38

x = = 3 +004 ete ON ON yal rt (aloes) 5 (Operators 1.1)


x =3 + ARK On— Os eep a ant f(s Nie) es (Operators 1.2)
Meese eae — | OF / 53 fopaatioesa(( MCaol\ia! 55) 2 (Operators 1.3)
pg Ee CF eee Gish FARR jopeaiionera
(Gel Nie ote) 2 (Operators 1.4)
4 PUZZLES

Operators 1: Basic Arithmetic Operators

OUTPUT:

11 (Operators 1.1)
(Operators 1.2)
0 (Operators 1.3)
1 (Operators 1.4)

Derivations begin on page 77.


RUZZLES

Operators 2: Assignment Operators

What does the following program print?

#define PRINTX printf("%d\n",x)

main()

i oe Qf AR iiss (Operators 2.1)


x=" yo e= (2 c= 4) PRINTX: (Operators 2.2)
=e ys =z; PPREEN IDX: (Operators 2.3)
ce Se ( 37 a )) 8 IWAN EEC 2 (Operators 2.4)
6 PUZZLES

Operators 2: Assignment Operators

OUTEUT:

10 (Operators 2.1)
40 (Operators 2.2)
1 (Operators 2.3)
1 (Operators 2.4)

Derivations begin on page 80.


PUZZLES 7

Operators 3: Logic and Increment Operators

What does the following program print?

#define PRINT(int) printf("%d\n",int)

main()
{
ane ety avon 4s

5S St A Wee oe hee ar ae
x= x && y i4 2; PRINT(x); (Operators 3.1)
PRINT(sx hi tf yy S&S 2) ); (Operators 3.2)

= iy = 1s
Ze= x +t = 1s PRINT ())5 (PRINT (z); (Operators 3.3)
Z += = X ++ + ++ y; PRINT(x); PRINT(z) 3 (Operators 3.4)
Zi eexcee7 echtee x se PRN T(z); (Operators 3.5)
8 PUZZLES

Operators 3: Logic and Increment Operators

OUTRUT:

1 (Operators 3.1)
1 (Operators 3.2)
2 (Operators 3.3)
0
3 (Operators 3.4)
0
? (Operators 3.5)

Derivations begin on page 83.


PUZZLES 9

Operators 4: Bitwise Operators

What does the following program print?

#define PRINT (ant) printé (“ant = %d\n",int)

main( )
{
apes oy. Say 248

x & WSs se 5 O78 fo a 12


PRINT( <x 4 -y & 2 )s (Operators 4.1)
PRINT( x 1 y & =~ z ); (Operators 4.2)
RULING aa Var Soe es) es (Operators 4.3)
PRINT( x & y && Zz ); (Operators 4.4)

eee yom YL;


PRINT( 1 xd x) )5 (Operators 4.5)
PRINT Ge aXe x, 5 (Operators 4.6)
BRCDNTD (xe ene Xn) es (Operators 4.7)
x <<= 3; PRINT(x); (Operators 4.8)
Vis <=. Gee ERENT (ya): (Operators 4.9)
Yrs = mS Gee DREN D(Gy )is (Operators 4.10)
10 PUZZLES

Operators 4: Bitwise Operators

OUTPUT:

iT Ww (Operators 4.1)
S053 (Operators 4.2)
7 ads
PP
—- alee = 1 (Operators 4.3)
al — N N (Operators 4.4)
coed
Pal
eer,
Lem
3| * i] = (Operators 4.5)
WwW
-- = =-1 (Operators 4.6)
* * " ° (Operators 4.7)
=-8 (Operators 4.8)
Nl \ @ (Operators 4.9)
= ?
|Seti (Operators 4.10)

Derivations begin on page 86.


PUZZLES 11

Operators 5: Relational and Conditional Operators

What does the following program print?

ACKER ALIAS) IDRUCKUE(staNe )) joretivenore (Valine cx 4cl\goy”


.sisaue ))

main()
{
Lee =a le ay =a eziselus

x t= Gy 4s) 23
IDIRIENON(C Se << Sh P a Ss Se is (Operators 5.1)

PRINT ( GS < yo P x +4 3 yo +4 9)
PRINT(x); PRINT(y); (Operators 5.2)

PRENT( (2 = x <) ty 0x ty et)

PRINT
(y) PRINT (zs (Operators 5.3)

X=33; y=z=4;
mine (~ Sa s7 Se o) P 1 8 Oe (Operators 5.4)
msueue GA Se 5, INS 4 SS se )) 2 (Operators 5.5)
12 PUZZLES

Operators 5: Relational and Conditional Operators

OUTPUT:

rai eyi See a (Operators 5.1)


Ho < yr tt Sy ee sa (Operators 5.2)
x = 3
y = 3
Bits e S-y ae sr ey. + eee (Operators 5.3)
y= 4
z= 4
CAS ys Ss ei 0 ed) (Operators
5.4)
Z>Ss y && y oS x = 1 (Operators 5.5)

Derivations begin on page 91.


PUZZLES 13

Operators 6: Operator Precedence and Evaluation

What does the following program print?

#define PRINT3(x,y,z) printf("x=%d\ty=%d\tz=%d\n"


,x,y,Z)

main( )
{
aaniite xX, YY, Z;

y=2zes1;
it ++y && ++2Z3 PRENTSi(s0,
yan Zs (Operators 6.1)

YouaS 2) = 1s

&& ++y 11 +423 PRINTS


(x ,y,2))3 (Operators 6.2)

Vee eats
PRIENTolexnyen
zon (Operators 6.3)

Y= Zi 1;
&& ++y 11 +4+Z3 PRINT3(x,y,2Z);3 (Operators 6.4)

yY = 20= =1;
it ++y && ++2Z3 PRINT3(x,y,Z)3 (Operators 6.5)

Ree Beads
&& ++y && +42; PRENTS
(xc yaerze es (Operators 6.6)
14 PUZZLES

Operators 6: Operator Precedence and Evaluation

OUTPUT:

x=2 y=1 z=1 (Operators 6.1)


x=2 (y=2 Z=1 (Operators 6.2)
x=2) y=2 Z=2 (Operators 6.3)
x=0 y=-1 z=0 (Operators 6.4)
x=0 y=0 z=-1 (Operators 6.5)
x=0) y==1 z=—1 (Operators 6.6)

Derivations begin on page 94.


Basic Types

1. Character, String, and Integer Types


2. Integral and Floating Point Casts
3. More Casts

C has a comparatively small set of primitive types. The types may blindly be
mixed in expressions, the results governed by a simple hierarchy of
conversions. This hierarchy is illustrated in Appendix 4.

For some of the puzzles in this section you will need to know the
corresponding integer value of some characters. The tables in Appendix 3
show the values for the characters in the ASCII set. A few of the puzzles yield
a different result on the VAX than on the PDP 11. For those puzzles, output
from both machines is given.
PUZZLES S/

Basic Types 1: Character, String, and Integer Types

What does the following program print?

#include <stdio.h>

#define PRINT(format,x) Piel


nc ty Gye m ot Oma Nia)

int integer = 5;
char character = ’5’;
Charewasiixing. = Sia:

main( )
{
PRINT(d,string); PRINT(d,character); PRINT(d,integer) ;
PRINT(s,string); PRINT(c,character); PRINT(c,integer=53);
PREEN (iclen Game me) ke (Basic Types 1.1)

{
Init ess =) —Sis
unsigned ux = -8;

PRINT(0,sx); PRINT(o,ux);
PROEN TCO) ssce
> Sim) iss REGEN
LE COr, mnt c> >see
PRUNT (di sx >> Sm) ise PRUNING) eeusc>
> 3) rs (Basic Types 1.2)
}
18 PUZZLES

Basic Types 1: Character, String, and Integer Types

OUTPUT:

string = an address (Basic Types 1.1)


character = 53
integer = 5
string = 5
character = 5
integer=53 = 5
(C5525 on)ee sa)
Sz = iy (Basic Types 1.2-PDP 11)
be = NITY,
Se SS mid tele Pen Oiled tanel
Ve Se ad,
sx>>3 = -1 or 8191
ik
> See O19

spe =e VOR
I SPER ING. (Basic
Types 1,.2-VAX)
Wx = ST
a Le
Sxe=S SS B70 TR LLL? OF OFF
TPL IS die
ibipceoeeysd as nl /Balak
ayiMay,
sx>>3 = -1 or 536870911
ux>>3 = 536870911

Derivations begin on page 97.


PUZZLES 19

Basic Types 2: Integer and Floating Point Casts

What does the following program print?

#include <stdio.h>

#define PR(x) Prantl x= oe Sg ceed


oOub desis)
#define NL putchar(’\n’)
#define PRINT4(x1,x2,x3,x4) PR(x1); PR(x2); PR(x3); PR(x4); NL

main( )
{
double d;
float f;
PornGguels:
nLighe alg

" Q TOOTS Wiss youd (si al 52 ,Gl)) 2 (Basic Types 2.1)


" 110107 33) PREN TAG,
bat dis (Basic Types 2.2)
Eh
eH iH} N00 Saas SPRINTS (ides t a )is (Basic Types 2.3)
ape
Ge £ Hh QP:
BH (double) 100/73;
nage ANel( pt 4 dl 5 %2 5Gl)) 2 (Basic Types 2.4)

i if =d (double) (100000/3) ;
(Basic Types 2.5)

100000/3; PRINT4(i,1,f£,4); (Basic Types 2.6)


20 PUZZLES

Basic Types 2: Integer and Floating Point Casts

OUTPUT:

i= 33 Jos 33: £ = 33 ad «= 33 (Basic Types 2.1)


Ti S3) Mea 33 -£ =433: 1d =155 (Basic Types 2.2)
1 =-33 d= 33° £ 2133, 3399324 6d p=.33, 058555 (Basic Types 2.3)
=o a= oo. Et wees Sd ea oS (Basic Types 2.4)
i= overtlow =1i9= S3333 £ =,33333 ad = 33333 #£(Basic Types 2.5-PDP 11)
i = overflow 1 = -32203 £ = -32203 d = -32203 (Basic Types 2.6-PDP 11)

ii=5 33333 i = 33333 £ = 33333 d= 33333 (Basic


Types 2.5-VAX)
1 = 3:33:33 S33 353 f= 33333 & = 33333 (Basic Types 2.6-VAX)

Derivations begin on page 99.


PUZZLES 21

Basic Types 3: More Casts

What does the following program print?

#include <stdio.h>

#define PRC) ee pate


ol(oe OO Neg CL Oo ne) (3c) )
#define Nim put ciar (Gann)
#define PRINT1(x1) PR(x1); NL
#define PRINT2(x1,x2) PR(x1); PRINT1(x2)

main( )
{
doubilie d=37 2.5.95
alge Sky AY

(y=d7a) )e2i5 PRENDEZSC,


yan (Basic Types 3.1)
(x=d/i)*2; PRINT2(x,y); (Basic Types 3.2)

Cian (= 2115/70)eee RENT aIkGyans (Basic Types 3.3)


dive Cy. = ((C(ant)'2..9+ t4)/4)s. PRINT2Z(x,9))s (Basic Types 3.4)
22) PUZZLES

Basic Types 3: More Casts

OUTPUT:

x = 2 y= 1 (Basic Types 3.1)


xs 6r “y=. 3 (Basic Types 3.2)
y = 72 (Basic Types 3.3)
x = 0 y = 0 (Basic Types 3.4)

Derivations begin on page 103.


Included Files

Each of the remaining programs in this book begins with the preprocessor statement
#include "defs.h"
When the programs are compiled, the preprocessor replaces this line with the contents of the
file defs.h, making the definitions in defs.h available for use. Here is a listing of
adersiin:

#include <stdio.h>

#define PR(format,value) printf("value = %format\t", (value) )


#define NL putchar(’\n’ )

#define PRINT1(f£,x1) PR(f,x1), NL


raefine PRINT2Z(CE,x1,x2)) |) PRL. x), PRENTI1(£ x2)
Fdefiane PRINTS (£,x1),x2),,x3) “PRE, xa), PRINT 2 (£5202), x«3))
#define PRINT4(f£,x1,x2,x3,x4) PR(f,x1), PRINT3(f£,x2,x3,x4)

defs.h begins with an include statement of its own, calling for the insertion of the file
stdio.h, as required by the standard C library. The rest of defs.h comprises macros for
printing. As an example, to print 5 as a decimal number, the PRINT1 macro could be called
by the expression
PRINT1(d,5)
which expands to
PR(d,5), NL
which further expands to
popealrmere (WS) ee Sache!
5((S)))) 4 joiechacie((
“Na” ))

The PRINT macros point out a feature of the preprocessor that often causes confusion. A
macro name that appears inside a string (i.e., enclosed within double quotes) will not be
expanded. However, argument names within the body of a macro will be replaced wherever
they are found, even inside strings. Notice that the macro PR takes advantage of the latter
property. See the Preprocessor Section, beginning on page 69, for a more detailed description
of macro substitution.

23
Wall Me6er G ae > iat a]
> wb @«¢: @o6 occ @ Ghee dass

%e

=—=»G : en) ee — ee |
a

NN yates
ly<t|\ Gee
3
7

7 18s S2SN® 49h eee


a bes seTned

7 7 ~~ > Caress oy +
ae 1a)A lapas an eee ieee oe
; eo aeee
at © £0rh pg

aes 2

— = ee
7 — 7 =>
7 id Ma # ns

°°. & — a
; a
Control Flow

1. if Statement

while and for Statements

Statement Nesting
woN
A switch, break, and continue Statements

C, as most programming languages, has control constructs for conditional


selection and looping. To work the puzzles in this section, you will need to
know how to determine the extent of each construct. In a well-formatted
program, extent is indicated by indentation. Reading a poorly-formatted
program is difficult and error prone; the following puzzles should convince you.

25
PUZZLES 27

Control Flow 1: if Statement

What does the following program print?

#include "defs.h"

main()
{
sie Pay Sly £40

a G(R y= Ole) c= 512


PRINT1(d,x); (Control
Flow 1.1)

ee (eyi== )) Sesh
else x=5;
PRINT1(d,x); (Control Flow 1.2)

x=1;
nell YAsO) i ES SE) )) seeshe
elsie x=573
PRENT Cdyn) (Control
Flow 1.3)

ise(( bHaSO) )) Seas} 9


else if( y==0 ) x=5;
else x=7;
PRN 2) Cae acr Za)is (Control
Flow 1.4)

PEG ZaCy==0)) le x=o ex aise


[NSE SEA (Cl shen %4)) 8 (Control
Flow 1.5)

el Gea= a) es).
PR UND 2dr Ze) (Control
Flow 1.6)
28 PUZZLES

Control Flow 1: if Statement

OUTPUT:

(Control Flow 1.1)


(Control Flow 1.2)
(Control Flow 1.3)
" l 0 (Control Flow 1.4)
Paes (0) (Control Flow 1.5)
tole
teh
ete
Late
thee ios
FO
2k
ST)
GOS1 (Control Flow 1.6)

Derivations begin on page 105.


PUZZLES 29

Control Flow 2: while and for Statements

What does the following program print?

#include "defs.h"

main( )
{
FMS bee S7A LAR

x=y=0;
Whaley < 10) Sysco =n ys
PRENG2 (dey) 5 (Control Flow 2.1)

x=y=0;
while( y<10 ) x += ++y;
PRINT
2 (@,20,y:) 5 (Control Flow 2.2)

YeA
while( y<10 ) {
X = yt; Z = ++Y3
}
PRENTSAdp
Gay. zis (Control Flow 2.3)

Lon (Sy=1se y< 10 yet) x=¥ ;


PRUNEZICAR yi: (Control Flow 2.4)

for( y=1; (x=y)<10; yt+t ) ;


PRINT2(d,x,y); (Control Flow 2.5)

for( x=0,y=10003; yo1; x++,y/=10 )


PRINT2(d,x,y);3 (Control Flow 2.6)
30 PUZZLES

Control Flow 2: while and for Statements

OUTPUT:

po hal a =F alts) (Control Flow 2.1)


tea S50 Ver=s 10 (Control Flow 2.2)
pid wer AS) ses I ee ils (Control Flow 2.3)
eo Fe) y = 10 (Control Flow 2.4)
SS ON yas =F 10) (Control Flow 2.5)
ae) ye =) 10/010 (Control Flow 2.6)
x = 1 y = 100
x =— 24 y = 10

Derivations begin on page 108.


PUZZLES 31

Control Flow 3: Statement Nesting

What does the following program print?

#include "defs.h"

#define ENUF 3
#define EOS ’\0’
#define NEXT(i) inputli++]
#define FALSE 0
#define TRUE 1

char input[ ]="PpI=3.14159, approximately";

main( )
{
charnec:
In teaonee hag. 37.0 nL Ow.

i=low=in=high=0;
while( c=NEXT(i) i= EOS )
Te ( te<2 0") tow++:
else if( c>’9’ ) high++;
else in++3
PRINT3(d,low,in,high) ; (Control Flow 3.1)

i=low=in=high=0; done=FALSE;
while( (c=NEXT(i))!=EOS && !done )
Pe c<0-)) low++:
else if( c>’9’ ) high++;
else in++;
if( low>=ENUF |i high>=ENUF ii
done = TRUE;
PRINT3(d,low,in,high) ; (Control Flow 3.2)

i=low=in=high=0; done=FALSE;
while( (c=NEXT(i))!=EOS && !done )
if( c<’0’ ) done = (++low==ENUF);
else if( c>’9’ ) done = (++high==ENUF) ;
else done = (++in==ENUF) ;
PRINT3(d,low,in,high) ; (Control Flow 3.3)
32 PUZZLES

Control Flow 3: Statement Nesting

OUTPUT:

Lows 25 sia fy), high) = 0 (Control Flow 3.1)


alfoRks = is! ail ae high = 16 (Control Flow 3.2)
low = 0 athe aes (0 High =—3 (Control Flow 3.3)

Derivations begin on page 112.


PUZZLES 33

Control Flow 4: switch, break, and continue Statements

What does the following program print?

#include "defs.h W

char inputl] SSSWILTECH1\1\11W\ 1WALLMP1" ;

main()
{
eos. legs ehp

BOX; (ela
ee ( Geayoenellalt))) le?\O? Sg shes) a
switch (ae) 4
case ane putchan(
4a )conta nue.
-

case ’ 1’: break;


case ales Wailea (eectinjeenell
sensi I) eK? BS SIESYNO* ) 8
case ey Puech asses Sie)
case ’ YS CASE “1G” 8 wCnmnesisnnes
defaul t putichan(¢)); continues
}
putcha mn as
}
putchar(’\n aes (Control
Flow 4.1)
34 PUZZLES

Control Flow 4: switch, break, and continue Statements

OUTPUT:

SWITCH SWAMP (Control Flow 4.1)

Derivation begins on page 114.


Programming Style

1. Choose the Right Condition


2. Choose the Right Construct

Much has been written about programming style, about which constructs to
avoid and which to imitate. A cursory conclusion from the seemingly diverse
advice is that good style is largely a matter of personal taste. A more reasoned
conclusion is that good style in programming, as elsewhere, is a matter of good
judgement. And while there are many good style guidelines, there are few
always appropriate, always applicable style rules.

With this in mind, the following puzzles illustrate a few common style
blunders. The solutions given are not so much answers, as in other sections,
but rather alternatives. If there is an overall key to good style, it is a
recognition of the final two steps in writing a readable program:
e Establish a clear statement of the idea to be coded.

e Develop the structure of the code from the structure of the idea statement.

3D
4 9 @p-eaey pet = >
°) GF EDS, MM eae
oy) OSs Gos (he,
Marea ee 6! Aang
hb eer et ™:
ee re
2 2@) CO eG. ow
0 © e® 62 cht Gamsae i :
@& st Be — i.

1D S| 4 gone, ay 3 re
Deel 6 tileed} rE Wes)

> (4 698 CQ ere

iF
~
PUZZLES 37

Programming Style 1: Choose the Right Condition

Improve the following program fragments through reorganization.

while(A) {
if(B) continue;
Cc;
} (Programming Style 1.1)

do {
if(!A) continue;
else B;

C;
} while(A); (Programming Style 1.2)

if(A)
obee ((is)))
ste((()}) yg
else;
else;
else
cia (G5)
if(C) E;
else F;
else; (Programming Style 1.3)

while( (c=getchar())!=’\n’ ) {
cinta (aC = — rn) mC One anwer:
fC == Nt) Cont aniter:
if( c<’0’ ) return(OTHER) ;
sine(( (eges“ Sy) saxsrerbivera((oeepagay))2
1f( ce<7a’ ) return (OTHER) ;
if( e<=’z’ ) return(ALPHA) ;
return(OTHER) ;
} return(EOL); (Programming Style 1.4)
38 PUZZLES

Derivations begin on page 117.


PUZZLES 39

Programming Style 2: Choose the Right Construct

Improve the following program fragments through reorganization.

done=i=0;
while( i<MAXI && !done
af (xc7=2))>) )
done++;
} (Programming Style 2.1)

{
if(A) { B; return;
SECC) )eeD seee Culenis
if(E) { F; return;
Gy return);
} (Programming Style 2.2)

plusflg=zeroflg=negflg=0;
if( a>O ) ++plusflg;
if( a== ) ++zeroflg;
else if( !plusflg ) (Programming Style 2.3)

i=0;
while((c=getchar())!=EOF) {
if(el="\n’sSc!l="\t’
){sli++ l=c; continue; }
Df(c=—— N\n)ibreaks:
se (eRe
we NOeo “se
sli++l=c;} (Programming Style 2.4)

se(( Sells) )}
stsel( Sjeeis ) SeSa/ere8
else y=k/x;
else
if( j>k ) y=j/NEARZERO;
else y=k/NEARZERO; (Programming Style 2.5)
40 PUZZLES

Derivations begin on page 119.


Storage Classes

1. Blocks
2. Functions

3. More Functions
4. Files

Each variable in C possesses two fundamental properties, type and storage class.
Type has been covered in an earlier section.

Storage class determines the scope and lifetime for a variable, scope being that
part of a program in which a variable is known and lifetime being that portion
of an execution during which a variable has a value. The boundaries of scope
and lifetime are blocks, functions, and files.

41
PUZZLES 43

Storage Classes 1: Blocks

What does the following program print?

#include "defs.h"

aate akOe

main()
{
AUTOM nite el = 1
PREN T(r) is
{
aes sh Aie
PRIN Ed. )s
{
i += 1;
PRINT1(d,i);
}
PRINT1(d,i);
u
pseeisns| (Cel. at )) 2 (Storage Classes 1.1)
44 PUZZLES

Storage Classes 1: Blocks

OUTPUT:

(Storage Classes 1.1)

ee
=ee Gd
ORS
Co
ai
Sk

Derivations begin on page 123.


PUZZLES 45

Storage Classes 2: Functions

What does the following program print?

#include "defs.h"

#define LOW 0

#define HIGH 5

#define CHANGE 2

int i=LOW;

main()
{
auto int i=HIGH;
weasel a/72 8 Tite
ee 4](cl. aL) 2
masaie( shos/72 ))8 ihieeae|(el..5h
))
Bh SS seaciena( shy/7y js iistaueme a(t. ak)) 2

workover(i); PRINT1(d,i); (Storage Classes 2.1)

workover(i)
alisha Bt
{
ci ei (G15) eka (cies)
4 (02 acl) tA)
PRINT1(d,i);
sareyeiwleasey((
SL})8

int reset(i)

plerditeam lars
{
i = i<=CHANGE ? HIGH : LOW;
return(i);
46 PUZZLES

Storage Classes 2: Functions

OUTPUT:

(Storage Classes 2.1)

"

BOR
oP
oH
Be WO
hw:
of
a

Derivations begin on page 124.


PUZZLES 47

Storage Classes 3: More Functions

What does the following program print?

#include "defs.h"
int i=1;

main()
{
Wie alice Sha Sfh
i = reset();
POrte jets. J<=35) je te 0 t
RUS
OA (Che at 55]))2
PRINT1(d,next(i));
PRINT1(d,last(i));
PRINT1(d,new(i+j)); (Storage Classes 3.1)

Init reset()

return(i);

next(j)

33

return( j=it++ );

last(j)
33

Sealeceea nit a — Or
return( j=i-- );

new(i)

at

Elie) alie SSR


return( i=j+=i );
48 PUZZLES

Storage Classes 3: More Functions

OUTPUT:

she t—te pi oh aah i (Storage Classes 3.1)


next(i) = 1
last(i) = 10
new(i+j) = 12
aly =) WeSee
next(i) = 2
Last(i) =
new(i+j) = 13
| 7 = 3
next(i) = 3
Last (a5)) =) 8
new(i+j) = 14

Derivations begin on page 125


PUZZLES 49

Storage Classes 4: Files

What does the following program print?

#include "defs.h"

eto <i ya[a

main( )
{
eubwee) alee Bb, 5/8

i = reset();
for( j=1; Wee5R sie j) xf
PREEN
L 2iCusrlisnyi as
PRINT1(d,next(i));
PRINT1(d,last(i));
PRINT1(d,new(i+j)); (Storage Classes 4.1)

In another file In yet another file

static int i=10; extern int i;

int next() reset()


{ {
return( it=1 ); return(i);
}

int last()
{
return( i-=1 )3
}

int new(i)
cighe obR
{
Sitatae eint j= 5's
raeran(( sleaGjabest ))e
50 PUZZLES

Storage Classes 4: Files

OUTPUT:

i 3 1 j = 1 (Storage Classes 4.1)


next) = 911

last) = 10
new(i+j) = 7
i= 1 4) =e
Rest (ci) =e
rarcits (215)) (= 110
new(it+j) = 10
= iS
nextGa)) = ail
haste Gis) =) 10
new(i+j) = 14

Derivations begin on page 127.


Pointers and Arrays

1. Simple Pointer and Array


Array of Pointers
Multidimensional Array
fae
ea Pointer Stew

Pointers have long been abused by programmers and thus maligned in style
guides. Specifically, pointers are criticized since, by their nature, it is
impossible to identify fully a pointer’s referent without backing up to where the
pointer was last defined; this adds complexity to a program and makes
verification much more difficult.

The C language, rather than restricting the use of pointers, often makes them
the natural choice for use. As the following puzzles will illustrate, pointers and
arrays are very closely related. For any application using array indexing, a
pointer version also exists. The warnings against the dangers of pointer misuse
apply as strongly to C as to any language.

51
,re
(nas ws OF beNA 4
apo dt @) 06 eaten GF oe a heme?
Gal we
PUZZLES 53

Pointers and Arrays 1: Simple Pointer and Array

What does the following program print?

#include "defs.h"

mame El ISO,
W525 Sacer s

main( )
{
algae ahs Eels

ere Hee seecte shes j) tear((el,


alls lly) 2 (Pointers and Arrays 1.1)
NL;
for( p= &al0]; p<=&al4]; p++ )
PR(d,*p); (Pointers and Arrays 1.2)
NL; NL;

fore pe SAU@I tee aicgesyG ateaes ))


PR(d,plil); (Pointers and Arrays 1.3)
NL;
for( p=a,i=0; pti<x=a+4; p++,i++ )

PR(d,*(pti))3; (Pointers and Arrays 1.4)


NL; NL;

for( p=a+4; p>=a; p-- ) PR(d,*p); (Pointers and Arrays 1.5)


NL;
for( p=a+4,i=0; i<=4; i++ ) PR(d,pl-il); (Pointers and Arrays 1.6)
NL;
for( p=a+4; p>=a; p-- ) PR(d,alp-al); (Pointers and Arrays 1.7)
NL;
54 PUZZLES

Pointers and Arrays 1: Simple Pointer and Array

OUTPUT:

ali) = 0 ali] = alil alil-=u 3 afi] = 4


(Pointers and Arrays 1.1)
*p = 0 *p = 1 *p " N *#p = 3 *p = 4

(Pointers and Arrays 1.2)

plat 4 plil = plil plLil =.4 pli] = ?


(Pointers and Arrays 1.3)
*(p+i) = 0 *(p+i) *(pt+i) iT] (Pointers and Arrays 1.4)

ep = 4 ‘nf = 3 +p = 1 *p = 0
(Pointers and Arrays 1.5)
pl=i)}c= pl-il] pl-i] =" 1 pl-il = 0
(Pointers and Arrays 1.6)
alp-al = 4 alp-al] alp-a] = 1 alp-a] = 0
(Pointers and Arrays 1.7)

Derivations begin on page 129.


PUZZLES 55

Pointers and Arrays 2: Array of Pointers

What does the following program print?

#include "defs.h"

tere ae W0y 12 8), Ads


int «pl l={a,a+1,a+2,a+3,a+4};
int **pp=p; (Pointers and Arrays 2.1)

main( )
{
PRINT2(d,a,*a) ;
PRINT3(d,p,*p,**p) ;
PRINT3(d,pp,*pp,**pp); (Pointers and Arrays 2.2)
NL;

pp++; PRINT3(d,pp-p,*pp-a,**pp) ;

*pp++; PRINT3(d,pp-p,*pp-a,**pp) ;
*++pp; PRINT3(d,pp-p,*pp-a,**pp) ;
++*pp; PRINT3(d,pp-p,*pp-a,**pp) ; (Pointers
and Arrays 2.3)
NL;

PP=P;
**ppt++; PRINT3(d,pp-p,*pp-a,**pp) ;

*++*pDp; PRINT3(d,pp-p,*pp-a,**pp) ;
++**pp; PRINT3(d,pp-p,*pp-a,**pp) ; (Pointers
and Arrays 2.4)
56 PUZZLES

Pointers and Arrays 2: Array of Pointers

OUTPUT:

a = address of a xa = 0 (Pointers and Arrays 2.2)


p = address of p *p = address of a ¥ep = 10
pp = addressof p -*pp = addressof a **pp = 0

pp-p = 1 *pp-a = 1 #**pp = 1 (Pointers and Arrays 2.3)


Pp-p = 2 *pp-a = 2 **pp = 2

pp-p = 3 *pp-a = 3 **pp = 3

pp-p = 3 *pp-a = 4 **pp = 4

pp-p = 1 *pp-a = 1 **pp = 1 (Pointers and Arrays 2.4)


pp-p = 1 *pp-a = **pp =
Pp-p = 1 *pp-a = 2 **pp =

Derivations begin on page 132.


PUZZLES 57

Pointers and Arrays 3: Multidimensional Array

What does the following program print?

#include "defs.h"

tntpalsilsi = {
Aliso Sook
tf Ub Gi Wop ee
ee Ce hae
iG
Wms GoelSi) B
ahoks calitd. ala)
};
inte ep = alOnl (Pointers and Arrays 3.1)

main()
{
aiielic) Eb2

re@ne(( sle@e alcesig shebes ))


PREN
TS (deal lle2i=a0 epee lean *(*(ati)+i) );
NL; (Pointers and Arrays 3.2)

eGye(( aie skeasp sleas ))


RUA (el, <yoerilai
I, jollstd| 3) 8 (Pointers and Arrays 3.3)
58 PUZZLES

Pointers and Arrays 3: Multidimensional Array

OUTPUT:

1
alill2-i] = *alil *(*(a+i)+i) (Pointers and Arrays 3.2)
alil(2-il] = *alil *(*(a+i)+i)

afill2-i] = *«alil *(*(a+i)+i)

*pavil= 4 Dies (Pointers and Arrays 3.3)


wpalil = 4 plil
*pali] = 7 piid

Derivations begin on page 136.


PUZZLES 59

Pointers and Arrays 4: Pointer Stew

What does the following program print?

#include "defs.h"

char acl] = {
"ENTER",
"NEW",

"POINT",
BUR Sian

};
char *«*cpl] = { ¢c+3, c+2, c+1, c };
char ***cpp = cp; (Pointers and Arrays 4.1)

main( )
{
print£("%s", **++cpp );3
printf("%s ", *--*++cpp+3 );
Printe("X%s"™, *seppl-21+3) );
Peince(“%se\n". cppl—-110-11+1)- (Pointers and Arrays 4.2)
60 PUZZLES

Pointers and Arrays 4: Pointer Stew

OUTPUT:

POINTER STEW (Pointers and Arrays 4.1) .

Derivation begins on page 138.


Structures

1. Simple Structure, Nested Structure


2. Array of Structures
3. Array of Pointers to Structures

A structure, that is the C data type struct, is a fundamental building block


for data structures. It provides a convenient way to package dissimilar but
related data items.

61
PUZZLES 63

Structures 1: Simple Structure, Nested Structure

What does the following program print?

#include "defs.h"

main( )
{
Staticestruct S41)
char cl4], «s;
jars (Set ADC "dete yc

Staticms tructmsG ou +
char, xCps
StesCG Caronmes Silne
fos oeaets Mog MedMee Mma ws ot ub (Structures 1.1)

PRINT2(c, et) cl0l, *s15s)5 (Structures 1.2)


PRUNE ZieseasulinCc mESuleiss)i> (Structures 1.3)

PRON DAGSeEISiZ: CD REIS 2 <Sisilieisois (Structures 1.4)


PRINT2(s, ++S2.cp, ++s2.ss1.s); (Structures 1.5)
64 PUZZLES

Structures 1: Simple Structure, Nested Structure

OUTPUT:

si.clol] = a +5s1,.8 = 4 _ (Structures 1.2)


sic = aba Si,8 © det (Structures 1.3)
Ss2Z.cp = ghi S256 1.8 = mio (Structures 1.4)
++S2.cp = hi ++82.8s1.8 = no (Structures 1.5)

Derivations begin on page 141.


PUZZLES 65

Structures 2: Array of Structures

What does the following program print?

#include "defs.h"

struct $1 {
char *s;
oleae, al 8
Seemche Si] oe ese

Static struct Si all = {


f Vetiyecl 5, “Wy “Eleal Ih-
fo Wewetepel yy Oe ee Ie
{ "ijkl", 3, a}
};
Sie ac Ga Sule k DEE srare (Structures 2.1)
ations, be

PRINT3(s, alO].s, p->s, al2].sip->s); (Structures 2.2)

reope(( shee skeep aivkes 9) 4


PR(d, --alil.i);
PR(c, +t+ali]l.sl3]); (Structures 2.3)
NL;

PRINT3(s, ++(p->s), al(++p)->il.s, al--(p->sip->i)].s);


(Structures 2.4)
66 PUZZLES

Structures 2: Array of Structures

OUTPUT:

alO].s = p->s = abcd .al2].sip->s = abcd


(Structures 2.2)
Said)ae ¢+tali)].s{3] ' (Structures 2.3)
~<a li) <i ee
el er Sek
++(p->s) al(++p)->il. i efgi al--(p->sip->i)].s = ijkl
(Structures 2.4)

Derivations begin on page 145.


PUZZLES 67

Structures 3: Array of Pointers to Structures

What does the following program print?

#include "defs.h"

struct si {
char *s;
StGue ees ies lip:
a
main( )
{
static struct S1 al] = {
{-"abeda", a+1 },
xf Uerecin’Y , Gee Ir.
te ake a oh
};
struct $1 *«pl3]; (Structures 3.1)
aipene Bhp

faene(( ala@)a siess}e steers )) jolkstll = allah


ll paajos
PRINT3(s, plO]->s, (*p)->s, (**p).s); (Structures 3.2)

swap(#*p,a);
PRINT3(s, plOJ]->s, (*p)->s, (*p)->sip->s); (Structures 3.3)

swap(pl[0], pl0OJ]->sip);
PRINT3(s, plOJ]->s, (*++pl0]).s, ++(*++(*p)->sip).s);3
(Structures 3.4)
}

swap(p1,p2)
struct Si-*xpi, «p23
{
char «temp;

temp = pi1->s;
pil->s = p2->s;
p2->s = temp;
68 PUZZLES

Structures 3: Array of Pointers to Structures

OUTPUT:

plO]->s = efgh (*p)->s = efgh (**p).s = efgh (Structures


3.2)
pl0O]->s = abcd (*p)->s = abcd (*p)->s1ip->s = ijkl (Structures 3.3)
plO]->s = ijkl (*++pl[0]).s = abcd ++(#++(*p)->sip).s = jkl
(Structures 3.4)

Derivations begin on page 152.


Preprocessor

1. The Preprocessor Doesn’t Know C


2. Caution Pays

Though in a strict sense the preprocessor is not part of the C language, few C
programs would compile without it. Its two most important functions are
macro substitution and file inclusion.

This section concentrates on macro substitution. When used judiciously,


macros are a versatile tool that can enhance the readability and efficiency of a
program. When used unwisely, macros, like other features in C, can lead to
insidious bugs. To solve the puzzles in this section, follow the rules for
expanding macros very carefully.

69
a
ay (2 Gest on Po
rei ete &1e
a 660 tn a NH | ;
-_
- > asPron
— &® GP Uni peers 5
s@u eames * ~ aa
=a 4) Gp i. ape
eres oer oeOe at
PUZZLES 71

Preprocessor 1: The Preprocessor Doesn’t Know C

What does the following program print?

#include <stdio.h>
#define FUDGE(k) k+3.14159
#define PRiCa) ee prance a= 4d Nt Gam cl Gaye)
#define PRINT(a) PRi¢ay) se putchar (Xn)
#define PRINT2(a,b) PR(a); PRINT(b)
#define PRINT3(a,b,c) PR(a); PRINT2(b,c)
#define MAX(a,b) Catia be may)

main( )
{

Inte s=2)3
PRINT( x*FUDGE(2) ); (Preprocessor 1.1)

anitacenss
for( cel=03 cel<=100; cel+=50 )

PRINT2( cel, 9./5*cel+32 ); (Preprocessor 1.2)

MiG x= y= 203
PRINT3( MAX(x++,y),xX,y )3
PRINT3( MAX(x++,y),xX,y )3 (Preprocessor 1.3)
72 PUZZLES

Preprocessor 1: The Preprocessor Doesn’t Know C

OUTPUT:

xX*FUDGE(2) = 7 (Preprocessor 1.1)


cel= 0 cel= 50 9../ 54661432 = 302 (Preprocessor
1.2)
MAX(x++,y)= 2 2 (Preprocessor 1.3)
MAX((xX+,
yy) = 3 2

Derivations begin on page 158.


PUZZLES 73

Preprocessor 2: Caution Pays

What does the following program print?

#include <stdio.h>
#define NEG(a)-a
#define weeks(mins) (days(mins)/7)
#define days(mins) (hours(mins)/24)
#define hours(mins) (mins/60)
#define mins(secs) (secs/60)
#define TAB(c,i,oi,t) cifea CC — a NV
OT Gt='S'— (Gl — On —alh)) Or Omics)IN
ohh
eon ol- al CnGmnan
#define PR(a) eee)
(Mey no CNG ((elataitce)
(cc)
#define PRINT(a) PR(a); putchar(’\n’)

main( )
{
{
Nee =a1/-2
PRINT( -NEG(x) ); (Preprocessor
2.1)
}

{
PRINT( weeks(10080) );
PRINT( days(mins(86400)) ); (Preprocessor
2.2)
}

{
Siac Cac hala mpuit a =n ct winch eatin
Chidieac!.
alsayic, ah5 copilelsi, ASehwmjeye

for( oldi= =1,i1=0;> (ezinputlil)\="\0"°s fae 4


f(nC <i ee) LAB CCy ae Ol dance mp))i.
else putchar(c);
putchar (Nn ))5 (Preprocessor
2.3)
}
74 PUZZLES

Preprocessor 2: Caution Pays

OUTPUT.

-NEG(x)= 0 (Preprocessor 2.1)


weeks(10080) = 1 (Preprocessor 2.2)
days(mins(86400)) = 1
eleven spaces (Preprocessor 2.3)

Derivations begin on page 161.


SOLUTIONS
BASIC ARITHMETIC OPERATORS 77

Operators 1.1

-3+4%*5-6 Begin by reading the precedence table in Appendix 1


from high to low.
(-3) +4*5-6 The highest level operator in the expression is the
unary -. We’ll use parentheses to indicate the order
of binding operands to operators.
(-3) + (4*5) -6 Next highest in the expression is +.

((-3)+(4*5)) -6 Both + and - are at the same precedence level. The


order of binding thus depends on the associativity rule
for that level. For + and -, associativity is left to
right. First the + is bound.
x GCC 3) 4(4#5.),)/\-6) And then the -.

Cx=(((=3)4(4*5))—6))) And finally, near the bottom of the precedence table,


is =. Now that we have completely identified the
operands for each operator, we can evaluate the
expression.

(x=((-3+(4#5))-6) For this expression, evaluation proceeds from the


inside out.
(x=((-3+20)-6) Replace each subexpression by its resulting value.

(x= (117 =6))))


(x=11)

i deanente ger The value of an assignment expression is the value of


the right-hand side cast in the type of the left-hand
side.

About printf. Printf is the formatted print routine that comes as part of the standard C
library. The first argument to printf is a format string. It describes how any remaining
arguments are to be printed. The character % begins a print specification for an argument.
In our program, %d told printf to interpret and print the next argument as a decimal
number. We will see other print specifications in later programs. Printf can also output
literal characters. In our program, we “‘printed’’ a newline character by giving its name
(\n) in the format string.
78 BASIC ARITHMETIC OPERATORS

Operators 1.2

x=3+4%5-6 This expression is very similar to the previous one.

x= 3+ (4%5)
-6 Following precedence
x = (3+(4%5)) - 6 and associativity
x = ((3+(4%5))-6) leads to
(x=((34+(4%5))-6) ) this. (The modulo, %, operator yields the
remainder of dividing 4 by 5.)

(x=((3+4)-6) Again, evaluation is from the inside out.

(x=(7-6))
(x=1)
1

Operators 1.3

x=-3%*4%-6/5 This expression is a bit more complex than the


last, but rigorous adherence to precedence and
associativity will untangle it.
x= (-3) * 4% (-6) 7/5

x= ((-3)*4)
% (-6) 45 *, %, and / are all at the same precedence level,
and they associate from left to right.
x = (((-3)*4)%(-6)) 75
x = ((((-3)*4)%(-6))/5)
(x=((((-3)*4)%(-6))/5))
(x=(((-3%4)%-6)/5)) Evaluating from the inside out.
(x=((-12%-6)/5) )

(x=(0/5))
(x=0)
0
BASIC ARITHMETIC OPERATORS 79

Operators 1.4

se Gi (CW ce i) 5 Spy a Of course we are not totally at the mercy of predefined


precedence. Parentheses can always be used to effect
or clarify a meaning.
va i) (HO)
5% 527 22 Subexpressions within parentheses bind first.
eS (7a AE 7H & Then, it is according to the precedence and associativity
rules as before.
EB (CPEG NWS) 7/2)
(x=(((7+6)%5)72) )
Cx=((913%5)))7-2)))) Evaluating.
(x= (372)

(x=1) Integer arithmetic truncates any fractional part.


1

About programming style. As mentioned in the Preface, the programs in this book are not
models to be copied. They were designed to make you think about the mechanics of how C
works. But the puzzles do contain messages about program style. If a construct always
forces you to consult a reference to find out how some detail is handled, then the construct
is either not well written or it should be accompanied by a comment that provides the
missing details.

The message from this first set of puzzles is to use parentheses in complex expressions to
help the reader associate operands with operators.
80 ASSIGNMENT OPERATORS

Operators 2.1

initially x=2
x*=3+2 Again follow the precedence table.
x #= (3+2) As we Saw earlier, the assignment operators have lower
precedence than the arithmetic operators. (*= is an assignment
operator.)

(Ce¥=1(3)-2))))

(x*=5) Evaluating.
(Sis Sap 15) Expanding the assignment to its equivalent form.

(x=10)

10

About define. This program begins with the line

#define PRINTX printf ("%d\n",x)

Any line in a C program that begins with the character # is a statement to the C
preprocessor. One job done by the preprocessor is the substitution of one string by another.
The define statement in this program tells the preprocessor to replace all instances of the
string PRINTX with the string printf("%d\n",x).
ASSIGNMENT OPERATORS 81

Operators 2.2

initially x=10
x*=y=z=4

x *= y = (z=4) In this expression all the operators are assignments, hence


associativity determines the order of binding. Assignment
operators associate from right to left.
x *= (y=(z=4))

(x*=(y=(z=4)))

(x*=(y=4) ) Evaluating.
(x*=4)
40

Operators 2.3

initially y=4, z=4


x=yr==2Z

am Gy —25) Often a source of confusion for programmers new to C is


the distinction between = (assignment) and == (test for
equality). From the precedence table it can be seen that
== is bound before =.

(x=(y==z))

Koc=alp) Relational and equality operators yield a result of TRUE, an


integer 1, or FALSE, an integer 0.
82 ASSIGNMENT OPERATORS

Operators 2.4

initially x=1, z=4


x==(y=z )

(x==(y=z) ) In this expression the assignment has been forced to have


higher precedence than the test for equality through the use
of parentheses.

(x==4) Evaluating.
FALSE,
or 0 The value of the expression is 0. Note however that the
value of x has not changed (== does not change its
operands), so PRINTX prints 1.
LOGIC AND INCREMENT OPERATORS 83

Operators 3.1

initially x=2, y=1, z=0


ese
IN Sy A
x iT] (x&&y) ti z Bind operands to operators according to precedence.
x ((x&&y)iiz)
(x=((x&&y)ttz))
(x=((TRUE&&TRUE) i iz) ) Logical operators are evaluated from left to right.
An operand to a logical operator is FALSE if it is
zero and TRUE if it is anything else.
(x=(TRUE:1z) ) The logical AND, &&, yields TRUE only when both
its operands are TRUE, otherwise FALSE.
(x= (TRUE! | whatever) Once one argument to the OR, | 1, is known to be
' TRUE we know the result of the |i will be TRUE
regardless of the other operand. Hence there is no
need to evaluate the expression further.

More about define. The define statement that begins this program is a little fancier than
that in the previous program. Here, PRINT is the name of a macro with arguments, not just
a simple string. The preprocessor performs two levels of substitution on macros with
arguments: first the actual arguments are substituted for the formal arguments in the macro
body, and then the resulting macro body is substituted for the macro call.
For example, in this program PRINT has one formal argument, int. PRINT(x) is a call
of PRINT with the actual argument x. Thus, each occurrence of int in the macro body is
first replaced by x, and then the resulting string, printf("%d\n",x), is substituted for
the call, PRINT(x). Notice that the formal parameter int did not match the middle
letters in printf. This is because the formal arguments of a macro are identifiers; int
only matches the identifier int.
84 LOGIC AND INCREMENT OPERATORS

Operators 3.2

initially
x=1, y=1, z=0
xa Wyk hez
x ion Cly) && z Binding operands to operators.

xii ((ly)&&z)
(xit((ly)&&z) )

(TRUE!1((ly)&&z) ) Evaluating from left to right.


( TRUE| | whatever)
TRUE,
Ox 4

Operators 3.3

initially x=1, y=1


Zo=
x t+ = 1

Z= (x++)) = 1 Following precedence.

Zo= ( (x) —1))


GZSisc)al) )
GZS) oi, andex=2 The ++ to the right of its operand is a post increment.
This means that x is incremented after its value is used
in the expression.

(z=0)
LOGIC AND INCREMENT OPERATORS 85

Operators 3.4

initially x=2, y=1, z=0


Zt+=-X+++ ++ y

Z+=- (x++) + (++y) Unary operators associate from right to left,


thus ++ binds before unary -. (Actually, the
expression would not be legal if it were
arranged so that the - bound first since ++ and
-- expect a reference to a variable (an lvalue)
as their operand. x is an lvalue, but -x is not.)

zt+= (-(x++)) + (++y)

z+= ((-(x++))+(++y) )

(qe (( (—a((eenbae ))))ae((aearsZ)) ))9)


(z+=((-2)+2)),andx=3, y=2 Evaluating from the inside out.
(z+=0)

(z = 0+0)
(z=0)
0

Operators 3.5

initially x=3, z=0


Z=x/++x

Z=x/ (++x)

Z= (x/(++x) )

(z=(x/(++x)))

You may be tempted at this point to begin evaluating this expression as before, from
the inside out. First the value of x would be retrieved and incremented to be divided
into the value of x. One question that might be asked is what value is retrieved from x
for the numerator, 3 or 4? That is, is the value for the numerator retrieved before or
after the increment is stored? The C language does not specify when such a side
effect! actually occurs; that is left to the compiler writer. The message is to avoid
writing expressions that depend upon knowing when a side effect will occur.

1. A side effect is any change to the state of a program that occurs as a byproduct of executing a
statement. By far the most common side effects in C relate to storing intermediate values in
variables, such as with the increment operator as above or with an embedded assignment operator.
86 BITWISE OPERATORS

Operators 4.1

initially x=03, y=02, z=01


eV OeZ, Integer constants preceded by 0 (zero) are octal
values. Octal notation is particularly useful when
working with the bitwise operators because it is
easy to translate octal numbers to binary. In this
problem, 01, 02, and 03 are equivalent to 1, 2,
and 3, so using octal is merely a cue to the reader
that the program will deal with the values of x, y,
and z as bit strings.

(x! (y&z) ) Following precedence.


er CO2&0s)) The innermost expression is evaluated first.

(x10) In binary, 01=1, 02=10, 03=11


10
& 01
00
(0310)
03
BITWISE OPERATORS 87

Operators 4.2

initially x=03, y=02, z=01


xiy&-zZz
(xt (y&(~z)))
(x1 (y&~01) ) ~ complements each of the bits of its operand.
hUssO Py eOMEDeCOmCSml creme OF
(x1 (02&~01) )

(03102) In binary,
OF LOMO
& 1 . 110
~~ 0000010
3

10
Feoried
abso

Operators 4.3

Initallvex=—Ol ney, O12 mez On


se SIR SS a be

(x*(y&(~-z))) This is the same as the previous problem except


that the exclusive or, ~, has been substituted for
the inclusive or, |}.

(x*(02&~01))

(08302)
4 In binary,

10
ali

01
88 BITWISE OPERATORS

Operators 4.4

initially
x=03, y=02, z=01

x& y && Zz

((x&y )&&z )

((038&02)&&z)

(028&z)

( TRUE&&z )
( TRUE&&0
1)

( TRUE&& TRUE )
TRUE, or 1 && yields TRUE whenever both operands are
TRUE.

Operators 4.5

initially x=0 1
Wisc ue

Gia ns)
(( 1!TRUE)
ix)
(FALSE:01)
(0101)
,
BITWISE OPERATORS 89

Operators 4.6

initially x=01
~xX 0x
((~x) 1x)
(~01101)

=I In binary,
loo
o WIG
re .001
A)Ae
(The answer is the same for all values of x. Actually, it is -1
on a two’s-complement machine, like the PDP-11. On a
one’s-complement machine 1...1 would be -0. For the few
cases in this book where it matters, two’s-complement will be
used.)

Operators 4.7

initially x=01
ia

GOnia OK)
0 In binary,
OFS 7 Onl
Fee Oteenet OM
7505200
(The answer is the same for all values of x.)
90 BITWISE OPERATORS

Operators 4.8

initially x=01
See ees

x = 01<<3

x=8 In binary,
CVG s. 04
<< 3
0...01000, whichis 8

Each place shifted to the left is an effective multiplication by 2.

Operators 4.9

initially y=-01
y <<=3

y = -01<<3
y= —8 In binary,
TOGA sae
<< 3
Tee VOUS) Bree

Operators 4.10

initially y=-08
Y +e2 3

y = -08>>3

It is tempting at this point to assume that y = -1. Unfortunately this is not always the
case, since the computer may not preserve the sign of a number when shifting. C does
not guarantee that the shift will be arithmetically correct. In any case, there is a much
clearer way to divide by 8, namely y=y/8.
RELATIONAL AND CONDITIONAL OPERATORS 91

Operators 5.1

initially x=3, y=2, z=1


bens Me Te Sig Bi bre

ae Minerey:)) 2 C5 ) The conditional operator, aside from taking three


operands, is parsed like any other operator.

((x<y)?(y):(x))
(FALSE? (y): (x) ) First the condition is evaluated. Then either the
true part or the false part is evaluated, but not
both.
eon) In this problem the value of the condition is
FALSE, thus the value of the conditional
expression is the value of the false part.

Operators 5.2

Minitiallivex= Srey — rez al


gas Oe Oh eecr ena

((x<y)?(x++):(yt+))

(FALSE? (x++):(y++) ) First evaluate the condition.

((y++)) The condition is FALSE so the false part is


evaluated.
(2) andiy=3
2 (And since x++ was not evaluated, x remains 3.)
92 RELATIONAL AND CONDITIONAL OPERATORS

Operators 5.3

initially x=3, y=3, z=1


Zo taee
eT Toate. sc Va toe

(z+=((x<y)?(x++)
3 (y++)))
(z+=(FALSE? (x++):(y++)))
(z+=((y++) ) The result of the conditional expression is
the right-hand side of the assignment.

(z+=(3)), and y=4


(z=z+3)

(z=4)
Ss

Operators 5.4

initially x=3, y=4, z=4


(2SSy¥
c= x) 7 120

(((z>=y)>=x)?(1):(0))
GCIRUE> ==) PC 11) 20.0) The condition is evaluated from the inside
out.

(Ct ex 701) CO))) The value of the innermost relation is


TRUE. It is compared to the integer x.
While this is legal in C, it is really playing
footloose with the value TRUE being an
integer 1, and, as in this problem, it is
usually not what’s wanted. (The next
puzzle shows the right way to compare
three values.)

(FALSE? (1):(0))

((0))
0
RELATIONAL AND CONDITIONAL OPERATORS 93

| Operators 5.5

initially x=3, y=4, z=4


z>=y&& y >=x

((z>=y)&&(y>=x) )
(TRUE&&(y>=x) ) Evaluating from left to right.

( TRUE&&TRUE )

(TRUE)
1
94 OPERATOR PRECEDENCE AND EVALUATION

Operators 6.1

initially x=1, y=1, z=1

++ x11 ++ y S& ++ Zz

((++x) 11 ((++y)&&(++z))) Binding operands to operators.


(211 ((++y)&&(++z))), and x=2 Evaluating from left to right.

( TRUE: | whatever) Since the left operand of the |1 is


TRUE, there is no need to evaluate
further. In fact, C guarantees that it
will not evaluate further. The rule is
that a logical expression is evaluated
from left to right until its truth value is
known. For this problem that means y
and z remain 1.

TRUE,
or 1

Operators 6.2

initially x=1, y=1, z=1


++ xGS
++ Yl ++ 2Z
(((++x)&&(++y)
)11 (++z))
((TRUES&(++y))11(++z)),
and x=2
((2&&2)i11(++2)), and y=2 Evaluating from left to right.

(TRUE!
1 (++z) )
TRUE, or 1 z is not affected.

About evaluation order and precedence. For most operators, the order of evaluation is
determined by precedence. As can be seen from the puzzles in this section, there are a few
exceptions to this general rule:

e Pre- increment and decrement operators are always evaluated before their operand is
considered in an expression.

e Post- increment and decrement operators are always evaluated after their operand is
considered.
e Logical AND and OR are always evaluated conditionally from left to right.
OPERATOR PRECEDENCE AND EVALUATION 95

Operators 6.3

initially x=1, y=1, z=1


++ x&& ++ y && ++ z

(((++x)&&(++y) )&&(++z) )
((28&&2)&&(++z)), and x=2, y=2

( TRUE&& (++z) )
(TRUE&& TRUE) , and z=2
TRUE,
or 1

Operators 6.4

initially x=-1, y=-1, z=-1


++ x68
++ yli++z
(((++x)&8&(++y))
ti (++z))
((O&&(++y))
ti (++z)), and x=0
( (FALSE&&(++y))
ti (++z) )
(FALSE! (++z) ) There is no need to evaluate ++y since
the left operand to && is FALSE. The
value of the ii operation is still not
known, however.

(FALSE! 1(0)), and z=0


(FALSE!1FALSE)
FALSE, or 0
96 OPERATOR PRECEDENCE AND EVALUATION

Operators 6.5

initially x=-1, y=-1, z=-1


++ X11 ++ yS&
++ Z

((+4+x) tt ((++y)&&(++z)))
(FALSE: 1 ((++y)&&(++z))),
and x=0
(FALSE! (FALSE&&(++z))),
and y=0
(FALSE!
| FALSE)
FALSE, or 0

Operators 6.6

initially x=-1, y=-1, z=-1


++x&&
++ y && ++ Zz

(((++x)&&(++y) )&&(++z) )
( (FALSE&&(++y) )&&(++z)), and x=0

(FALSE&&(++z) )
FALSE, or 0

About side effects in logical expressions. As you have surely learned by now, the evaluation of
a logical expression can be tricky in C because the right-hand part of the expression is
evaluated conditionally on the value of the left-hand part. Actually, conditional evaluation is
a useful property of the logical operators. The trouble arises when the right-hand part of a
logical expression contains a side effect; sometimes the side effect will occur and sometimes
it won’t. So, while in general it is good practice to use side effects carefully, it is vital in
logical expressions.
CHARACTER, STRING, AND INTEGER TYPES 97

Basic Types 1.1

PRE NT(Cdi5.))) %d format instructs printf to print the argument as a


decimal number. "5" is a pointer to a character array
(i.e., the address of the two character array ’°5’,
ONAN,
PRINTG,, o>) %d causes the decimal value of the character ’5’ to be
printed.!
PRINT(d,5) The integer 5 is printed in decimal.
PRINT(s,"5") %s format instructs printf that the argument is a
pointer to a character array. Since "5" is a pointer toa
character array, the content of that array, 5, is printed.

PRUENTGChae ee) %c format instructs printf to translate the argument


into the character its value represents. Since ’5’ is
the encoded value for 5, 5 is printed.
PRINT(c,53) As seen earlier, the decimal number 53 is the ASCII
code value for the character 5.

PREND (din G@: 5. >5)))) One last time. ’5’ has the integer value 53 which is
greater than the integer 5.

1. The value given here is that for the ASCII character code (see Appendix 3). The ASCII code is but
one of several codes used by computers to represent characters. It will be used in this book for those
few cases where it matters.
98 CHARACTER, STRING, AND INTEGER TYPES

Basic Types 1.2

initially sx=-8, ux=-8


PRINT(0o,sx) %o instructs printf to print the argument as an octal
number.
PRINT(0,ux) The value -8 is a string of 1’s and 0’s just as valid for
unsigned variables as for signed ones.
PRINT (oO, 8x>>3) We have seen this problem earlier. With some
versions of C, right shifting of a signed integer causes
the sign bit to be copied into the vacated high order
bits, thus having the desirable property of preserving
sign. Beware—this is compiler dependent!
PRINT(0,ux>>3) When right shifting an unsigned integer the high
order bits are always filled with 0’s.
PRINT(d,sx>>3) In decimal, right shifting a signed -8 three places
yields the expected - 1 if sign is preserved, 8191
otherwise (in two’s-complement on a 16-bit machine).
PRINT(d,ux>>3) For an unsigned -8, the result is always 8191 (ona
16-bit machine).
INTEGER AND FLOATING POINT CASTS 99

Basic Types 2.1

i=l=f
=d= 1000/3

(i= (l= (f£= (d= (100/73)) ))) Evaluation is from right to left.
(Gia l= a(er—s id= iso) me) ee) Since both 100 and 3 are integers,
the division is integer division and
thus the quotient is truncated.
(i= (l= (£=(double)33) )), and d=33 Recall that the value of an
assignment expression is the value
of the right-hand side cast in the
type of the left-hand side.
(C= (l= (Gf Loa)
is si) meander =3'5

Gaon
g sis rand l= 313
(integer)
33, and i=33

33, an integer

Basic Types 2.2


d=f=1=i1
= 100/73

(d= (f= (l= (i=(100/3)) )))


(d=sGe—s@l— (integer)
35) ™)))nands—3)3

(d=s(£=(Gong))33)))))), anda =33


(di=i(Grltoats)is/3)) ieanditi=3)3
((double)
33), and d=33

33,
a double
100 INTEGER AND FLOATING POINT CASTS

Basic Types 2.3

i=l=f=d=100/3.

(Qe (Lea fa bd= 1004350).)) Jr)>


(i= (l= (f=(double)33.333333) )) ‘

andd=s sscsS a5 '3. isa double so the quotient


retains its precision.
(creat esl(See oe ties e Sess el

and £=33.33333x The printf specification in this


program is ‘*%.8g’’, which tells
printf to output numbers of up
to eight significant digits. Seven
significant digits is about the limit
of precision for floats on the
PDP-11 and VAX, so the eighth
digit is unreliable. The number of
significant digits is, of course,
machine dependent.
(i=(long)33.33333x), and 1=33 The float to long conversion is
through truncation.
(integer) 3 ), and i=33
33, an integer

Basic Types 2.4

d=f=1=i1s= (double) 100/3


(d= (f= (1= (i= ((double) 100) /3)))) Notice that type cast has higher
precedence than /.
Ve (ra eeae
r Soca a) }
(d= (f= (l=(integer)33.333333) ))
and i=33

(d= (£f=(long)33) ), and 1=33

(d=(ftloat) 3 ), and f=c3

( (double) 3 ), and d=33

33, a double
INTEGER AND FLOATING POINT CASTS 101

Basic Types 2.5

i=1=f =d = (double) (100000/3)

(i= (1= (f= (d= ((double)(100000/3)) ))))

(i= (l= (f= (d=(double)33333) ))) The operand to the


type cast is the quotient
from the integer
division of 100000 by
3:

Cu=s(G =s (t= ((doubwen 3333s). and:d=3 3333

Cl=sGlaiCeloat) 3/3333) ) andst=s S343

Gu—iGlong) 33333) eengdel=s3i5o5

( (integer )33333), and i=33333 or overflow 33333 cannot be


represented as a 16-bit
signed integer. Most
implementations of C
will happily permit
arithmetic over- or
underflow. When your
calculations potentially
push the limits of your
machine, it is wise to
insert explicit range
checks.
33333, an integer, or overflow
102 INTEGER AND FLOATING POINT CASTS

Basic Types 2.6

d=fel=i= 100000/3

(d= (f£= (l= (1210000073) ) ))

(d= (feu(l=(inceger)sssoce 740

and i=33333, or overflow As we’ve seen before, 33333 is


overflow for a 16-bit signed integer.
For integer representations with more
bits, i would get 33333, as would 1,
f, and d. We’ll continue with the case
for 16-bit integers.

(d=(f£=(Long)-32203)) )
and 1=-32203 The result of an operation that leads to
overflow is a legitimate number, just
not the number expected. The 33333
is lost, regardless of future type casts.

(d=(float)-32203), and f=-32203

( (double) -32203), and d=-32203

-32203, a double

About numbers. The treatment of numbers is not one of C’s strong points. C does not
provide a way to catch arithmetic errors even if the hardware so obliges. The range of the
numerical data types is fixed by the compiler writer; there is no way to specify a range in the
language. To achieve range checking, about the best one can do is explicitly test the value
of variables at critical points in a calculation.
MORE CASTS. 103

Basic Types 3.1

initially d=3.2, i=2


x = (y=d/i)«2

(x= (y=3.2/2) *2)


(Sc a(Gy=alienG)) 3628) 3.2,a double, is of higher type than 2, an int.
Thus the quotient is a double.
(Gxc=alse2))enandyi=i y, an int, gets 1.6 truncated.

(x=2)
Qreandes—2

Basic Types 3.2

imitiallyad=Sr)2)u=2
y = (x=d/i)*2
(y= (x=1.6)*2)
(y=1.6%2),
and x=1.6 Since x is a doubl1le, the result of the assignment is a
double.

(Cyi=3ee2)) 1.6, a double, determines the type of the product.


3, and y=3 y, an int, gets 3.2 truncated.
104. MORE CASTS

Basic Types 3.3

initially d=3.2, i=2


Vrencee (x= 257 i)

(y= d* (x=2.5/d) )
(y= "d*2..57d ), and x=2.57d x is a double, so the precision of
2.5/4 is retained.

(y=2).5)
2, ange =2 y gets 2.5 truncated.

Basic Types 3.4

initially d=3.2, i=2


c=a ey = (CLmb
2, 9 Is ae

(x="de (y=(2+7
2.1) 7a) } Type cast has higher precedence than
+.

(xan (y= 1Adu)


(x= d* (y=.something) )

(x=d*0), and y=0 y gets 0 regardless of the value of


**something’’, since *‘. something’’ is
between 0 and 1.
0, and x=0

About mixing types. By now you have seen enough examples of how mixing floating point
and integer values in expressions can lead to surprises. It is best to avoid arithmetic with
operands of mixed type. If you do need it, make the type conversions explicit by carefully
using casts.
IF STATEMENT 105

Control Flow 1.1

initially y=1
aia ( 7 tS) )) Seebys The first step is to evaluate the condition.
(ya 08)

(n=O)
TRUE Since the condition is TRUE, the true part of
the if statement is executed.
ee)

Control Flow 1.2

initially y=1
itary = 0m) eS) em serac=) 5)

(Sy==09) Evaluate the condition.

FALSE

pe
ey 1S Execute the false part of the if statement.
106 IF STATEMENT

Control Flow 1.3

initially y=1
x=
Dl v0) LEC yo0) mass
else x=5;

Bea First x is assigned 1.


eee <0) at The braces indicate statement nesting.
Le( y>O0 )ixsSs
else x=5;
}
( y<O )
FALSE The condition of the first if is FALSE, thus the
true part is skipped. The else clause is contained
in the true part of the first if since it belongs to
the second if. The rule in Cis that an else
clause belongs to the closest if that can accept it.

Control Flow 1.4

initially y=1

oie ( PABi
a s10)e)) Bac
else =
if ( y==0 ) x=5;
)
else x=7;

(z= (a7<0))) Begin by evaluating the first condition. We will


use parentheses, as before, to indicate the binding
of operands to operators.
(get 10)" )

( z=FALSE )

FALSE, and z=0


( y==0 ) Since the condition of the first if statement is
FALSE, the false part of the if is executed. The
false part is another if statement, so its condition
is evaluated.
FALSE

x=7 The condition is FALSE, thus the false part of the


second if statement is executed.
IF STATEMENT 107

Control Flow 1.5

initially y=1
if( z=(y= )) )) seeath.e secs)
whie(43 (ye ) ) dt seeSg } seoBig The true part of an if is the single
statement or block following the condition
for the if.

( z=(y==0) ) Evaluate the condition.

( z=FALSE )
FALSE, and z=0

x 3 Since the if statement does not have a


false part, control falls through to the next
statement.

Control Flow 1.6

initially y=1
Je ((xezey jy x=3)3

Teo eete ys ea soy ke Ss The true part of the if is a null statement.

( x=(z=y)) ) Evaluate the condition.

( x=(z=1))
(ce) pea ne zi=a0

TRUE eanGdisc=—i

x 3 The if condition is TRUE, so the true part


of the if is executed. The true part is a
null statement and has no effect. Finally,
the statement following the if is executed.
108 WHILE AND FOR STATEMENTS

Control Flow 2.1

initially x=0, y=0


while( y<10 ) ++y; x +=y;3

while( y<10 ) ++y; Begin by analyzing the factors that control


the execution of the while statement:

( y<10 ) The loop condition. The body of the loop is


executed as long as the loop condition
evaluates to TRUE.
( y>=10 ) The exit condition. The exit condition, the
negation of the loop condition, is TRUE
upon a normal termination of the loop.
The initial value of the control variable.
This is the value of the control variable
during the first iteration of the loop body.
++y The effect on the control variable of
executing the body of the loop.

y = 0 through 9 in the loop y=0 the first time in the loop. Each time
through the body y is incremented by 1.
y = 10 on exit When y= 10 the loop condition evaluates
to FALSE and the iteration terminates.

x += Y; Control passes to the statement following


the loop body.
x= 0+70

x= 10
WHILE AND FOR STATEMENTS 109

Control Flow 2.2

initially x=0, y=0


while( y<10 ) x += ++y;

(y <10 ) The loop condition.


Gy =ni0) The exit condition.
y= 0 The initial value of the control variable.

The effect of the loop on the control


variable.
0 through 9 in the loop As in the previous problem.
=++y x gets the sum of the values of y (after
y is incremented) in the loop.

ID The sum of the integers 1 to 10.


10 on exit

Control Flow 2.3

initially y=1

while( y<10) {x=y+t; z=+ty; }


ey <10 ) The loop condition.

Cy. e340) )) The exit condition.

The initial value of the control variable.

The effect of the loop on the control


variable.
3 5 S35 By 752 in Ne Oyo y= 1 the first time in the loop and is
incremented by 2 each time through
the loop.
* |2 Wig ig Sin gS x takes on the value of y in the loop
before it is incremented.
N reagan, (hn
I z takes on the value of y in the loop
after it has been incremented by 2.

< WW 11 on exit
110 WHILE AND FOR STATEMENTS

Control Flow 2.4

for yea ls y< 10) yr ) xeys The for statement aggregates the
controlling factors of the loop.
y<10 Loop condition.
y>=10 Exit condition.
al Initial value.
yt+t Effect.
y = 1 through 9 in the loop
x = 1 through 9 x gets the value of y in the body of the
loop.
y = 10 on exit

Control Flow 2.5

for (y=15) (s=7) <0) yer ) 3

y<10 Loop condition.


ene) Exit condition.
y=1 Initial value.
ytt+ Effect.
y = 1 through 9 in the loop
x = 1 through 10 x gets the value of y just before the
evaluation of the loop condition. Note that
the condition is evaluated one time more
than the body is executed.
y = 10 on exit
WHILE AND FOR STATEMENTS 111

Control Flow 2.6

for( x=0,y=1000; y>1; x++,y/=10 )


PAREN2 Cd ava) ns

yo Loop condition.
y<=1 Exit condition.
y=1000 Initial value.
y/=10 Effect.
y = 1000, 100, 10 in the loop

x 0,1,2 inthe loop x=0 from the for statement


initialization. x is incremented
after the body and before the
test. (The PRINT2 statement
is in the body.)
y = 10n exit

<e=eS Onvexit
112 STATEMENT NESTING

Control Flow 3.1

initially i=in=high=low=0, input="PI=3.14159, approximately’

while( c=(NEXT(i)!=EOS) ) The loop condition effectively is


NEXT(i) !=EOS, where
NEXT(i) successively takes on the
character values from input. c
gets the truth value of
NEXT(i)!=EOS, which, by
definition, is TRUE in the loop and
FALSE on exit.

LE (°1<"0" ) Vow+-+ c is always 1 in the loop, so low is


always incremented (1 < 060).

while( c=(I!=EOS) ) The iteration continues until all the


characters in input have been
read. C uses the ASCII nul
character, 00, as the end of string
marker.

Control Flow 3.2

initially i=in=high=low=0, done=FALSE,

input="PI=3.14159, approximately n

while( (c=NEXT(i))1!=EOS && !done ) c successively takes on the value of


each character from input.
i E(B 0a) The first time through the loop
c=’P’, hence the if condition is
FALSE.

@lge 1£( “Pp s°9" } TRUE, and high++.


while( ’I’1!=EOS && !done ) Back at the loop test. (The if
statement comparing low, high,
and in with ENUF is outside the
loop, indentation to the contrary.)
Since done is not effected within
the loop, the iteration ends when
c=EOS. In the loop, the counters
low, in, and high are
incremented depending upon the
value of c with respect to the digit
characters ‘0’ to ’9’.
STATEMENT NESTING 113

Control Flow 3.3

initially i=in=high=low=0, done=FALSE,

input="PI=3.14159, approximately"

while( (c=NEXT(i))1!=EOS && !done ) { c successively takes on the


value of each character from
input.
cea Bape 1()\e)
FALSE.

else if( ’P’>’9’ ) TRUE.

done = (++high==ENUF) high, after being incremented,


is not equal to ENUF, so done
is assigned FALSE. high=1.
while( ’I’!=EOS && !done ) TRUE.

aig Bo(pee eine SO) FALSE.

edisienif (41.09 _) TRUE.

done = (++high==ENUF) high=2, done=FALSE.

while( ’=’!=EOS && !Idone ) TRUE.

DE <n. 0h" 92) FALSE.

else if( ’=’>’9” ) TRUE.

done = (++high==ENUF) high=3, done=TRUE.

while( ’3’1!=EOS && !done ) done=TRUE, so


!done=FALSE, and the loop
terminates.
114 SWITCH, BREAK, AND CONTINUE STATEMENTS

Control Flow 4.1

char input[ ]="SSSWILTECH1\1\11W\1WALLMP1" The character array input is


initialized to the character
sine SSS: MPT".

for(t=2: (e=inputl2]) l=" XO": c takes character values from


input beginning at the third
character.

ewiten(’*s*)} 4 The first time through the


switch statement c=’S’”.

default: putchar(’S’ ) The default case is taken


since none of the case labels
match ’S”’. S is printed.
continue The continue statement
forces the next iteration of
the innermost enclosing loop,
in this case, the for loop.
Notice that continue is
effectively a branch to the
reinitialization expression of
the for.

for(s (c=inputlsi l="N0 > 1+) 4 c gets the fourth character


from input.

switch(’w’) { c=’W’.
default: putchar(’W’); continue As before, W is printed.

Similarly for i=4, c=’I’.


Switch t) i=5,c=’L’.
case ’L’: continue The ’L’ case is taken;
nothing is printed.
In the for loop:
dw S;5 ae Tye Nothing is printed.
126, c= Ts T printed.
i=], cans Nothing is printed.
1=8, o=’C’s C is printed.
i=9, c=’H’; H is printed.
BWiten(
1 jit i=10,c=’1".
SWITCH, BREAK, AND CONTINUE STATEMENTS 115

case ‘1’: break The break statement forces


ta

an exit from the innermost


enclosing loop or switch. In
this case, it causes a branch to
the statement following the end
of the switch.
pucchar( =~ ) A space is printed.
fort. (exanputt 11) )t=*\0*s i+4) Back at the top of the for
loop.
switch(’\1") t The character constant ’\n’,
where n is up to four octal
digits, yields a character with
the octal value n. For instance,
\0 yields the ASCII character
nul, and \101 the character
A.

case 1: Case labels may be either


character or integer constants.
\1 matches the integer 1 since
C automatically coerces char
town:

while( (c=input[++il)!=’\1’ && cl=’\0’) ; = The exit condition for the


while is either c==’\1’ or
end of string. Each time the
while test is made, i is
incremented by 1, thus, the
loop advances i past the
characters of input to either
the next ’\1’ character or the
end of string.
In the while loop:
Laon Cau Nati lias Nothing is printed.
SiC —aWhes Nothing is printed.
ee, Gar? 8 The while loop terminates.
case 9: putchar(’S’) The statements from each case
follow one another directly;
there is no implied break
between cases. Case 9 follows
case 1. S is printed.
case ’E’: case ’L’: continue Cases ’E’ and ’L’ follow case
9.
116 SWITCH, BREAK, AND CONTINUE STATEMENTS

for( 3; (c=input(15]); i++) f Again, back to the top of the


for loop.
In the for loop:
LieiouuiGat Wiis W is printed.
mes Si, Aol
IN Oe A is printed.

nha Eamon aaes Nothing is printed.

Teer Cer alr Nothing is printed.

= Oem oe a M is printed.

P= te= bes P is printed.

P= 2 C= tes Space is printed.


V=22.1Car NOM s The for loop terminates.
putchar(’\n’ )
CHOOSE THE RIGHT CONDITION 117

Programming Style 1.1

The need for a continue statement can often be eliminated by altering a test condition.
The resulting code is sometimes remarkably cleaner.

For this problem, simply negating the test to the if statement will do.
while(A)
ska
(([132))) (OR

Programming Style 1.2

The do...while is another of the C constructs that can sometimes be replaced to


advantage. If either a do...while or a while can be used, the while is always
preferred since it has the desirable property that the condition is tested before every
iteration of the loop. That the condition is not tested before the first iteration of a
do...while loop has been the source of many a program bug.

In this problem, the if and do...while are redundant; they are effecting a while.

do { First, eliminate
the continue.
np ail(YW as a = eo
} while(A);

while(A) { Then replace the do. ..while and if witha while.


B; C;
}
118 CHOOSE THE RIGHT CONDITION

Programming Style 1.3

The problem of deeply nested if statements is well known to most experienced


programmers: by the time one gets to the innermost condition the surrounding conditions
have been forgotten or obscured. The counter approach is to qualify each condition fully,
but this tends to generate long conditions that are obscure from the start. Alas, good
judgement must prevail!

Here are two possibilities for this problem:

LTE( A && BSE C )) Ds


elspe-vait( VA && BOS&& Ci) Bs
else if( IA && B && IC ) F;

or,

te es)
4e( ASE
OC YDS
else if( !A && C ) E;
else af( WA 6&& TC) F:

Programming Style 1.4

This problem has a straightforward idea hierarchy:


e while there are more characters on the line
e multiway switch based on character type
e return ALPHA
e return DIGIT
e return OTHER.

This translates easily into C:

while( (c=getchar()) != ’\n’ ) {


if( c>=’a’ && c<=’z’ ) return(ALPHA);
else if( c>=’0’ && c<x=’9’ ) return(DIGIT);
else LE( cle* ° && ele*\t” J return (OTHER):
}
return(EOL);
CHOOSE THE RIGHT CONSTRUCT 119

Programming Style 2.1

done = i = 0; The first observation is that the


while( i<MAXI && !done ) { if...continue construct is
DEQ ORS B2)) 3 We) eas effectingan if...else. So
else done++; make itanif...else!
}

a S&S WP Then it becomes clear that

ee cet geOn (ie


2) > eas e one loop condition is done
equal to FALSE;
e done is FALSE as long as
the if condition is TRUE;
e thus, one loop condition is
(Rey
Wes tl,
Make it explicit!

for( i=0; i<MAXT && (x/=2)>1; i++ ) ; A while statement that is


preceded by an initialization
and that contains a change of
the loop control variable is
exactly a for statement.

Programming Style 2.2

There are usually many ways to express an idea in C. A useful guideline is to group ideas
into chunks. C provides a hierarchy of packaging for these chunks:
e the lowest level ideas become expressions;

@ expressions are grouped together into statements;


e statements are grouped together into blocks and functions.

In this problem there is a two level idea hierarchy. At the lowest level are the expressions
B, D, F, and G. They are related as the mutually exclusive cases of a multiway switch. A
cohesive representation for a general multiway switch is the if ...else if construction.
rig ((Z\)) Uste
else if(C) D;
else if (E) F;
else G;
return;
120 CHOOSE THE RIGHT CONSTRUCT

Programming Style 2.3

The key observation in this problem is that the underlying structure is a three-way switch
with mutually exclusive cases.

plusflg = zeroflg = negflg = 0;

if( a>0O ) ++plusflg;


else if( a==0 ) ++zeroflg;
else ++negflg;
CHOOSE THE RIGHT CONSTRUCT 121

Programming Style 2.4

oh et UES Reformatting the


while( (c=getchar())!=EOF && cl=’\n’ ) { statements to indicate
ae CHEM IS Gil Ne? jal nesting is a good start.
sli++] = ¢; Then look closer at the
continue; break and
} continue statements
ave GbS Mat i) eB 4 se to see if they are really
slit++] = c; necessary. The break
} goes easily by adding
the negation of the
break condition to the
condition for the
while.

aL ch WR The first if condition


while( (c=getchar())!=EOF && cl=’\n’ ) { can then be reduced.
awe @ieree )) al (c l= ’\n’ is nowa
sli++] = ¢c; loop condition, hence it
continue; must always be TRUE
} in the if test.)
wet Ges ve? )) silsissl o % %.
}

ct, 2 es The continue


while( (c=getchar())!=EOF && cl=’\n’ ) statement is effecting
ae Glee? ) elie) Ss @x an aif... elise:
else sli++] = Cas

for( i=0; (c=getchar())!=EOF && cl=’\n’3; i++ ) Finally, it is clear that


me ele we? )) oilsill c oe slil gets the next
Gea glial) a ° 8 character if the
character is not a tab,
or, otherwise it gets a
space. In other words,
for( i=0; (c=getchar())!=EOF && cl=’\n’; i++ ) the code merely
Siiacnclac Nt Pe omy bes replaces
tabs by spaces.
The last two versions
show this quite clearly
while also pointing out
the close relationship of
the if to the
conditional. In this
example, the if
emphasizes the test for
tab and the conditional
emphasizes the
assignment to sli].
122 CHOOSE THE RIGHT CONSTRUCT

Programming Style 2.5

tf jek.) vous 37 (ela fox 2 NEARZERO) < In this problem it is quite clear
else y = & / (xl=0 ? x 4° NEARZERO); that x !=0 is not the primary
idea; the test simply protects
against division by zero. The
conditional nicely subordinates
the zero check.

R= MASlesiie)) of Cs LaOn ie akan) Ni Ain blReis A case can be made that the
assignment to y is the primary
idea, subordinating both tests.
(MAX returns the greater of its
two arguments.)
BLOCKS 123

Storage Classes 1.1

int i=0; id=0


(The notation x.n is used to reference the variable x defined at
block level n.') The storage class of i.0 is extern.” The scope of
i.0 is potentially any program loaded with this file. The lifetime
of i.0 is the full execution time of this program.
main( )

if Block level is now 1.

auto int i=1; i.l = 1 (i at level 1).


The storage class of i.l is auto. The scope of i.1 is the function
main. The lifetime of i.1 is the duration of the execution of
main.

PRUEN Dilla ale) When two variables have the same name, the innermost variable is
referenced when the name is given; the outer variable is not
directly accessible.
Block level is now 2.

inter=2\ 22212
The storage class of i.2 is auto, the default storage class for
variables defined in block 1 or deeper. The scope of i.2 is block 2
and its lifetime is the duration of execution of block 2.
PREN Tadd) rs

{ Block level is now 3.


ab,Jaa 4|.2 123)

PRINT1(d,i.2); i.2 is printed since it is the innermost variable named i.


} Block level returns to 2.
PRINT1(d,i.2); i.2 is printed again.
} Block level returns to 1; i.2 dies.
PRINT1(d,i.1); With the death of i.2, i.1 became the innermost variable named
an
Block level returns to 0.

i. The block level at any point in the text of a programis the count of left braces ({) minus the count of
right braces (}). In other words, it is the number of textually open blocks. The outermost level of a
program, i.e., no blocks open, is block level 0.
You might ask why the storage class of i is not explicitly declared here using the extern keyword.
Unless declared otherwise, the storage class for variables defined at block level 0 is extern. Tagging
a variable with extern does not define the variable. Instead, it tells the compiler that the variable
has been defined elsewhere at block level 0.
124 FUNCTIONS

Storage Classes 2.1

int i=LOW; i.0 Il =


main( )

{
auto int i=HIGH; vi) IPs

reset (1-25 The function reset is called with the value i.1/2, or
2. Its execution has no effect on i.l.

PRINT Caan) ¢
reset lai 2). reset is again called with i.1/2. This time i.1 is
assigned 2 as a side effect of the function call. Again,
reset has no effect on i.l.
PRIENT
Gade 2tel ie

ii=Tesec
(ual 72s) ¢ i.l gets the value returned by reset called with
i.1/2. We will expand the function call in line.
int reset(1) The type of the value returned by a function is
specified in its declaration. reset returns a value of
type int.

a(@tmteea =" 1) T.reset = "1:


Parameters in a function behave like initialized local
variables. We indicate these implied assignments by
surrounding them with parentheses.
ireset.= L.reset<=2 7 5% 25 i.reset = 5.

return (i-reset))s reset returns the integer 5; thus, i.l = 5.


}

PRENT
(de dade)
workover(i.l);3 workover is passed the value of i.1; i. is not
affected by the call. We'll expand workover since it
includes a PRINT.
workover(5) If not otherwise specified, functions return an int.
{ (int i=5;) i.workover = 5.
i.workover = 0 * whatever; i.workover = 0.

PRINT1(d,i.workover) ;

return(i.workover) ; workover returns 0, but the value is ignored in the


calling routine.
}
PRINT1(d,i.l);
}
MORE FUNCTIONS 125

Storage Classes 3.1

alae, SLEPIPR S10) 4,

main()
{

aueonn Gray. s i.l and 35.1 are defined, but not yet set.

Iily= reset ()): i.l gets the value returned by reset.


reset()

{
return(i.0); As reset has neither a parameter nor a
local variable named i, the reference to i
must refer to i.0. reset returns 1, so
stgi) 34,
}
eepe(( SpilSds spilsske sil )) x J.—
I —

PRINT
2 (0052.1 5.5.15);
PRINT1(d,next(i.l));

TONS
soKEb e185((41),

{o(Gintey= 113) TolNed! = le

return ( j.next=i.0++) ; i.O = 2 but next returns 1 since the


increment occurs after the value of i.0 is
taken.

The return statement references i.0


since next knows of no other i. j.next
dies with the return.

PRINT1(d,last(i.l));

lnitcelialsit (a)

xf (Gieke 5jS41 8) j.last = 1.

Static int 1=0); ilast = 1/0"


last has a local variable named i
initialized to 10. The storage class of i is
static, which means that i is initialized
when the program is loaded and dies when
the program is terminated.
126 MORE FUNCTIONS

return( j.last=i.last--—) ; i.last = 9 but 10 is returned since the


decrement occurs after the value is taken.

j.last dies with the return, but i.last lives


on. Thus, when last is called again,
i.last will be 9.

}
PRINT1(d,new(i.l+j.1));
int new(2)

i ((Giboke ale). i.new = 2.

ine y= 105 j.new Il 10.

return(i.new=j.new+=i.new ) ; j.new = 12, i.new = 12, and 12 is


returned.
j.new and i.new die with the return.

}
for( J.le=t; 4.1<3; 4.14% 34 4.1 = 2.
Back to the for statement. For this
iteration we will generalize about the effect
of each statement.

RELN
A (i tel guelede ne The effect of executing the loop body is to
increment j.1 by one. The loop has no
effect on the value of i.1.
PRIUNT
1 (di enext (i.0 ))s next ignores the value it is passed and
returns the current value of i.0. Asa side
effect of executing next, i.0 is
incremented by one.

PRINT
1 (dad, last (d,.1).)% last also ignores the value of its passed
argument. It returns the current value of
its local static variable, i.last. Asa
side effect of executing last, i.last is
decremented by one.
PRINT1(d,new(i.l+j.1)); new returns the value of its argument plus
10. There are no lasting side effects.
FILES 127

Storage Classes 4.1]

aiselas SWE 4}.8

main( )

Envoy slic ak A'ghs

ole=eresie tio)

extern int i; The extern statement tells the compiler that i is an


external variable defined elsewhere, possibly in
another file. Here i refers to i.0.
reset()

return(i.0); i.0 is the external i referenced in reset.


i.l = 1.

}
eopel( Spills siallesie gipileses: jak j.1 = 1.
PRINT2\G,
4.15 gelt)s
PRINT1(d,next(i.l));
static int i=10; The second source file begins with an external
definition of a variable named i. This definition
might appear to be in conflict with the external
variable i defined in the first file. The designation
static, however, tells the compiler that this i is
known only within the current file. In other words, it
is only known within the functions next, last, and
new. We will reference it by i.nln; i.nln = 10.

next ()

The declaration of next does not include any


arguments. The value passed by main is ignored.
return(i.nin+=1) ; i.nin = 11 and next returns 11.

}
PRINT1(d,last(i.1));
Lase()
{
return(i.nln-=1) ; i.nln = 10 and last returns 10. last references
the same i previously incremented by next.
128 FILES

PRINT1(d,new(i.l+j.1));
new(2)

it.((aleaieesh She) i.new = 2.

static int yo; 4j.new = 3.

return (i.new=j.new=5+2) 5 j.new = 7, i.new = 7, and 7 is returned.


i.nln is unaffected, i.new will die with the
return, and j.new will be 7 when new is called
again.

}
for( j.1=1; j.1<3; j.l++) { 4.1 = 2.
In this iteration we will generalize about the
effect of each statement.

PRENT
Zi(de calnmyalaie The effect of the loop is to increment j.1 by
one.
PRINT1(d,next(i.l)); next increments i.nln and returns the
resulting value.

PRINT WC d ac te(acl ys last decrements i.nln and returns the


resulting value.

PRINT1(d,new(i.l+j.1)); new adds its argument to j.new and returns


the resulting sum.
SIMPLE POINTER AND ARRAY 129

Pointers and Arrays 1.]

Pera lentO. Ton Ad a is defined to be an array of five integers, with


elements ali]=i for i from 0 to 4.
fon (W=0;502<=4 5 244) ) i takes on the values 0 to 4.

PRidgat ad) ali] successively accesses each element of a.

Pointers and Arrays 1.2

int *p; Declarations of the form type *x tell the compiler


that when *x appears in an expression it yields a
value of type type. x is a pointer-to-type taking on
values that are addresses of elements of type type.
Type is the base type of x. In this problem, p is
declared as a pointer-to-integer; the base type of p
issunt.

for( p= &al01; &al0] evaluates to the address of alO].


p<=&al4]; Array elements are stored in index order, that is,
al0O] precedes al 1] precedes al2] and so on.
Thus p, initialized to &al 0], is less than &al 4].
PR(d,*p);3 *p evaluates to the integer stored at the address
contained in p. Since p holds &al01], *pis
alo].
p++ ) When applied to a pointer variable, the increment
operator advances the pointer to the next element
of its base type. What actually happens is that the
pointer is incremented by sizeof (base type)
bytes. C does not test to insure that the resulting
address is really that of a valid element of the base
type. In this problem, p is advanced to the next
element of a.
p<=&al4] p is again tested against the end of the array. The
loop is terminated when p points beyond the last
element of a. While in the loop, p points
successively to each element of a in index order.
130 SIMPLE POINTER AND ARRAY

Pointers and Arrays 1.3

for( p=&al0],i=1; i<=5; i++ ) p points to the start of the array a. i takes
on the values 1 through 5.
PR(d,plil); plil] successively refers to the elements of
a. pl[5] points outside of the array.

About arrays and indices. Though by far the most common use of [] is to-represent array
subscripting, [] actually is a general indexing operator. xl[iJ] is defined to be *(x+i),
where x is usually an address and i is usually integral. The rules of address arithmetic
apply, so i is in units of sizeof (base type of x). (it should by now be clear why array
indices begin at 0. An array name is actually a pointer to the first element in the array. An
index is the offset from the array start. The offset to the first element from the array start is
0.) In this last problem, i is used to index off p. pli] = *«(p+i) = *(a+i) = alil.
i goes from 1 to 5. When i=5, p+i points just beyond the end of the array, hence the
value at p+i is unknown. This is such a common mistake, it is worth noting again: an
array with n elements has indices of 0 through n-1.

Pointers and Arrays 1.4

for( p=a,i=0; p gets the address of the first element of a.


Dti <=\asa- p=a, i=0, so p+i=a+0, which is less
than a+4.

PR(d,*(p+i)); *(p+i) = *(a+0) = alo].


Pp+t+, i++ ) P points to the second element of a, i is
af

pti <= a+4 p=at+i1, i=1, thus p+i=a+2.

PR(d,*#(p+i)); *(p+i) = al2].


p++, i++ p=a+2, i=2.
pti <=a+4 pti = a+4.

PR(d,*(p+i)); *(p+i) = al4l].


P+t+, i++ p=a+3, i=3.

pti <=a+4 p+i = a+6, and the loop terminates.


SIMPLE POINTER AND ARRAY 131

Pointers and Arrays 1.5

for( p=a+4; Pp points to the fifth element of a.


Pp >= a; The loop terminates when p points below a.
PR(d,*p) 5; The integer pointed to by p is printed.
joo
p is decremented to the preceding element.

Pointers and Arrays 1.6

for( p=a+4,i=0; i<=4; i++ ) P points to the last element of a, i goes from
0 to 4.

PR(d,pl-il); The element -i away from the last element of


a is printed.

Pointers and Arrays 1.7

for( p=a+4; p>=a; p-- ) Pp points successively to the elements of a from


the last to the first.
PR(d,alp-al); p-a evaluates to the offset from the start of
the array to the element pointed to by p. In
other words, p-a is the index of the element
pointed to by p.
132 ARRAY OF POINTERS

Pointers and Arrays 2.1

int al ie £05 1,2 ;'3 4+ a is initialized to be an array of five


integers.

int «p(] = {a,at+1,a+2,a+3,a+4}; When encountered in an expression,


*pl] evaluates to an integer, thus
pl] must point to an integer, and p is
an array of pointer-to-integer. The five
elements of p initially point to the five
elements of a.

int **pp iT} ue) **pp evaluates to an integer, hence


*pp must point to an integer, and pp
must point to a pointer-to-integer. pp
initially points to p[0].

Figure 2.1 illustrates the relationships between pp, p, and a.

Figure 2.1
ARRAY OF POINTERS 133

Pointers and Arrays 2.2

PRINT2(d,a,+#a); As noted earlier, the name of an array is


synonymous with the address of the first element in
the array. The value of a is thus the address of the
array a, and *a is equivalent to al0].

PRINT3Z(d,p,*p,*#p); p evaluates to the address of the first element of


the array p, *p yields the value of the first
element, i.e., p(0J, and **p yields the integer at
the address.contained in p[ 0], i.e., the value at
alo].

PRINT3(d,pp,*pp,**pp) ; pp yields the contents of pp, which is the address


of p. *pp yields the value at p, or p[0]. And
*+*pp yields the integer pointed to by p[ 0], or
alo].

Pointers and Arrays 2.3

pprtr+e pp is a pointer to pointer-to-integer (the base type


of pp is pointer-to-integer), so pp++ increments
pp to point to the next pointer in memory. The
effect of pp++ is indicated by the bold arrow in
Figure 2.3-1.

PpPp-p pp points to the second element of the array p,


pl1J. The value of pp is thus p+1.
pp-p = (p+1)-p, which is 1.

#pp-a pp points to p[ 1] and «pp points to the second


element of the array a. The value of *pp is thus
a+1. *#pp-a = (a+1)-a.
&%#FDD *pp points to al 1], so **pp yields the contents
atal1].

#DD++ *(ppr+rt)
Unary operators group from right to left. First the
increment is bound, then the indirection. The bold
arrow in Figure 2.3-2 shows the effect of the
increment.
#++DDp *(++pp)
(Figure 2.3-3)
++4Dp ++(#pp)
(Figure 2.3-4)
134 ARRAY OF POINTERS

Figure 2.3-1 Figure 2.3-2

pp PP

p p

a a

Figure 2.3-3 Figure 2.3-4


ARRAY OF POINTERS 135

Pointers and Arrays 2.4

pp n Ppp

Pasi] talitilis|9 of) REAREY


[eseoES EEN
a (0)1]2/3]4 a (011) 2/3] 4)
Figure 2.4-1 pp=p Figure 2.4-2 *(*(pp++) )

Ppp

Figure 2.4-3 *«(++(*pp) ) Figure 2.4-4 ++(*(*pp) )


136 MULTIDIMENSIONAL ARRAY

Pointers and Arrays 3.1

a is a 3 by 3 matrix with rows 123, 456, and 789.


alil][ 4] evaluates to an integer at offset j from
the start of row i. ali] yields the address of the
first element of row i. And a yields the address of
the first row of the matrix a. Thus a is a pointer to
three-element-integer-array, and al ] is a pointer-
to-integer.

*pal] evaluates to an integer, thus pal] isa


Ite pallvsall =e 4 pointer-to-integer and pa is an array of pointer-to-
aloOd,alt)sal2] integer. pal0O] is initialized to the first element of
}; the first row of a, pal 1] to the first element in the
second row, and pal 2] to the first element in the
third row.

p is a pointer-to-integer initially pointing to the first


int *«p = alo]; element of the first row of the matrix a.

Figure 3.1 illustrates the relationships between a, pa, and p.

Figure 3.1
MULTIDIMENSIONAL ARRAY 137

Pointers and Arrays 3.2

LOC = 0)se < Sie ait) i goes from 0 to 2 in the loop.


alil(2-i] alil[2-i] selects the diagonal from al01[2] to
al2)[ol.
xalil ali] yields the address of the first element of the
ith row in the matrix a. *ali] yields the value of
the first element of the ith row.
*(*(ati)+i) ati yields the address of the ith row of a. *(at+i)
yields the address of the first element from the ith
row. *(a+i)+i yields the address of the ith
element from the ith row. And *(*(a+i)+i) gets
the integer value from the ith element of the ith
row.

Pointers and Arrays 3.3

Lor =O) < 3+) i goes from 0 to 2 in the loop.


palil palil] accesses the ith element of pa. *«palil]
accesses the integer pointed to by the ith element of
pa.
plaid P points to the first element of the first row in the
matrix a. Since the base type of pis int, pli]
yields the ith element of the first row in a.

About array addresses. We have noted several times that the address of an array and the
address of the first element in the array have the same value. In this past puzzle, we saw
that a and al0] evaluated to the same address. One difference between the address of an
array and the address of the first element in the array is the type of the address and, hence,
the unit of arithmetic on an expression containing the address. Thus, since the type of a is
pointer to three-element-integer-array, the base type of a is three-element-integer-array and
a+1 refers to the next three-element-integer-array in memory. Since the type of al0] is
pointer-to-integer, the base type of al 0] is integer and al01]+1 refers to the next integer
in memory.
138 POINTER STEW

Pointers and Arrays 4.1

char «*cl] = { *cl] evaluates to a character, so cl] points to


"ENTER", characters and c is an array of pointer-to-character.
"NEW", The elements of c have been initialized to point to the
PPOZNT: , character arrays "ENTER", "NEW", "POINT", and
“ELRS T "FIRST":
rs

char **cpl] = { **cpl] evaluates to a character, *«cpl[ ] is a pointer-


c+3,c+2,c+1,¢ to-character, and cpl] is a pointer-to-pointer-to-
BS character. Thus cp is an array of pointers to pointer-
to-character. The elements of cp have been initialized
to point to the elements of c.

char ***Cpp = cp; ***cCpp evaluates to a character, **cpp points toa


character, *cpp points to a pointer-to-character, and
cpp points to a pointer-to-pointer-to-character.

Figure 4.1 illustrates the relationships between cpp, cp, and c.

Figure 4.1
POINTER STEW 139

Pointers and Arrays 4.2

#(#(4++cpp ) ) Increment cpp then follow the pointers.


(Figure 4.2-1)
(*(--(*(++cpp))))+3 Increment cpp, follow the pointer to cp[2],
decrement cp[ 2], follow the pointer to c[0],
index 3 from the address in c[0]. (Figure
4.2-2)
(*(ceppl(-2)]))4+3 Indirectly reference -2 from cpp yielding
cp[0], follow the pointer to c[3], index 3
from the address in c[3]. (Figure 4.2-3)
((cppl-1])C-1])+1 Indirectly reference -1 from cpp yielding
cpl 1], indirectly reference -1 from cp[1]
yielding c[ 1], index 1 from the address in
cl1]. (Figure 4.2-4)

About pointers. If you can work this puzzle correctly then you know everything you will ever
need to about the mechanics of using pointers. The power of pointers lies in their
generality: we can chain them together to form an endless variety of complex data
structures. The danger of pointers lies in their power: complex pointer chains are seldom
readable and even more seldom reliable.
140 POINTER STEW

Pointers and Arrays 2.4

cpp

cp

Figure 4.2-3 Figure 4.2-4


SIMPLE STRUCTURE, NESTED STRUCTURE 141

Structures 1.]

Static struct $1) { The structure tag $1 refers toa


char cl4], «s; structure containing a character
msi = { "apc". “der 3 array, c, of length 4, anda
character pointer, s. The
structure variable s1 is an instance
of the structure $1 initialized to
char cl4]="abc",
*s="def"

The structure has been defined as


static so that it may be
initialized in the definition.

Sitactems CrUCcte Smt The structure tag S2 refers toa


char *cp; structure containing a character
STEmUC tm Sims Sms pointer, cp, and an instance of the
Peso a to ght" Mia skies Sano nee structure $1, ss1. The structure
variable s2 is an instance of the
structure $2 initialized to
char *cp="ghi";
Seu Ce Soses Sal
i Wesfen ew "mno"};

Figure 1.1 depicts the structures s1 and s2.

s1

ble]a
OQ
nN

Figure 1.1
142 SIMPLE STRUCTURE, NESTED STRUCTURE

Structures 1.2

PRINT2Z (:c;, A character is to be printed.


Cates) oe) Reference the first character of the c field of the structure s 1.
(Figure 1.2-1)

GR ss) Reference the character pointed to by the s field of the


structure s1. (Figure 1.2-2)

Figure 1.2-1

Figure 1.2-2
SIMPLE STRUCTURE, NESTED STRUCTURE 143

Structures 1.3

PRINT2(s, A string is printed.


si.c Reference the string pointed to by the c field of the structure
s1. Recall that c = &c[0]. (Figure 1.3-1)
si.s Reference the string pointed to by the s field of the structure
s1. (Figure 1.3-2)

s1
= alien
: dje] £/8|
Figure 1.3-1

Figure 1.3-2
144 SIMPLE STRUCTURE, NESTED STRUCTURE

Structures 1.4

Figure 1.4-1 s2.cp

Figure 1.4-2 (s2.ss1).s

Structures 1.5

Figure 1.5-1 ++(s2.cp

Figure 1.5-2 ++((s2.ss1).s)


ARRAY OF STRUCTURES 145

Structures 2.1

S1 is declared to be a tag referring to a


Seeneis Sy) structure containing a character pointer, s, an
char *s; integer, i, and a pointer to structure of type
reMe ah $1, sip. This is only a declaration; an
StruCe Sil ees ips instance of $1 is not created.
};

a is a three-element array with elements of


static struct S1 all = { type structure S1. a has been defined as
iecabed "4, Atl, static so that it can be initialized in the
velo hiwewe2 wat oie definition.
{ "ijkl", 3, a }
};

p is a pointer to structures of type $1. p is


struct S1 *p=a; initialized to point to the first element of a.

Figure 2.1 depicts the array a and the pointer p.

Figure 2.1
146 ARRAY OF STRUCTURES

Structures 2.2

PRINT3(s, Strings are to be printed.


(ako)is Reference the string pointed to by the s field of the
structure that is the first element of a. (Figure 2.2-1)

p->s Reference the string pointed to by the s field of the


structure pointed to by p. (Figure 2.2-2)

(((al2]).sip)->)s Reference the string pointed to by the s field of the


structure pointed to by the s1p field of the structure
that is the third element of a. (Figure 2.2-3)

Figure 2.2-1
ARRAY OF STRUCTURES 147

Figure 2.2-3
148 ARRAY OF STRUCTURES

Structures 2.3

for( i=0; i<2; i++) f i takes on the values of 0 and 1.

PR(d, Print an integer.


--((alil).i) Decrement then reference the integer in the i
field of the structure that is the ith element of
a. (Figure 2.3-1 shows the case for i=0)

PR(c, Print a character.

ereC(ala hy, ey tSe) Increment then reference the fourth character


of the string pointed to by the s field of the
structure that is the ith element of a. (Figure
2.3-2 shows the case for i=0)

Figure 2.3-1
ARRAY OF STRUCTURES 149

Figure 2.3-2
150 ARRAY OF STRUCTURES

Structures 2.4

++(p->s) Increment the s field of the structure pointed


to by p, then output the string pointed to by
the s field. (Figure 2.4-1)

al((++p)->i)l.s First p is incremented, then the s field of the


p->ith structure of a is accessed. (Figure
2.4-2)

al--((p->sip)->i)].s The i field of the structure pointed to by the


s 1p field of the structure pointed to by p is
decremented then used as an index into a.
(Figure 2.4-3)

Figure 2.4-]
ARRAY OF STRUCTURES 151

Sei Ss

Figure 2.4-3
152 ARRAY OF POINTERS TO STRUCTURES

Structures 3.1

struct $1 { $1 is declared to be a tag referring to a


char *S; structure containing a character pointer, s, and
struct S1 #s' Ip; a pointer to structure of type S1, s1p.
};

static struct $1 al] = { a is a three-element array with elements of


1 Wabed", adil tag type structure $1. a has been defined as
{ “etek”; a2 3y static so that it can be initialized in the
{ "ijk1", a } definition.
};

struct $1 *(pl3]); When encountered in a program statement, the


expression «(pl ]) yields a structure $1.
Thus, pl] points to a structure $1, and pisa
three-element array of pointers to structures of
type S1.

Figure 3.1 depicts the arrays a and p.

plo]
Pid
pl2]

Figure 3.1
ARRAY OF POINTERS TO STRUCTURES 153

Structures 3.2

for ( i1=0;3 i<3; i++) i takes on the values 0, 1, 2.

plil= Cali))<s1p3 The ith element of p gets a copy of


the pointer in the s1p field of the ith
element of a. (Figure 3.2-1)

(pl0])->s, (*p)->s, (**p).s These are all ways of saying the same
thing. (Figure 3.2-2)

p
plo] al0O]
pi 14
pl2] al1]

aiezs

p
plol al 0]
pl 1]
pl 2) a4]

aih2

Figure 3.2-2
154 ARRAY OF POINTERS TO STRUCTURES

Structures 3.3

swap(*p,a); p points to p[ 0], so *p yields the content of


pl0] or &al1J. a yields &al0].
temp = (&a[1])->s; Equivalently, temp = al1].s.
(&al1])->s = (&al[0])->s Or, ald] cs = alotves
(&al0])->s = temp swap swaps the strings pointed to by the s
fields of its arguments. (Figure 3.3-1)
(pl0O])->s, (*p)->s (Figure 3.3-2)

((*p)->sip)->s (Figure 3.3-3)

p
plo] al0] 4 |a]b] c} a]
pit sip
pl2] al 1] s -e| f]a]nh]@)
sip
al2] s i] 5]«} 2]8
sip

Figure 3.3-1
ARRAY OF POINTERS TO STRUCTURES 155

plo]
D1)
al] ~s
sip
aelepaye
p[2] allah -& fel£{/g|h|Q|
sip

bf2] 5
= 189)
EIGIEIESC
Figure 3.3-2

pl[0]
pL.el
D102

Figure 3.3-3
156 ARRAY OF POINTERS TO STRUCTURES

Structures 3.4

swap(pl0], (pl0])->s1p); p[0] contains &a[1], (pl0])->s1p


contains &al2]. (Figure 3.4-1)

p
plo] al0O]
pit)
Dies a let

al2]

p
plo] al0]
8 ee
0 9aeaad Ne Sas

at2]

Figure 3.4-2 (pl0])->s


ARRAY OF POINTERS TO STRUCTURES 157

Pp a |
plo] al0] s anieen
ca og
mile sip
pie! afi] s felfig{h/Q
sip

al2] sip
ESEIESESLS
Figure 3.4-3 (*(++(pl0]))).s

Figure 3.4-4 ++((*(++((*p)->s1p))).s)


158 THE PREPROCESSOR DOESN T KNOW C

Preprocessor 1.1

Trt Bose. §
PRINT( x*FUDGE(2) ); To understand the effect of a
preprocessor macro, expand it in place.

PR(a)3; putchar(‘“\n’") Always expand the leftmost macro.


First, substitute the macro replacement
. string for the macro call.

PR(-x*xFUDGE(2) )} putehar(“\n> ) Then substitute the argument(s) in the


call for those in the replacement string.
Dewees (A= so ve ay bie.) (a)) Expand the leftmost macro, PR this
time.

printf(" x*FUDGE(2) = KANE s Substitute the macro arguments.


(int) (x*FUDGE(2) ))
printf(" x*FUDGE(2) = %a\t", A macro name that occurs between
(int) (x*#k+3.1459) ) quotes is not expanded. However,
macro arguments are expanded
wherever they occur in the macro body.
Thus, x* FUDGE( 2) replaces a in the
macro PR, but FUDGE ( 2) is left
unexpanded in the format of the call to
printe£.

(Ive
eek2-3 5. 159") Replace the formal parameter k by the
actual parameter. Surprise! First
multiply, then add (then truncate).

Beware! Macros can be a source of subtle trickery. Expanding a macro is strictly a matter
of replacing one string by another. The macro preprocessor knows next to nothing about C.
Most surprises can be avoided by adhering to a few conventions.

Convention |: Parenthesize all macro bodies that contain operators.

The unwanted interaction between the replacement string and its context in this problem is
avoided if FUDGE(k) is defined to be (k+3.14159).
THE PREPROCESSOR DOESN T KNOW C 159

Preprocessor 1.2

for(cel=0; cel<=100; cel+=50)


PRINT2( cel,9./5*cel+32 );

for(cel=0; cel<=100; cel+=50) First expand the call to PRINT2.


PR( cel);
PRINT( 9../5xcel+32 );

for(cel=0; cel<=100; cel+=50) Then expand the call to PR.


prance(Ge cel="4dNtar Cintjiliceds)))s
PRINT( 9./5x*cel+32 );

for(cel=0; cel<=100; cel+=50) Expand the call to PRINT.


Dranee@. Cel = 4ONt eit) ced)! re
PRG Zo eCel+32) 9) 3 iputchaniGs\n. ))s

Lon (cel —0rmcell <= (100; celi+—50)) Expand


the call to PR
joneririere
((Y vexcjiles SxelNaeY
4(signe) (eal) ))9
DRinte(uo becell +32) =hONt.,
(int) (9./5*cel+32));
DiUltechaws (mente)

The call to PRINT2 may look like a single statement, but it expands to three. Only the first
PR is contained within the for loop. The second PR is executed following the loop, with
cel 150;

Convention 2: Keep macro bodies cohesive; prefer an expression to a statement, a single


statement to multiple statements.

For this problem, using commas in place of the semicolons in the body of the PRINT
macros satisfies Convention 2.
160 THE PREPROCESSOR DOESN T KNOW C

Preprocessor 1.3

int x=1,yee3

PRINT3( MAX(x++,y),X,y )3

(arch nb) A). ey The PRINT3 macro is, of course, expanded


before MAX. However, to avoid obscuring
the point of the puzzles, in this and
following solutions the PRINT macros will
not be expanded. The first step then is to
substitute the replacement string for the call
to MAX.

(x++<y Py: x++),X,Y Next, substitute the actual arguments for


the formal arguments.

(1<2
? y: x++),
and x=2 Finally, evaluate.

(y)
2

PRINT3( MAX(x++,y),xX,y );3 Now execute the second call to PRINT3.

(x++<y ? y : x++),X,y

(2<2 ? y : x++), and x=3

(x++)

3, and x=4

x++ appears only once in the macro call but twice in the expansion, causing x to be
incremented sometimes by one and sometimes by two. The burden of protecting against
such unfortunate side effects can be placed either with the macro writer or the macro user.

Convention 3: Avoid macro bodies that can cause obscure or inconsistent side effects.
Convention 3A: Avoid expressions with side effects in macro calls.

In general, the problem of side effects in macros is quite tricky. Following Convention 3
often means copying arguments into local variables within the macro; this extra overhead
reduces the speed advantage of macro calls over function calls. Following Convention 3A
requires knowing when a routine has been coded as a macro rather than a function; at best,
this violates the notion of the routine as an abstraction, and at worst, the routine may be
rewritten causing the assumption no longer to be valid.

For this problem following Convention 3A preserves MAX intact.


CAUTION PAYS 161

Preprocessor 2.1

Tee Sree
4]8

PRINT( -NEG(x) );
--a First substitute the macro replacement string
for the macro call. (As before, the PRINT
macro will not be expanded.)
--x, and x=0 Then substitute the argument in the call for the
one in the replacement string.

The macro replacement string is exactly those characters that follow the closing parenthesis
of the argument list. The trick in this puzzle is that the -a immediately follows the
parenthesis. Still, following Convention 1 by defining NEG(a) to be (-a) produces the
expected expansion. It is also a good practice to begin each replacement string with either a
tab or a space.

Preprocessor 2.2

PRINT( weeks(10080) )

(days(10080)/7) Replace each macro call with the macro body.


Notice that there is not a conflict between the
macro parameter mins and the macro mins.

((hours(10080)/24)/7)

(((10080/60)/24)/7)
1 Evaluate.

PRINT( days(mins(86400)) )
(hours(mins (86400) )/24) Expand the leftmost macro.

((mins(86400)/60)/24)

(( (86400/60)/60)/24)
1 Evaluate.
162 CAUTION PAYS

Preprocessor 2.3

static char Input = "“Ntwhich\i£?”;

PHUG<" 17 )ATAB (Gt, Olds temp.) 3


else putchar(c);

tit Git iet 4)


PPite==—aNee)
for(temp=8-(i-oldi-1)%8,oldi=i; temp; temp--)
putchar(’ ’);
else putchar(c);

TAB includes an open if statement. On expansion, the if consumes the following else.

Convention 4: Make macro replacement strings complete C entities, be they expressions,


statements (minus the closing semicolon), or blocks.

For this problem, appending a null else clause to the TAB macro alleviates the difficulty.
(Notice that enclosing the macro replacement string in braces, i.e., making it a block, does
not solve the problem.)

About macros and functions. Very often a routine can be implemented using either a macro
or a function. The advantage of using a macro is that it will be executed faster since the
runtime overhead of a function call is avoided. The advantages of using a function are that
none of the tricky situations we’ve seen in the puzzles with macros will occur, and if the
routine is called several times, the implementation will probably require less memory. This
leads us to the final convention for using macros:

Convention 5: Keep macros simple. If you can’t keep a macro simple, make it a function.
APPENDICES
APPENDIX 1: Precedence Table

OPERATOR
primary: () [] ->.
TIUGUNE | sete re (an?) tS. Sal raSore
multiplicative: * / %

relational: < <= > >=


equality: == |=

logical: 8.8
logical: 1
assignment: = += -= etc. right to left
left to right

The precedence table illustrates the relative precedence of operators. Precedence determines
the order in which operands are bound to operators. Operators receive their operands in order
of decreasing operator precedence.

To determine the relative precedence of two operators in an expression find the operators in the
OPERATOR column of the table. The operator higher in the list has the higher precedence. If
the two operators are on the same line in the list, then look at the corresponding
ASSOCIATIVITY entry. If it indicates ‘‘left to right’’, then the operator to the left in the
expression has the higher precedence; if it indicates “‘right to left’’, then vice versa.

165
ae
altet worobeniel ° rae

- es. re
5 A
é e
2 eee
pa is Fi j
=a % a On '

: Leo 4
ss , en a
j
ng Con a
Par
e ° > vat

. 2a
a!
@euc <s i
paw - 7 a a |

p moles | “7 ;

ne 1a -

@ 7 ) aac 40464 ‘i

of ey tnd) Gms Be) CO

5 §
APPENDIX 2: Operator Summary Table

Arithmetic operators (operands are numbers and pointers)


e Additive

operator restrictions
x+y sum of x and y if either operand is a
pointer the other must
be integralt
x-y difference of x less y if either operand is a
pointer the other must
be integral or a pointer
of the same base type

e Multiplicative

operator restrictions
X*Y product of x and y x, y must not be
pointer
x/y quotient of x divided x, y must not be
by y pointer
x%*y remainder of dividing x x, y must not be
by y double, float, or pointer
-x arithmetic negation of x, y must not be
x pointer

e Incremental

operator restrictions
x++ (x--) x x must be a reference
x is incremented to a numeric value ora
(decremented) after pointer
use

++x (--x) x+1 (x-1) x must be a reference


x is incremented to a numeric value ora
(decremented) before pointer
use

+ Integral stands for the types int, char, short, long, and unsigned.

167
168 OPERATOR SUMMARY TABLE

Assignment operators

operator restrictions
x=y y cast in the type of x, x, y may be any type
x gets the value of y but array
x op= y x op (y) cast in the x, y may be any type
type of x, x gets the but array or structure
value of x op (y)

Bitwise operators (operands are integral)


e Logical

restrictions
x&y bit by bit AND of x and
y; AND yields a 1 for
each place both x and
y havea 1, 0
otherwise
xIy bit by bit inclusive OR
of x and y; inclusive
OR yields a O for each
place both x and y
have a 0, 1 otherwise
ey bit by bit exclusive OR
of x and y; exclusive
OR yields a 0 for each
place x and y have the
same value, 1
otherwise
~x one’s-complement of
x; 1s become Os and
Os 1s

e Shift

operator restrictions
x<<y x left shifted y places, y must be positive and
the lowest y bits get 0s less than the number of
bits per computer word
x>>y x right shifted y places; y must be positive and
the highest y bits get less than the number of
Os for positive x, 1s or bits per computer word
Os depending on the
compiler for negative x
OPERATOR SUMMARY TABLE 169

Logical operators (operands are numbers and pointers)

operator restrictions
x&&y AND of x and y: 1 if result is of type int
both x and y are
nonzero, 0 otherwise
xily inclusive OR of x and result is of type int
y: Oif both x and y
are zero, 1 otherwise

1x logical negation of x: 0 result is of type int


if x is nonzero, 1
otherwise

Comparison (operands are numbers and pointers)


e Relational

operator | yields restrictions


x<y (x>y) 1 if x is less than result is of type int
(greater than) y, 0
otherwise

x<=y (x>=y) 1 if x is less than or result is of type int


equal to (greater than
or equal to) y, 0
otherwise

e Equality

operator restrictions
x==y (x! =y) 1 if x is equal to (not result is of type int
equal to) y, 0
otherwise

e Conditional

operator restrictions
Kicavasrz y if x is nonzero, z
otherwise
170 OPERATOR SUMMARY TABLE

Address operators

operator restrictions
*X the value at the address x must be a pointer
contained in x cast in
the base type of x
&x the address of x x must be a reference
to a value

xy] the value at the address one of the operands


x+y cast in the base must be an address and
type of the address the other must be
operand integral
ay the value of the y field x must be a structure,
of the structure x y a structure field
x->y the value of the y field x must be pointer toa
of the structure at the structure, y a structure
address x field

Type operators

operator restrictions
(type) x x cast in the type type x may be any
expression
sizeof x the size in bytes of x x may be any
expression
sizeof (type) the size in bytes of an
object of type type

Sequence operator

operator restrictions
x,y b x, y may be any
x is evaluated before y expression
APPENDIX 3: ASCII Table

In octal

|000 nul|001 soh|002 stx|003 etx|004 eot|005 enqg|006 ack|007 bel|


|010 bs ht |012 nl |013 vt |014 np |015
|011 cr |016 so |017
|020 dlelo21 dc 1/022 ac2|023 dc3|024 dc4|025 nak|026 syn|027 etb|
|030 can|031 em |032 sub|033 escl034 £5 |035 gs |036 xs) (037 G n
|040 sp |o41 |042 |043 # |044 A |045 eS |046 & |047 .

|050 |051 |052 * |053 |o54 |055 |056 |057


|060 |o61 |062 iS) |063 Ww
+ |064 |065 |066 6 |067
|070 |071 |072 |073 |074 |075 |076 > |077
|100 [101 [102 |103 |104 |105 [106 P07
[110 1111 lagi \113 \114 [115 1116 N [117
{120 24 |122 |123 \124 |125 |126 Vv\127 sli
SOR
|130 1131 |132 |133 |134 [135 [136 1137
|140 “sx
oOo,
UO
\141 \142 |143 \144 |145 |146 £ |147
|150 |151 |152 |153 |154 \155 |156 n (157
|160 |161 |162 |163 |164 |165 |166 v |167
|170 alice
xO — \172
PO
OH
“~QeHPK
A~ We
GO
DW
NRUONge An \174 he [175
AAMTMNMNAN-»:
de
Sitar
re
YN
os
Wh)
toe ~se|176
wrAini
Boras mula aiao=zouai

In hexadecimal

| 00 nul| 01 soh| 02 03 etx| 04 eot|


stx| 05 enq| 06 ack| 07 bel|
| o8 bs 09 ht | Oa Ob vtnl | Oc np | 0d cr | Oe so: |-0f ¢s16)]
| 10 dle| le dc1| 13 dc3| 14 dc4|
alkz; dc2| WS nak| 16 syn| 17 etb|
| 18 can| 19 em | 1a sub|
1b esc| le £s)| 1d gs | le rsy{ tls.)
| 20 sp 244, Ze, 23 # 24 $ 2D % | 26 |
| 28 29 2a 2b ZG 2d | 2e |
| 30 3a 32 33 Wt 34 SNS) | 36 |
| 38 39 3a 3b Sie) 3d | 3e |
| 40 41 42 43 44 45 | 46 |
| 48 49 4a 4b 4c 4d | 4e | 4£
| 50 By 52 53 54 BS) | 56 |
| 58 So 5a 5b 5G 5d | 5e |
| 60 “sx
oOo
UEO
61 62 63 64 65 | 66 |
| 68 69 6a 6b 6c 6d | 6e |
| 70 aa WA Ws 74 US | 76 |
| 78 O!
mm YE —
AW~
PO
OH 7a
~QreMK WD 7b
NRUONDWO 1c
MHNAN-:
WaT"
An de)
tel
Th
fete
ta)
Se
Sa
0 7d re | Je
wnt =|
BoOuQGCsewau

ASCII (American Standard Code for Information Interchange) maps a set of control and
printable characters into a set of seven bit binary numbers. The tables above show the
correspondence between each character and its value. Generally, the characters below 040
octal (20 hexadecimal) are considered control characters and are not printable, though newline,
tab, formfeed, etc. are located here. 040 and above are the familiar printing characters. Digits
and letters are ordered in their natural way; 1 is before 2 and A is before B.

7
ety (Epis come
It
|ia s
vy “tw er ar Fe
an y® YA Or" Da
ba g é i<be p89 7

- a ae, @> 14 “i
aes 4 ate) Lee] &
S
> os +a
a 7
ins ,o%; el 2 _

ri |
p> 7 j rovirs
ee & »
Lp on a Puli a -@
rth & 7
a ; Parl: ¢@ 8
- ,

. “Th oe
_
APPENDIX 4: Type Hierarchy Chart

long

fl
unsigned

T
int. <— char, short

The type hierarchy chart illustrates the ordering of the arithmetic types. The execution of each
arithmetic operator in an expression yields a result with the type of its highest typed operand.
Similarly, when two quantities are compared by a relational operator, the lower typed operand is
cast in the type of the higher typed operand. The vertical arrows in the chart show the basic
ordering: double is the highest type, int the lowest. The horizontal arrows indicate the
automatic type conversions. That is, operands of type float are always converted to type
double before being considered in an expression. Likewise, operands of types char and
short are always converted to type int.

17S
ble ™alow. ia Geei oh edetar sti ieee
ae dutTceta oe «wee wind r® Of Sale neg
toed! ft) ee
(sper Gaewe § > CsI : o@
ewiien "y
ped AY ay, Teds Oh Of pete Gre GT yaeee So Z eae Lda
i @ Se 5028S BTSs 26! =a of! => oartane ® :
WD i ape ont aie ‘(a))y> are «€ wy —<—sz ;
as Ȏ5 oy UU Cae =i : ls ed Ԣ ay? Gy
>=) oe weae
Ornate am ORM,

‘y
if
PUZZLE BOOK
Puzzles for the C Programming Language
' ALAN R. FEUER

The process of learning C may be modeled by three steps:

1. understand the language syntax;


2. know what meaning the translator will ascribe to properly formed constructions;
3. develop a programming style fitting for the language.

The puzzles in this book are designed to help the reader through step two. They will
challenge the reader’s mastery of the basic rules of C and lead the reader into seldom-
reached corners, beyond reasonable limits, and past a few open pits. In short, they
provide the reader with insight into C that is usually only gained through considerable
experience.

The C Puzzle Book is a workbook intended to be used with a C language textbook. The
book is divided into sections, each containing C programs that explore a particular aspect
of C. Accompanying detailed descriptions of how the programs work are tips and caveats
for writing successful C programs.

Another book of interest...

The C Programming Language by Brian W. Kernighan and Dennis M. Ritchie is the


definitive textbook on the C language. It includes a tutorial introduction to C giving a
quick orientation to most of the language; it incorporates complete programs as
examples; it describes the standard I/O library showing how to write programs that can
be ported between computer systems; and it illustrates how to interface with the UNIX
Operating System.

Published 1978 228 pages :

PRENTICE-HALL, INC., Englewood Cliffs, N.J. 07632

ISBN 0-13-109%5eb-4

You might also like