Sei sulla pagina 1di 60

C Ya In The Bathroom

About the Author Legal Notice Table of Contents Bathroom Principle Now, C Now Just C And Yet... The C Compiler C Fundamentals Functions T pes and !perators "ata T pes Constants !perators Control Flow #tandard $nput%!utput print&'( scan&'( !ther #tandard $%! Functions Pointers and Arra s )hat $s A Pointer* Pointers As Function Parameters Pointers To +ulti,"imensional Arra s Pointers to Functions #tructures and -nions #tructures Pointers and #tructures -nions The Preprocessor .de&ine and .include +acros Conditional Compilation Prede&ined +acros #cope and +odular Programming Local /ariables 0lobal /ariables +odular Programming +a1e&iles "irectories and Files "irector +anipulation File +anipulation File $%! Formatted $%! Character $%! Bloc1 $%! 2andom Access " namic Allocation +emor Allocation Functions +anipulating +emor Bloc1s 3

Bits and B tes $ntegers Floating Points Bitwise +anipulation

Now, C Now
Note: Code segments in this document ha4e been tested using 0N- C compiler 4ersion 5.6 under Linu7 !#.

Just C And Yet...


C is the mother o& all computing toda . $t8s almost impossible to use an o& toda 8s man popular applications that does not ha4e codes in it written in C9 -ni7, )indows, word processors, graphics, spreadsheets, and e4en compilers and interpreters &or other languages. C was &irst standardi:ed b AN#$ in 3;<;, the 4ersion 1nown as C<;, which most programmers thin1 o& as C. The latest 4ersion was adopted in 3;;; and 1nown as C;;. $t includes all o& C<; plus some borrowed &rom C== and some new ones not supported b C==. C was in4ented in 3;>6 b "ennis 2ichie at ATT Bell Labs and was named a&ter its predecessor the B language which was in4ented b ?en Thomson, also o& Bell Labs. C is portable, meaning that it can be written in one s stem and be made to run in another with 4er little or no change. C gi4es the programmer the abilit to manipulate the bits and b tes and memor addresses o& the computer, thus gi4ing them almost complete control o4er the machine.

The C Compiler
-nli1e interpreted programs such as those written in Bash, Basic or Perl, C programs ha4e to be compiled into assembl language or machine instructions that the machine chip 'or CP-( such as our $ntel inside or m A+" ?@,6 itsel& can understand and e7ecute A and that means speedB This process o& translating source codes into machine language instructions generall in4ol4es two steps 'ignoring intermediate steps such as preprocessing and optimi:ation(9

Compiling the source code to create what traditionall is called an CobDectC 'not to be con&used with object in obDect oriented programming( or obDect module. Lin1ing or combining all the obDect modules, including those that are stored in C libraries, to &orm the &inal e7ecutable &ile.

$nterpreted languages such as Basic or Perl, on the other hand, understand source codes and immediatel e7ecutes them as the are being encountered. )hile this has the ad4antages o& an immediate result and rapid de4elopment, it has se4ere limitations. First, the interpreter has

to be loaded into the CP-. This means that when ou gi4e someone a Perl program, he better ha4e Perl installed, and the operating s stem better 1now where the Perl interpreter is located 'i.e., its path(. #econd, most interpreters reEuire that all source codes be brought into memor at once. This can place a se4ere limitation on space and speed on 4er large proDects. Fere8s the traditional wa to start programming in C, the CJello )orldBC program which is in the source &ile named jello.c.
/* jello.c */

#include <stdio.h> // to use printf() int main () { printf ("Jello World\n") return ! "

To compile the program, open a terminal window and in4o1e the 0N- C compiler b entering
# $cc %Wall %o jello jello.c

The %Wall option tells the compiler to report all error and warning messages. The %o jello tells the compiler to output the resulting e7ecutable &ile as jello instead o& the de&ault output &ile a.out. 'The compiler automaticall deletes the obDect &ile jello.o since we8re creating an e7ecutable output &ile.( To run the program, enter
# ./jello

You should see Jello World printed on our screen. The ./ in &ront o& the program name is reEuired because when ou enter a name li1e jello at the # prompt, the bash shell will search &or that program name in our path. But since our wor1ing director is not in our path '&or reasons o& securit (, ou must use ./ to tell the bash shell to search our wor1ing director . Fowe4er, i& ou reall want to e7ecute our program without the ./, then place it in our /&in director which is included in our path '/home/joel/&in(. To see what8s our path,enter
# echo #'()*

You should see a list o& directories separated b a colon. Fere8s what mine loo1s li1e.
# usr/local/&in+/usr/&in+/&in+/usr/,!!-./&in+/home/joel/&in

C Fundamentals
5

The source &ile is the beginning o& a C program. For our Jello World program, it is called jello.c. The &irst line o& our program begins with a comment. $n C;;, comments can be o& two 1inds9 // and the /* */ pair. The &ormer tells the compiler to ignore an thing to the end o& the line, while the latter tells it to ignore an thing bounded b the opening /* and the closing */. The #include <stdio.h> statement tells the compiler to include the contents o& the standard C input%output librar header &ile 'stdio.h( which contains among others the printf() &unction that we use to output data to the screen. Fere, printf() simpl outputs the string Jello World &ollowed b a newline ' \n (. All C programs must ha4e a main() &unction since it is the &irst &unction that the program e7ecutes. The parentheses to the right o& main indicates an empt parameter list, meaning that it does not need an thing passed to it. The int to the le&t o& main indicates that main will return an integer to the operating s stem when it8s done. The &unction bod contains the C statements to be e7ecuted. The opening brace indicates the beginning o& the &unction bod o& main and the closing brace indicates the ending. All C statements end with a semi,colon.

Functions
A &unction consists o& a &unction header and a bod 'or statement bloc1(, which is composed o& C statements enclosed in a pair o& braces, { ". The &unction header contains the &ollowing in&ormation9 3. the name o& the &unction, 6. a list o& &ormal parameters 'which are placeholders &or 4alues or arguments passed to the &unction( and its t pe, 5. the return t pe All C programs begin with the main &unction, which must use either one o& the &ollowing signatures or protot pes.
int main(/oid) int main(int ar$c0 char *ar$/12)

The &irst protot pe reEuires no argument '/oid, or this can simpl be an empt parentheses( while the second accepts two9 an integer indicating the number o& command line arguments and a pointer to those arguments. '#ee Pointers and Arrays &or a detailed discussion on pointers.( The &unction main() must return an int to the operating s stem. Fere8s a program that demonstrates the use o& command line arguments. The source &ile is called test!.c.
/* file name+ test!.c */ // for printf() function

#include <stdio.h>

int main (int ar$c0 char *ar$/12) { int i if (ar$c < 3) printf ("4nter somethin$ after the pro$ram name5\n") else { printf ("6ou entered 7d (includin$ the pro$ram name)\n"0 ar$c) for (i89 i < ar$c i::) printf("7d+ 7s\n"0 i0 ar$/1i2) " return ! "

To compile and run the program, enter


# $cc %Wall %o test! test!.c # ./test! a;aaa5 uh ah

Fere8s the result


6ou entered < (includin$ the pro$ram name) 9+ ./test! !+ a;aaa5 3+ uh =+ ah

)hile main() is alwa s e7ecuted, other &unctions are not, not until the 8re actuall called either &rom main() or &rom a chain o& &unction calls that begins at main(). )hen a &unction is called, it per&orms its tas1 and when it &inishes, returns to the point in the program where it was called. Functions are called b its name &ollowed b a list o& arguments. And li1e a 4ariable, a &unction can be used in an e7pression.
list(">a&u$"0 !.) // ?all function list @ith t@o ar$uments total 8 calcAsum(u;a&s) // (ssi$n return /alue of function calcAsum printf("7d\n"0 calcAsum(u;a&s)) // 'rint return /alue of calcAsum

A &unction can be called as man times as necessar , and it can e4en call itsel&, that is, recursi4el . Fere8s a program that calls the recursi4e &unction dismiss, which acts to reduce the 4alue o& the 4ariable count and then calls itsel& repeatedl until the 4alue is down to :ero. Note the declaration o& a &unction protot pe Dust be&ore main(). $t tells the compiler that a &unction named dismiss will be de&ined later, and that it will accept an integer and return nothing '4oid(. Function protot pes allow us to to place &unction de&initions an where in our program, e4en in a separate &ile. Parameters and 4ariables declared inside the &unction bod ha4e local scope. The are 4isible onl within the &unction bod and distinct &rom an other 4ariable in the program that ha4e the same name. Thus, the 4ariable named total in main is not the same as the 4ariable named total in the &unction dismiss. Local 4ariables, a1a automatic 4ariables, are created when the &unction is entered and destro ed when the &unction is e7ited. 'For more on 4ariable scope and li&etime see Scope and Modular Programming.( H

#include <stdio.h> /oid dismiss (int) // function protot;pe

int main () { int total 8 B printf("Cet rid of m; u;a&s5") dismiss(total) return ! " /oid dismiss(int count) { int total 8 !9 if (count <8 9) return if (total > !9) { printf("6ou are l;in$5") return " printf("Cet lost m; num&er 7d u;a&5\n"0 count) dismiss(%%count) // reduce u;a& &; ! "

)hen arguments are passed to a &unction it is passed b 4alue, meaning that the &unction onl gets a cop o& the actual 4alue stored in the memor location o& the 4ariable to wor1 with. As a result, a &unction such as dismiss can ne4er change the 4alue o& a 4ariable passed to it. 'Pointers As Function Parameters tal1s about how to pass memor addresses to a &unction allowing that &unction to wor1 with the 4ariable8s actual 4alue instead o& a cop .( Note: $n C<; or standard C, local 4ariables declarations must be placed at the top o& the bloc1, be&ore an program non declaration statement, such as a call to printf().
int main () { printf("Cet rid of m; u;a&s5") int u;a&s 8 B // 4eeeD5 4rror. return ! "

T pes and !perators


There are three sections here. The &irst section discusses the C data t pes, the ne7t discusses literal and s mbolic constants, and the third section discusses arithmetic, relational and logical operators.

"ata T pes
All data, 4ariables and constants must ha4e a t pe. $n C, the can be an o& the &ollowing elementar data t pes 'the last three added in C;;(9

char int &loat double 4oid IBool IComple7 I$maginar

Characters $ntegers Floating points "ouble &loating points /alueless Boolean true or &alse Comple7 numbers $maginar numbers

#ome o& these data t pes can be modi&ied using one or more o& the modi&iers si$ned0 unsi$ned0 lon$0 and short. The &ollowing table summari:es the data t pes, their length in b tes and the range o& 4alues the can hold. The length in b tes is based on a 56,bit s stem, which is what most modern computers are. Table #. C "ata T pes "ata T pe Character -nsigned character $nteger #hort integer Long integer -nsigned integer -nsigned short integer -nsigned long integer Floating point ?e word char B te 2ange 3 ,36< to 36> J to 6HH ,56>@< to 56>@> ,56>@< to 56>@> ,6,3G>,G<5,@G< to 6,3G>,G5<,@G> J to @HH5H J to @HH5H J to G,6;G,;@>,6;H 3.6K,5< to 5.GK5<3 6.6K,5J< to 3.<K5J<6

unsigned char 3 int short long unsigned int G 6 G 6

unsigned short 6 unsigned long G &loat G <

"ouble,precision &loating point double

Fere8s a program that prints the si:e in b tes &or some selected data t pes as returned b siEeof, which is a compile time operator that returns the number o& b tes a speci&ied data t pe occupies. The printf() &unction accepts a &ormat string speci&ier and the corresponding number o& 4alues. The &ormat speci&ier determines how 4alues are to be displa ed. Fere, the 7d &ormat speci&ier tells the printf() &unction to output the 4alue returned b siEeof as an integer. 'Standard Input/Output ta1es a closer loo1 at the printf &unction.(
int main () {

>

printf( "char 8 7d\n"0 siEeof( char )) printf( "unsi$ned char 8 7d\n"0 siEeof(unsi$ned char)) printf( "int 8 7d\n"0 siEeof( int )) printf( "short int 8 7d\n"0 siEeof(short int)) printf( "lon$ int 8 7d\n"0 siEeof(lon$ int)) printf( "unsi$ned int 8 7d\n"0 siEeof( unsi$ned int )) printf( "unsi$ned short 8 7d\n"0 siEeof( unsi$ned short int)) printf( "unsi$ned lon$ 8 7d\n"0 siEeof( unsi$ned lon$ )) printf( "float 8 7d\n"0 siEeof( float )) printf( "dou&le 8 7d\n"0 siEeof( dou&le )) return ! "

All 4ariables in C must be declared be&ore use. 0enerall , 4ariables are declared b speci& ing the data t pe &ollowed b the 4ariable name or a list o& 4ariable names separated b a comma. /ariables can also be assigned initial 4alues when the 8re declared and their assignments chained. /ariables declared outside o& an &unction ha4e permanent location 'i.e., ha4e static storage( and are assigned e7ternal s mbols. This means that the 8re 4isible &rom other source &iles and can be accessed there with the 1e word eFtern. The 1e word static limits the 4isibilit o& e7ternal 'a1a global( 4ariables to its own source &ile, &rom the point the 8re declared to the end o& the &ile.
/* file!.c */ int G(,A'(C4H 8 !9 static int G(,AI(?)J- 8 !99 int main() { . . . /* file3.c */ int main() { eFtern int G(,A'(C4H . . . // /isi&le also in other files // /isi&le from here to end of file!.c

// references G(,A'(C4H in file!.c

)hile static 4ariables are automaticall initiali:ed when the program starts, automatic 'or auto( 4ariables are not. B de&ault, local 4ariables, i.e., those declared inside a &unction or as &unction parameters are auto 4ariables. The are created when the &unction is entered and destro ed when the &unction is e7ited. Fence, uninitiali:ed local 4ariables could contain garbage. 'For more on global and local 4ariables, see Scope and Modular Programming.( A char is actuall numeric since e4er computer8s memor holds onl numbers. Fowe4er, &or e4er character there is a corresponding numeric code in what is 1nown as the A#C$$ character set. The standard A#C$$ codes go to 36> and which includes letters, digits, punctuation mar1s, etc. A#C$$ codes &rom 36< to 6HH are what is 1nown as the e7tended A#C$$ codes and represent other letters and s mbols. The header &ile ct;pe.h contains se4eral &unctions to test &or the character t pe. Among them9 isalpha to chec1 &or letters o& the alphabet, isdi$it to test &or digits, isspace to test &or spaces, etc. An arra is composed o& similar t ped data occup ing contiguous area o& memor , &or e7ample, an arra o& integers representing the 36 months o& the calendar. The starting inde7 o& an arra is :ero. Arra s are constructed using a pair o& sEuare brac1ets9 single dimensional

<

arra s use a single pair o& sEuare brac1ets, two,dimensional arra s use two, and so on. Arra s can be initialia:ed b listing each 4alue inside a pair o& sEuiggl brac1ets and separating them with comma. $& the arra si:e is not speci&ied at initiali:ation, the compiler will automaticall &igure it out based on the number o& initiali:ers. A string in C is reall Dust an arra o& characters terminated b a null character 'K\9K(. A string literal is automaticall terminated b the compiler with a null.
char name12 8 "LuDsamana" // a strin$ !9 chars lon$ (countin$ null) int maF12 8 {BB0 <.0 MM" // creates initialiEed arra; of = inte$ers printf("maF192 8 7d\n"0 maF192) // maF192 8 BB int &oard1!921!32 // a &oard of !9 ro@s and !3 columns &oard1321B2 8 !99 // set ro@ 30 col B of &oard to !99 int arr132132 8 {{!9!039!"0 {!!03!"" // initialiEed arra; printf("7d\n"0 &oard1321B2) // !99 printf("7d\n"0 arr1921!2) // 39!

The 1e word t;pedef can be used to create a s non m &or a particular data t pe using the general &orm t;pedef t;pe s;non;m.
t;pedef unsi$ned int miles miles distance 8 !9 // miles is s;non;m for unsi$ned int // declare distance as t;pe miles

Constants
Literal constants cannot be changed nor can the be assigned a 4alue. 'The appear on the right side o& an assignment, what is re&erred to as an rvalue.( An integer literal constant is written without a decimal point 'eg., ,6, 33, =3J(L otherwise, an thing &rom the decimal point to the right o& it would simpl be ignored. Floating point numbers '&loat and double( are usuall written with a decimal point, but it8s not necessar . B de&ault numeric constants are alwa s &it b the compiler into the smallest possible t pe, e7cept &or &loating point constants which are assumed to be double. A su&&i7 o& I0 N0 and L A indicate &loat, unsigned and long, respecti4el A can be used to speci& the number8s e7act data t pe. Fowe4er, don8t gi4e this importance since the de&aults almost alwa s su&&ice. !ctal 'base <( number literal constants begin with a 9 ':ero( and he7adecimal 'base 3@( number literal constants begin with a 9,. ConseEuentl , ne4er begin a numeric literal constant with 9 ':ero( unless ou mean octalB A character literal constant must be enclosed in single Euotation mar1 and a string literal must be in double Euotation mar1. Character literal constants include escape seEuences such as the newline character '\n(, tab '\t( and others.
int h 8 9F!9 // h is heFadecimal !9 (decimal !.) int oc 8 939 // oc is octal 39 (decimal !.) float F 8 3..O // F is floatin$ point int a0 & // a and & are inte$ers char ch 8 K\"K // ch is assi$ned a dou&le Puote0 " short E 8 a 8 & 8 %! // declare E and set all /alues to %! float f 8 =.!3I // f is float not the default dou&le

A s mbolic constant can be declared with the 1e word modi&ier const. $t is read onl , and an attempt to change its 4alue produces a compiler warning. $t can be used to declare the si:e o& an arra .
const float 'Q const int RJQLQSCA'JQS) 8 !99 'Q 8 =.!<!. // 'roduces @arnin$ messa$e from compiler const int G(, 8 B int u;a&s1G(,2

The preprocessor directi4e #define can also be used to create s mbolic constants. Fere8s a program that uses it.
#include <stdio.h> #define 'Q =.!<!. #define RJQLQSCA'JQS) !99 int main () { printf ("'i 8 73.<f\n"0 'Q) printf ("Roilin$ point 8 7d\n"0 RJQLQSCA'JQS)) return ! "

Note that the #define statement does not end with a semicolon. )hat the preprocessor directi4e does is replace, li1e our word processor, an occurence o& the s mbolic name with the gi4en 4alue, &or e7ample, 'Q with =.!<!.. 'The 0N- C Preprocessor is discussed in The Preprocessor.( The 1e word enum creates a series o& named integer constants. -nless e7plicitl pro4ided 4alues, the le&tmost name is gi4en the 4alue :ero b de&ault and subseEuent names are gi4en 4alues 3 higher than the pre4ious.
enum da;s {Hunda;0 Gonda;0 )uesda;0 Wednesda;0 )hursda;0 Irida;0 Haturda;" printf("Iri87d0 Hat87d0 Hun87d\n"0 Irida;0 Haturda;0 Hunda;) // Iri8B0 Hat8.0 Hun89

!perators
Along with the usual arithmetic operators ' : % * / 7 (, C pro4ides an increment operator : : and a decrement operator %% which are shorthand notations &or operations such as the &ollowing.
; 8 F : ! ; 8 F % ! // @hich can &e @ritten as ; 8 ::F< // @hich can &e @ritten as ; 8 %%F

$ncrement and decrement operators can also be made post&i7, in which case, the 4alue is &irst assigned be&ore incrementing or decrementing is per&ormed.

3J

int F 8 !9 int ; 8 F:: printf ("; 8 7d\n"0 ;) printf ("F 8 7d\n"0 F)

// assi$n then increment // ; 8 !9 // F 8 !!

C also pro4ides se4eral relational and logical operators, arranged here in terms o& precedence &rom highest to lowest. 'Normall , operators are e4aluated &rom le&t to right.(
5 > >8 < <8 88 58 TT UU Sot Creater than Creater than or ePual to Less than Less than or ePual to 4Pual Sot ePual (nd Jr 'recedence *i$hest Hecond *i$hest % same % % same % % same % )hird *i$hest % same % Iourth *i$hest Lo@est

Assignment operators consist o& a single eEual sign. Compound assignment operators are made b combining a mathematical operator with an eEual sign to ser4e as shortcuts &or common operations. For e7ample, F :8 ! instead o& F 8 F : !.
int F 8 ; 8 E 8 3B F *8 !9 ; /8 3 // assi$nin$ ePual /alues // multipl; itself &; !90 same as F 8 F * !9 // di/ide itself &; 30 same as ; 8 ; / 3

The comma operator is used &or per&orming a series o& operations, the 4alue o& the entire operation being the last e7pression e4aluated. Thus in the &ollowing code snippet, the 4alue o& E is arri4ed at b &irst di4iding F b H 'which eEuals 6( and then multipl ing the result with ; to gi4e G.
int F 8 !90 ; 8 3 float E 8 (F8F/B0 ;*F) printf ("73.=f\n"0 E)

// <.999

Another 4er commonl used operator is the conditional or ternar operator V which has the general &orm (eFpression)V statement + statement. $t is used in place o& the commonl used construct o& the general &orm
if (eFpression) statement else statement

As an e7ample, the &ollowing statements would produce the same results9


)ernar; Jperation F 8 (ch88K(K)V ! + 9 if%else Htatement if (ch88K(K) F 8 ! else F 8 9

There are man other operators in C such as the bitwise operators '#ee Bits and Bytes( and pointer operators '#ee Pointers and Arrays(.

Control Flow
33

$n C, an e7pression that e4aluates to :ero is &alse, e4er thing else is true 'including negati4e 4alues(. To control the &low o& a program, C pro4ides se4eral wa s &or writing conditional e7pressions9 i&,else, &or, while, do,while and switch,case. The if statement is used to e7ecute a statement or a bloc1 o& statements i& an e7pression 'enclosed in parentheses( e4aluates to true. The optional else is used to e7ecute a statement or a bloc1 o& statements i& the e7pression e4aluates to &alse. Note that a bloc1 o& statements must be enclosed in sEuiggl brac1ets.
if (%! ) printf (")rue") // prints )rue

if (month 88 W) printf("($osto+ Rahu$ sa Gam&alin$5") // J> if month is W else if ( month 88 M) printf("Heptem&re+ Rahu$ sa Han Sicolas5") // J> if month is M else printf(")a&oan na lan$.") // if month is neither

The for loop has an initial e7pression, a conditional e7pression and an increment 'or decrement( e7pression. $& the conditional e7pression is true, a statement or statement bloc1 is e7ecuted and the increment e7pression is e4aluated. Then the conditional e7pression is again e4aluated, and the process is repeated until the conditional e7pression is true no more.
int F for (F 8 ! F <8 !3 F::) { printf ("Gonth 7d\n"0 F) if (F 88 W) printf ("Rahu$ sa Gam&alin$5\n") "

The initial e7pression can be omitted i& the test 4ariable alread has a 4alue. Li1ewise, the increment 'or decrement( e7pression can be omitted i& it is being incremented 'or decremented( inside the statement bloc1.
int F 8 ! for ( F <8 !3 ) printf("Gonth 7d\n"0 F::)

The comma operator can be used to per&orm a series o& e7pressions. For e7ample,
for (F 8 !0 ; 8 9 F <8 !3 F::0 ;::)

The @hile loop e7ecutes a statement bloc1 as long as a gi4en condional is true.
int F 8 ! @hile ( F <8 !3 ) { printf ("Gonth 7d\n"0 F) if (F 88 W) printf ("Rahu$ sa Gam&alin$5\n") F:: "

36

The do%@hile loop e7ecutes a statement bloc1, test a gi4en conditional e7pression and then loops until the conditional e7pression is no longer true. Thus, the statement bloc1 is alwa s per&ormed at least once.
int F 8 ! do { printf ("Gonth 7d\n"0 F) if (F 88 W) printf ("Rahu$ sa Gam&alin$5\n") " @hile ( ::F <8 !3)

The &reaD and continue 1e words can be used to control a loop. &reaD gets ou out o& a loop and continue s1ips statements to the end o& the loop and goes bac1 up to the beginning o& the loop.
int F 8 ! for ( F <8!3 F::) { if (F < W ) continue // Co to top. HDip the rest if (F > W) &reaD // Iinished. Cet out of the loop printf ("Rahu$ sa Gam&alin$\n") "

The s@itch statement is much li1e the if%else%if statement but is much easier to &ollow than a multi,le4el if%else%if. $t e4aluates an e7pression to an integer 'hence, we can also use an e7pression that e4aluates to a character(, and i& an o& the speci&ied case label matches the 4alue o& the e7pression, it branches to the statements &or that case label. The &reaD 1e word e7its the s@itch bloc1. $& no match is &ound, statements &or the default 1e word are e7ecuted. $& no default statement is pro4ided, control goes to the end o& the s@itch bloc1.
s@itch (F) { case W+ printf("($osto+ Rahu$ sa Gam&alin$\n") &reaD case M+ printf("Heptem&er+ Rahu$ sa Han Sicolas\n") &reaD default+ printf(")a&oan na lan$\n") "

$tandard Input%!utput
$n C, all input and output are done with streams, which essentiall is Dust a seEuence o& b tes. #treams &lowing into a program &rom an input de4ice 'the 1e board, &or e7ample( is an input stream while streams &lowing out o& a program to an output de4ice such as our screen is an output stream. C has three prede&ined stream9 stdin 'standard input, t picall the 1e board(, stdout 'standard output, the screen( and stderr 'standard error, the screen(. C8s standard librar o&&ers se4eral &unctions that read &rom or write to the standard streams9 printf0 scanf0 35

and $etchar. The &unction sprintf is Dust li1e printf e7cept that it sends the output to a string. 'There are also the perror and /printf &unctions but we won8t tal1 about them here in the bathroom unless it becomes necessar .(
puts0 $ets0 putchar

printf&'
The printf() &unction writes to standard out a string &ormatted according to a gi4en set o& arguments and &ormat speci&iers. $t returns the number o& characters printed or a negati4e 4alue on error. The &ormatted string consists o& two t pes9 the &irst being the characters to be printed as the are, and the second being the &ormat speci&iers which determine how a gi4en argument is to be displa ed. The &ormat speci&ier begins with a 7 sign &ollowed b the &ormat code, &or e7ample9 7c &or characters, 7d &or integers, 7f &or &loating points, 7s &or strings, 7F &or he7adecimal numbers, and 7o 'the letter o( &or octal numbers, 7p &or memor addresses in he7adecimal number &ormat to name Dust the more common data. To print a 7 sign, use the 77 speci&ier. There must be as man number o& arguments to be &ormatted as there are &ormat speci&iers. For a numeric &ield, the &ormat speci&ier can indicate the minimum width and precision. The mimimum width is placed a&ter the 7 sign, &ollowed b a decimal point, then b the precision, and &inall b the &ormat code. For e7ample, MH.5& would displa a number at least H characters wide with 5 decimal places o& precision. $& the width is less than H, it is padded with spaces, the de&ault pad. To speci& a pad, place the pad character a&ter the 7 signL &or e7ample, 79B.=f to pad the number with :eros. To displa a short integer, use the h modi&ier, &or e7ample, 7hd. To displa a long integer use the l 'letter CellC( modi&ier, eg., 7ld. To indicate a double, use the l 'letter CellC( modi&ier with &loat, eg., 7lf. To indicate a long double, use the L modi&ier, eg., 7Lf. )hen applied to a string the width speci&ies the minimum and the precision the ma7imum length o& the string. Fere8s a code snippet to demonstrate the use o& &ormat speci&iers to print a character, a string, an integer and a &loating point. Notice that the speci&ier M3J.3Hs indicates a string that is at least 3J characters wide but not more than 3H. As a result, the string drinD gets truncated on displa since it8s been assigned a 4alue that is more than 3H characters long
int ch 8 K(K printf(")he letter 7c is decimal 7d\n"0 ch0 ch) char drinD12 8 "$allons of s@eet &ahal" int Pt; 8 3 float price 8 !!.3 printf("7d 7!9.!Bs for 7!.3f pesos\n"0 Pt;0 drinD0 price) short sh 8 < printf("m$a u;a& 8 7hd\n"0 sh) dou&le d& 8 3WM=<M.<B printf("Q o@e #7=.3lf\n"0 d&) // indicates a short // indicates a dou&le

char s1W92 sprintf(s0 "Q o@e #7=.3lf\n"0 d&) puts(s) // does same thin$ as a&o/e

3G

The abo4e codes will result in the &ollowing output9


)he letter ( is decimal .B 3 $allons of s@ee for !!.39 pesos m$a u;a& 8 < Q o@e #3WM=<M.<B Q o@e #3WM=<M.<B

And here8s a code snippet to print decimal numbers below 3JJ and in multiples o& < and their eEui4alent in octal and he7adecimal.
int F 8 9 for ( F < !99 F:8W) printf("7d 8 Jctal 7o 8 *eF 7F\n"0 F0 F0 F)

scanf&'
The general purpose input &unction scanf() reads data &rom standard input and stores them in the speci&ied 4ariables8 address. $t returns the number o& 4ariables that were actuall assigned 4alues. Li1e printf(), it uses a &ormat string to determine how input is to be stored. This string consists o& '3( &ormat speci&ier, '6( whitespace and '5( non,whitespace. The &ormat speci&iers are the same ones that are used with printf()9 7c &or characters, 7d &or integers, 7f &or &loating points, 7s &or strings, 7F &or he7adecimal numbers, and 7o 'the letter o( &or octal numbers, etc.
scanf("7d7f"0 Tid0 Tprice) // -ead id num&er and price

All 4ariables passed to scanf() must be passed b their addresses, thus the use o& N in &ront o& the 4ariable names to indicate their address. This means that arguments to scanf() must be pointers to the 4ariables. 'For more on pointers, see Pointers and Arrays.( As with printf(), we can indicate an e7act data t pe with l 'letter CellC( to read a long integer '7ld( and a double '7lf(, h to read a short integer '7hd( and L to read a long double '7Lf(. A whitespace 'i.e., spaces, tabs and newlines( causes scanf() to read, but not store, the whitespace 'or whitespaces( until it &inds a non,whitespace. A nonwhitespace character that is not a &ormat speci&ier causes scanf() to read and discard that matching character. $& no matching character is &ound, an error would occur. Fere8s a program to demonstrate this. The 4ariable ret/ar tells us how man input 4alues ha4e been success&ull stored.
#include <stdio.h> int main() { float fl short sh int ret/al printf("4nter a float0 a comma and an inte$er 8> \n") ret/al 8 scanf ("7f07hd"0 Tfl0 Tsh)

3H

printf("returned 8 7d\n"0 ret/al) printf("fl 8 7f and sh 8 7hd\n"0 fl0 sh) return ! "

$n this program scanf() e7pects a 1e board input o& a &loat &ollowed a comma and then :ero or more whitespace and &inall an integer. Thus we could input
=.<<0M

or
=.<<0 M

and either one would be o1a .


4nter a float0 a comma and an inte$er 8> =.<<0 M returned 8 3 fl 8 =.<<9999 and sh 8 M

But to input
=.<< 0 M

would not be 4alid since the &loat is &ollowed b a whitespace, not b a comma. !nl the &irst number would be success&ull stored.
4nter a float0 a comma and an inte$er 8> =.<< 0 M returned 8 ! fl 8 =.<<9999 and sh 8 39B3

An asteris1 'O( placed between the M sign and the &ormat code o& the &ormat speci&ier would cause scanf() to read, but not store, input with the matching data t pe. For e7ample, consider the &ollowing code snipet9
printf("4nter a character0 an inte$er and a float 8> \n") ret/al 8 scanf("7c7*d7f"0 Tch0 Tprice)

An input o&
( !3=<B <.BB

tells scanf() to ignore the integer !3=<B and store onl the character ( and the &loat <.BB. can be used to accept a character arra or string. The number o& characters it reads is either the number o& characters up to the whitespace or the speci&ied ma7imum, whiche4er comes &irst. Note that an arra name itsel& indicates the address o& the arra 4ariable and, thus, the T is unnecessar . $n the &ollowing code snippet, a ma7imum o& 3J characters will be stored in the arra . $& more than 3J characters are input, the will be read and stored into the
scanf()

3@

ne7t 4ariable, which ma be an error, unless the happen to be a &loating point literal constantB
float price char name1!B2 printf("4nter a strin$ and a float 8> \n") scanf("7!9s7f"0 name0 Tprice)

!ther $tandard I%! Functions


$n addition to printf() and scanf(), there are se4eral other &unctions that write to stdout or accept input &rom stdin. accepts no argument and returns the ne7t character &rom stdin as an integer. Note that when ou8re entering a character &rom a 1e board ou also need to press carriage return, which result in another character, the newline character, being read.
$etchar()

accepts a character and writes it to standard out. $t returns the P character written or K!F on error.
putchar()

accepts input &rom standard in and stores them in the gi4en address. The characters are read until the newline or K!F. The newline is not stored. Be warned that $ets is dangerous and has been deprecated because there is no wa to limit the amount that can be entered and which can cause an o4errun o& the arra the are being stored in. $n &act, ou8ll get a compiler warning i& ou use it. A better alternati4e to $ets are the &unctions f$ets and the e4en better 0N- e7tension $etline. Both o& these &unctions reEuire a pointer to an input de4ice such as, &or e7ample, stdin, the standard input. 'For more on f$ets and $etline see Formatted I/O(
$ets()

accepts a character arra or string and writes it to standard out replacing the null terminator with a newline. $t returns a positi4e 4alue or K!F on error.
puts()

Fere8s a program that demonstrates the use o& these &our $%! &unctions. 2emember that i& ou run this program, ou8d get a compiler warning with respect to the $ets() &unction. Also, notice that we84e declared a <J character bu&&er. The reason is that 1e board input does not get stored into the recei4ing 4ariable until ou press the return 1e . And when ou &inall do press return, onl enough characters to satis& the &ormat speci&ication will be used. Thus, unused input characters remain in standard input. To pre4ent these unused characters &rom getting into the name &ield, we ha4e to capture them. This is what we use the bu&&er &or.
#include int main { char char char <stdio.h> () &uffer1W92 name1392 ch // $et De;&oard input // echo it // $et @hate/er remains

puts("4nter a char 8 > ") ch 8 $etchar() putchar(ch) $ets(&uffer)

3>

"

puts("\n4nter ;our name 8> ") $ets(name) // $et De;&oard input puts(name) // echo it return !

(ointers and Arra s


There are &our sections here9 the &irst is an introduction to pointers, what the are and their relationship to arra sL the second is about using pointers as parameters to a &unctionL the third discusses pointers to multi,dimensional arra sL and &inall , the &ourth is about using pointers to &unctions.

)hat Is A (ointer*
A pointer is a 4ariable that contains the memor address o& another 4ariable and, there&ore, points to a speci&ic t pe o& data. There is one e7ception, howe4er9 a pointer to 4oid, which is used to hold an t pe o& pointer. Pointers to 4oid must be t pecast to its appropriate t pe i& their pointed at 4alues are to be used. A pointer is de&ined with an asteris1 'the indirection or dere&erencing operator( be&ore the 4ariable name and a t pe that determines what t pe o& data it is pointing at. The address operator T assigns the address o& a 4ariable to a pointer. To re&er to the 4alue o& the 4ariable pointed at b the pointer, dere&erence the pointer with an asteris1.
#include <stdio.h> int main() { int i 8 !B int *pi 8 Ti // assi$n the address of i to the pointer pi printf("(ddr of i0 Ti87p (ddr of pi0 Tpi87pi\n"0 Ti0 Tpi) printf("Xalue stored in i87d Xalue stored in pi87p\n"0 i0 pi) printf("Xalue pointed at &; pi0 *pi8 7d\n"0 *pi) return ! "

The program, when compiled and run, produces the &ollowing9


(ddr of i0 Ti89F&fffdcM< (ddr of pi0 Tpi89F&fffdcM9i Xalue stored in i8!B Xalue stored in pi89F&fffdcM< Xalue pointed at &; pi0 *pi8 !B

Be care&ul when using the unar operator :: or %%.


%%*pi (*pi):: // decrement the /alue of i // increment the /alue of i

$n the second statement, we ha4e to place the dere&erenced pointer in parentheses since the unar operators :: and * associate le&t to right. !therwise, we would be incrementing the pointer 4ariable pi, not the 4alue pointed at.

3<

Arra s and pointers are so closel related that an operation that can be done with arra s can also be done with pointers. B de&inition the arra name is the address o& the &irst element o& an arra . This means that an arra name is a pointer. But there8s a di&&erence9 an arra name is a pointer constant 'an Cr4alueC( which, unli1e a pointer 4ariable, can be assigned but cannot be the target o& an assignment or be a subDect o& a :: or %% operator. Fowe4er, ou can change the 4alue o& an element in an arra . An arra occupies contiguous b tes o& memor . This means that &or an arra o& 5 integers, there are 36 contiguous b tes in all. The &irst element occupies the &irst G b tes, the second occupies the ne7t G b tes and the third occupies the last G b tes. Thus, i& arr1=2 is such an arra , then arr192 would be in the &irst location, arr1!2 in the ne7t, and arr132 will be in the &inal location. $t &ollows then that i& ptr is a pointer to the arra arr, the &ollowing relationships must hold9
ptr 8 arr 8 Tarr192 all pointin$ to the same memor; address ptr : i 8 Tarr1i2 8 arr : i @here i is the arra; indeF ptr1i2 8 *(ptr : i) 8 arr1i2 8 *(arr : i) the /alue at indeF i

Fere8s a program that tra4erses an arra and prints its elements using both pointer and arra notations.
#include <stdio.h> int main () { int arr1=2 8 {!0 30 =" int *ptr 8 arr int i 8 9 for ( i < = i::) printf("ptr1i2 8 7d0 arr1i2 8 7d\n"0 return ! "

ptr1i20 arr1i2)

The printf statement abo4e could also be accomplished b incrementing the pointer, which mo4es the pointer one si:e o& data higher, &or e7ample, G b tes &or an int. 2emember that an arra name is a constant, thus we cannot appl :: to it.
printf("*ptr:: 8 7d0 *(arr : i) 8 7d\n"0 *ptr::0 *(arr : i))

A string can be constructed using either arra notation or pointer notation. But there are two signi&icant di&&erences between them. First, o& course, is that ou cannot assign a 4alue to an arra since it is an r4alue. $& ou want to do this, use the &unction strcp;() in the header &ile <strin$.h>. The &unction strcp;() copies one string character b character into another string. #econd, while ou ma modi& an indi4idual element o& an arra , doing so to a pointer 4ariable will produce unde&ined results.
#include <stdio.h> #include <strin$.h> int main() { char hisname12 8 "Jose" char *nameptr 8 "*a$i&is"

3;

// hisname 8 ">a&u$" // 4rror5 nameptr 8 "JoluF" // J> strcp;(hisname0 ">a&u$") printf("hisname 8 7s0 nameptr 8 7s\n"0 hisname0 nameptr) hisname1!2 8 K,K // nameptr1!2 8 K,K // J> // 4rror5

"

(ointers As Function (arameters


A &unction can be made to accept a pointer through which it can change the 4alue o& the actual 4ariable used to call the &unction. This is, in &act, how a &unction can change the 4alue o& the 4ariable passed to it since in C arguments are alwa s passed b 4alue and thus cannot be changed b the &unction. )hen an arra is passed to the &unction, what is passed is not the arra but the address o& the arra 8s initial element, eliminating the o4erhead o& passing huge amount o& data. The &unction creates a pri4ate cop o& the pointer and wor1s on this pointer, lea4ing the 4alues in the arra it is called with una&&ected. Fowe4er, the &unction can change the actual indi4idual elements o& that arra , thus changing the actual arra . $n the &ollowing program, the &unction chint assigns a 4alue o& !99 to the actual 4ariable it is called with, thereb changing its 4alue. The other &unction, chs, changes the actual contents o& the arra it is called with b cop ing to it a string letter b letter. Fowe4er, be warned that once this is done, both pointers 'the one whose 4alues pointed at are being changed and the one that is used to change it( will no longer hold 4alid 4alues. The &unction should not do an thing more with these pointers, and should simpl Dust return to where it was called. Li1ewise, i& ou use the pointer cop , ou will no longer be able to a&&ect the actual arra because it will then be alwa s using the pointer cop .
#include <stdio.h> /oid chint (int *i) { *i 8 !99 " /oid chs (char *s) { char *sF 8 "*a$i&is" printf("s 8 7s0 Ts 8 7p\n"0 s0 s) // s 8 Jose0 Ts 8 9F&ffffMc9 @hile( (*s:: 8 *sF::) 58 K\9K ) // ?han$e actual arra; to *a$i&is // (t this point s and sF no lon$er ha/e meanin$ful /alues " printf("s 8 7s0 Ts 8 7p\n"0 s0 s) // prints a ton of $ar&a$e5

// ?han$e the actual /alue

int main() { char he12 8 "Jose" int F 8 ! chint(TF)

// ?all function

6J

"

chs(he) // ?all function printf("he is 7s0 F is 7d\n"0 he0 F) // he is *a$i&is0 F is !99

A pointer can also point to a pointer i& declared with the double indirection operator **. $n the &ollowing program, pF is a pointer to F and ppF is a pointer to the pointer pF. The &irst print statement outputs the address and 4alue o& 7 and the ne7t two outputs the address, 4alue and 4alue pointed at b the pointer. Notice that the 4alue o& the pointer pF is the address o& F and that o& the pointer ppF is that o& pF.
#include <stdio.h> int main () { int F 8 !99 int *pF 8 TF int **ppF 8 TpF printf("F+ 7p 7d\n"0 TF0 F) // F+ 9F&ffffMd< !99 printf("pF+ 7p 7p 7d\n"0 TpF0 pF0 *pF) // pF+ 9F&ffffMd9 9F&ffffMd< !99 printf("ppF+ 7p 7p 7d\n"0 TppF0 ppF0 **ppF) // ppF+ 9F&ffffMcc 9F&ffffMd9 !99 return ! "

(ointers To +ulti,"imensional Arra s


?eep the &ollowing things in mind when ou consider multi,dimensional arra s, &or e7ample, a two,dimensional integer arra ha4ing 5 rows and 6 columns declared as
int arr1=2132 8 { " { !0 3"0 {!90 39"0 {!9!0 !93"

3. The arra arr can be 4iewed as ha4ing 5 elements 'corresponding to its 5 rows(. 6. Kach o& the 5 elements o& arr is an arra ha4ing 6 data elements, where each data element is o& t pe int. 5. The arra name arr, there&ore, is a pointer to the &irst o& its 5 elements. $t points to arr192 'or to arr192192, which has the same address(. $t is a pointer to an arra o& 6 integers, not to an intL thus, the &ollowing will not wor1
int *parr 8 arr // ?ompiler error

G. #ince an arra is also a pointer, then the arra name arr is a pointer to an arra o& pointers. Fere8s a program to demonstrate these things. The program loops through each o& the 5 elements o& the arra arr, prints its location, and then the 4alue o& the two data elements 'in the arra ( in each o& the 5 arra elements o& arr.
#include <stdio.h>

63

int main () { int arr1=2132 8 {

" int F for (F 8 9 F < = F::) printf("arr17d2+ addr 8 7u0 /alues 8 7d0 7d\n"0 F0 (unsi$ned)*(arr:F)0 **(arr:F)0 *(*(arr:F):!) ) return ! "

{ !0 3"0 {!90 39"0 {!9!0 !93" // arra; of = ro@s and 3 columns

Fere are the results. Notice that the addresses go up b a multiple o& < because there are 6 integers in each element o& arra arr and each integer is G b tes long. The (unsi$ned) be&ore *(arr:F) coerces printf() into printing the memor address *(arr:F) as an unsigned integer. The **(arr:F) dere&erences the address *(arr:F) to get to the 4alue stored there. The *(*(arr:F):!) means add 3 si:e o& integer b tes 'meaning, G in m s stem( to the address *(arr:F) and dere&erence the result to get to the 4alue stored there. $& this ma1es C loo1s rather mess , it does. But so does e4er thing in Perl.
arr192+ addr 8 =33!33=WB.0 /alues 8 !0 3 arr1!2+ addr 8 =33!33=W.<0 /alues 8 !90 39 arr132+ addr 8 =33!33=WO30 /alues 8 !9!0 !93

Karlier we said that the declaration


int *parr 8 arr

would not wor1 because the arra arr is not a pointer to int but to an arra o& 6 integers. #o how do we declare a pointer to an arra 'o& 6 elements, &or e7ample( so that we can access indi4idual elements o& a multi,dimensional arra * The answer is that we must use the &ollowing declaration.
int (*parr)132 8 arr // pointer to an arra; of 3 ints

The parentheses are reEuired because the brac1ets e4aluate le&t to right. )ithout them the declaration int *parr132 would mean an arra o& 6 pointers to int. Fere8s how the preceding program could ha4e used a pointer to the multi,dimensional arra .
int (*parr)132 // pointer to 3%element arra; arr

parr 8 arr for (F 8 9 F < = F::) printf("arr17d2+ addr 8 7u0 /alues 8 7d0 7d\n"0 F0 (unsi$ned)*(parr:F)0 **(parr:F)0 *(*(parr:F):!) )

An arra o& strings can be constructed as a true 6,dimensional arra 'an arra o& character arra s( or as an arra o& pointers to a char.
char name121!92 8 {">a&u$"0 "(son"0 "*a$i&is""

66

// = &; !9 arra; of char char *name12 8 {">a&u$"0 "(son"0 "*a$i&is"" // arra; of = pointers to char

The true 5 b 3J arra creates e7actl 5 times 3J 'or 5J( contiguous b tes o& memor plus the terminating null character \9 while the arra o& pointers to char onl creates as man storage spaces as needed an where in the computer8s memor plus storage &or the pointer addresses. $n practice an arra o& strings is built not as a true arra but as arra s o& pointers to char. The &ollowing program demonstrates an arra o& strings 'arra o& character arra s( and the use o& pointers to pointers, the **pn, to print each string in the arra .
#include <stdio.h> int main () { int F 8 9 char *name12 8 {">a&u$"0 "(son"0 "(ndot"" char **pn 8 name // pointer to the name arra; for (F89 F<= F::) printf("7s\n"0 *pn::) return ! " // print the strin$ pointed at

(ointers to Functions
K4er &unction is loaded into memor at some speci&ic address. A pointer to &unction then is simpl a pointer that holds the address o& a particular &unction. $t pro4ides a program greater &le7ibilit b allowing it to load a selected &unction &or e7ecution d namicall . A pointer to &unction is de&ined b its return t pe, the pointer operator with the &unction name enclosed in parentheses, and the parameter list enclosed in parentheses. The pointer operator and &unction name must be enclosed in parentheses because it has lower precedence than the parentheses that enclose the parameter list. For e7ample, the &ollowing two declarations mean two di&&erent things.
int (*f)() int *f() // a pointer to function that returns an int // a function that returns a pointer to an int

A &unction name, li1e an arra , is b de&inition the address o& the &unction. Thus it can be assigned to a pointer to &unction without the T 'the address o operator(. Fowe4er, both the return t pe and the parameter list o& the &unction must match those o& the pointer to &unction. $n the &ollowing program the &unction pfunc declares three parameters9 F and E, which are both pointers to char, and pf, which is a pointer to a &unction that accepts two pointers to char and returns nothing '4oid(. The &unction pfunc basicall does nothing but call the &unction pointed to b pf. $n main, pfunc is &irst called with the &unction f! 'actuall , its address( and then with the &unction f3.

65

!& course, f! or f3 could ha4e been called directl and the same results would still be accomplished. But there8s a reason &or pointers to a &unction9 its &le7ibilit . The &unction pfunc can be made to e7ecute an &unction, not Dust f! or f3, as long as that &unction has the signature 'i.e., parameters and return 4alue( called &or in the declaration.
#include <stdio.h> /oid f!(char *F0 char *;) { printf("7s 7s\n"0 F0;) " /oid f3(char *F0 char *;) { printf("-ainman 7s 7s\n"0 ;0 F) " /oid pfunc(char *F0 char *;0 /oid(*pf)(char *0 char *)) { pf(F0;) " int main() { int choice char *F 8 ">Gart" char *; 8 "sucDs" pfunc(F0;0f!) pfunc(F0;0f3) return ! " // prints >Gart sucDs // prints -ainman sucDs >Gart

$tructures and -nions


There are three sections here9 the &irst is an introduction to structuresL the second tal1s about using pointers inside a structureL and the &inal section introduces unions.

$tructures
A structure is a user de&ined data t pe that acts li1e a record or a collection o& 4ariables. #tructures are declared with the 1e word struct &ollowed b the tag name, then b 4ariable declarations enclosed in a pair o& braces. The 4ariables contained in the structure can be an t pe o& data, including pointers, arra s and e4en other structures. /ariables in the structure are accessed with the dot '.( operator. $n the &ollowing code snippet, a structure tag point is de&ined to represent a coordinate pair. p3 and p= are declared on the same line with p3 initiali:ed. Then the coordinates &or p= are assigned their respecti4e 4alues.
struct point {

6G

"

int F int ;

// F coordinate // ; coordinate

struct point p3 8 {%<!!0 !!9"0 p= p=.F 8 !3 // set F coordinate to !3 p=.; 8 3B // set ; coordinate to 3B

Note: 3. point is a tag while struct point is a t pe. 6. The declaration &or 4ariables p3 or p= could ha4e been done inside the declaration &or struct point, as in the &ollowing,
struct point { int F // F coordinate int ; // ; coordinate " p3 8 {%<!!0 !!9"0 p=

5. but real programmers discourage us &rom doing so. G. The 1e word t;pedef can be used to create a s non m &or struct point, as in the &ollowing, eliminating the 1e word struct &rom the declaration. But real programmers pre&er to use the 1e word struct which ma1es the declaration more e7plicit.
t;pedef struct { int F int ; " point point p! 8 { B0 !9 " // cannot use struct point no@

A structure can contain comple7 t pe o& data structures such as arra s, pointers and other structures. The ne7t program de&ines a structure called circle that contains the point structure we created abo4e and a 4ariable called color which is an arra o& characters. Notice especiall two things here9 3. )e ha4e to use two dot operators to re&er to the F or ; coordinate o& the point p! in the circle 4ariable dot, &or e7ample, dot.p!.F 6. )e ha4e to use the &unction strcp; in the header &ile strin$.h because the character arra dot.color is a pointer constant 'an r4alue( and, i& ou recall, we can not assign a 4alue directl to it.
#include <stdio.h> #include <strin$.h> int main () { struct point { int F int ; " // for strcp; function

// F coordinate // ; coordinate

6H

struct circle { int radius struct point center char color1392 " struct circle dot dot.radius 8 B dot.center.F 8 !9 dot.center.; 8 !B strcp;(dot.color0 "&lue /el/et") printf("radius87d0 center8(7d07d)0 color87s\n"0 dot.radius0 dot.center.F0 dot.center.;0 dot.color) " return !

The program simpl prints


radius8B0 center8(!90!B)0 color8&lue /el/et

An arra o& structures can be 4er power&ul. Consider three pol1a dots o& di&&erent si:es and colors9
-adius B < !9 ?enter(F0;) (!90!B) (390=) (B0!!) ?olor Rlue /el/et Cra; popon Creen $iant

From these data we can declare and initiali:e an arra o& structures o& t pe struct circle containing three elements as &ollows.
struct circle polDadots12 8 { { B0 {!90 !B"0 "Rlue /el/et" "0 { <0 {390 ="0 "Cra; popon" "0 {!90 { B0 !!"0 "Creen $iant" " "

This results in an arra o& polDadots containing 5 elements, the &irst o& which 'at inde7 J( has the &ollowing 4alues9
polDadots192.radius 8 B polDadots192.center.F 8 !9 polDadots192.center.; 8 !B polDadots192.color 8 Rlue /el/et

Fere8s a program to demonstrate arra s o& structures. Notice that we84e placed the de&inition o& the structures point and circle abo4e main. )hat this means is that these structures now ha4e &ile scope, that is, the are now accessible &rom the point the are de&ined up to the end o& the &ile. There8s reall no reason &or doing this in this program other than ma1e the main &unction a little smaller and ma1e us &ocus our attention to the main obDect o& discussion.

6@

#include <stdio.h> struct point { int F int ; "

// F coordinate // ; coordinate

struct circle { int radius struct point center char color1392 " int main () { int n struct circle polDadots12 8 { { B0 {!90 !B"0 "Rlue /el/et" "0 { <0 {390 ="0 "Cra; popon" "0 {!90 { B0 !!"0 "Creen $iant" " " for ( n 8 9 n < = n:: ) { printf("radius87d0 center8(7d07d)0 color87s\n"0 polDadots1n2.radius0 polDadots1n2.center.F0 polDadots1n2.center.;0 polDadots1n2.color) " " return !

2unning this program produces the &ollowing results9


radius8B0 center8(!90!B)0 color8Rlue /el/et radius8<0 center8(390=)0 color8Cra; popon radius8!90 center8(B0!!)0 color8Creen $iant

(ointers and $tructures


The problem with the circle structure we created in the preceding section is that it wastes space when color is shorter than 6J characters or lac1s space when it is longer than 6J characters. But with pointers to char, the structure can simpl hold a pointer 4ariable that points to an arra o& characters stored somewhere else. )here* )e don8t care. 'Actuall , in the computer8s memor 1nown as the heap or &ree store.( This arra is created onl &or as much storage space as is reEuired. Thus, we reall should ha4e de&ined struct circle with color as a pointer to char, and with e4er thing else sta ing the same.
struct circle { int radius

6>

"

struct point center char *color

// instead of char color12

)hen using a pointer to a structure, an incrementation or decrementation o& the pointer is based on the si:e o& the structure, which we can &ind using the siEeof operator. That is, i& ptr is a pointer to struct circle then the &ollowing are eEui4alent9
ptr:: ptr 8 ptr : siEeof(struct circle)

The siEeof(struct circle) in a 56 bit s stem li1e mine returns 3@ b tes since
radius 8 < &;tes (an int) center 8 W &;tes (struct point has 3 /aria&les of t;pe int) color 8 < &;tes (a pointer)

)hile the dot operator '.( applied to actual obDect is used to access member o& a structure, the arrow operator ',Q( is used with a pointer to access a member o& a structure. For e7ample, to print each element in the polDadots arra , we could also use a pointer, li1e this.
struct circle *ptr // pointer to struct circle ptr 8 polDadots // point to polDadots arra; for ( n 8 9 n < = n:: ) { printf("radius87d0 center8(7d07d)0 color87s\n"0 ptr%>radius0 ptr%>center.F0 ptr%>center.;0 ptr%>color) ::ptr // increment the pointer "

A structure or a pointer to a structure can be passed to a &unction. $n the &ollowing program we constructed two &unctions9 area() which accepts a circle structure and returns its area, and sho@() which accepts a pointer to a circle structure and an integer that it uses to iterate an arra o& circles.
#include <stdio.h> struct point { int F int ; "

// F coordinate // ; coordinate

struct circle { int radius struct point center char *color " int main () { /oid sho@(struct circle *0 int) // protot;pe dou&le area(struct circle) // protot;pe struct circle dot 8 {B0 {!90 !B"0 "Rlue /el/et"" printf("(rea of dot 8 7f\n"0 area(dot)) // call area()

6<

struct circle polDadots12 8 { { B0 {!90 !B"0 "Rlue /el/et" "0 { <0 {390 ="0 "Cra; popon" "0 {!90 { B0 !!"0 "Creen $iant" " " struct circle *ptr // pointer to struct circle ptr 8 polDadots // point to polDadots arra; sho@(ptr0 =) // call sho@() " return !

dou&le area(struct circle c) { const float 'Q 8 =.!<!. return ('Q * c.radius * c.radius) " /oid sho@(struct circle *p0 int counter) { int n for ( n 8 9 n < counter n:: ) { printf("radius87d0 center8(7d07d)0 color87s\n"0 p%>radius0 p%>center.F0 p%>center.;0 p%>color) ::p // increment the pointer " "

Fere are the results o& running this program.


(rea of dot 8 OW.B=MMMO radius8B0 center8(!90!B)0 color8Rlue /el/et radius8<0 center8(390=)0 color8Cra; popon radius8!90 center8(B0!!)0 color8Creen $iant

-nions
A union, li1e a structure contains a collection o& 4ariables which are accessed with the dot '.( operator. Fowe4er, unli1e a structure, all the 4ariables share the same memor location. -nions are declared with the 1e word union &ollowed b the tag name, then b 4ariable declarations enclosed in a pair o& braces. !nl one 4ariable can be accessed at one time since the all share the same memor location. The &ollowing program declares a union o& char, &loat and int. Notice that a&ter we assign a 4alue to the 4ariable o@ed, the other 4ariables would no longer contain meaning&ul 4alues.
#include <stdio.h> int main () { union stats { char seF

6;

" union stats un // declare /aria&le of t;pe union stats un.seF 8 KGK printf("HeF is 7c\n"0 un.seF) un.a$e 8 B printf("($e is 7d\n"0 un.a$e) un.o@ed 8 !3=.<B printf("J@ed 7O.3f\n"0 un.o@ed) printf("($e is 7d0 seF is 7c\n"0 un.a$e0 un.seF) // junD5 return ! "

int a$e float o@ed

The (reprocessor
The preprocessor is part o& the 0N- compiler. $t is in4o1ed b entering cpp at the prompt along with its input C source &ile. $t acts upon the directi4e # and, in addition, replaces an comment in the program b a blan1 line. The modi&ied source code then becomes the input &or the ne7t compilation step. )hen compilation is completed, the compiler deletes this modi&ied source &ile. Preprocessor directi4es &all into three 1inds9 &ile inclusion '#include( macro de&inition '#define(, and conditional compilation 'e$.0 #if0 #ifdef0 #endif(. "irecti4es can appear an where in the program but the 8re normall placed at the top o& the source &ile. A directi4e can be continued to the ne7t line b ending the current line with a \ character. There are three sections here9 the &irst discusses the #include and #define macrosL the second discusses conditional compilationL and the &inal section introduces some prede&ined macros.

.define and .include +acros


The #include directi4e tells the preprocessor to read a speci&ied &ile and insert it at the location o& the directi4e. $& the name o& the &ile is enclosed in angle brac1ets A &or e7ample, #include <stdio.h> A the preprocessor would search &or that &ile in the standard director whose path is implementation de&ined and, i& it8s not there, in the current director . $& the name o& the &ile is enclosed in double Euote A &or e7ample, "m;header.h" A then an implementation de&ined director 'normall , the current director ( is searched and, i& not there, the standard director . The #define directi4e or macro de&inition can be used &or di&&erent purposes9

Create s mbolic constants.


#define )-N4 ! if ()-N4) { ... // -eplaces )-N4 @ith ! // &ecomes if (!)

5J

This is li1e doing search,and,replace with a word processor in which an occurence o& the macro is replaced with its de&inition. Change the s nta7, which is usuall discouraged since it ma1es the program di&&icult to read &or others.
#define R(LQ>AR(LQ> for( ) // infinite loop )

R(LQ>AR(LQ> // &ecomes for( { printf("?ontinueV (;/n) 8> ") scanf("7c"0 Tans@er) if(ans@er 88 K;K) eFit(9) ...

Control compilation
#define Y4RNC // compile onl; in de&u$$in$ mode

Create parameteri:ed macro, a1a &unction macro


#define HZN(-4(F) (F)*(F) /al 8 HZN(-4(3) // sPuare of F // &ecomes /al 8 (3)*(3)

"o not put an e7tra to1en with the macro de&inition. For e7ample,
#define )-N4 ! #define HZN(-4(F) 8 (F) * (F) if ()-N4) { /al 8 HZN(-4(3) // &ecomes if (! ) // &ecomes /al 8 8 (3) * (3)

)ell,chosen macro names de&ining s mbolic constants ma1e programs easier to read. +acros also ma1e it easier to modi& a program since ou onl need to modi& the de&inition instead o& e4er occurence o& the constant. $deal candidate &or s mbolic constants are T2-K, FAL#K, YK#, N!, the 1e board 1e s and ph sical and mathematical constants 'inches per &oot, P$(. A &unction macro has the ad4antage o4er a real &unction because the reEuire no run,time o4erhead, that is, no call stac1 to worr about, and thus the program run &aster. And there8s also the ad4antage that there8s no t pe chec1ing in4ol4ed. The HZN(-4(F) macro abo4e, &or e7ample, can ta1e an t pe9 &loat, integer, etc., as long as it is numeric. Fowe4er, a &unction macro has its disad4antages9 3. The compiled code becomes large as a result o& substitution, 6. The absence o& t pe chec1ing can result in improper con4ersion, and 5. -ne7pected results ma appear i& ou8re not care&ul with precedence. Fere8s a program to illustrate the problem with precedence in a macro. The &irst two macro de&inition are both bugg .

53

#include <stdio.h> #define ((F) F*!9 #define Z(F) (F*!9) #define [(F) ((F)*!9) int main() { int a 8 <0 & printf("((a) printf("Z(a) printf("[(a) // &u$$;5 // &u$$;5

8 8 8 8

30 c 8 7d\n"0 7d\n"0 7d\n"0

! ((a) ) Z(a) ) [(a) )

printf("((a:&:c) 8 7d\n"0 Z(a:&:c) ) printf("Z(a:&:c) 8 7d\n"0 Z(a:&:c) ) printf("[(a:&:c) 8 7d\n"0 [(a:&:c) ) " return !

To see the results o& the macro substitution, sa4e the program into a &ile, sa test.c, and then in4o1e the 0N- C Preprocessor. '$& ou want to sa4e the modi&ied source &ile, ou can add the option %o outputAfile where outputAfile is the name o& the &ile to sa4e the results to.(
# cpp %Wall test.c

The output &rom the preprocessor scrolls b and when it stops scrolling, ou should see the &ollowing. Notice how the problem o& precedence was eliminated in the CRC macro.
int main() { int a 8 <0 & printf("((a) printf("Z(a) printf("[(a)

8 8 8 8

30 c 8 7d\n"0 7d\n"0 7d\n"0

! a*!9 ) (a*!9) ) ((a)*!9) )

printf("((a:&:c) 8 7d\n"0 (a:&:c*!9) ) printf("Z(a:&:c) 8 7d\n"0 (a:&:c*!9) ) printf("[(a:&:c) 8 7d\n"0 ((a:&:c)*!9) ) " return !

As a rule, ne4er be sting with parentheses. $& the macro8s replacement list contains an operator, alwa s enclose the replacement list in parentheses. #econd, put parentheses around a parameter e4er time it appears in the macro. A macro can ha4e more than one parameter, but the must all be used in the substitution and must be passed the correct number o& arguments.
#define G(,(F0 ;) ((F) > (;) V (F) + (;)) // multiple parameters

There must be no whitespace between the macro name and the opening parenthesis. $n the &ollowing, HNG would be erroneousl substituted with (F0;) ((F) : (;))

56

#define HNG (F0;) ((F) : (;)) paren

// 4eeeD5 space &et@een HNG and left

A longer macro can be created using multiple C statements. But wh not Dust write a &unction instead*
#define C4)AS(G4(n) \ do { \ $ets(s) \ puts(s) \ ... \ " @hile ()-N4) ... C4)AS(G4(her)

To rede&ine or replace a macro with another, &irst unde&ine it with the directi4e undef.
#undef HNG // old macro #define HNG(F0;0E) ((F) : (;) : (E)) // ne@ macro

The # operator 'a1a Cstringi:ationC operator( con4erts a macro argument into a string literal. B preceding a macro parameter with #, the argument is con4erted into a Euoted string on e7pansion.
#define H*JWASNG(F) printf(#F " 8 7d\n"0 F) H*JWASNG(count) // printf("count" " 8 7d\n"0 count)

Because adDacent strings are concatenated in C, the macro substitution actuall becomes
printf("count 8 7d\n"0 count)

The ## operator, a1a Cto1en,pastingC operator concatenates two strings in the macro e7pansion. First the parameter is replaced b its argument, then the 4alues surrounding the operator are Doined.
#define ?-AX(-(F) num##F int ?-AX(-(!)0 ?-AX(-(3) // &ecomes int num!0 num3

Conditional Compilation
Conditional compilation is a term applied to a directi4e or a set o& directi4es instructing the preprocessor to compile a bloc1 o& source codes onl i& certain conditions are met. $t in4ol4es the #if0 #elif0 #else0 #endif0 #ifdef0 #ifndef directi4es along with the defined operator. For e7ample, in the process o& debugging and testing a program, we might want to scatter some printf messages in our program. )e could proceed as &ollows9
#define Y4RNC !

55

... #if Y4RNC printf("Same 8 7s0 price 8 7!.3f\n"0 drinD0 price) #endif

#ince Y4RNC is set to ! then the printf will be compiled. !nce we8re done debugging, we could then set Y4RNC to 9 and the preprocessor will remo4e all three lines so that the compiler won8t e4en see them. )e don8t ha4e to actuall remo4e an o& the three lines. )e could use the defined operator, in which case, we8re simpl testing i& Y4RNC is de&ined, not testng its 4alue. The parentheses around defined are not reall
#define Y4RNC ... #if defined(Y4RNC) printf("Same 8 7s0 price 8 7!.3f\n"0 drinD0 price) #endif

The test e7pression &or #if must e4aluate to a constant, o&ten s mbolic constants created with #define. You can8t use the siEeof() operator, t pecasts, or the &loat t pe. The statement bloc1 ma include preprocessor directi4es and the can be enclosed in braces. The #ifdef and #ifndef directi4es can be used &or the same purpose as the defined
#ifdef Y4RNC #ifndef Y4RNC // same as #if defined Y4RNC // same as #if 5defined Y4RNC

There are unlimited uses &or conditional compilation directi4es but some o& the most common are 3. to write programs that are portable,
#if defined NSQ, .... #elif defined WQSYJWH .... #if defined LQSN, .... #else .... #endif

6. to pro4ide a macro de&ault de&inition,


#ifndef G(,ARNII4#define G(,ARNII4- 3BB #endif

5. to a4oid multiple inclusion o& a header &iles in a large program that is bro1en into se4eral &iles. For e7ample, here8s a header &ile named jheader.h.
/* Iile name+ jheader.h #if 5defined(J*4(Y4-) */

5G

#define J*4(Y4/* start of header statements */ #define )-N4 ! /oid sho@(struct shape *) .... .... #endif

(redefined +acros
There are also a4ailable some 4er use&ul prede&ined macros. Note that their names are preceded and terminated b two underscores.
AAY()4AA AA)QG4AA AALQS4AA AAIQL4AA

the date compiled 'C+on dd YYYYC( the time compiled 'Chh9mm9ssC( the line number being compiled the name o& the &ile

Fere8s a program that uses them. $t8s in a source &ile called tester.c.
#include <stdio.h> int main() { printf("?ompilin$ line 7d of file 7s\n"0 AALQS4AA0 AAIQL4AA) printf("?ompiled 7s at 7s\n"0 AAY()4AA0 AA)QG4AA) return ! "

)hen run, it produces the &ollowing results.


?ompilin$ line = of file tester.c ?ompiled Jun 3M 399= at 33+<W+=!

There are three other 1inds o& directi4e9 #error0 #line and #pra$ma. But the 8re not used much.

$cope and +odular (ro/rammin/


The 4isibilit or accessibilit and scope o& 4ariables, constants and other obDects are go4erned b scope rules. 0enerall , there are two 1inds o& scopes9 local and global.

0ocal 1ariables
Local scopes are de&ined b a bloc1. That is, it begins with the opening brace and ends with the closing brace. Names declared in the &unction, as parameters or as 4ariables, are local to that &unction. The 8re created when the &unction is entered and destro ed when the &unction is 5H

e7ited. Local 4ariables, there&ore, do not hold their 4alue. The 8re also 1nown in C as automatic or auto 4ariables. )e can, howe4er, preser4e their 4alue between &unction calls b using the static modi&ier. $n the &ollowing program, the &unction demostat basicall Dust increments b H both the auto 4ariable nstat 'auto b de&ault( and the static 4ariable stat )ith repeated calls to the &unction, the static 4ariable stat is able to hold its 4alue and thus we8re able to repeatedl increment its 4alue. But this is not the case with the non static or auto 4ariable nstat since it alwa s gets recreated and initiali:ed e4er time the &unction is entered.
#include <stdio.h> int demostat() { int nstat 8 9 static int stat 8 9 nstat :8 B stat :8 B printf("stat 8 7d0 nstat 8 7d\n"0 stat0 nstat) " int main() { int n for (n89 n<= demostat() return ! "

n::)

Fere are the results o& running the program.


stat 8 B0 nstat 8 B stat 8 !90 nstat 8 B stat 8 !B0 nstat 8 B

A computer8s CP- contains a small number o& memor locations called registers. "ata mo4e &rom the 4ariable8s storage in main memor to the registers where it is manipulated and then bac1 to memor . ?eeping an o&ten used 4ariable in the register would ma1e its manipulation much &aster. The 1e word re$ister suggests to, not &orces, the compiler that a local auto 4ariable be stored in a CP- register instead o& regular memor . The 1e word re$ister can be used onl with simple numeric 4ariables 'int, &loat, etc(, and it can not be used with static and global 4ariables.
re$ister int n for (n89 n<= n::) func!()

2lobal 1ariables
0lobal scopes e7ist outside o& all scopes. A name '4ariable and other obDects( declared in the global scope are 4isible throughout the program, e4en in another source &ile. The sta in e7istence &or the duration o& the program. 0lobal 4ariables 'a1a e7ternal 4ariables( must be declared outside o& all &unctions, including main(). The 8re normall placed at the top o& the 5@

source &ile so that one can easil &ind them and also to ma1e them a4ailable throughout the program since a 4ariable must &irst be declared be&ore the are used. 0lobal 4ariables, unli1e local 4ariables, are automaticall initiali:ed b the compiler i& ou don8t do so oursel&. $n the &ollowing program, the name &ahal is de&ined as a global 4ariable. Thus, it is 4isible throughout the entire program. But the &unction compare() also de&ines a 4ariable named &ahal which, as a result, hids the global &ahal inside that &unction.
#include <stdio.h> float &ahal 8 =.3B /oid compare(float price) { float &ahal 8 3.MM // hides the $lo&al &ahal printf("6our price is 7!.3f /s. mine of 7!.3f\n"0 price0 &ahal) " int main() { compare(&ahal) return ! "

// refers to $lo&al &ahal

The program when run prints


6our price is =.3B /s. mine of 3.MM

0ood programming practice calls &or one not to use global 4ariables, since it de&eats the principle o& modularit . $nstead 4ariables should be passed in a &unction call. #ometimes, howe4er, the 8re reall una4oidable, &or e7ample, when the are needed b man di&&erent &unctions or in man other source &iles. But i& so, a better practice is to use the eFtern 1e word when re&erring to a global 4ariable. The 1e word eFtern in&orms the compiler that a particular 4ariable with a gi4en t pe e7ists somewhere else in the program and that it should not be rede&ined here. B being e7plicit ou are also telling our reader that ou reall mean it. Fere8s what main() would then loo1 li1e9
int main() { eFtern float &ahal compare(&ahal) return ! "

// refers to the $lo&al &ahal

)hen the static modi&ier is applied to global 4ariables '&or e7ample. static float &ahal(, it ma1es such 4ariables 4isible onl &rom its point o& de&inition in the source &ile up to the end o& that &ileL the are not 4isible &rom an other &ile. This is what is normall done in practice so that one need not worr about name con&lict, that is, using names that e7ists in some other source &iles in a multi &ile program.

+odular (ro/rammin/
5>

)hen an application program grows bigger, it o&ten becomes necessar &or the source codes to be bro1en into separate and smaller &iles called modules. Function protot pes, structure de&inition, e7ternal 4ariables and s mbolic constants go into a header &ile. Kach secondar &unction, stripped o& codes that go into the header &ile 'eg., structure de&inition(, goes into its own source &ile with a #include directi4e &or the header &ile Dust mentioned. The part o& the program that contains the main() &unction becomes the main module with a #include directi4e &or the same header &ile. $n Pointers and Structures, we wrote a program that consists o& two &unctions other than main()9 area() which calculates the area o& circle, sho@() which displa s the propert o& each circle in an arra o& circles. Fere below, we brea1 the source o& that program into &our separate &iles or modules.
circle.h

contains the protot pes and structure de&initions.

// *eader file+ circle.h #if 5defined ?Q-?L4A*4(Y4#define ?Q-?L4A*4(Y4struct point { int F // F coordinate int ; // ; coordinate " struct circle { int radius struct point center char *color " dou&le area(struct circle c) /oid sho@(struct circle *p0 int counter) #endif area.c

is the source module &or calculating the area o& a circle.

// module+ area.c #include "circle.h" dou&le area(struct circle c) { const float 'Q 8 =.!<!. return ('Q * c.radius * c.radius) " sho@.c

is the source module &or displa ing in&ormation about a circle.

// module+ sho@.c #include <stdio.h> #include "circle.h" /oid sho@(struct circle *p0 int counter)

5<

{ int n for ( n 8 9 n < counter n:: ) { printf("radius87d0 center8(7d07d)0 color87s\n"0 p%>radius0 p%>center.F0 p%>center.;0 p%>color) ::p // increment the pointer " " m;circle.c //

contains the &unction main(), thus becoming the main module.

module+ m;circle.c

#include <stdio.h> #include "circle.h" int main () { struct circle dot 8 {B0 {!90 !B"0 "Rlue /el/et"" printf("(rea of dot 8 7f\n"0 area(dot)) // call area() struct circle polDadots12 8 { { B0 {!90 !B"0 "Rlue /el/et" "0 { <0 {390 ="0 "Cra; popon" "0 {!90 { B0 !!"0 "Creen $iant" " " struct circle *ptr // pointer to struct circle ptr 8 polDadots // point to polDadots arra; sho@(ptr0 =) // call sho@() return ! "

Kach o& these source &iles must &irst be compiled separatel . #eparate compilation gi4es the programmer the ad4antage o& wor1ing with a smaller &ile since the smaller the &ile, the easier it is to locate bugs.
# $cc %Wall %c area.c # $cc %Wall %c sho@.c # $cc %Wall %c m;circle.c

The ,c option tells the 0N- compiler to compile the speci&ied source &ile into an obDect &ile and not bother producing an e7ecutable output &ile. The obDect &ile created will ha4e the same name as the source &ile but with the e7tension o. )hen all three source &iles compile properl , create the e7ecutable with the &ollowing command9
# $cc %o m;circle area.o sho@.o m;circle.o

This tells the compiler to ta1e all three obDect &iles and create an e7ecutable output &ile named m;circle instead o& the de&ault output &ile a.out &rom the obDect &iles area.o sho@.o and m;circle.o. To run the program, simpl enter
# ./m;circle

5;

But that8s a lot o& t ping Dust to create one e7ecutableB )hat i& we add &i4e more modules to our program* That8s e4en more t pingB )hat i& we simpl ma1e a tin change to one o& our source &ile* That8s wh there8s a +a1e&ileB

+a3efiles
To ma1e it easier to build large programs, a ma!e ile becomes necessar . A ma1e&ile is a &ile that stores in&ormation about which &iles are needed to build the program and the dependencies among &iles. $t is recommended that the &ile be named GaDefile so that it would apear prominentl in a director listing. Kach time ou want to recompile the program, all ou need to do is t pe maDe at the # prompt. The maDe program loo1s at the last modi&ication time o& each &ile and, based on that, recompiles it, i& necessar . Fere8s how our GaDefile loo1s.
# )ar$et is eFecuta&le file named m;circle. Qt depends # on the o&jects area.o0 sho@.o and m;circle.o m;cirle+ area.o sho@.o m;circle.o $cc %o m;circle area.o sho@.o m;circle.o # )ar$et is o&ject module area.o. Qt depends on area.c and circle.h area.o+ area.c circle.h $cc %Wall %c area.c # )ar$et is o&ject module sho@.o. Qt depends on sho@.c and circle.h sho@.o+ sho@.c circle.h $cc %Wall %c sho@.c # )ar$et is o&ject module m;circle.o. Qt depends on m;circle.c and circle.h m;circle.o+ m;circle.c circle.h $cc %Wall %c m;circle.c

The # sign indicates a comment, which is ignored b the maDe utilit . To the le&t o& the colon is called the target &ile, the &ile to create i& necessar . To the right o& the semicolon are the &iles that the target depends on. $n the case o& the e7ecutable &ile m;circle, the are area.o sho@.o and m;circle.o. The ne7t line is the command &or the compiler to create the target. You must indent this line with with the tab !ey or it won8t wor1. The maDe commands &or the three other targets wor1s the same wa .

"irectories and Files


GJ

C pro4ides a rich set o& &unctions to manipulate directories and &iles, and to read and write to a &ile.

"irector +anipulation
The header stdio.h pro4ides the &ollowing &unctions &or deleting and renaming a director .
int remo/e(char *path) A 2emo4es a director int rename (const char *oldname0 const char *ne@name) A 2enames the &ile &rom oldname to ne@name. $& the &ile has an other names 'hard lin1s( aside &rom

oldname, the 8ll continue to ha4e those names. The header &iles unistd.h also pro4ides &unctions &or manipulating directories in -ni7,li1e &ashion. Among them9

A 2eturns an absolute &ile name representing the current wor1ing director and stores it in &uffer. The numchars argument tells the s stem how much to allocate. $& a null pointer is passed as argument to &uffer, the appropriatel si:ed bu&&er is automaticall allocated. int chdir(char *dirpath) A Changes the current director to the gi4en director path. 2eturns J on success and ,3 on error.
char* $etc@d(char *&uffer0 int numchars)

A Creates a director using the gi4en path name and permission bits using s mbolic constants 'HAQ-NH- &or read onl &or owner, HAQWNH- &or write onl &or owner, etc.(. 2eturns J on success or ,3 on error. Note9 You must include s;s/stat.h &or this to wor1.
int mDdir(char *path0 modeAt mode) int unlinD(char *path)

A 2emo4es the gi4en director path. 2eturns J on

success else ,3 on error.


int rmdir(char *path)

A A s non m &or unlinD

The &ollowing program demonstrates the use o& these &unctions. Note that $etc@d alwa s returns an absolute path e4en though a relati4e path to the director ma be speci&ied.
#include <stdio.h> #include <unistd.h> #include <s;s/stat.h>

// for mDdir and HAQ-W,N // relati/e path

const char HNRYQ-12 8 "projects" int main() { char *p&uff p&uff 8 $etc@d(SNLL09) puts(p&uff) /* Jr @e could do this0 too */ char &uffer1W92 $etc@d(&uffer0siEeof(&uffer))

G3

puts(&uffer) if ( chdir(HNRYQ-) 88 9 ) // ?han$e director; { p&uff 8 $etc@d(SNLL09) puts(p&uff) // print current @orD director; if (mDdir("ne@dir"0 HAQ-W,N)889) // create director; puts("director; successfull; created") if (rmdir("ne@dir")889) // delete director; puts("director; remo/ed") " else puts("4rror+ ?an not find director;") " return !

The header &ile dirent.h contains se4eral &unctions &or reading director entries. The opendir &unction opens a speci&ied director name and returns a pointer to t pe YQ-, the director stream, i& success&ulL otherwise, it returns a N-LL pointer. The readdir &unction retrie4es these entries, which is a structure o& t pe struct dirent and which contains the &ollowing members9
char *dAname A The null terminated &ile name inoAt dAfileno A The &ile serial number siEeAt dAnamlen

A The length o& the &ile name, e7cluding terminating null

Also included in dirent.h are &unctions that allow reading director entries at an speci&ied position in the director stream.

A 0oes to the &irst entr in the director stream but does not set the &ile position to :ero. offAt telldir (YQ- *dirstream) 2eturns the &ile position o& the director stream dirstream.
/oid re@inddir (YQ- *dirstream) /oid seeDdir (YQ- *dirstream0 offAt pos) A #ets the &ile position o& the director stream to the o&&set pos. The 4alue pos must be the result o& a pre4ious to telldir.

call

Fere8s a program to demonstrate these &unctions. The header stdli& is where the eFit &unction is protot ped and the macros 4,Q)AHN??4HH and 4,Q)AI(QLN-4 de&ined. 4,Q)AHN??4HH indicates success&ul termination, 4,Q)AI(QLN-4 indicates otherwise. Also included is the header strin$.h which contains the &unction strcmp which returns a :ero i& two strings are ali1e. )hat the program does is &ind the &ile circle.h in the director named circles. $& &ound, it mar1s the &ile8s position and stops looping. $t goes bac1 to that position and re,reads it, then rewinds the director stream and reads the &irst entr .
#include #include #include #include <stdio.h> <dirent.h> <stdli&.h> <strin$.h // for director; entries // for eFit() // for strin$ compare strcmp()

G6

const char HNRYQ-12 8 "circles" const char H4(-?*A>4612 8 "circle.h" int main() { YQ- *dp if ( (dp 8 opendir(HNRYQ-) ) 88 SNLL) { puts("4--J-+ ?annot open file") eFit(4,Q)AI(QLN-4) " struct dirent *de // director; entr; structure offAt pos 8 telldir(dp) // &e$innin$ position @hile ( (de 8 readdir(dp)) ) { printf("(t position 7d+ 7s\n"0 (unsi$ned)pos0 de%>dAname) if (strcmp(de%>dAname0H4(-?*A>46)889) { puts("Iound match\n") &reaD // stop loopin$ " pos 8 telldir(dp) " if (5de) { // if pointer is SNLL closedir(dp) puts("?annot find file") eFit(4,Q)AI(QLN-4) " seeDdir(dp0pos) // set position @here fileKs found de 8 readdir(dp) // read it printf("7s is at position 7d\n"0 de%>dAname0 (unsi$ned)pos) re@inddir(dp) // does not set position to &e$innin$ pos 8 telldir(dp) // $et position de 8 readdir(dp) // read it printf("7s is at position 7d\n"0 de%>dAname0 (unsi$ned)pos) closedir(dp) " return !

Compiling and running the program produce the &ollowing results. Note that re@ind does not set the position to :ero as e4idenced when we use telldir a&ter rewinding to gi4e us the position.
(t position (t position (t position (t position Iound match 9+ . !3+ .. 3<+ area.o <W+ circle.h

circle.h is at position <W . is at position .<

File +anipulation
G5

There are se4eral &unctions included in the header &iles s;s/stat.h and s;s/t;pes.h &or manipulating &iles. Among them9
int remo/e(char *path)

A "eletes a named &ile. This is also a4ailable in stdio.h


// deletes the file Ffile.tFt

remo/e("Ffile.tFt")

int rename(char *oldname0 char *ne@name) a4ailable in stdio.h rename("test.c"0 "final.c")

A 2enames a &ile. This is also

// rename test.c to final.c

int chmod(char *path0 int pmode)

A Changes permission settings o& a &ile to

read, write, e7ecute.


chmod("final.c"0OBB) // r@F for o@ner0 rF for $roup and others

int stat (const char *filename0 struct stat *&uffer) A #ets the attributes o& filename in the structure pointed at b &uffer. 2eturns J on success

else ,3 on &ailure. The structure contains, among man others, in&ormation such as the mode, inode number, user $" o& the owner, the number o& hard lin1s, etc. The status mode contains two 1inds o& in&ormation9 access permission and the t pe o& &ile, that is, whether it8s a director 'QHAQHYQ-(, a regular &ile 'QHAQHYQ-(, etc.
struct stat *filestat if (stat(HNRYQ-0 filestat) 88 9 TT HAQHYQ-(filestat%>stAmode)) puts("( director;")

File I%!
Be&ore ou can wor1 with a &ile 'read or write to it(, it must &irst be opened. And when ou8re done with it, ou must close it. The protot pe &or opening and closing a &ile, which is in the header stdio.h, are
IQL4 *fopen(const char *filename0 const char *mode) int fclose(IQL4 *stream)

returns a &ile pointer 'SNLL on error( and reEuires the name o& the &ile to be opened 'with the path, i& necessar ( and the mode, which controls how the &ile should be opened. fclose() closes the &ile pointer and returns :ero on success or the error code 4JI on error. The mode string can be an o& the &ollowing9
fopen() r @ a

!pen &or reading 'returns N-LL on error( !pen &or writing, truncate i& e7ists else create !pen &or appending, create i& not e7ists

GG

The plus sign : can be added to open the &ile &or both reading and writing, that is, r:, @: and a:. +odes r: and @: are actuall the same. The both create the &ile or o4erwrite it i& it e7ists. And i& ou8re un&ortunate enough to be running under "!# or )indows, which di&&erentiates between te7t and binar &iles, append a & to the mode to indicate that the &ile is binar , &or e7ample, r:& or r&: will open a binar &ile &or reading and writing. -ni7 and Linu7 don8t di&&erentiate between te7t and binar &iles whereas "!# stores binar &iles and te7t &iles in di&&erent wa s. Te7t &iles are di4ided into lines. )hile -ni7 onl has the line &eed character, Pn, to mar1 the end o& line, "!# e7pands it into a pair o& characters in a te7t &ile, a carriage return and a line &eed. but onl writes a single newline character in a binar &ile. Also, to mar1 the end o& a te7t &ile, "!# normall puts the control,: or \F!a character, but places no signi&icance to it in a binar &ile. There are three wa s data can be read &rom or written to a &ile9

as &ormatted data, when ou want to create &iles containing te7t and numeric data 'spreadsheets, &or e7ample(. as character data, to sa4e te7t but not numeric data 'an te7t &ile, &or e7ample(. as direct output, that is writing an entire bloc1 or section o& memor directl to the &ile.

Formatted I/O
To read &ormatted data &rom a dis1 &ile, the stdio.h header pro4ides the &ollowing &unctions.

A 0ets a character &rom a stream and returns it as an integerL returns K!F 'or ,3( at end o& &ile. "eclare the character 4ariable to store the result into as an integer or the test &or end o& &ile ma not be right. Comparing character to to signed integer, &or e7ample, ma cause K!F to be con4erted to 6HH instead o& ,3. char *f$ets(char *strin$0 int maF0 IQL4 *fileApointer) A 2eads a string &rom a &ile including the newline up to maF , 3 and then adds a newlineL i& alread at end o& &ile, the recei4er string is le&t undisturbed.
int f$etc(IQL4 *fileApointer)

A 2eads &ormatted input &rom a streamL returns the number o& success&ul assignments.
int fscanf(IlL4 *fileApointer0 char *format strin$0 ar$s)

Note that each o& the &unctions listed has its eEui4alent that reads &rom stdin9 $etc0 $ets0 and scanf. 'Standard Input/Output discusses standard input%output and these &unctions, including &ormatted input string speci&ications( $n addition, 0N- pro4ides a sa&er alternati4e to the dangerous $ets and f$ets.
ssiEeAt $etdelim (char **lineptr0 siEeAt *len0 int delimiter0 IQL4 *stream) A reads character string &rom a stream up to and including delimiter, and

allocates the necessar storage space or reallocates space in increments o& 36< i& si:e len is not enough, which e&&ecti4el means that len is Dust a hint(, and returns the number o& b tes read and sets lineptr to point to the string being allocated and len to the amount o& memor allocated. But don8t ta1e this memor pointed to b

GH

as an ordinar string since it could contain a null character '\9( be&ore the delimiter. Also, when ou no longer need the memor allocated, &ree it using the free &unction, passing it the pointer to that memor 'lineptr(. ssiEeAt $etline (char **lineptr0 siEeAt *len0 IQL4 *stream) A same as $etdelim e7cept that the delimiter used is the newline character.
lineptr

The &ollowing program shows how to use $etline() using stdin as the input stream. #ince we8re getting input &rom stdin, where the newline is the delimiter, we could Dust set the length to :ero and let $etline() allocate the necessar amount o& memor .
#include <stdio.h> #include <stdli&.h> int main(/oid) { char * line 8 SNLL siEeAt len 8 9 ssiEeAt numread

// allocate ne@ memor; &locD // as man; as rePuired

puts("4nter a line") numread 8 $etline(Tline0 Tlen0 stdin) printf("read 7d0 allocated 7d\n"0 numread0 len) if (line) free(line) return ! "

Fere8s a sample interaction


# ./$etline 4nter a line *ala &ahu$5 read !30 allocated !3W

To write &ormatted output to a dis1 &ile, the &ollowing &unctions are a4ailable 'which also ha4e their eEui4alent that writes to stdout9 putc0 puts0 and printf A #ee Standard Input/Output &or details(.

A writes &ormatted output to a &ileL returns the number o& characters written or less than J on error, int fputc(int c0 IQL4 *fileApointer) A con4erts the character to an unsigned char and writes it to the &ileL returns the character or K!F on error.
int fprintf(IlL4 *fileApointer0 char *formatAstrin$0 ar$s) int fputs(char *strin$0 IQL4 *fileApointer) A writes a string to the &ile but unli1e puts, which writes to stdout, does not write the newline characterL returns a

positi4e 4alue or K!F on error. To test &or a speci&ic condition, the &ollowing &unctions, protot ped in stdio.h, can be used.
int feof (IQL4 *stream)

A returns non:ero i& the end,o&,&ile indicator &or the

stream is set.

G@

A returns non:ero i& the error indicator &or the stream is set, indicating an error on a pre4ious operation on the stream.
int ferror (IQL4 *stream) /oid clearerr (IQL4 *stream)

A clears the error indicators &or the stream.

Character I/O
The macro 4JI 'which has the 4alue ,3( can indicate 4arious 1inds o& error condition. This is o1a i& the stream contains onl A#C$$ te7t characters since no character has a ,3 4alue. Thus, the &ollowing would wor1
@hile ( (ch 8 f$etc(fp)) 58 4JI) printf("7c"0 ch)

But a problem arises i& we read a binar stream b te b b te since there is no wa to di&&erentiate K!F &rom ,3. The &unction feof() eliminates this problem.
ch 8 f$etc(fp) @hile ( 5feof(fp) ) { printf("7c"0 ch) ch 8 f$etc(fp) "

The &ollowing program uses scanf() to accept input &rom the 1e board 'stdin(, opens the &ile tester.tFt with mode @: 'both reading and writing( and then writes the data to both &ile and the screen 'stdout(.
#include <stdio.h> #include <stdli&.h> const char )4H)IQL412 8 "tester.tFt" int main() { char in&uffer1W92 IQL4 *fp float price1B2 int n char *dr12 8 { "&ahal"0 "&eer"0 "s;oDton$"0 "Dulafo"" for (n 8 9 n < < n::) { printf("4nter price for 7s 8> "0 dr1n2) scanf("7f"0 Tprice1n2) f$ets(in&uffer0 siEeof(in&uffer)0 stdin) " if ( (fp 8 fopen()4H)IQL40 "@:")) 88 SNLL) { fprintf(stderr0 "4rror openin$ file 7s."0 )4H)IQL4) eFit(!) " printf("\n\nWritin$ to disD\n")

G>

for (n 8 9 n < < n::) { fprintf(fp0 "7s 7f\n"0 dr1n20 price1n2) printf("7s 7f\n"0 dr1n20 price1n2) " fclose(fp) return !

"

Fere are the results when run.


4nter 4nter 4nter 4nter price price price price for for for for &ahal 8> !.BB &eer 8> 3.<B s;oDton$ 8> .MB Dulafo 8> .WB

Writin$ to disD &ahal !.BB9999 &eer 3.<B9999 s;oDton$ 9.MB9999 Dulafo 9.WB9999

And here8s a code snippet to demonstrate the use o& fscanf(), f$ets() and f$etc() to read data &rom the &ile along with the re@ind() &unction, which rewinds the &ile pointer to the beginning o& the &ile. Notice how di&&icult it is to use fscanf() to read data &rom a &ile. fscanf() sees a single continuous stream o& characters, ignoring e4en the newline character. $t returns immediatel when it &inds a matching error or has success&ull matched input with the &ormat speci&ications. Fortunate , fscanf() is not normall used this wa in practice.
float p!0 p30 p=0 p< char s!1W920 s31W920 s=1W920 s<1W92 printf("\nHcannin$ file\n") re@ind(fp) // Htart at the top fscanf(fp0 "7s 7f 7s 7f 7s 7f 7s 7f"0 (char *)Ts!0 Tp!0 (char *)Ts30 Tp30 (char *)Ts=0 Tp=0 (char *)Ts<0 Tp<) if ( count < W ) { puts("4eeeeD5 fscanf() input matchin$ error5") fclose(fp) return(%!) " printf("7s 8 7!.3f0 7s 8 7!.3f0 7s 8 7!.3f and 7s 8 7!.3f\n"0 s!0 p!0 s30 p30 s=0 p=0 s<0 p<) char line1W92 printf("\nNsin$ line oriented f$ets\n") re@ind(fp) // Htart at the top @hile (f$ets(line0 siEeof(line)0 fp)) printf("7s"0 line) int ch // *as to &e an int printf("\nNsin$ f$etc() function\n")

G<

re@ind(fp) // Htart at the top @hile ( (ch8f$etc(fp)) 58 4JI) printf("7c"0 ch)

Fere8s what the snippet produces.


Hcannin$ file &ahal 8 !.BB0 &eer 8 3.<B0 s;oDton$ 8 9.MB and Dulafo 8 9.WB Nsin$ line oriented f$ets &ahal !.BB9999 &eer 3.<B9999 s;oDton$ 9.MB9999 Dulafo 9.WB9999 Nsin$ f$etc() function &ahal !.BB9999 &eer 3.<B9999 s;oDton$ 9.MB9999 Dulafo 9.WB9999

Block I/O
2eading and writing bloc1s o& data 'also called direct input or output( are done with the &unctions fread and f@rite which are protot ped in stdio.h as &ollows9
int fread(/oid *&uffer0 int siEe0 int count0 IQL4 *fp) int f@rite(/oid *&uffer0 int siEe0 int count0 IQL4 *fp)

where
&uffer is a pointer to the region o& memor that recei4es the data read &rom the t pe /oid, which means an t pe o& data, siEe is the number o& b tes idual data items being read, which is normall determined b the siEeof operator. count fp

&ile,

is the number o& items to read,

is the pointer to the &ile opened b fopen

Thus, &or e7ample, to read a 3JJ,integer arra bloc1, we could write


int count 8 !99 if ( (fread(&uffer0 siEeof(int)0 count0 fp)) 58 count ) { puts("4eeeeeD5 4rror") . . .

2emember that in a 56,bit s stem, siEeof(int) will return G b tes. or f@rite() returns the number o& items read or written, resp., which can be less than the argument count i& the end o& &ile is reached or there is an error.
fread()

G;

The &ollowing program writes to the &ile, prices, the prices o& &our o& m &a4orite drin1s, each o& which can be thought o& as a &i7ed length record consisting o& two data elements9 name and price.
#include <stdio.h> #include <stdli&.h> const char IQL4AS(G412 8 "prices" struct prices { char name1392 float price " const int ?JNS)8 < int main() { IQL4 *fp struct prices drinDs12 8 { { "&ahal"0 !.39 "0 { "&eer"0 =.3B "0 { "s;oDton$"0 .MB "0 { "Dulafo"0 .WB " " if ( (fp 8 fopen(IQL4AS(G40 "@")) 88 SNLL) { fprintf(stderr0 "4rror openin$ file 7s."0 IQL4AS(G4) eFit(!) " printf("Writin$ to disD\n") if ( f@rite(drinDs0 siEeof(struct prices)0 ?JNS)0 fp) 58 ?JNS) ) { perror("?annot @rite data") eFit(4,Q)AI(QLN-4) " fclose(fp) return ! "

Fere8s a code snippet to read bac1 the prices &rom the &ile and print them to standard output.
// Jpen and read the file if ( (fp 8 fopen(IQL4AS(G40 "r")) 88 SNLL) { fprintf(stderr0 "4rror openin$ file 7s."0 IQL4AS(G4) eFit(!) " printf("-eadin$ the file \n") if ( fread(drinDs0 siEeof(struct prices)0 ?JNS)0 fp) 58 ?JNS) ) { perror("-ead failure") eFit(4,Q)AI(QLN-4) " int n

HJ

for (n 8 9 n < ?JNS) n::) printf("7s 8 7!.3f\n"0 drinDs1n2.name0 drinDs1n2.price) fclose(fp)

Fere8s the snippet produces.


-eadin$ the file &ahal 8 !.39 &eer 8 =.3B s;oDton$ 8 9.MB Dulafo 8 9.WB

Random Access
To read and write to an part o& the &ile, the &ollowing &unctions are a4ailable. Kach o& these positioning &unctions automaticall clears whate4er error indicators e7ist &or the stream.
int fseeD(IlL4 *fileApointer0 lon$ offset0 int ori$in) A current position in &ile to a new location. The macros H44>AH4)0 H44>A?N-0 or H44>A4SY

indicates whether the o&&set is relati4e to the beginning o& the &ile, the current &ile position, or the end o& the &ile, respecti4el . 2eturns J on success. int f$etpos(IlL4 *file pointer0 fposAt *pos) A stores the current position to a memor location pointed b posL returns J on success
int fsetpos(IlL4 *file pointer0 fposAt *pos) A sets current position in &ile to position pointed b pos obtained b pre4ious call to f$etposL returns J on success. lon$ ftell(IlL4 *fileApointer) /oid re@ind(IlL4 *fileApointer)

A gets current position in the &ile. A rewinds the &ile pointer.

)riting fseeD(fp090H44>AH4)) has the same e&&ect as re@ind(fp). Li1ewise, ftell can ta1e the place o& f$etpos. But because ftell uses a long integer to represent the &ile position, this ma not ha4e room to encode all the &ile positions in a large &ile. Thus, it is better to use the &unctions f$etpos instead. The &ollowing e7ample demonstrates reading and writing to an position in the &ile. The &unction fflush() &lushes the output bu&&er into dis1 since with stdio &unctions, data are &irst written to an output bu&&er and not &lushed to dis1 until the bu&&er is &ull. The fflush() &unction accepts a &ile pointer and returns J on success or K!F on error
#include <stdio.h> #include <stdli&.h> const char )4H)AIQL412 8 "a&acada.tFt" int main() { char line1W92 IQL4 *fp fposAt pos if ((fp8fopen()4H)AIQL40"@:"))88SNLL)

H3

{ puts("?annot open file") eFit(4,Q)AI(QLN-4) " fputs("a&cdef$hijDlmnopPrstu/@F;E"0 fp) fflush(fp) fseeD(fp090H44>AH4)) f$ets(line0 siEeof(line)0 fp) printf("7s\n"0 line) fseeD(fp0<0H44>AH4)) printf("(t pos 7ld+"0 ftell(fp)) f$etpos(fp0 Tpos) f$ets(line0 siEeof(line)0 fp) printf(" 7s\n"0 line) fseeD(fp0%!B0H44>A4SY) fputs(",,,"0 fp) fsetpos(fp0 Tpos) fputs("666"0 fp) fflush(fp) fseeD(fp090H44>AH4)) f$ets(line0siEeof(line)0 fp) printf("(t 9+ 7s\n"0 line) fclose(fp) return ! // initialiEe // @rite output &uffer // at start // retrie/e the data // sho@ the data // // // // // <th offset sho@ position sa/e this position retrie/e the data sho@ the data

// !Bth offset from end // @rite ,,, there // the sa/ed position (<th offset) // @rite 666 there // flush the output &uffer // // // // position at &e$innin$ retrie/e the data sho@ the data close the file

"

Fere are the results o& running the program.


a&cdef$hijDlmnopPrstu/@F;E (t pos <+ ef$hijDlmnopPrstu/@F;E (t 9+ a&cd666hijD,,,opPrstu/@F;E

" namic Allocation


The term d namic allocation re&ers to the process o& allocating memor storage space at runtime, as opposed to staticall allocating memor b declaring 4ariables in our program. )hen we declare a static 4ariable 'global 4ariables and 4ariables inside &unctions with static modi&ier(, a &i7ed si:e memor bloc1 is allocated once, when our program starts and at the point the 8re de&ined, and remains a4ailable until our program stops running. For automatic 4ariables '&unction arguments and local 4ariables(, storage space is automaticall allocated inside the statement bloc1 that de&ines them and automaticall &reed when the bloc1 is e7ited. #tatic memor allocation reEuires programmers to ha4e 1nowledge in ad4ance o& how much memor to allocate. #ometimes this is impossible. For e7ample, in a database program, we could set up a 4er large arra to accomodate current and &uture reEuirements. But this not onl is a waste o& space in the present but will also run out e4entuall and will ha4e to be increased and the program recompiled.

H6

+emor Allocation Functions


" namic memor allocation allows the program while it8s e7ecuting to allocate memor when it8s needed. The &ollowing &unctions are used &or d namic memor allocation and are protot ped in stdli&.h9
/oid *malloc(siEeAt num&;tes) A which allocates a speci&ied number o& b tes num&;tes and returns a pointer to it or SNLL on &ailure. The t pe siEeAt is de&ined in stdli&.h as unsigned. The memset &unction, protot ped in the header strin$.h, can

be used to initiali:e each b te o& the allocated bloc1.


float *price int arra;AsiEe 8 = price 8 malloc(arra;AsiEe * siEeof(float)) if (price 88 SNLL) eFit(4,Q)AI(QLN-4) memset (price0 90 arra;AsiEe * siEeof(float))

A which allocates an initiali:ed 'with :ero( bloc1 o& memor as a product o& the number o& obDects and the si:e in b tes o& each obDectL returns a pointer to the &irst b te else SNLL on &ailure. calloc is reall malloc but with the memset &unction called to set each element o& the allocated bloc1 to :ero. 'The memset &unction will be discussed later below.(
/oid *calloc(siEeAt numo&jects0 siEeAt siEe) float *price int arra;AsiEe 8 = price 8 calloc(arra;AsiEe0 siEeof(float)) if (price 88 SNLL) eFit(4,Q)AI(QLN-4)

/oid *realloc(/oid *ptr0 siEeAt siEe) A which reallocates or resi:es the bloc1 o& memor pointed at b ptr to a new siEe in b tes. Note that ptr must be a pointer returned pre4iousl b a call to either malloc or calloc. 3. $& enough space e7ists to e7pand the memor bloc1 pointed at b ptr, allocation succeeds and realloc returns ptr.

6. $& there8s not enough space to e7pand the memor bloc1 pointed at b ptr, a new bloc1 o& the speci&ied si:e is allocated, e7isting data are copied &rom the old bloc1 to the new bloc1, the old bloc1 is &reed, and the &unction returns a pointer to the new bloc1. 5. $& the ptr argument is SNLL, a memor bloc1 o& the speci&ied si:e is allocated and a pointer to it is returned, Dust li1e malloc(). G. $& the siEe argument is :ero, the memor bloc1 pointed at b ptr is &reed and realloc returns SNLL.

H5

H. $& there is not enough memor &or e7panding the current bloc1 or &or allocating a new bloc1, realloc simpl returns SNLL. To allocate more b tes into the price arra allocated b malloc() in the code snippet abo4e,
arra;AsiEe:: // room for one more element price 8 realloc(price0 arra;AsiEe*siEeof(float)) if (price 58 SNLL) { *(price:arra;AsiEe%!) 8 B.BB // price of ne@ element for (i89 i < arra;AsiEe i::) printf("7d+ 7!.3f\n"0 i0 *(price:i)) "

/oid free(/oid *ptr) mdashL &rees realloc and returns it to the heap. free(price)

memor allocated b malloc0 calloc0 or

!nce &reed, the memor will no longer be under the control o& the pointer. 2eusing &reed memor can 'and will e4entuall B( lead to serious error.

Fere8s a program that puts them all together.


#include <stdio.h> #include <stdli&.h> #include <strin$.h> int main(/oid) { int i float *price int arra;AsiEe 8 = price 8 malloc(arra;AsiEe * siEeof(float)) if (price 88 SNLL) eFit(4,Q)AI(QLN-4) memset (price0 90 arra;AsiEe * siEeof(float)) for (i89 i < arra;AsiEe i::) { *(price:i) 8 ! : (i * !.!) // price each element printf("7d+ 7!.3f\n"0 i0 *(price:i)) " arra;AsiEe:: // room for one more element price 8 realloc(price0 arra;AsiEe*siEeof(float)) if (price 58 SNLL) { *(price:arra;AsiEe%!) 8 B.BB // price of ne@ element for (i89 i < arra;AsiEe i::) printf("7d+ 7!.3f\n"0 i0 *(price:i)) " free(price)

HG

return ! "

)hen run, the program produces the &ollowing results9


9+ !+ 3+ 9+ !+ 3+ =+ !.99 3.!9 =.39 !.99 3.!9 =.39 B.BB

+anipulatin/ +emor Bloc3s


$n addition to the 4arious string manipulation &unctions, the header strin$.h in the standard C librar also contains &unctions that can be used to manipulate bloc1s o& memor 9 set each b te to a speci&ied 4alue, or cop and mo4e them &rom one location to another. ?eep trac1 o& the length o& the te7t and ma1e e7plicit chec1s &or o4er&lowing the arra o& characters in a string. These librar &unctions do not do all these things &or ouB 2emember also that ou need to allocate an e7tra b te to hold the null character that mar1s the end o& the string.

A copies the 4alue o& ch, con4erted to an unsigned char 'onl low order b te is used(, into each o& the &irst siEe b tes o& the obDect beginning at destL returns dest. Note9 memset should not be used to initiali:e integers, &loats, etc. to an 4alue other than :ero.
/oid * memset (/oid *dest0 int ch0 siEeAt siEe) struct point { int F int ; " struct point *p! p! 8 malloc(siEeof(struct point)) memset(p!0 90 siEeof(struct point)) printf("p!(7d07d)\n"0 p!%>F0 p!%>;)

// initialiEe to 9

/oid * memmo/e (/oid *dest0 const /oid *ori$0 siEeAt siEe) siEe b tes at ori$ into dest, e4en i& those two bloc1s o& space o4erlap. struct point *@estApoint @estApoint 8 malloc(siEeof(struct point)) @estApoint%>F 8 !=B @estApoint%>; 8 399 memmo/e(p!0 @estApoint0 siEeof(struct point)) printf("point p!(7d07d)\n"0 p!%>F0 p!%>;)

A copies

/oid * memcp; (/oid *dest0 const /oid *ori$0 siEeAt siEe) A copies siEe b tes &rom the obDect beginning at ori$ into the obDect beginning at destL

HH

returns dest. $& o4erlapping is possible as a result, a4oid using memcp;. -se memmo/e instead.
char cr;12 8 "*ala &ahu$5" char title12 8 "Jperation+ Rahu$" memcp;(cr;0 title0 siEeof(title)) printf("cr; 8 7s\n"0 cr;) /oid * memccp; (/oid *dest0 const /oid *ori$0 int ch0 siEeAt siEe) A copies no more than siEe b tes &rom ori$ to dest stopping when a matching ch is &oundL returns a pointer to dest one b te past where ch was copied or SNLL i& no matching ch in the &irst siEe b tes o& ori$. char hi12 8 "Ralut5" char &;12 8 "-un Hamson0 run5" memccp;(hi0 &;0 K0K0 siEeof(&;)) printf("hi 8 7s\n"0 hi)

// cop; up to the comma

Fere8s a program that puts them all together.


#include <stdio.h> #include <stdli&.h> #include <strin$.h> int main(/oid) { struct point { int F int ; " struct point *p! p! 8 malloc(siEeof(struct point)) memset(p!0 90 siEeof(struct point)) printf("p!(7d07d)\n"0 p!%>F0 p!%>;)

// initialiEe to 9

struct point *@estApoint @estApoint 8 malloc(siEeof(struct point)) @estApoint%>F 8 !=B @estApoint%>; 8 399 memmo/e(p!0 @estApoint0 siEeof(struct point)) printf("point p!(7d07d)\n"0 p!%>F0 p!%>;) char hi12 8 "Ralut5" char &;12 8 "-un Hamson0 run5" memccp;(hi0 &;0 K0K0 siEeof(&;)) printf("hi 8 7s\n"0 hi) free(p!) free(@estApoint) " return !

// cop; up to the comma

Fere are the results o& running the program. The last line o& Dun1s results &rom cop ing onl up to the comma and not pro4iding a terminating null '8PJ8(.

H@

p!(909) point p!(!=B0399) hi 8 -un Hamson0\'VVVJpera

Bits and B tes


C has two arithmetic numbers9 integers and &loating points.

Inte/ers
There are three t pes o& integers. These are short0 int and lon$. T pe short has 3@ bitsL while int and lon$ ha4e 56 bits. The can be signed or unsignedL the le&tmost bit 'the sign bit( is :ero &or positi4e numbers and 3 &or negati4e numbers. The largest 3@,bit integer is 56,>@> '63H , 3( and the largest 56,bit integer is 6,3G>,G<5,@G> '653 , 3(. NoteB For a more portable program, use short or int &or numbers up to 56,>@> and long otherwise. $nteger constants can be written in decimal 'base 3J(, octal 'base <( and he7adecimal 'base 3@(. "ecimal constants must contain an digit J thru ; and not begin with a :ero.
%=3! =3<O

!ctals must contain an digit J thru > and must begin with a :ero
9=< 9OO

Fe7adecimals must contain an digit J thru ; and an letter A thru F 'upper or lower case( and must begin with a J7
9F=I 9Fff

The number 3=! is eEui4alent to =<O octal 'i.e., 5O<6 = GO<3 = >O<J( and 4O he7adecimal 'i.e., 3GO3@3 = >O3@J( and thus can be written as
3=! or 9=<O or 9F4O

The compiler treats a number as int i& it &alls within its range, otherwise it treats the number as lon$. To &orce a number to be a lon$, &ollow it with an L,&or e7ample, <=L To indicate that an integer constant is unsigned, &ollow it with a N, &or e7ample, <=N &or unsigned and <=NL &or unsigned long.

Floatin/ (oints
C pro4ides three &loating points, based on $KKK #tandard >HG9

H>

3. &loat A single precision, 56 bits, 3.3>,5< to 5.GJ5<, @ digit precision 6. double A double precision, at least G5 bits 'usuall @G(, 6.66,5J< to 3.>;5J< and 3H digits o&precision 5. long double A e7tended precision, at least >; bits 'usuall <J to 36<(, rarel used A &loating point has three parts9 sign, e7ponent and &raction. The number o& bits &or the e7ponent determines how large numbers can be while the number o& bits in the &raction determines the precision. $n single precision, &or e7ample, the e7ponent is < bits while the &raction is 65 bits long. Floating point literals are written with a decimal point or in e7ponential &orm and are stored b the compiler as double,precision. To &orce the compiler to store &loating points in single, precision, put the letter I a&ter the literal. To indicate a long double, use an L.
<=.3 <=.3e%3 <=. <=I <=f <=.3L

Bitwise +anipulation
C pro4ides the &ollowing operators &or manipulating bit patterns9 SS QQ T U N V #hi&t le&t b a speci&ied number o& bit positions #hi&t right b a speci&ied number o& bit positions Bitwise inclusi4e !2 Bitwise e7clusi4e !2 Bitwise AN" Bitwise N!T

SSW #hi&t le&t assignment '7 W 7 SS ( QQW #hi&t right assignment '7 W 7 QQ ( TW UW K7clusi4e !2 assignment '7 W 7 T ( $nclusi4e !2 assignment '7 W 7 U (

NW AN" assignment '7 W 7 N ( The bitwise shi&t operators trans&orm the binar representation o& a number b shi&ting bits to the le&t or to the right. For e4er bit shi&ted le&t, a :ero bit enters the rightL &or e4er bit shi&ted right, a :ero bit enters the le&t. Note, howe4er, that shi&ting does not modi& the number shi&ted. For e7ample, i& F 8 !3, shi&ting bits two places will result in the &ollowing. 'Fere, we8re showing onl the integer8s rightmost b te.(
int F 8 !3 printf("7d\n"0 F << 3) printf("7d\n"0 F >> 3) // 9999!!99 &inar; // <W or 99!!9999 &inar; // = or 999999!! &inar;

H<

To modi& the number shi&ted, use the SSW or QQW operator.


int F 8 !3 printf("7d\n"0 F <<8 3) printf("7d\n"0 F >>8 3) // 9999!!99 &inar; // <W or 99!!9999 &inar; // !3 or 9999!!99 &inar;

The bitwise shi&t operators ha4e lower precedence than the arithmetic operators. Thus, F << 3 : ! means F << (3 : !). The inclusi4e or 'T( and the e7clusi4e or 'U( operators per&orm boolean or operation. The U produces a 3 i& either one o& the operands is a 3L the ] produces a 3 i& onl one, not both, o& the operands is a 3.
int F 8 !3 int ; 8 != printf("7d\n"0 F U ;) printf("7d\n"0 F ] ;) // // // != or // ! or 9999!!99 9999!!9! 9999!!9! 9999999! &inar; &inar; &inar; &inar;

The bitwise and operator 'N( produces a 3 onl i& both operators are a 3.
int F 8 !3 int ; 8 != printf("7d\n"0 F T ;) // 9999!!99 &inar; // 9999!!9! &inar; // !3 or 9999!!99 &inar;

The bitwise not 'V( operator, also called the bitwise complement is a unar operator. $t replaces ones with :eros and :eros with ones 'twos complement(. Thus, J becomes ,3, 3 becomes ,6, etc.
999999!9 9999999! 99999999 !!!!!!!! !!!!!!!9 !!!!!!9! 8 8 8 8 8 8 :3 :! 9 %! %3 %=

Bitwise operators are o&ten used with Cmas1sC, which are bit &ields wherein a particular bit is used to store a boolean 4alue, &or e7ample, bit &ields to indicate whether or not s;oDton$0 Dulafu and &ahal are sold at a particular store. To set a bit &ield, use the U8 operatorL to test i& a particular bit is set, use the T8 operatorL and to clear a particular bit, use the T8 and the ^ operators.
enum { s;oDton$ 8 !0 Dulafu 8 30 unsi$ned int F 8 9 F U8 s;oDton$U&ahal // F T8 ^ s;oDton$ // if (F T s;oDton$) // printf("H;oDton$ is sold\n") if (F T &ahal) // printf("Rahal is sold\n") if (F T (s;oDton$U&ahal)) // printf("Qt is sold\n") &ahal 8 < " set s;oDton$ and &ahal clears s;oDton$ test for s;oDton$ test for &ahal test for s;oDton$ and &ahal

Finall , here8s a program that prompts the user &or a number and prints its binar representation using the &unction sho@&in(). Kach bit is tested 'with the T operator( starting H;

with the le&tmost bit b shi&ting them right &irst b 3H, then 3G, and so on. )e8re assuming 3@ bit integers here, i.e., onl numbers up to 56>@> are allowed. Thus, the le&tmost bit is bit 3H.
#include <stdio.h> #include <stdli&.h> int $etnum(char *prompt) /oid sho@&in(int num) int main (/oid) { int num num 8 $etnum("Sum&er8> ") @hile (num > 9) { if (num > =3O.O) puts("Sum&er must &e <8 =3O.O") else sho@&in(num) num 8 $etnum("Sum&er8> ") " " return !

int $etnum(char *prompt) { char str1M2 printf("7s"0 prompt) f$ets(str0 siEeof(str)0 stdin) return atoi(str) " /oid sho@&in(int num) { int i printf("7d (&ase !9) 88 "0 num) for (i 8 !B i >8 9 i%%) { if (i88O) printf("+") if ( ((num >> i) T !) 88 ! ) printf("!") else printf("9") " printf(" &inar;\n") "

Fere8s a sample interaction.


# Sum&er8> !3 (&ase !9) 88 99999999+9999!!99 &inar; # Sum&er8> .B (&ase !9) 88 99999999+9!99999! &inar; # Sum&er8>

@J

Potrebbero piacerti anche