1

Table of Contents

Unit 1: Unit 2: Unit 3: Unit 4: Unit 5: Unit 6: Unit 7: Unit 8: Unit 9 Unit 10

The Fundamentals of C Variables and Operations Conditions and Repetition Modularity Arrays & Structures Dynamic Allocation Sorting Searching
Data Structures C and Persistence

3 28 57 98 124 147 175 194 198 229

2

Unit 1

3

The Fundamentals of C

What is C? C and Other Languges

Starting with this unit, you will explore the origins, syntax, and usage of the C languages\. A study of C’s history is a worthy endeavor. For example you may fully appreciate the architectural beauty of a brand new house that you have just seen completed. However, it is the underlying structure of the edifice that will determine whether or not the building will still be standing in fifty years. Likewise, to recognize the valid popularity of the C language you need to understand its fundamental strengths.

What is C?
A history of the C language begins with a discussion of the UNIX operating system, since both the system and most of the programs that run on it are written in C. However, C is not tied to UNIX or any other operating system or machine. This code development environment has given C a reputation for being a system programming language because it is useful for writing compilers and operating systems. It can also write major programs in many different domains.

4

and other features associated with high-level structured languages. and a relatively open environment. by Martin Richards. Bell Labs. BCPL 's creators wanted to boil CPL down to its basic good features. They 5 . when Ken Thompson designed the B language for an early implementation of UNIX. providing useful development tools lean commands. both BCPL and B may have carried their streamlining attempts a bit too far. This made the language hard to learn and difficult to implement and explains its eventual downfall. CPL was big. in 1972 The American National Standards Institute committee is formed for the purpose of standardizing the C language. he was trying to further simplify CPL. However. Ken Thompson implemented a compiler for a new language called B. By design. on what would now be considered a small DEC PDP-7 at Bell Laboratories in New Jersey. Soon after the development of UNIX. in 1983 Algol appeared only a few years after FORTRAN was introduced. Unfortunately. Its authors paid careful attention to the regularity of syntax. A true C ancestry would look like this: Algol 60 CPL BCPL B C ANSI C Designed by an international committee in early 1960 (Combined Programming Language) developed at both Cambridge and the University of London in 1963 (Basic Combined Programming Language) developed at Cambridge. This new language was more sophisticated and greatly influenced the design of future programming languages. UNIX was written entirely in PDP-7 assembly language. perhaps because of its abstractness and generality. Still clinging to the best of what CPL had to offer. in 1970 Developed by Dennis Ritchie. Algol never really caught on in the United States. this operating system was intended to be “programmer-friendly”.UNIX was originally developed in 1969. in 1967 Developed by Ken Thompson. At this point we need to digress to the origins and history behind Ken Thompson's B language. The inventors of CPL intended to bring Algols’s lofty intent down to the realities of an actual computer. Bringing the discussion back to the origins of B. Bell Labs. But like Algol. He succeeded in creating a very sparse language that was well suited for use on the hardware available to him. modular structure.

and program generators. He accomplished this with his shrewd use of data types. work began in 1971 on a successor to B. Some considered rewriting UNIX in B.became limited languages. In addition. UNIX and the B compiler were immediately transferred to this machine. C is a relatively low-level language that lets you specify every detail in an algorithm's logic to achieve maximum computer efficiency. operating systems. . Relationship to Other Languages You may be wondering about C's relationship to other languages. Dennis Ritchie is credited with creating C. while maintaining the simplicity and computer contact that were the original design goals of CPL. which restored some of the generality lost in BCPL and B. a language written by one person typically reflects the author's field of expertise. one can quickly understand why C is a language of choice for systems software design. a new machine was introduced. Pascal. For example. . Artificial Intelligence Operating System Command Languages Problem-Oriented Languages Machine-Oriented Languages . There was another problem: B was word-oriented while the PDP-11 was byte-oriented. 6 . and APL) have a cohesiveness missing from languages developed by large programming teams (Ada . While the PDP-11 was larger than its PDP-7 predecessor. Many languages that have been developed by a single individual (C. of which the system used 16K. Here is a possible continuum: Direct Neural Path Communication . and one 512K fixed disk. the PDP-11. It had only 24K of memory. and Algol 68). it was still quite small by today's standards. Dennis Ritchie was noted for his work in systems software computer languages. But C is also a high-level language that can hide the details of the computer's architecture. but the B language was slow due to its interpretive design. useful only for certain kinds of problems. PL/I. For these reasons. LISP. thereby increasing programming efficiency. shortly after Ken Thompson implemented the B language. With C having a genetic link to its creator. appropriately named C.

Programmers who wanted to write systems software still had to rely on their machine’s assembler. the creators of high-level languages made the fallacious assumption that everyone who had been driving a standard would always prefer driving an automatic! Excited about providing ease in programming. adding . Theses languages 7 . Out of this frustration. Assembly languages provide a fairly painless way for programmers to work directly with a computer's built-in instruction set and go back to the first days of electronic computers. High-level languages were by design much more general and abstract. they are problem-oriented languages. The dots represent major advancements. shifting register contents from one register to another. The first high-level languages.them. were created as alternatives to assembly languages. you had to specify every operation in the machine's terms. The day may well come when you will program a machine by plugging a neural path communicator into a socket implanted into the temporal lobe (language memory) or Broca’s area (language motor area) of the brain's cortex. with many steps left out. were programmed in hardware. such as FORTRAN. You were always moving bits in or out of registers.. Unfortunately. and finally storing the result in memory. FORTRAN and Algol are too abstract for system-level work. BCPL and B fit into this class of very low-level software tools. Assembly languages forced you to think in terms of the hardware. a few systems software developers took a step backwards or lower in terms of the continuum and created the category of machine-oriented languages. Early ancestors of the computer. Assembly Language Actual Hardware Starting at the bottom of the continuum and moving upward. the kind used for solving problems in engineering. or business. they left out some necessary options. like the Jacquard loom (1805) or Charles Babbage ' s "analytical engine" (1834). the languages go from the tangible and empirical to the elusive and theoretical. and they allowed the programmer to think in terms of the problem at hand rather than in terms of the computer’s hardware. This was tedious and error-prone endeavor. As you saw in C’s genealogy. science.

and low-level language. yet far enough away to ignore the details of the hardware. It is close enough to the computer to give you great control over the details of an application’s implementation. but not much use for anything else-they were too closely related to a particular architecture.were excellent for a specific machine. This is why C language is both a high. 8 . The C language is one step above machine-oriented languages yet is still a step below most problem-oriented languages.

Many programmers new to C will find its syntax cryptic and perhaps intimidating. software progenitor. C has unusual-looking operators and a plethora of pointers. assembly language has its columns of mnemonics. Instead. Small Size There are fewer syntax rules in C than in many other languages. and then there’s C. and you can write a top-quality C compiler that will operate in only 256K of total memory.Characteristics of C • • • • • • • • Small Size Languge Command Set Speed Not Strongly Typed Structured Language Memory Efficiency Easy Interface to Assembly Language Routines Bit Manipiulation All computer languages have a particular look. There are actually more operators and combinations of operators in C than there are keywords. You will quickly grow used to C’s syntax. New C programmers will soon discover a variety of language characteristics whose roots stem back to its original hardware. APL has its hieroglyphic appearance. The following sections highlight the strengths of the C language. Pascal has its easily read syntax. Language Command Set 9 . C contains few of the familiar and friendly English-like syntax structure found in many other programming languages.

C is an extremely small language. Speed The C code produced by most compilers tends to be very efficient. This flexibility allows you to view data in different ways.As you would therefore expect. a small . which was also an untyped language. In fact. The combination of a small language. One of the strengths of C. This is a carryover from B. which is a strongly typed language. C treats data types somewhat more loosely.. The ANSI C standard (discussed later in the Unit) has an additional 5 reserved words. is its loose structure. and string manipulation. Structured Language C includes all of the control structures you would expect of modern languages. For example.run-time system. the original C language contained a mere 27 keywords. nor does it contain any arithmetic operations (beyond those of basic addition or subtraction) or stringhandling functions. Not Strongly Typed Unlike Pascal. and yet for purpose of upcasing (by subtracting 32) may want to see the same memory cell as the ASCII equivalent of the character. and a language close to the hardware makes many C programs run at speeds close to their assembly language equivalents. however. This agreed-upon library set is so common that it is practically part of the language. which enables you to recode these functions easily. at one point in a program the application may need to see a variable as a character. arithmetic operations. C does not include many of the functions commonly defined as part of other programming languages. For example. C does not contain any built-in input and output capabilities. since any language lacking these capabilities is of little use. C provides a rich set of library functions for input/output. C incorporates 10 . This is impressive when considering that C predated formal structured programming. Borland C added 45 more keywords. This brings the total keyword count to 77.

the language provides a rich set of bit manipulation operators. the amount of time required to compile a complete program can make the change. You can also integrate C routines into assembly language programs on most systems. Combined with the separation of compilation and linking. or even medium-sized programs on slow systems. which allows you to recompile only the parts of a program that have been changed during development. and while loops. if and if-else constructs. Without support for modular programming. and modify cycle prohibitively slow. Easy Interface to Assembly Language Routines There is a well-defined method of calling assembly language routines from most C compilers. 11 . this makes C a strong contender in applications that require a mix of high-level and assembler routines. Bit Manipulation In systems programming. C also enables you to compartmentalize code and data by managing their scope. Because C's origins are so closely tied to the UNIX operating system. For example. compile. case (switch) statements. you often need to manipulate objects at the bit level. test. C provides local variables for this purpose and call-by-value for subroutine data privacy.for loops. Support of Modular Programming C supports the concept of separate compilation and linking. This feature can be extremely important when you are developing large programs.

if the variable index points to the first element of an array student _records[index+1] will be the address of the second element of student records. For example. C is noted for its ability to perform pointer arithmetic. This capability also enhances the execution speed of a program. Flexible Structures In C all arrays are one-dimensional. The C language meets these design requirements by using pointers. Multidimensional arrangements are built from combinations of these one-dimensional arrays. You can join arrays and structures (records) in any manner. The lack of built-in functions saves programs from having to include support for functions that 12 . Memory Efficiency C programs tend to be very memory efficient for many of the reasons that they tend to be fast. While other languages implement pointers. creating database organizations that are limited only by your ability.Characteristics of C (continued) Pointer Variables Flexible Structures Memory Efficiency Special Function Libraries Portability Pointer Variables An operating system must be able to address specific areas of memory.

data entry. Programs written in C are currently among the most portable in the computer world. file handling. By using these libraries. 13 . and general support functions. communications.are not needed by a particular application. Portability Portability is a measure of how easy it is to convert a program that runs on one computer or operating system to run on another computer or operating system. you can save a great deal of development time. This is especially true for mini. Special Function Libraries There are many commercial function libraries available for all popular C compilers. screen windowing. database support.and microcomputers. There are libraries for graphics.

For experienced programmers. integer and floating point are two different types of numbers). this is one of the first decisions that you need to make. you cannot assign one data type to another without invoking a conversion function. C will allow an integer to be assigned for a character variable or vice versa. On any project.This means that you have to manage your variables properly. and it is nearly irrevocable once you start coding. Different programming problem’s require different solutions. this task 14 . Not Strongly Typed The fact that it is not strongly typed is one of C's strengths but is also one of its weaknesses. Technically. In some languages. typing is a measure of how closely a language enforces the use of variable types (for example. The choice of a programming language can also make the difference between a project's success or failure. It is the software engineer's task to choose the best language for a project.Weaknesses of C Not Strongly Typed Lack of Run-Time Checking There are no perfect programming languages. This section covers some of the weaknesses of the C language so that you will have a better idea of when and when not to use C for a particular application. This protects the data from being compromised by unexpected round offs As mentioned.

A side effect in a language is an unexpected change to a variable or other item. However. or had eliminated all side effects and unpredictable results. which you can use to your advantage. =. C would have lost much of its power and appeal as a high-level assembly language. For example. the run-time system would not warn you if your application exceeded an array's bounds. Because C is a weakly typed language. it gives you great flexibility to manipulate data. For example. the assignment operator. novice program developers may want to remind themselves that mismatched data type assignments can be the source of side effects. Lack of Run-Time Checking C's lack of checking in the run-time system can cause many mysterious and transient problems to go undetected. means that you can write expressions that have no definite value.presents no problem. If C had restricted the use of the assignment and similar operators. This is one of the costs of streamlining a compiler for the sake of speed and efficiency. This feature. can appear more than once in the same expression. 15 .

C imposes a heavy responsibility on its users. In C. 16 .and its relative consistency from machine to machine have led to its acceptance in science. It has directly contributed to the wide availability of the UNIX operating system on computers of all types and sizes. programming discipline is essential. The ANSI C Standard The ANSI (American National Standards Institute) committee has developed standards for the C language. The good news is that it comes almost automatically with practice. This section describes some of the significant changes suggested by the committee. however. A number of these changes are intended to increase the flexibility of the language while others attempt to standardize features previously left to the discretion of the compiler implement. and business applications.from bit-manipulation to high-level formatted I/O . Like any other powerful tool. engineering.Why C? Consistency between different platform Standard Programming iscpline ANSI C Standard C's tremendous range of features . C programmers quickly adopt various rules and conventions in order to make their programs understandable both to themselves and to others.

17 .Previously. This book was not specific on some language details. Although a few of the proposed changes could cause problems for some previously written programs. • Don't prevent the programmer from doing what needs to be done. The ANSI C standard provides an even better opportunity to write portable C code. which led to a divergence among compilers. they should not affect most existing code. and because C interfaces efficiently with machine hardware. The standard has not corrected all areas of confusion in the language. many programs will always require some revision when you move them to a different environment. however. • Keep the language small and simple. The ANSI committee adopted as guidelines several phrases that collectively have been called the "spirit of C/7 Some of those phrases are • Trust the programmer. The ANSI standard strives to remove these ambiguities. the only standard was The C Programming Language by Brian Kerning Ham and Dennis Ritchie.

The compiler translates the C program into machine language code (object code). under the control of its CPU. and execute. A linker links the object code with the code of functions to produce an executable file. executes the program one instruction at a time. The programmer types a C program with the editor The program is then stored on a secondry storage device such as a disk. These are: edit. link. the computer. The next phase is called linking. 18 .c’ extension. This is accomplished with an editor program. such as in the standard libraries or in the private libraries of groups of programmers working on a particular project.obj’ file. Finally. the programmer gives the command to compile the program. The first phase consists of editing a file. the generated file normally has ‘. C programs typically contain references to functions defined elsewhere. The file created is named the ‘source file’ which is usually has ‘. Next. compile.Basics of C Environment • Four phases of C Program Edit Compile Link Execution o o o o C programs typically go through four phases to be executed.

Subroutines 4. Programs must use a set of instructions to manipulate the input. Loops d. Programs must report the results of the data manipulation. and a good indentation scheme. 1. These instructions can be divided into four major categories: a. How this input is to be arranged and stored. Instructions to manipulate the input Report the results of the data manipulation. 2. Programs must obtain information from some input source. 3. The following list elaborates on these three fundamentals and encapsulates the entire application development cycle. IFO diagrams were a stylized approach to the input/process/output-programming problem. self-documenting code. Programs must decide how this input is to be arranged and stored. Conditional statements c. you may have learned a problem-solution format called an IPO diagram. All programs must address the following nine components. In one of your introductory programming courses. Single statements b. Incorporates all of the fundamentals just listed. expressed using good modular design.The Basic Components of a Program Obtain information from some input source. 19 .

expressed using good modular design. and a good indentation scheme.5. meaningful variable names). A well-written application incorporates all of the fundamentals just listed. 20 . self-documenting code (for instance.

h> int main() { printf(“ HELLO World! “).Your First C Program /* * Your first example C program. } The following C program will illustrate the basic components of a C application.First is the comment block: /* * Your first example C program. comments begin with 21 . return 0. */ #include <stdio. A meaningful comment respects the intelligence of the programmer while not assuming too much. You should enter each example as you read about it /* * Your first example C program. return 0. */ #include <stdio. */ All well-written source code includes meaningful comments.h> int main() { printf(“ HELLO World! “). In C. } There is a lot happening in this short piece of code.

identifiers. Notice the { and } symbol pairs.h is called a header file. In this example. Every C program must have one called main. The compiler ignores anything between these unique symbol pairs.the /* symbols and end with */. . The next statement #include <stdio. These are called braces. the sentence will be printed to the display monitor. A preprocessor statement is like a precompiled instruction. Because no other parameters are specified. In this case. } All C programs are made up of function calls. stdio. is the only statement in the body of the main program and is the simplest example of an output statement. and function prototypes and have these declarations pulled out of the main program for purposes of modularity. Following the #include statement is the main function declaration: int main() { . The main function is usually where program execution begins and ends with a return 0 from main. Header files can include symbolic constants. as is the case when several statements are executed based on the validity of an if statement. The printf function has been previously prototyped in stdio. Following the main function header is the body of the function itself. the braces define the body of the main program. These statements may define the body for a function. or they may bundle statements that are dependent on the same logic control statement. 22 . the statement instructs the compiler to retrieve the code stored in the predefined stdio.h file into the source code on the line requested.h> represents one of C's unique features known as a preprocessor statement. Technically. A 0 return value indicates that the program terminated without any errors. braces are used to encapsulate multiple statements.h. . return 0. The line printf(" HELLO World! ").

printf("%d yard(s) = \n".feet). scanf(“%d”.inch). while(yard > 0 ) { inch=36*yard.h> int main() { int yard.Your Second C Program #include <stdio. printf("Please enter the length to be converted: "). feet .&yard). printf("Please enter another length to be \n"). } At this point. The following program not only outputs information but also prompts the user for input.yard). scanf(“%d”.yard). printf("%d feet \n".&yard). feet=3*yard.h> int main() { int yard. you are probably waiting for a slightly more meaningful example. while(yard > 0 ) { inch=36*yard. printf("converted (0 stops program): ").inch.inch. 23 . scanf("%d".&yard). * in yards. printf("%d inches \n". feet=3*yard. printf("%d feet \n". printf("Please enter another length to be \n"). printf("%d inches \n". /* * This C program prompts the user for a specified length. printf("Please enter the length to be converted: "). */ #include <stdio. and then outputs the value converted to * feet and inches. feet .feet). return 0. } printf(“>>> End of Program <<<”).inch). printf("%d yard(s) = \n".

The scanf function has a requirement that is called a format string. feet. and the three variables yard. 24 .&yard). and inch are denied. scanf("%d". The scanf function has been written to expect the address of the variable to be filled. format strings define how the input data is to be interpreted and represented internally. The "%d" function parameter instructs the compiler to interpret the input as integer data (in Borland C++ an integer occupies 2 bytes Address Operator In the previous listing. Whenever a variable is preceded by this symbol. &. } printf(“>>> End of Program <<<”). User Input The next unconventional statement is used to input informal ton from the keyboard: printf("Please enter the length to be converted: "). scanf("%d". The & is known as an address operator. the integer variable yard was preceded by an ampersand symbol. the compiler uses the address of the specified variable instead of the value stored in the variable. inch. return 0. } Data Declarations The first new thing in the program is the declaration of three variables: int yard. the integer type is represented by the key word int.&yard). In this example. One of the standard data types supplied by the C language is integer. All C variables must be declared before they are used. The syntax for declaring variables in C requires the definition of the variable's type before the name of the variable. feet.printf("converted (0 stops program): ").

inch). If you are familiar with the PL/I language developed by IBM. The format string represents two things: a picture of how the output string is to look. you will be at home with the concept of a control string. or code blocks. } This pretest loop starts with the reserved word while followed by a Boolean expression that evaluates to cipher TRUE or FALSE. a format string is required. . yard). }. are optional and are only needed when more than one executable statement is to be associated with the loop repetition. printf("Please enter another length to be \n"). printf("%d feet \n". Braced statements are sometimes referred to as compound statements. Format strings are always between double quotation marks. and the closing brace in the same column as the first character in the test condition. and closing brace. {. Whenever a printf function is invoked to print not only literal strings (any set of characters between double quotation marks) but also values. compound blocks. The opening brace. and the format interpretation for each of the values printed. If you are using compound blocks. programmers reading your code will certainly appreciate the style and effort. printf("converted (0 stops program): ").feet).Loop Structure One of the simplest loop structures to code in C is the while loop: while(yard > 0) { .yard) 25 . You place opening loop braces at the end of the test condition. While the compiler doesn't care where you place the braces (skipped spaces/lines). printf("%d inches \n". Formatted Output The second program contains more complex printf function calls: printf("%d yard(s) = \n". The following table breaks down the first printf format string ("%d yard(s) = \n". make certain that you use the agreed-upon brace style.

and prints it After printing the integer yard. your output would look much like this: Please enter the length to be converted: 4 4 yard(s) = 12 feet 144 inches Please enter another length to be converted (0 stops program): 0 The next table lists all of the output control symbols and describes how they can be used in format strings Sequences \a \b \f \n \r \t \v \\ \’ \” \? \O \H Function Bell Backspace Formfeed Newline Carriage return Tab Vertical tab Backslash Single quote Double quote Question mark Octal number Hexadecimal number 26 . and ending with a new line feed. followed by a literal string. Action Takes the value of yard. interprets it as an integer. only one %d) The next two-printf statements are similar in execution. executes a newline feed In this example. skips one blank space and then prints the literal 'yard(s) =’ Once the line is complete. Each statement prints a formatted integer value. If you ran the program.into its separate components: Control %d yard(s) \n . the comma separates the format string from the variable name(s) used to satisfy all format descriptors (in this case.

As you learn more about the various C data types. you can refer back to these two tables for a reminder of how the various controls affect input and output. Control %c %d %u %f %e %O %x %s %ld %lf %Lf Data type Character Signed integer Unsigned integer Float in decimal form Float in exponential form Octal Hexadecimal String Long integer double Long double 27 .The next table lists all of the C language value formatting controls.

Unit 2 28 .

or function. digits. An identifier is a sequence of one or more letters. you will explore the underlying structures of the C. or underscores that begins with a letter or underscore. Identifiers can contain any number of characters. such as the Linker. (Other programs that read the compiler output. Identifiers Identifiers are the names that you use to represent variables. functions.) 29 . You create an identifier by specifying it in the declaration of a variable. but only the first 32 characters are significant to the compiler.Variables and Operations Identifiers Keywords What you have learned so far of C is only the tip of the iceberg. The great stability of C comes from the standard data types and the modifiers and operations that you can perform on them. You can then use the identifier in later program statements to refer to the associated item. types. constants. may recognize even fewer characters. Starting with this unit. and labels in your program. type.

Here are some sample identifiers: k count templ reservations_planel fathom_6_ft See if you can determine why the following identifiers are illegal: 1st_place #1bs action_taken! The first identifier is illegal because it begins with a decimal number. Although it is syntactically legal. The selection of case can also help a programmer understand your code. This means that the compiler considers uppercase and lowercase letters to be distinct characters. For example. Since uppercase and lowercase letters are considered distinct characters. and produce errors. identifiers declared in include header files are often created with only uppercase letters. The second identifier begins with a # symbol. For example. the compiler sees the variables MAX and max as two unique identifiers representing different memory cells. Often. As a result. you can assume that identifier's definition is in an include header file. identifiers beginning with an underscore can cause conflicts with the names of system routines or variables. and the last identifier ends with an illegal character.C is case sensitive. you should not use leading underscores in identifiers that you create. each of the following identifiers is unique: SIZE size Size siZe 30 . programs that contain names beginning with leading underscores are not guaranteed to be portable. whenever you encounter an uppercase identifier in the source file. This feature enables you to create distinct identifiers that have the same spelling but different cases for one or more of the letters. Because of this.

However. the name of a program identifier cannot have the same spelling and case as a C keyword. will invoke unknown identifier complaints from the compiler. you can specify text that can be substituted for keywords before compilation by using C preprocessor directives. In Pascal. when it was typed PRINTF. however. Keywords Keywords are predefined identifiers that have special meanings to the C compiler. You cannot redefine keywords. a writeln is a WRITELN is a WriteLn.The C compiler's case sensitivity can create tremendous headaches for the novice C programmer. 31 . trying to reference the printf function. For example. Remember. You can use them only as denied.

enumerated or enum. usually. These are also known as real numbers (usually. 8 bytes. and pointers. let him hear"). you are working with some kind of information that you can usually represent by using one of the seven basic C types: text or char.Standard C Data Types char int float double enum void unsigned modifier long modifier When you write a program. • • • Text (data type char) is made up of single characters (a.4E-38 to 3. or 1 byte. You can also use this type to create generic. with the range of 0 to 255.7E+308). 2 bytes. 7. and exponents (7. integer values or int. with the range of -32. double floating-point values or double. 3) and strings ("He who has an ear to hear.563X1021). 4 bytes. • • • Double floating-point values have an extended range (usually. and 1345). Integer values are those numbers you learned to count with (1.768 to 32. or 1 word. Z.4E+38). -45. 2. 32 . floatingpoint values or float. or 2 words. 8 bits.14159). usually. ?. Floating-point values are numbers that have a fractional portion such as π (3. 16 bits wide.767. or 4 words. with the range of 3. The type void signifies values that occupy 0 bits and have no value. Enumerated data types allow for user-defined types. 64 bits. with the range of 1. 32 bits.7E-308 to 1. valueless or void.

For instance. lowercase_a='a'. all books written in English use combinations of 26 letters of the alphabet. Instead. are also valid C and C++ characters. abcdefghijklmnopqrstuvwxyz the 26 uppercase letters of the alphabet. printf(“The character \‘%c \‘ has a decimal ASCII" \ " value of %d \n" .?\"'~|!#%$&()[ ]{}A@ C also use the blank space. Combinations of symbols. the 10 digits. C programs are written with a set of characters consisting of the 26 lowercase letters of the alphabet..• The pointer data type doesn't hold information as do the other data types._:. sometimes referred to as white-space.h> int main() { char uppercase_A='A' . the following code is a mixture of valid C and C++ symbols: ++ -. 0123456789 and the following symbols: +-*/=. Similarly. In fact. each pointer contains the address of the memory location holding the actual data. Characters Every language uses a set of characters to construct meaningful statements.uppercase_A) .== && || << >> >= <= += -= *= /= ?: :: /* */ // The following C program illustrates how to declare and use char data types: /* * AC program demonstrating the char data type and showing * how a char variable can be interpreted as an integer. and the punctuation marks. printf(“The ASCII value represented in hexadecimal"\ 33 . ABCDEFGHIJKLMNOPQRSTUVWXYZ the 10 digits. with no intervening blank space. */ #include <stdio.uppercase_A.

return 0. Since the C language is so tied to the hardware.. An automobile odometer starts at 000.. you can think of the range of values it holds as representing the numbers displayed on a car odometer. The type long occupies 4 bytes of storage.lowercase_a.. int. a variable of type short will not be larger than one of type long. and then recycles back to 000 it also only displays positive whole numbers. When one of these data types is modified to be unsigned. Unsigned Modifier C also allows you to declare certain types as unsigned. int. the actual sizes of short.. printf(“If you add sixteen will you get \‘%c\’\n”.(uppercase_A+16)). and long int.is %X\n”. However. “ Three Integers C actually supports three types of integers. printf(“The character \’%c\’ has a decimal ASCII" \ “value of %d\n". printf(“The calculated ASCII value in hexadecimal” \ " is %X\n". uppercase_A+16). you can apply the unsigned modifier to four types: char. } The output from the program looks like this: The character 'A' has a decimal ASCII value of 65 The ASCII value represented in hexadecimal is 41 If you add sixteen will you get 'Q' The calculated ASCII value in hexadecimal is 51 The character 'a' has a decimal ASCII value of 97 The %X format control instructs the compiler to interpret the value as a hexadecimal number.. In a similar way. Borland C allocates 2 bytes for both types short and int.lowercase_a). These are most often abbreviated to short and long. increases to a maximum of 999. Currently. and long depend upon the implementation. an unsigned data type can hold only positive values from 0 to the maximum number that 34 . the compiler supports short int and long int. Along with the standard type int.uppercase_A). short int..

applying the unsigned data type modifier to a tiny variable would yield a range of 0 to 7. Fundamental Type Storage and Range of Values 35 . tiny's range is a subset. and you want to represent both positive and negative values. When the most significant bit is 0. and decide that tiny variables can hold only 3 bits. Therefore.can be represented. suppose that you are designing a new data type called tiny. Unique Combinations of O's and 1's 000 001 010 011 100 101 110 111 Decimal Equivalent +0 +1 +2 +3 -1 -2 -3 -4 However. Unique Combinations of 0's and 1's 000 001 010 011 100 101 110 111 Decimal Equivalent +0 +1 +2 +3 +4 +5 +6 +7 This simple analogy holds true for any of the valid C data types defined to be of type unsignedThe storage and range for the fundamental C data types are summarized in the following tables. When the most significant bit is 1. This gives a tiny variable the range of -4 to +3. You also decide that the data type tiny is signed by default. the value is positive. You can't have both positive and negative numbers in the range 0 to 7 because you need one of the 3 bits to represent the sign of the number. you have a problem. Since a variable of type tiny can only contain the bit patterns 000 through 111 (or 0 to 7 decimal). since the most significant bit can be combined with the lower 2 bits to represent a broader range of positive values instead of identifying the sign of the number see next table. the value is negative. For example. as shown in the next table.

double. 36 . the standard does require each type to hold a minimum of any value in the range 1E-37 to 1E+37. signed short long.295 3. the Borland C++ environment has greatly expanded upon this minimum requirement. The ANSI C committee added the third type long double. and long double.647 0 to 255 0 to 65._ds. double my_balance.4E+38 1.4E-4932 to 1.767 -2.648 to 2.768 to 32. Most C compilers have always had the types float and double._cs. unsigned unsigned short unsigned long Floating Point C uses the three floating-point types: float. int short.1E+4932 (near.294.967.huge pointers) Valid Data Type Modifier Abbreviations Type Modifier signed char signed int signed short int signed long int unsigned char unsigned int unsigned short int unsigned long int Abbreviations Char signed. While the ANSI C standard does not specifically define the values and storage to be allocated for each of these types.Type char int short long unsigned char unsigned int unsigned short unsigned long float double long double pointer pointer Storage 1 byte 2 byte 2 bytes 4 bytes 1 byte 2 bytes 2 bytes 4 bytes 4 bytes 8 bytes 10 bytes 2 bytes 4 bytes Range of Values (Internal) -128 to 127 -32.767 -32. Here are some examples of floating-point numbers: float body_temp = 98.535 0 to 65. As you see in previous table 6-4.483. signed long no abbrv. long double IRS_balance.4E-38 to 3._es.768 to 32.7E+308 3.535 0 to 4.147.7E-308 to l.147._ss pointers) (far.6.483.

1. 37 .800000e-03 -1. float2). float1).601234e+03 2.You can use long double on any computer. GULP=5 } bills_tank.0028. The following C program illustrates how to declare and use float variables: // // A C program demonstrating use of the float data type. The variable can contain any one of the constants at any time.233887 0. return(0). printf(“\t\t %f\t”. float2). However if the computer does not have a long double data type the data item will have the same size and storage capacity as a double. #include <stdio.234. it is associated with a set of named integer constants called the enumeration.421000e+02 Enumerated When an enumerated variable is defined. float1). printf(“\t\t %f\t”. printf(“\t\t %f\t”.h> int main() { float float1 = 3601. even one that has only two types of floating-point numbers. printf(“%e\n\n”.00028 -142. float3). float2 = 0. LOW. and you can refer to the constants by name.100006 3. printf(“%e\n\n”. For example. the definition enum tank__pressure{ OK. float3). float3 = -142. } The output looks like this: 3601. printf(“%e\n\n”.

which will place the value 0 into the variable bills_tank. and each constant is automatically provided a default initial value unless another value is specified. chriss_tank = GULP. LOW. In the preceding example. You can perform tests on the variables in conjunction with the constants. chriss_tank. and GULP. was specifically initialized to the value 5. It is a "type" of data that you can use later to create additional enum variables. The names OK LOW. Having created tank_pressure. type of tank_pressure. they are not variables and you cannot change their values. as follows: enum tank_pressure chriss_tank.h> int main() { enum tank_pressure { OK. the enum constants of OK. you can use hills_tank on the left of an assignment operator and it can receive a value. All the constants and variables are of type int. and GULP are names of constants. it is legal to say bills_tank = OK. After this statement. Since the name bills_tank is an enumeration variable of type tank_pressure. The value of LOW is 1 since it occurs immediately after a constant with the value 0. the constant name OK has the int value 0 by default since it is the first in the list and was not specifically overridden. it would have the int value of 6. The constant GULP. This occurred when the enema constant OK was explicitly assigned to it. 38 . and the value 5 into the variable chriss_tank. If another constant were included after GULP. One common mistake is to think that tank_pressure is a variable. and the enum variable of bills_tank.creates the enum. The following C program shows a complete program that uses the preceding definitions: /* * AC program demonstrating the use of enumeration variables */ #include <stdio. such as chriss_tank. LOW. you can later define another variable.

chriss_tank).GULP=5 } bills_tank. chriss_tank = GULP. if (chriss_tank == GULP) printf("The value of chriss_tank is %d\n”. } 39 . else printf("bills_tank does not equal chriss_tank"). bills_tank = OK. return(0). if (bills_tank == chriss_tank) printf("bills_tank equals chriss_tank"). printf("The value of bills_tank is %d\n”.bills_tank). enum tank_pressure chriss_tank.

In such cases.14159. You might think that you should declare a variable called pi with an initial value of 3.Constant Data const Modifier #define Constants const Modifier At times. Using descriptive names can also help prevent errors. an interest rate might be a constant. Suppose also that you type the wrong value at one or more of these points. For example. the value of pi would be changed. In a financial program. If the constant has a name. causing all subsequent calculations 40 . you may need to use a value that docs not change throughout the program. Suppose that you are writing a program that repeatedly uses the value π. For instance. you can improve the readability of the program by giving the constant a descriptive name. if you inadvertently wrote pi to the left of an equal sign. it will frequently use the constant value pi=3. if a program deals with the area and circumference of a circle. However.14159. Suppose that you use a constant value (not a constant variable) at many points throughout the program. Such a quantity is called a constant. the compiler would then detect a typographical error because you probably didn't declare the incorrect name. the program should not be able to change the value of a constant.

to be in error. Normally. double) in the declaration.INTERVAL=15. #define Constants C provide another method for establishing constants-the #define compiler directive.. int. it must be initialized in its declaration. you declare a constant by writing const before the keyword (for instance. count. the constants are not lvalues. they cannot appear to the left of an equal sign.7. The only difference is that you cannot change the initial values assigned to the constants that is.0 has been established for distance.obj ect: double distance=0. One example of a modifiable lvalue expression is a variable name declared without const. Because a constant cannot be changed. float. The int constants MAX and INTERVAL are declared with values 9 and 15. C provides mechanisms that prevent such errors from occurring-that is. Finally. the left-hand operand of an assignment operation (or the single operand of a unary assignment expression) must be an expression that refers to a modifiable memory location. In addition.count=10. respectively.7. the assignment operation assigns the value of the right-hand operand to the storage location named by the left-hand operand. the int (nonconstant) variables index. Expressions referring to modifiable locations are modifiable lvalues. respectively. Suppose that you have the following statement at the beginning of a program: 41 .velocity. An initial value of 0. distance and velocity have been declared to be (nonconstant) variables of type double. Expressions that refer to memory locations are called lvalue expressions. For example: const int MAX=9. The constant rate is of type float and has been initialized to 0. Therefore. Initial values of 0 and 10 have been established for index and count. You use constants and variables in the same way in a program. In C. and object have been declared.0. int indexed=0. you can establish constants whose values cannot be changed. const float rate=0.

no value can be assigned to VOLUME because it has never been declared as a variable. The keyword const and the #define compiler directive. When the program is compiled. VOLUME has all the attributes of a constant. in many programs. the compiler preprocessor carries out the #include and #define directives. it replaces every occurrence of the first string of characters (VOLUME) in the program with the second string of characters (10). When the preprocessor encounters the #define directive. As a result of the syntax. it replaces every occurrence of VOLUME in the source files with the number 10. the use of the modifier keyword const results in a "variable" whose value cannot be changed. If a semicolon followed the value 10. the action of each of these two methods is essentially the same.. several passes are made through it. 42 . every occurrence of VOLUME would be replaced with 10. The directive replaces the first string with everything in the second string. In general. Additionally. when the preprocessor encounters a #define directive.#define VOLUME 10 The form of this statement is #define followed by two strings of characters separated by spaces. Note that the #define statement is not terminated by a semicolon. First. On the other hand.

that is. Suppose that the following operation is executed. The 43 . where both float_result and float_value2 are of type float.Data Type Conversion Implicit Conversion Explicit Conversion In the programs so far. C performs automatic conversions from one type to another. it generates code to perform the following operations. and the variable int_value is of type int. Suppose that the number 10 is being stored. These operations are called mixed mode operations. Unlike some other programming languages. Therefore. The compiler recognizes that a mixed mode operation is taking place. When the statement is executed. float_result = float_value2 * int_value. Data of different types are stored differently in memory. the pattern of 0’s and 1’s in memory will be different when 10 is stored as an int or when it is stored as a float. the value of int_value will be converted into a floating-point number before the multiplication takes place. The statement is therefore a mixed mode operation. Its representation will depend upon its type. int or float. You can write statement that performs operations involving variables of different types. the variables and numbers used in any particular statement were all of the same type-for example.

since the division of int_valuel/int _value2 was a mixed mode operation. Consider the following sequence of statements: int_value1 = 3. it represents the division of two integers. in that the object of lower priority is temporarily converted to the type of higher priority for the performance of the calculation. 0. float_value = 7. This value is then converted to the corresponding float value. and the resulting float value is assigned to float_result.75. Suppose that the variables int_value1 and int_value2 have been defined to be of type int. float_result = float_value + int_valuel/int_value2. the compiler performs the conversion automatically.integer value assigned to int_value is read from memory. In other words.75. the value of int_value1 is temporarily converted to the floating-point value 3. What if int_value2 had been defined to be of type float? In this case. and its result is zero since the fractional part. The division of int_value1/int_value2 is not a mixed mode operation.75 in this case. is discarded when integer division is performed. which is then multiplied by the real value assigned to float_value2.0. Here is the hierarchy of conversions. float_result would have been assigned the floating-point value 7. 44 . instead. the value stored in float_result is 7. Therefore. When added to float_value. the result is 7.0. Look at what happens when a conversion from type float to type into takes place. When a type is converted to one that has more significant digits. int_value2 = 4. Under these circumstances. the type double has a higher priority than type int. the value of the number and its accuracy are unchanged. from highest to lowest priority: double float long int short For example. There is a hierarchy of conversions. while float_value and float_result have been defined to be of type float. and the result of the division is 0. Note that the value assigned to int_value is unchanged by this process and remains of type int.0.75.

0.0 + float_x/float_y The result of the division float_x/float_y is 3.5 is therefore converted into an integer. However. One of these procedures is called the cast operator. and the value assigned to int_result is the integer number 7. the fractional part is truncated. All three statements would perform a float conversion and division of the variables int_value1 and int_value2. floaty = 2. you must specifically designate that a change of type is to be made.The type of the value to the left of the equal sign determines the type of the result of the operation. the following three statements would perform the same operation: float_result = float_value + (float)int_value1/int_value2. float_result = float_value + (float)int_value1/(float)int_value2. when this is added to 4. under certain circumstances.0. and float_value and float_result were defined as type float. this value cannot be assigned to int_result because int_result is of type int. Consider the following statements: float_x = 7.5. For example. For example. Due to the usual rules of mixed mode arithmetic. These explicit specifications also clarify to other programmers the statements involved. if int_value1 and int_value2 were defined as type int. How ever. if either variable is cast to type 45 . When this is done. Explicit Type Conversions Using the Cast Operator You have seen that the C compiler automatically changes the format of a variable in mixed mode operations using different types. The resulting whole number is converted from a floating-point representation to an integer representation. the floating-point value generated is 7. The C language provides several procedures that allow you to indicate that type conversion must occur. you simply precede the variable's identifier with the type (in parentheses) that you want it converted to. type conversions would be desirable although automatic conversion is not performed. suppose that float_x and float_y were declared to be of type float and int_result was declared to be of type int. For those occasions. float_result = float_value + int_valuel/(float)int_value2. The number 7. Whenever you want to change the format of a variable temporarily.0. int_result = 4.5.

46 . The third statement explicitly highlights the operation to be performed. a float division occurs.float.

These are the AND &. AND The logical AND operation compares two bits. They are useful for accessing the individual bits in memory. 47 . These include bitwise operators. Note that this is different from binary addition. which simply inverts each bit. If both bits are a 1 the result is a 1. Three bitwise operators act just like the logical operators. the comma operator. where the comparison of two 1 bits results in a sum flag set to 0 and the carry flag set to 1. and assignment and compound assignment operators. but they act on each bit in an integer. Bitwise operators can only operate on integral data types. conditional operators. Bitwise Operators Bitwise operators treat variables as combinations of bits rather than as numbers. not on floating-point numbers.OPERATORS Bitwise Operators Increment and Decrement Arithmetic Operators Assignment Operator Relational and Logical Operators Conditional Operator C has many operators not found in other languages. increment and decrement operators. OR |. An additional operator is the one's complement ~. and XOR ^. such as the screen memory for a graphics display.

Logical AND Bit 0 0 0 1 1 Bit 1 0 1 0 1 Result 0 0 0 1

Very often, the AND operation is used to select out, or mask, certain bit positions.

OR
The logical OR operation compares two bits and generates a 1 result if either or both bits are a 1. The OR operation is useful for setting specified bit positions. Logical OR Bit 0 0 0 1 1 Bit 1 0 1 0 1 Result 0 1 1 1

XOR
The exclusive OR operation (XOR) compares two bits and returns a result of 1 only when the two bits are complementary. This logical operation can be useful when you need to complement specified bit positions, as with computer graphics applications. Exclusive OR (XOR) Bit 0 0 0 1 1 Bit 1 0 1 0 1 Result 0 1 1 0

The following example uses these operators with the hexadecimal and octal representation of constants. The bit values are shown for comparison. 0xFl 0361 11110011 & & & 0x35 0065 00110101 yields 0x31 yields 061 yields 00110001 (hexadecimal) (octal) (bitwise)

48

0xFl 0361 11110011 0xFl 0361 11110011 ~0xFl ~0361 ~11110011

| | | ^ ^ ^

0x35 0065 00110101 0x35 0065 00110101

yields 0xF5 yields 0365 yields 11110111

(hexadecimal) (octal) (bitwise)

yields 0xC4 (hexadecimal) yields 0304 (octal) yields 00000000 11000110 (bitwise) yields 0XFF0E (hexadecimal) yields 7777416 (octal) yields 11111111 00001100 (bitwise)

Left Shift and Right Shift
C incorporates two shift operators: the left shift, <<, and the right shift, >>.The left shift moves the bits to the left and sets the rightmost bit (least significant bit) to 0. The leftmost bit (most significant bit) shifted out is discarded. With unsigned int numbers, shifting the number one position to the left and filling the LSB with a 0 will double the number's value. The following C code demonstrates how you would code this: unsigned int valuel = 65; value1 = value1 << 1; printf(“%d”, valuel); In memory, examining the lower byte, you would see the following bit changes performed: << 0100 0001 (65 decimal) 1000 0010 (130 decimal) The right shift operator, >>, moves bits to the right. The lower order bits shifted out are discarded. Halving an unsigned int number is as simple as shifting the bits one position to the right, filling the MSB position with a 0. A C-coded example would look similar to the preceding example: unsigned int valuel = 10; valuel = value1 >> 1; printf("%d",value1); 49

Examining just the lower byte of the variable valued would reveal the following bit changes: >> 0000 1010 (10 decimal) 0000 0101 (5 decimal)

Increment and Decrement
Adding one to or subtracting one from a number is so co`mmon in programs that C has a special set of operators to do this. They are the increment ++ and decrement - - operators. You must place the two characters next to each other without any whitespace. You can only apply them to variables, not to constants. Instead of coding Value1 = valuel +1; you can write value1++; or ++ valuel; When these two operators are the sole operators in an expression, you don't have to worry about the different syntax. A for loop very often uses this type of increment for the loop control variable: total = 0; for (i = 1; i <= 10; i++) total = total + i; A decrement loop would be coded as: total = 0; for (i = 10; i >= 1; i - -) total = total + i; If you use these operators in complex expressions, you have to consider when the increment or decrement actually takes place. The postfix increment, for example i++, uses the value of the variable in the expression first, and then increments its value. However, the prefix increment, for example ++i, increments the value of the variable first, and then uses the value in the expression. Assume the following data declarations: 50

int i=3,j,k=0; See if you can determine what happens in each of the following statements. For simplicity, assume the original initialized values of the variables for each statement: k = ++i; k = i++; k = --i; k = i--; i = j = k--; // // // // // i = 4, k = 4 i = 4, k = 3 i = 2, k = 2 i = 2, k = 3 i = 0, j = 0, k = -1

Arithmetic Operators
The C language incorporates the standard set of arithmetic operators for addition +, subtraction -, multiplication *, division /, and modulus %. The first four operators need no explanation. However, the following example will help you understand the modulus operator: int a=3,b-=8,c=0,d; d = b % a; d = a % b; d = b % c; // returns 2 // returns 3 // return an error message

The modulus operator returns the remainder of integer division. The last assignment statement attempts to divide 8 by 0, resulting in an error message.

Assignment Operator
The assignment operator in C is unlike the assignment statement in other languages. It is performed by an assignment operator, rather than an assignment statement. As with other C operators the result of an assignment operator is a value that is assigned. An expression with an assignment operator can be used in a large expression such as: value1 = 8 * (value2 = 5); Here, value2 is first assigned the value 5. This is multiplied by 8, with value receiving a final value of 40.

51

If you overuse this feature, you can wind up with unmanageable expressions. There are two places in which this feature is normally applied. First you can use it to set several variables to a particular value, as in: Value1 = value2 = value3 = 0; The second use is most often seen in the condition of a while loop, for example: while ((c = getchar ()) != EOF) { … … … } This assigns the value that getchar returned to c and then tests the value against EOF. If it is EOF, the loop is not executed. The parentheses are necessary because the assignment operator has a lower precedence than the nonequality operator. Otherwise, the line would be interpreted as: c = (getchar() != EOF) { . . . } The variable c would be assigned a value of 1 (TRUE) each time getchar returned EOF.

Compound Assignment Operators
The C language also incorporates an enhancement to the assignment statement used by other languages. This additional set of assignment operators allows for a more concise way of expressing certain computations. The following code segment shows the standard assignment syntax applicable in many high-level languages: result = result + increment; depth = depth – one_fathom; cost = cost * 1.07; square_feet = square_feet / 9; The C language compound assignment statements would look like this: result += increment; depth -= one_fathom; 52

and NOT ! produce a TRUE (1) or FALSE (0) based on the logical relationship of their arguments. The next table lists the C relational operators.cost *= 1. 53 . Looking closely at these two code segments. See if you can predict the results. you must remove the redundant variable reference from the right-hand side of the assignment operator and place the operation to be performed immediately before the =. you will quickly see the required syntax.07. square_feet /=9. The logical OR || operation in turn will only return a FALSE (0) when both arguments are FALSE (0). If you use a C compound assignment operator. The next table lists the C logical operators. The simplest way to remember how the logical AND && works is to say that an ANDed expression will only return a TRUE (1) when both arguments are TRUE (1). The logical NOT ! simply inverts the value. C Relational Operators Operator == != > < >= <= Meaning Equal (not assignment) Not equal Greater than Less than Greater than or equal Less than or equal The logical operators AND &&. C Logical Operators && || ! AND OR NOT Have some fun with the following C program as you test the various combinations of relational and logical operators. Relational and Logical Operators All relational operators are used to establish a relationship between the values of the operands. They always produce a value of 1 if the relationship evaluates to TRUE or a value of 0 if the relationship evaluates to FALSE. OR ||.

(value1 < value2)). printf(“ valuel > value2 is %d\n”.h> int main() { float value1. (value1 && value2)). (value1 == value2)). printf(“ valuel == value2 is %d\n”. a strict comparison occurs for both data types float and double when values of these types are compared with zero . printf("\nPlease enter a valuel: “ ). } You may be surprised at the results obtained for some of the logical comparisons. Otherwise. a number that is just slightly above or below zero is still TRUE (1).&value1). printf(“\n”). printf(“ valuel !^ value2 is %d\n”. however. return 0. (value1 || value2)). For example. value2. Remember. (value1 >= value2)). Also. the value of the conditional expression is true-expression.a number that is very slightly different from another number is still not equal. printf(“ valuel <= value2 is %d\n”.'A'). scanf(“%f”. 54 ./* * * */ A C program demonstrating some of the subtleties of logical and relational operators. it is the value of false-expression. printf(“ valuel >= value2 is %d\n”. you could rewrite the following statement if('A' <= c && c <= 'Z') printf(“%c”. (value1 != value2)). #include <stdio.'a' + c . printf(“ valuel || value2 is %d\n”. Conditional Operator The operator has the syntax: condition ? true-expression : false-expression If the condition is TRUE. printf("Please enter a value2: "). (value1 > value2)). scanf(“%f”.&value2). printf(“ valuel && value2 is %d\n”. (value1 <= value2)). printf(“ valuel < value2 is %d\n”.

c. the comma operator. Side effects are those operations that change the value of a variable while yielding a value that is used in the expression. you can specify a typical test as while((c=getchar() != EOF) && (c!='\n')) and know that the second part of the logical AND (&&) is performed after the character value is assigned to c.else printf("%c". There are.'A') : c ). unless you have written one with side effects.All operators between lines have the same precedence level. 55 . using the conditional operator: printf("%c". The next table lists all of the C operators from highest to lowest precedence and describes how each operator is associated (left-to-right or right-to-left). and 4 is then assigned to valuel. Because of this default order of evaluation.('A' <= c && c <= 'Z') ? ('a' + c . This normally does not alter the value of the expression. and the conditional operator. result = (valuel = 4) + valuel. The other operators that have side effects are the assignment and compound assignment. and result is assigned 8 (4+4). value of 3 is retrieved from valuel. however. is always lowercase. Operator Precedences The compiler determines the order of evaluation of an expression in C. Calls to functions that change values of external variables also are subject to side effects. as seen with the increment and decrement operators. This could be evaluated in one of two ways: valuel is assigned 4. Both statements will make certain that the character printed. For example: value1 = 3. with result being assigned a 7. logical OR (II). four operators for which the order of evaluation is guaranteed to be left-toright: logical AND (&&).c).

-~ ! & * (type) sizeof * / % + << >> < <= > >= == != & ^ | && || ?: = %= += -= -= *= /= >>= <<= &= ^= |= . Associates from Precedence left Highest Left Left Left Right Right Right Right Right Right Right Right Left Left Left Left Left Left Left Left Left Left Left Left Left Left Left Left Left Left Right Right left lowest 56 . ++.Operator Precedence Levels Description Function expr Array expr Struct indirection Struct member Incr/decr One's complement Unary NOT Address Dereference Cast Unary minus Size in bytes Multiplication Division Remainder Addition Subtraction Shift left Shift right Less than Less than or equal Greater than Greater than or equal Equal Not equal Bitwise AND Bitwise XOR Bitwise OR Logical AND Logical OR Conditional Assignment Comma Operator () [] -> .

Unit 3 57 .

Conditions and Repetition

Conditional Statements if switch Repetition Statements for while do…while
In this Unit you will learn about two of C’s most important program control statements: if and for. In general, program control statements control your program's flow of execution. As such, they form the backbone of your programs- In addition to these, you will also learn about blocks of code and the relational and logical operators. You will also learn more about the print () function.

58

The if Statement

if (expression) statement; if {expression) statement1; else statemanat2; if (expression) { statement1; statement N; } else { statements1; statement N; }
The if statement is one of C's selection statements (sometimes called conditional statements). Its operation is governed by the outcome of a conditional test that evaluates to either true or false. Simply put, selection statements make decisions based upon the outcome of a condition. In its simplest form, the if statement allows your program to conditionally execute a statement. This form of the if is shown here .if{expression) statement; The expression may be any valid C expression. If the expression evaluates as true, the statement will be executed. If it does not, the statement is bypassed, and the line of code following the if is executed. In C, an expression is true if it evaluates to any non-0 value. If it evaluates to 0, it is false. The statement that follows an if is commonly referred to as the target of the if statement. Commonly, the expression inside the if compares one value with another using a relational operator. Although you will learn about all the relational operators later in this Unit, three are introduced here so that we can create some example programs. A relational operator tests how one value relates to another. For example, to see if one value is greater than another, C uses the >

59

relational operator. The outcome of this comparison is either true or false. For example, 10 > 9 is true, but 9 > 10 is false. Therefore this if will cause the message true to be displayed. if (10 > 9) print("true"); However, because the expression in the following statement is false, the if does not execute its target statement, if(l > 2) print ("this will not print"); C uses < as its less than operator. For example,10 < 11 is true. To test for equality, C provides the == operator. There may be no space between the two equal signs. Therefore/10 == 10 is true, but 10 == 11 is notOf course, the expression inside the if may involve variables. For example, the following program tells whether a number entered from the keyboard is positive or negative. #include "stdio .h" int main( ) { int num.; print("enter a number: ") ; scanf("%d", &num) ; if(num > 0) printf("number is positive"); if(num < 0) printf("number is negative") ; } Remember, in C, true is any non-0 value and false is 0. Therefore, it is perfectly valid to have an if statement such as the one shown here, if(count +l) print C' not zero") ; The next example forms the basis for an addition drill. It displays two numbers and asks the user what the answer is. The program then tells the user if the answer is right or wrong. #include "stdio .h" 60

int main( ) { int answer; printf (“What is 10 + 14? “) ; scanf ("%d", &answer) ; if (answer == 10+14) printf ("Right!"); return 0; } This following program either converts feet to meters or meters to feet, depending upon what the user requests. #include "stdio.h" int main( ) { float num; int choice; printf("enter value: ") ; scanf("%f", &num); printf ("l: feet to meters/ 2: meters to feet ") ; printf ("enter choice: ") ; scanf ("%d", &choice); if(choice == 1) printf ("%f", num / 3.28); if(choice == 2) printf ("%f", num * 3.28); return 0; }

Add The else
You can add an else statement to the if. When this is done, the if statement looks like this: if {expression) statement1; else statemanat2; If the expression is true, then the target of the if will be executed, and the else portion will be skipped. However if the expression is false, then the target of the if is bypassed, and the target of the else will be executed. Under no circumstances will both statements execute. Thus, the addition of the else provides a two-way decision path,

61

return 0. } 62 . &num2) . scanf ("%d". there is no reason to test num. so the program uses an if and an else statement to prevent division by 0 from occurring. for num. &num) . scanf("%d". the else requires far fewer machine instructions than an additional if.You can use the else to create more efficient code in some cases. However/ division by 0 is undefined. printf("enter a number: ") . to be greater than 0 using a second if statement. divides the first by the second. } Since there are only two possibilities. Because of the way a C compiler generates code. which determines whether a number is positive or negative. if(num < 0) printf("number is negative") . For example. else printf("number is positive"). &num1) . if(num2==0) printf("cannot divide by zero"). printf("enter first number: ") . num1 / num2) . The following program prompts the user for two numbers. and displays the result. #include "stdio. return 0. else printf ("answer is: %d". here the else is used in place of a second if in the program from the preceding section. scanf("%d". #include "stdio.h" int main( ) { int num. again to see if it is 0 or greater the original version of this program explicitly tested .h” int main( ) { int num1. num2 . printf("enter second number: ").

} 63 . then all the statements in the block of code associated with the if will be executed. the statements form one logical unit. which may be used anywhere that a single statement may. you surround the statements in the block with opening and closing curly braces. if (num. & nun ) . . > 0) { printf("This is ") . printf("an example of ") . Once this is done. . If the expression is false. (Remember. } If the expression evaluates to true. statement 2. To create a block of code. you can link two or more statements together. printf("a code block"). . For example. statement N. scanf ("%d". the general form of the if using blocks of code is if (expression) { statement1. .Create Blocks of Code In C. . statement2. This is called a block of code or a code block.) For example this fragment prints the message This is an example of a code block if the user enters any positive number. the else is optional and need not be present. } else { statements1. . then all the statements in the else block will be executed. statement N.

In the example shown. the way they are shown in the example is a common method . &num) . we can improve the addition drill program so that it also prints the correct answer when the user makes a mistake. This program is an improved version of the fact -to-meters meters-to-feet conversion program. scanf ("%f". #include "stdio. int choice.Keep in mind that a block of code represents one indivisible logical unit. Although C does not care where a statement appears on a line/ it is common practice to indent one level at the start of a block. num * 3. Also.h” int main( ) { float num. This means that under no circumstances could one of the printf() statements in this fragment execute without the others also executing. printf ("1: feet to meters.h" int main( ) 64 . Notice how the use of code blocks allows the program to prompt specifically for each unit. &num) .28). However. } else { printf("enter number of meters: ") . 2: meters to feet ") . printf("feet: %f". num / 3. the placement of the curly braces is arbitrary. #include “stdio. if (choice == 1) { printf("enter number of feet: ") . the statements that appear within the block of code are indented.28). scanf("%d". scanf ("%f". printf("meters: %f". } Using code blocks. &choice) .Indenting makes the structure of a program easier to understand. printf("enter choice: ") . } return 0.

printf("What is 10 +• 14? ") . else { printf ("Sorry. &answer) . scanf("%d". the target of if is a single statement.{ int answer. } This example illustrates an important point: it is not necessary for targets of both the if and the else statements to be blocks of code. } return 0. while the target of else is a block. if(answer == 10+14) printf ("Right!"). ") . Remember. you are free to use either a single statement or a code block at either place. you're wrong. 65 . printf("the answer is 24") .In this case.

and program execution picks up with 66 . the loop stops. It allows one or more statements to be repeated. The initialization section is used to give an initial value to the variable that controls the loop. The for loop is considered by many C’ programmers to be its most flexible loop. increment) statement. for (initialization. If it is false. The conditional-test portion of the loop tests the loop-control variable against a target value each time the loop repeats. Although the for loop allows a large number of variations/ we will examine only its most common form in this section.Use The for Loop for (initialization. } The for loop is one of C's three loop statements. statement n. conditional test. conditional test. conditional test. increment) statement. The initialization section is executed only once/ before the loop begins. Its general form for repeating a single statement is shown here. This variable is usually referred to as the loop-control variable. such as BASIC or Pascal. the for loop is used to repeat a statement or block of statements a specified number of times. If you have programmed in any other computer language. for (initialization. the loop repeats. you will be pleased to learn that the for behaves much like other languages. In its most common form. If the conditional test evaluates true. increment) { statement1.

As a simple first example.the next line of code that follows the loop. this program only displays terminating because num. This process continues until num equals 11. /* this loop will not execute */ for(num=ll. As stated earlier/ the conditional test is performed at the start of each iteration. That is/ the increment portion is executed after the statement or block has been executed. 67 . the loop control variable num. < 11 is evaluated. The purpose of the increment portion is to increase (or decrease) the loop-control value by a certain amount. The conditional test is performed at the start or top of the loop each time the loop is repeated. is initialized to 1. is initialized to 11. the for loop begins running. but before the conditional test. Next. First. num) . num) . num<ll. The increment portion of the for is executed at the bottom of each loop. the loop will not execute even once For example.h" int main( ) { int num. #include "stdio. num<ll. num++) printf("%d ". Keep in mind that the initialization portion of the for loop is only executed once. printf("terminating") . is incremented by one and the conditional test is evaluated again. and terminating is displayed. After the number is printed/ num. when the loop is first entered. return 0. this program uses a for loop to print the numbers 1 through 10 on the screen. for(num=l. Since it is true. } This program produces the following output: 1 2 3 4 5 6 7 8 9 10 terminating The program works like this.h" int main( ) { int num. This means that if the test is false to begin with. causing the conditional test to fail. num=num++) printf("%d ". printf("terminating") . the expression num. When this happens/ the for loop stops. #include "stdio.

#include "stdio. and so on.h" int main( ) { int num. prod = 1. this program computes the product and sum of the numbers from 1 to 10. } The addition-drill program created earlier can be enhanced using a for loop. num<11. the loop-control variable maybe incremented or decrement by more than one. num++) { sum += num. } • A for loop can run negatively. } printf("product and sum: %d %d". For example. } To repeat several statements.h" main( ) { int i . use a block of code as the target of the for loop. sum = 0. for(i=0. prod. #include "stdio. num--) …. for (num=1. return 0. Further. For example. i<101. i) .h" 68 .return 0. I+=5) printf("%d ". num>0. return 0. #include "stdio. sum). For example. then 2 + 2. this fragment decrements the loop-control variablefor(num=20. prod *= num. sum. The version shown here asks for the sums of the numbers between 1 and 10. This program would be useful to a first grader who is learning addition. prod. this program counts to "100 by fives. That is it asks for 1 + .

count < 11. return 0. scanf("%d". i<num/2.int main( ) { int answer. else printf("The number is not prime -") . count+count) . i. /* now test for factors */ is_prime = 1. scanf("%d". } } return 0. &answer) . } 69 . count++) { printf ("What is %d + %d? ". In C. We can use a for loop to create a program that determines if a number is prime. Notice how the indentation adds clarity to the structure of the program. if(answer == count+count) printf("Right! ") . */ #include "stdio. Notice further that the target of else is a block of code. This is perfectly valid. for(i=2.h" int main ( ) { int num.") . else { printf ("Sorry. printf("the answer is %d. for (count=1. is_prime. ". if(is_prime==1) printf("The number is prime. &num). count. a code block may contain statements that create other code blocks. count). The following program asks the user to enter a number and then checks to see if it has any factors. /* Prime number tester. count. } Notice that this program has an if statement as part of the for block. you're wrong ") . i++) if((num%i)==0) is_prime = 0. printf ("Enter the number to test: ") .

to display a character.h” int main ( ) { char ch . your program will also need to read characters from the keyboard. which returns a single character typed on the keyboard when called . ch) . let’s begin with the traditional way characters are read from the keyboard. the function waits for a key to be pressed then getchar() echoes the keystroke to the screen and returns the value of the key to the caller the getchar() function is defined by the ANSI C standard and requires the header file stdio. The original version of C defined a function called getchar () .h” int main ( ) { 70 . this conceptually simple task is complication by some baggage left over from the origins of C. /* read a char */ printf ( “ you typed : % c”. ch = getchar ( ). (Remember. } Although numbers are important.Input Character #include “stdio. in C you can do this in a variety of ways.h. use the % c prinf() format specifier) #include “stdio. This program illustrates its use by reading a character and then telling you what it received. However. Unfortunately. return 0.

you may compare characters just like you compare numbers. The trouble is this: in many C compilers. ch) . for which C was developed . it is rendered nearly useless. 71 . This is useful because the ASCII characters codes are an ordered sequence. For most compilers. ch = getchar ( ). it waits until you press ENTER before doing so . it does not line buffer input . This manes that “a” is less than “b. Therefore. it may behave differently than you expected. For example. but it might be called something different in your compiler. for the sake of compatibility. You use it just like getchar( ) . When C compilers were created for other interactive environments. /* read a char */ printf ( “ you typed : % c”. most C compilers supply another function to perform interactive console input Although it is not defined by the ANSI C standard. characters returned by either getchar() or getche() will be represented by their ASCII codes . getchar () is implemented in such a way that it line buffers input .” and so on. } If you try this program. Virtually all computers use the ASCII character codes when representing characters . (in fact. In C. the ANSI standard states that getchar () need not be line – buffered . If (ch < ‘f‘ ) printf (“character is less than f “ ).h. Because many implementations have implemented line – buffered versions of getchar() . line buffered input. developers had to decide how to make getchar() behave.char ch . even though there is no reason for it. most compilers call this function getche(). Many C compiler developers have decided. the reason for this is that the early version of UNIX. return 0. This means that even though it will return one character to your program . each letter’s code is one greater than the one it precedes. this function requires a header file called conio. except that it will return its value immediately after a key is pressed . to keep getchar () line –buffered . is a perfectly valid fragment that will display its message if the user enters any character that comes before f. ) when getchar() is implemented in a line–buffered fashion In modern interactive environment. ch = getche( ) .

ch = getche ( ) .h” int main ( ) { char ch . if ( ch == ‘M‘ ) printf ( “ %d “ . # include “conio. printf ( “ Enter second number : “ ) . ch = getche ( ) . } One of the most common uses of getche( ) is to return a selection . b. subtract. printf ( “ \ n “ ) . Multiply . if ( ch == ‘S’ ) printf ( “%d” . & b ) . 72 . scanf ( “ % d “ . printf (“\nits ASCII code is %d”. subtract . or Divide ?\ n “ ) . ch). scanf ( “ %d “ . printf ( “ \ Enter first number : “ ) . For example.h” #include “stdio. a + b ) . printf (“enter a character: “) . This illustrates an important feature of C: you can use a character as if it were a “little integer “ #include “conio.h“ # include “stdio. return 0. multiply. this program allows the user to add. & a ) . or divide two numbers.The folowing program reads a character and displays its ASCII code . printf ( “ Do you want to : \n “ ) . char ch . printf ( “ Enter first letter : “ ) . if ( ch == ‘A‘ ) printf ( “%d “ .h“ main ( ) { int a. a * b) . a – b ) . printf ( “ Add .

if ( ch == ‘D‘ && b != 0 ) printf ( “ % d “ . For example. } 73 . printf ( “ Do you which to continue ? ( Y / N ) : “ ) . . ch = getche ( ) . Another common reason that your program will need to read a character form the keyboard is to obtain a yes / no response from the user . if ( ch = = ‘ Y ‘ ) { / * continue with something * / . return 0. So. a / b ) . the program will not recognize it as a request to subtract. if the user enters an s. . this fragment determines if the user wants to proceed. } One point to keep in mind is that C makes a distinction between upper-and lowercase.

. it is said to be nested within the outer if. else if (expression) statement . if (p) if (q) printf (“ a and b are true “) . else statement When an if statement is the target of another if or else. the answer is quite easy. An else always associates with the nearest if within the same block in this examples. Here is a simple example of a nested if. The question. / * nested if * / Notice how the nested if is indented This is common practice it enables anyone reading your program to know quickly that the if is nested and what action are nested . try again “ ) . as suggested by the second printf (). the else is associated with the second if 74 . if( expression) statement . is: which if is associated with the else? Fortunately.An ANSI –standard compiler will allow you to nest ifs at least 15 levels deep One confusing aspect of nested ifs is illustrated by the following fragment.Nest if Statements if (expression1) statement 1 if (expression 2) stsement 2. . if ( count > max ) / * outer if * / if ( error ) printf ( “ error . else printf (“to which statement does this else apply? “).A nested if may appear inside a block of statements that are the target of the outer if . else if (expression) statement .

no action will take place if all other conditions are false. . else if (expression) statement . . As soon as a true conditions found. . If none of the conditions is true. else if (expression ) statement . else if (expression) statement . . That is. in this situation a nested if has as is target another if the general form of the if –else –is ladder is shown here . else statement The conditions are evaluated from the top downward. if all other conditional test fail. the statement associated with it is executed. as shown here. else statement. If the final else is not present. else if (expression ) statement . We can improve the arithmetic program developed previously by using an if –else-if ladder.else –if ladder or if –else staircase because of its visual appearance . . and the rest of the ladder is bypassed. it can lead to overly deep indentations. the last else statement is performed. the if-else-if ladder is generally indented like this: if ( expression ) statement . Although the indention of the general form of the if-else-if ladder is technically correct. 75 . Because of this. if( expression) statement .it is possible to string together several ifs and elses into what is sometime called an if. . the final else will be executed. .

count . printf (“Enter first letter : “) .a*b). Multiply . printf (“\n”). here is a further improvement to the addition drill program developed in the preceding Unit it lets the user have a second try at getting the right answer. a+b). else if (ch == ‘D’ && b != 0) printf(“%d”. scanf (“%d”.a-b). printf (“Do you want to :\n”) . if (ch == ‘A’)printf(“%d” . printf (“Enter second number : “ ) . } This is an improvement over the original version because once a match is found.h” #include “stdio. ch = getche ( ) . char ch. any remaining if statements are skipped this means that the program isn’t wasting time on needless operation whiles this not too import in this example.count ). scanf ( “%d”. count <11. for (count = 1 .h “ # include “stdio. Subtract . you will encounter situations where it will be. count ++) { printf (“what is %d+%d? “.h “ int main ( ) { int a. &a ) . printf (“Add. Nested if statements are very common in programming for example. 76 . &b ) . printf (“Enter first number : “ ).h” int main () { int answer . return 0. b. else if (ch == ‘N’) printf(“%d”.# include “conio. #include “conio. else if (ch == ‘S’) printf(“%d”. a/b). char again . count . or Divide ? \ n “ ).

scanf (“%d” . again = getche ( ) . printf (“would you like to try again ? ( Y/N ) “) . scanf ( “%d “. if ( answer == count + count ) printf ( “ Right ! \ n “ ) . else { printf (“Sorry . /* nested if */ if (again == ‘Y‘) { printf ( “ \ nWhat is %d + %d ? “ . } else printf ( “the answer is %d \ n” . printf ( “\n” ). & answer is % d \ n” . } 77 . count ) . count . & answer ) . count + count ). } } return 0. count + count ). you ‘re wrong \ n”) .

control variable Further. when you were introduced to the for loop in previously. there is no need for an initialization expression. you will see that for is much more flexible. if the loop control variable has already been initialized outside for. The reason that of is so flexible is that the expressions we called the for loop are not limited to these narrow roles The C for loop places no limits on the types of expressions that occur inside it for example you do not have it use the initialization section initialize a loop. Another important reason that for is so flexible is that one or more of the expressions inside it may be empty. However.Examine for Loop Variations no limits on the types of expressions initialization section is not mandatory control variable is optional one or more of the expressions inside it may be empty The for loop in C significantly more powerful and flexible then in most other computer languages. you were only shown the from similar to that used by other languages . the conditional test in this for checks the value of a character entered by the 78 . For example. This program continues to loop unit a q is entered at the keyboard. Instead of testing a loop control variable. there does not need to be any loop –control variable because the conditional test expression that is evaluated each time the loop iterates it does not have to increment or decrement variable.

return 0.h” int main ( ) { int i . &i ) . 79 . /*give ch initial value */ for (i =0.h” int main () { int i. i-. the loop –control variable is initialized by the user outside the loop. } return 0. #include “stdio. For example. for ( . printf(“Enter an integer: “). } Another variation to for is that its target may be empty. so the initialization portion of the loop isempty #include “stdio. Here. i++) { printf (“pass: %d\n”. that condition that control variable The reason ch is given an initial value is to prevent it from accidentally containing a q when the program begins As stated earlier.h” #include “conio. this program simply keeps inputting characters until the user types q . } Here. ch = ‘a’ . char ch.user. i. ch = getche () .) printf (“%d” . i). & i ) . it is possible to leave an expression in a loop empty. For example. ch !=’q’ . scanf (“%d” . this program asks the user for a value and then counts down to 0 from this number.

ch = getche ()) . The reason the target of the for can be empty is because C allows null statements . printf (‘found the q”). use a for construct like this : for ( . conceptually. return 0. In C. the value of ch is tested against q next . the compiler assumes that it is true therefore. the nonexistent target of the increment portion of the loop is executed. } Notice that statements assigning ch a value have been moved into the loop. #include “stdio. Although accident an infinite loop is a bug . Using the for. This means that when the loop starts. . you will sometimes want to create one on purpose. getche() is called . the following program manually increments i at the bottom of the loop. To create an infinite loop. . ch !=’q’ . it is perfectly valid for the loop control variable to be altered outside the increment section for example. unlike most other computer languages.h” #include “conio. it is possible to create a loop is usually called an infinite loop. ) { . for (ch=getche().#include “stdio. } As you can see. This process repeats until the user enters a q . . then .h” int main() { char ch . the loop continues to run . there are no expressions in the for when there is no expression in the conditional portion.h” int main () { 80 .

i < 10. } 81 . i++. } return 0. i). ) { printf(“%d “. for ( i = 0 .int i.

the loop stops. you will see how much clearer this version is. For example. #include “stdio.C’s while Loop while loop is precondition iteration statement while( expression ) statement . This means that if the expression is false to begin with. Statementn. while(expression) { statement1.h” #include “conio. you should generally select the loop that best fits the needs of the situation. the loop will not execute even once. Of course. the target of while may also be a block of code the while loop works by repeating its target as long as the expression is true when it becomes false.h” int main() 82 . The value of the expression is checked at the top loop. Even though the for is flexible enough to allow itself to be controlled by factors not related to its traditional use. } Another of C’s loops is while it has this general from : while( expression ) statement . a better way to wait for the letter ‘q’ to be typed is shown here using while if you compare it to the previous example.

h” #include “conio. \n”).{ char ch . ‘A’ becomes ‘B’ and so forth. printf(“Enter your massage. } The following program is a simple code machine. ch = getche () . The program stops when you press ENTER (the gtche() function returns \r when ENTER is pressed. printf ( “found the q” ) . ch = getche() . That is. ch = getche( ). } 83 .) #include “stdio. ch+1) . } return 0. while ( ch!=’q’) ch = getche ( ) . It translates the characters you type into a coded from by adding 1 to each letter. return 0. while (ch!=’\r’) { printf(“%c”.h” int main() { char ch .

the curly braces are not necessary. which has this general form: do{ Statements } while (expression). Most programmers include them. It stops when the expression becomes false. The fact do will always execute the body of its loop at least once makes it perfect for checking menu input. The do loop is unique because it will always execute the code within the loop at least ones.h” 84 . since the expression controlling the loop is tested at the bottom of the loop. However. if only one statement is begin repeated.Use do Loop do .h” #include “conio. so that ends the do is part of a do loop.. not the beginning of a while loop. The do loop repeats the statement or statement while the expression is true. For example. this version of the arithmetic program reports the user until a valid response is entered #include “stdio.while loop is postcondition iteration statement do{ Statements } while (expression). C’s final loop is do.

printf(“add. b. return 0. return 0. ch=getche ().int main() { int a. #include “stdio. this program waits for the user to type a q. }while (“ch ! = ‘q’). do { ch = getche (). else if (ch==’D’ && b!=0 ) printf (“%d” . else if (ch==’M’ ) printf (“%d” . printf(“Enter first number: “). printf(“do you want to :\n”). Notice that it contains one less call to getche () then the equivalent program described in the section on the while loop. printf(“Enter second number : “). else if (ch==’S’ ) printf (“%d” . &b). a+b). scanf(“%d”. char ch. or divide?\n”). if (ch == ‘A’) printf (“%d” . a-b). printf(“found the q”). multiply. } The do loop is especially useful when your program is waiting for some event to occur.&a).h” int main() { char ch . a/b). } while (ch!=’A’ && ch !=’S’ && ch!=’M’ && ch!=’D’ ). subtract. For example. a*b). scanf(“%d”. printf (“\n”). /* force user to enter a valid response */ do { printf ( “Enter first letter : “). } 85 .h” #include “conio.

Since the loop condition is tested at the bottom. it is not necessary to initialize ch prior to entering the loop. 86 .

Loops Features Loops may be nested for 15 levels(A NSI Standard) You may exit loop using break ststement Control the flow of execution using continue statement Create Nested Loops When the body of one loop contains another. this fragment prints the numbers 1 to 10 on the screen ten times. As a simple example of nested fors. most compilers allow nesting to virtually any level. The ANSI C standard specifies that loops may be nested for 15 levels deep. In the version shown below. Notice the use of the variable right to stop the loop early if the correct answer is given. #include “stdio. j < 11. printf(“\n”) . However. for (i=0.h” #include “conio. j++) printf(“%d “. i<10. the second is said to be nested inside the first. j) . } You can use a nested for to make another improvement to the arithmetic drill. Any of C’s loops may be nested within any other loop.h” int main() 87 . i++) { for (j= 1. the program will give the user three chances to get the right answer.

& answer ). } } /* if answer still wrong. \n”. &answer ). right = 0. ‘A’ +j ) . } The statement Printf (“%c”. i <3.count. count. k<2. right = 1 . k. j. } This program uses three for loops to print the alphabet three times. printf(“Try again \n”). count. you’re wrong\n”). count). ‘A’+j) . chances <3 && ! right . count) . each time printing each letter twice #include “stdio. Works because ASCII codes for the letters of the alphabet are strictly ascending. 88 . for (i = 0 . count <11 . if (answer == count + count ) { printf(“ Right! \n”) . j <26. /* nested for */ for (chances = 0 . j++) for (k=0. if (answer == count + count ) printf (“Right ! \n”) . scanf(“%d”. for (count = 1 . count ++ ) { printf (“what is %d + %d? “. chances. else { printf (“sorry.h” int main() { int i. tell user */ if (!right ) printf (“the answer is %. chances ++) { printf( “\nwhat is %d + %d? “. scanf (“%d”. count + count ). k++) printf(“%c”.{ int answer. i ++) for (j=0 . each one greater than the one that precedes it. return 0. } } return 0. right .

since too many exit points from a loop tend to distracter your code.h” int main() { int i.h” int main() { int i . For example. } The break statement can be used with all three of C’s loops. i< 1000. if (i == 10) break .h” #include “conio. The break statement is commonly used in loops in which a special can cause immediate termination.Use break to Exit a Loop The break statement allows you to exit a loop from any point within its body. This is an example of such a situation. /* exit the loop */ } return 0. You can have as many break statements within a loop as you desire. this loop prints only the numbers 1 to 10 #include “stdio. i <100. i). i++) { 89 . bypassing its normal termination expression. the loop is immediately terminated following the loop. for (i = 1. /* display all numbers which are multiples of 6 */ for (i= 1. When the break statement is encountered inside a loop. However. it is generally best to use the break for special purposes. char ch. where a keypress can stop the execution of the program #include “stdio. not as your normal loop exit. i ++) { printf(“%d “.

i++) { for (j=0. For example. It forces the next iteration of the loop to take place. j). j. ch = getche ( ) . j++) { printf (“%d”. i) . j<100. } printf (“\n”). this program never displays output. } } The continue Statement The continue statement is somewhat the opposite of the break statement. this program prints the numbers 1 to 5 five times. x++) { continue . if (j == 5 )break . x<100. } } return 0. skipping any code in between itself and the test condition of the loop.h” int main ( ) { int x. i<5.if (!(i%6)) { printf (“%d more ? (y/n)”. for (i=0 . x) . } A break will cause an exit from only the innermost loop. for (x=0. /* this is never is executed */ } } 90 .h” int main ( ) { int i. if (ch ==’N’) break . For example. printf (“%d ”. printf (“\n”) . #include “stdio. #include “stdio.

i). do { printf(“Enter next number (0 to stop ) :”). skipping the printf () statement. } while (i) . In the case of for. ch = getche ( ) .h” int main() { int total. it uses continue to restart the loop. it causes the loop to repeat. Poor practice to use it. Before adding a value to the running total. } 91 . char ch. scanf(“%d”. One good use continue is to restart a statement sequence when an error occurs. i. printf(“\n”). printf(“total is %d\n”. this program computes a running total of number entered by the user. If it wasn’t. total = 0 .h” #include “conio. #include “stdio.Each time the continue statement is reached. In while and do-while loop. it verifies that the number was correctly entered. &i) . total = total + i. return 0. but simply because good applications for it are not common. a continue statement will cause control to go directly to the test condition and then continue the looping process. For example. total ). and the loop continues. the test is executed. if (ch == ‘N’) continue. printf(“is %d correct? (y/n) : “.

Statement sequence break. . case constant3. the statement sequence associated with that match is executed. When a match is found. The switch statement is C’s multiple selection statement. default: 92 .Select Paths with he switch Statement switch is a multibranch conditional statement switch (variable) { case constant1 : Statement sequence. . break. case constant2. default: Statement sequence } While if is good for choosing between two alternatives. C’s solution to this problem is the switch statement.. case constant2. it quickly becomes cumbersome when several alternatives are needed. break. Statement sequence. The general from of the switch statement is switch (variable) { case constant1 : Statement sequence break. It is used to select one of several alternative paths in program execution and works like integer or character constants. Statement sequence break. .

Also. for example. the end of the switch is reached. in that switch can only test for equality. the program displays two. whereas the if conditional expression can be of any type.Statement sequence } where the default statement sequence is performed if no match are found. That is. scanf (“%d”. break . this program recognizes the numbers 1. You cannot.h” int main() { int i . the statements associated with that case are executed until break is encountered or.and 4 and prints the name of the one you enter. When a match is found. #include “stdio. As a very simple example. use floating-point numbers. case 3 : printf(“three”). 93 . } return 0. switch will work with only int or char types. in the case of default or the test case.3. switch (i) { case 1: printf(“one”). printf(“Enter a number between 1 and 4: “). If all matches fail and default is absent. case 4 : printf(“four”). The default is optional. break .2. default : printf(“unrecognized number “) . break. no action takes place. & i ). if you enter 2. } The switch statement differs from if. case 2 : printf(“two”). break .

h” int main() { int a. In practice. the following code fragment is perfectly acceptable. you should limit the amount of case statements to a much smaller number for efficiency reasons. the arithmetic program can recoded as shown here. The ANSI standard states that maximum 257 case statements will be allowed. they are not enclosed by curly braces. no two case constants in the same switch can have identical values. break. . switch (a) { case 1: switch(b) { case 0: printf(“b is false “). It is possible to have a switch as part of the statement sequence of an outer switch. Also. } break. An ANSI-standard compiler will allow at least 15 levels of nesting switch statements . printf (“do you want to : \n”) . case 1: printf (“b is true”). . multiply. This version reflects the way professional C code is written . subtract.h” #include “stdio. #include “conio. For example. no conflicts will arise. The switch statement is often used to process menu commands. /* force user to enter a valid response */ 94 . or divide? \n”) . If the case constants of the inner and outer switch contain common values. printf (“Add.The statement sequences associated with each case are not blocks. char ch. b . For example. This is called a nested switch. case 2 : .

when encountered within a switch causes the program flow to exit from the entire switch statement and continue on to the next statement outside the switch. case ‘D’ : if (b!=0 ) printf (“%d”. The break statement.do { printf (“Enter first letter : “) . printf ( “\n”) .h” int main() { char ch. } Technically. break. printf(“\n”). break. switch (ch) { case ‘a’ : 95 . a-b). ch = getche ( ) . if a break statement is omitted. the break statement is optional. That is. case ‘M’ : printf(“%d”. printf (“Enter first number : “) . printf (“Enter second number : “) . study this program carefully. scanf (“%d”. break. a*b). } return 0. a/b). a+b). However. switch (ch) { case ‘A’ : printf(“%d”. case ‘S’ : printf(“%d”. q to quite : “ ). #include “stdio. & a). the execution continue into the following case or default statement (if either exists).h” #include “conio. } while (ch !=’A’ && ch != ‘S’ && ch !=’M’ && ch != ‘D’) . scanf (“%d”. & b). do { printf(“\nEnter a character . For example. This is much the way it works when breaking out of a loop. ch = getche( ) . when a break statements or the end of the switch is encountered.

For example. break . #include “stdio. it continues until a break statement or the end of the switch is encountered. case ‘e’ : printf (“soldier “) .h” #include “conio. here is a program that categorizes letters into vowels and consonants. case ‘c’ : printf (“for all good men “) . case ‘d’ : printf (“the summer “) . switch ( ch) { case ‘a’ : case ‘e’ : case ‘i’ : case ‘o’ : case ‘u’ : case ‘y’ : printf(“is a vowel \n “ ) . default : printf(“is a consonant “ ) . printf(“\Enter the letter : “ ) . the entire phrase New is the time for all good men. 96 . As you can see. once execution begins inside a case. ch = getche ( ) .h” int main() { char ch. return 0. } if the user types a. The statement sequence two or more case to share a common statement sequence without duplication of code. case ‘b’ : printf (“the time “) . } }while (ch != ‘q’) .printf (“new is “) .

} } 97 .

Unit 4 98 .

As you expand your programming skills. 211 Function Style and Prototyping C functions changed greatly during the ANSI standardization process. How functions work determines to a large degree the efficiency. This Unit includes numerous C examples that illustrate how to write simple functions to perform specific tasks. You do all C programming within a function. and portability of C program code. you are well on your way to becoming a power C programmer. If you learn to write good functions. and assembly language uses just procedures. you will find C functions similar to modules in other languages. Pascal uses procedures and functions. readability. FORTRAN uses just functions. The functions are short to make the concepts easier to understand and to prevent you from being lost in reams of code. This new C standard is 99 . which is itself a function.Modularity Modularity and Functions Function Prototyping Function Arguments Function Type Functions form the cornerstone of C programming. Many of these examples use functions contained in the standard C libraries. This is because all programs must include main. If you have programmed in other languages. your programs will take on a modular appearance when you begin programming with functions.

. . and so on. return_type function_name(argument_type(s) argument_name(s) ). The return_type gives this specification. For example. return(). (data declarations and body of function) .largely based on the function prototype used in C++. } 100 . The function_name is any meaningful name you choose to describe the function. Argument types may also be of type void. float. The function can be of type void. You can pass many values to a function by repeating the argument type and name separated by a comma. you should give an argument_type followed by an argument_name. The function prototype is simple and is included at the start of program code to notify the compiler of the type and number of arguments that a function will use. whenever possible you should use the function prototype form that is a replication of the function's declaration line. If any information is passed to the function. The function itself is an encapsulated piece of code that usually follows the main function definition. int. Although other variations are legal. It is also correct to list just the argument type. The function can take on the following form: return_type function_name(argument_types and names) { . but that prototype form is not used as frequently. float. Function Prototyping Function declarations begin with the C function prototype. and so on. int. It also enforces a stronger type checking than was possible when C was not standardized.

Actually. which are arguments or parameters that are passed to the function.) to the prototype that is listed at the beginning of a program. c). the ANSI standard suggests that every function be prototyped in a separate header file. return(z). Function arguments are optional. z=y-x. As you might guess. Function arguments can be mixed-that is. /* function return int type */ int main() { int a=5. int b=93. you can include the function prototype within the body of the program. } int subtractor(int x. c=subtractor(a. some functions may receive no arguments while others may receive many.b). int c.int y). Function Arguments The following sections cover function arguments.Notice that the first line of the function is identical (except for the missing . return (0). is shown in the following C example: /* * C program to illustrate function prototyping. * Function subtracts two integers and returns an integer * result. The prototype states that the function will accept two int arguments and return an int type. An actual function prototype and function. this is how header files are associated with their appropriate C libraries. */ #include <stdio. used in a program. For simple programs. 101 . printf(“The difference is: %d\n”. } The function is called subtractor.int y) /* function declaration */ { int z.h> int subtractor(int x. you can use any of the standard data types.

*/ 102 . When you write ANSI C code. float. when printer has completed its task. Using void as an Argument In ANSI C. The main function calls the function printer. This list is called the actual argument list. such as integer. The following program has a simple function named printer that receives no arguments and does not return a value. The list may be empty or may contain any combination of types.Formal and Actual Function Arguments void as an Argument Characters as Arguments Integers as Arguments Floats as Arguments Doubles as Arguments The function definition contains an argument (or parameter) list called the formal argument list. you must use void to state explicitly the absence of function arguments. control is returned to the main function. When the function is actually called from within the body of the program. an argument list is also passed to the function. /* * C program will print a message with a function. there is usually a one-to-one match between the formal and actual argument lists. * Function uses a type void argument and sqrt function * from the standard C library. or character.

The function intercepts a character from the standard input device (keyboard) and returns a character value. double x. return (0).h. and getche.z. Characters as Arguments Characters can also be passed to a function. contained in math. a single character is intercepted from the keyboard in the function main and passed to the function printer. } void printer(void) { double z=5678. printf("The square root of %1f is %f \n". accepts a double and returns the square root as a double value. int main() { printf("This program will extract a square root. } Notice that the printer function calls a C library function named sqrt.x).0. x=sqrt(z). printer(). \n\n"). getchar. without echo to the screen.h> void printer(void). In the next example. The prototype for this library function. The getch function intercepts the character. In the standard C library.h> #include <math. 103 .#include <stdio. these other character functions are closely related to getch: getc.

mychar=getch(). 104 .ch).i<10. \n”).h> void printer(char ch). a single int will be read from the keyboard with C’s scanf function. printf("Enter a single character from the keyboard. */ #include <stdio. The function then prints a message and the character ten times. return (0). Integers as Arguments In the next example. for(i=0. The radius function uses the supplied radius to calculate and print the area of a circle. the volume of a sphere. * pass it to a function and print a message using * the character.h> #include <conio./* * C program will accept a character from keyboard. int main() { char mychar.i++) printf(“The character is %c \n”. That int will be passed to the function radius. } void printer(char ch) { int i. printer(mychar). } Note that a single character is passed to the function. and the surface area of a sphere. The %c in the printf function specifies that a single character is to be printed.

scanf intercepts both float values from the keyboard. printf(“A sphere would have a volume of %f \n".area)./* * C program will calculate values given a radius. * Function uses a type int argument. printf(“A circle would have an area of %f \n”.sarea). printf("Enter the radius. as an integer.0/3. void radius(int r). In the following C example.0*(float) (r*r). volume=PI*4. printf(“The radius is %d \n\n”.volume. return (0). \n"). area=PI*(float) (r*r). the calculations are cast to float. } void radius(int r) { float area. printf("from the keyboard.\n"). accepts radius * from keyboard with scanf function* */ #include <stdio. radius(myradius). scanf (“%d”. int main() { int myradius. Floats as Arguments Floats are just as easy to pass as arguments as are integers.14159.sarea. &myradius).0*(float) (r*r*r). Notice that PI was defined as a const. two float values are passed to a function called hypotenuse. printf(“The surface area of the sphere is %f \n". 105 .h> const float PI=3. } While the value of radius is an int type. sarea=PI*4.volume).r).

xlength. printf("Enter the base of a right triangle. \n"). float y). 106 .&xlength).h> void hypotenuse(float x.h functions accept and return double types. return (0).(double) y).float y) { double myhyp. * Function uses a type float argument and accepts * input from the keyboard with the scant function. scanf(“%f". printf(“The hypotenuse of the triangle is %g \n”./* * C program will find hypotenuse of a right triangle. } Notice that both arguments received by the hypotenuse are cast to doubles when used by the hypot function from math. \n”). } void hypotenuse(float x.h> #include <math. printf("Enter the height of a right triangle.myhyp). */ #include <stdio. The next able shows other mathematical functions that your programs can use.h. int main() { float ylength.&ylength). hypotenuse(ylength. All math.xlength). scanf("%f”. myhyp=hypot((double) x.

h functions accept and return double types.h Function Name abs acos asin atan atan2 atof cabs ceil cos cosh exp fabs floor fmod hypot log log10 modf poly pow pow10 sin sinh sqrt srand tan tanh Description Absolute value of a number Arc cosine Arc sine Arc tangent Arc tangent of two numbers ASCII string to type float Absolute value of complex number Largest integer in list Cosine Hyperbolic cosine Exponential value Absolute value of float Smallest integer in list Floating-point mod Hypotenuse of right triangle Natural logarithm Common logarithm Return mantissa and exponent Create polynomial Raise n to power x Raise 10 to power x Sine Hyperbolic sine Square root Random number initializer Tangent Hyperbolic tangent Doubles as Arguments The double type is a very precise float value.07182. 107 . The following program will accept two double values from the keyboard. The function will raise the first number to the power specified by the second number. As you have learned all math.63.Mathematical Functions Described in math.2 is really equal to 8358270. Now you can find out that 146.

int main() { double xnum.double y). printf(“The result is %1f \n". * Function uses a type double argument and the pow function. power(xnum. 108 .&ynum).h> #include <math. return (0).ynum.result). } void power(double x.double y) { double result. \n"). */ #include <stdio. scanf(“%1f”. \n"). scanf(“%1f”. printf("Enter the number to be raised to a power. } This function uses the pow function prototyped in math. printf("Enter the power.y).&xnum).h. result=pow(x.ynum)./* * C program will raise a number to a power.h> void power(double x.

and octal. C permits numeric information to be formatted in hexadecimal.h> 109 . Specifying data in a binary format is useful when you are doing binary arithmetic or developing bit masks.Function Types Function Type void Function Type char Function Type int Function Type long Function Type float Function Type double This section will illustrate numerous function types. A function type is the type of value returned by the function. but not binary. decimal. To view the binary number. you must print the contents of the array. The function binary will convert a decimal number entered from the keyboard to a binary representation. Function Type void You have already learned about void function types so the next example will be dressed up a bit. */ #include <stdio. The binary digits are not packed together as a single binary number but are stored individually in an array. * Program will print the binary equivalent of a number. None of the previous examples have returned information from the function and thus were of type void. /* * C program illustrates the void function type.

is either a one or a zero. scanf("%d". printf ("\n”). number/=2.>1 0 (msb) 1 0 (binary) (lsb) 10/2 5/2 2/2 1/2 In the function. The modulo operator determines the remainder and saves the bit in the array. } You can convert base ten numbers to another base by dividing the number by the new base a successive number of times. Division is then 110 . a two is repeatedly divided into a base ten number.\n"). a while loop performs the arithmetic as long as number has not reached zero.void binary(int number). while (number !=0) { myarray[i]=(number % 2).. i++.&number). to convert 10 to binary: quotient 5 2 1 0 remainder 0 (lsb) 1 0 1 (msb) .myarray[i])..i>=0. after each division. binary(number). For example. } i--. for(. The remainder becomes the binary digit.i--) printf("%1d". printf("Enter a decimal number for conversion to binary. The remainder. int main() { int number. } void binary(int number) { int i=0. The base ten number becomes the quotient from the previous division. In the case of conversion to a binary number. int myarray[40]. return (0).

/* * C program illustrates the character function type. saving only the integer result. printf("%c\n".h) to convert the character to uppercase. Function Type char Here is a minor expansion to an earlier example. must be unloaded from the array in reverse order. This process is repeated until the quotient (also number in this case) is reduced to zero.h> #include <ctype. a lowercase letter received from the keyboard is passed to the function. The function uses the toupper function (which is from the standard library and is prototyped in ctype. */ #include <stdio. } char uppercase(char letter) { return(toupper(letter)). The individual array bits. lowchar=getchar(). Study the/or loop used in the function.h> char uppercase(char letter). \n"). The C function uppercase accepts a char argument and returns the same. } 111 . Functions related to toupper include toascii and tolower.hichar. int main() { char lowchar.performed on number. For this example. which form the binary result.hichar). return (0). hichar=uppercase(lowchar). printf("Enter a lowercase character. * Function receives lowercase character and * converts it to uppercase. as you can see from the preceding numeric example.

} Function Type long The following C program accepts an int value as an argument and returns a long.i<20. /* * C program illustrates the integer function type.). 112 . and returns the int value to main. one at a time. and * returns the cube of each. } return (0).cubes the number.i. } int cubenumber(int number) { return (number*number*number).8.. The function will raise the number 2 to an integer power.Function Type int The following function accepts and returns int types. * Function receives integers. Function receives integers.cube.10. The function cube-number accepts a number generated in main (0.4. for (i=0. one at a time. printf(“The cube of %d is %d \n”.h> int cubenumber(int number).cube).. one at a time. The original number and the cube are printed to the screen..6. int main() { int i. */ #include <stdio. // // // // // C program illustrates the long integer function type. and returns 2 raised to that integer power.i+=2) { cube=cubenumber(i).2.

for (i=0. printf(“2 raised to the %d power is %ld\n”. for (t=0.t<number. } return (0). long weight. weight). Function receives an array of floats and returns their product as a float. The array contains floats and will return a float product. 113 . the program will perform the following multiplication equation: 2 * 2 * 2 * 2 = 16 Function Type float The next C example will find the product of all the elements in an array. int main() { int i. } The function simply multiplies the original number by the number of times it is to be raised to the power. I. long value=1l.#include <stdio. For example. // // // C program illustrates the float function type. return (value).h> long twopower(int number).i++) { weight=twopower(i).t++) value*=2. } long twopower(int number) { int t. if you want to raise 2 to the fourth power (24).i<31.

Function Type double The following C example accepts and returns a double type. for (t=1. } Since the elements are multiplied together. return (temp).#include <stdio. int main() 114 .h> const double PI=3.h> #include <math.2.09876}.t<5. temp=floatarray[0]. expressed in degrees. one at a * time. /* * C program illustrates the double function type. one at a time.t++) temp*=floatarray[t]. product=times(myarray). product).6. float product. to its sine value. and returns the sine of each. the first element of the array must be loaded into temp before the for loop is entered.4.14159265359. } float times(float floatarray[ ]) { int t. The function trigsine will convert an angle. double trigsine(double angle).5. return (0). * Function receives integers from 0 to 90.05.14. */ #include <stdio.0. float temp.7. int main() { float myarray[5] ={1. printf(“The product of the array's numbers is: %f \n“.h> float times(float floatarray[ ]).

Angles must be converted from degrees to radians for all trigonometric functions. printf(“The sine of %d degrees is %20.{ int i. for (i=0.i.181f \n". double sine.sine).h is utilized by trigsine to obtain the answer.i<91. } double trigsine(double angle) { double temp. temp=sin((PI/180. Recall that PI radians equal 180 degrees. } Notice that the sin function described in math. 115 . } return (0). return (temp).i++) { sine=trigsine((double) i).0)*angle).

external to the present program.Storage Classes and Functions extern Storage Class static Storage Class Functions can also use extern and static storage class types. is not permitted. a function can be declared static when external access apart from the present program. 116 . In a somewhat related manner. A function is declared with an extern storage class when it has been defined in another file.

the local scope takes precedence 117 .Variable Scope Global Scope File Scope Local Scope A local variable may be used completely within a function definition. Variables of this type are global in range. The variable is said to be accessible or visible within the function and has a local scope. The same variable may be used with a file scope and later within a function definition with a local scope. Its scope is then limited to the function. In this case. Variables with a file scope are declared outside of individual functions. They have visibility or accessibility throughout the whole file.

Recursion is permitted in C. * Example: 5! =5x4x3x2x1. * Calculation of the factorial of a number. /* * C program illustrates recursive function calls. since the product increases very rapidly.h> double factorial(double answer).120 */ #include <stdio. the factorial of 14 is 87178291200. 118 .Recursion C Language supports recursive functions Local variable is essintial to implment recursive Recursion is another type of iteration Some algorithms can be more easiar using the recursion technique Recursion occurs when a function calls itself.) For example: 6! =6*5*4*3*2*1 = =720 Take care when choosing data types. You can generate the factorial of a number with recursion. (The factorial of a number is defined as the number multiplied by all successively lower integers. As an example.

return (0). else return(answer*factorial(answer-1. the l is a modifier to the f and specifies a double instead of a float. %…If. } double factorial(double answer) { if (answer <= 1.01f \n".int main() { double number=20. } Notice that the function includes a call to itself. double fact.0). fact=factoria(number) .0)).0) return(1. Also notice that the printf function uses a new format code for printing a double value.fact). Here.0. 119 . printf(“The factorial is: %15.

the user will be returned to the command linewith a reminder to try again and enter several names. One argument received by main. is an int giving the number of command-line terms plus one. argc. C>MYPROGRAM Bill Chris Jeff Cindy Herb 10 20 30 In this example. it is main that is given specific information. the program anticipates that the user will enter several names on the command line. In fact. The following examples explain various techniques for retrieving information from the command line Strings Since the arguments are passed as strings of characters. if argc isn't greater than two. eight values are passed from the command line to myprogram. Command-line arguments are passed when the program is called from DOS. Since all programs have a name. Actually. The second argument is a pointer to the strings called argv.Function Arguments for main Passing values from command line Passing strings Passing integers Passing floats C can accept command-line arguments. In the following example. argc is always one or greater. For example. so argv is of type char *[argc]. The program title is counted as the first term. 120 . All arguments are strings of characters. they are the easiest to work with.

if(argc<2) { printf(“You must enter several names on the command\n”). exit(1). return (0).\n”). i++) printf(“Name #%d is %s\n”. char * argv[ ]) { int i.h> #include <stdlib.h> 121 . i<argc. with no additional functions. The function will convert the value in number to a string of binary digits be printed in octal and hexadecimal formats. they will be interpreted as ASCII strings and must be printed as character data. */ #include <stdio. Since the number is actually a character string.h> int main(int argc.i. it must be converted to an integer via the atoi function.h> #include <stdlib. printf(“line when executing this program! Try again. } for (i=1. Integers This C example will accept a single int number on the command line. Then number is passed to the binary function. // C program illustrates how to read an integer // into the program with a command-line argument. // #include <stdio. double sine. The names are received on the command line and printed to the screen in the same order. } The program is completely contained in main.argv[i]). If numbers are entered on the command line./* * C program illustrates how to read string data * into the program with a command-line argument.

\n"). number). if(argc!=2) { printf("Enter a decimal number on the command line. } Floats As you can imagine. 122 . printf(“The binary equivalent is: "). printf(”The hexadecimal equivalent is: %x\n“. octal and\n").0. exit(1). myarray[i]). } void binary(int digits) { int i=0. while (digits != 0) { myarray[i]=(digits % 2). i++. int main(int argc. } i--. they can take on values such as 45. binary(number).\n").i--) printf(“%d”.32. 76. printf("hexadecimal. digits/=2. int myarray[40]. return (0). for(. floats will not be any more difficult to intercept than integers. Since the angles are of type float. printf(“\n”). printf(“The octal equivalent is: %od\n“. number).i>=0. The following C example allows several angles to be entered on the command line. } number=atoi(argv[1]). or 0. char *argv[ ]) { int number.02345. The sine of the angles will be extracted and printed to the screen.void binary(int digits). printf("It will be converted to binary.

double angle. i<argc. 123 .h> #include <math. int main(int argc. i++) { angle=(double) atof(argv[i]).\n”). exit(1). // into the program with a command-line argument.sin((PI/180. */ #include <stdio. printf(“Program will return the sine of the angles.0)*angle)). } return (0).14159265359. if(argc<2) { printf(“Enter several angles on the command line.h> #include <stdlib.\n”). angle./* // C program illustrates how to read float data types . } for (i=1. } The atof function converts the command-line string argument to a float type.h> const double PI=3. The program uses the sin function within the printf function to retrieve the sine information. printf(“The sine of %f is %15.141f\n”. char *argv[ ]) { int i.

Unit 5 124 .

Arrays Arrays is a set of hemogenous data Arrays can be one dimentional or multidimensional Strings in C are array of characters In this Unit you will learn about arrays. you will also learn about strings and several of C’s string functions. 125 . An array is essentially a list of related variables and can be very useful in a variety of situations. Since in C strings are simply arrays of characters.

This means that if you want to access the first element in array. all arrays begin at 0. a one-dimensional array is a list of variables that are all of the same type and are referenced through a common name. To declare a one-dimensional array. An individual variable in the array is called an array element. Arrays form a convenient way to handle groups of related data. To index an 126 . use 0 for index. Where type is a valid C data type. In C. For example. to declare an integer array with 20 elements called myarray. An array element is accessed by indexing the array using the element. use the general form Type var_name[size]. and size specifies the number of elements in the array. var_name is the name of the array. use this statement. int myarray [20]. Array decleration has the general form Type varName[Size] Size of array must be constant value Array index starts from 0 In C.Declare One Dimensional Arrays One dimensional array is a list of hemogenous variabls Array element is an indivedual variable.

arrays start at 0. sqrs [i] ) . Remember. put the array on the left side of an assignment statement. myarray[0] = 100. For example. 127 . specify the index of the element you want inside square brackets. the following statement accesses the second element of myarray.h” int main() { int sqrs[10]. for (i =1 . for (j=0. int I [5] . C stores one-dimensional arrays in one contiguous memory location with the first element at the lowest address. i++) printf(“%d “. int i . for (i =0 . j++) I [j] =j . myarray[1]. return 0. i<11. so an index of 1 reference the second element. For example. i++) sqrs[i-1] = i*i . For example the following program loads the sqrs array with the squares of the number 1 through 10 and then displays them.array. To assign an array element a value. this gives the first element in myarray the value 100. int j . Array I will look like this: 0 0 1 2 3 4 1 2 3 4 You may use the value of an array element anywhere you would use a simple variable or constant. j<5. i<10. For example. #include “stdio. after this fragment executes.

scanf (“%d”. For example. printf (“How many days in the month ? “ ) . char a1 [10]. to make sure that the ends of arrays are never overrun. &count[9] ) . attempting to access non-existent elements will generally have disastrous results. max. this fragment is incorrect. C does not perform any bounds checking on array indexes. Of course. For example. the programmer. . often causing the program even the computer to crash. This means that it is possible to overrun the end of an array. In C. if an array called a is declared as having five elements. For example.h” int main() { int temp[31]. min. you must do so by copying each element separately. For example. as will as its hottest and coolest days . the compiler will still let you access the (non-existent) tenth element with a statement like a[9]. Arrays are very useful in programming when lists of information need to be managed.} When you want to use scanf () to input a numeric value into an array element. int days . /* this is wrong */ If you wish to copy the values of all the elements of one array to another. . this scanf () call reads an integer into count[9] . scanf (“%d”. i . a2 = a1 . you may not assign one entire array to another. 128 . It is up to you. . #include “stdio. avg. simply put the & in front of the array name. a2[10]. &days ) . this program reads the noonday temperature for each day of a month and then reports the month’s average temperature.

if necessary. i++) { printf (“Enter temperature for day %d : “. i++ ) { if (min > temp[i] ) min = temp [i] .h” int main() { int a1[10]. For example. printf (“Maximum temperture : %d\n “. i++ ) printf (“%d “. to copy the contents of one array to another. &temp [i]). if (max < temp [i]) max =temp [i] . i< 11. } /* find average */ avg = 0 . #include “stdio. return 0. for (i =1 . /* initialize min and max */ max = 0 . i< 11. } Arrays are especially useful when you want to sort information. this program lets the user enter up to 100 numbers and then sorts them. /* find min and max */ min =200 . min ) . i< days . i++ ) a2 [i] =a1 [i] . i +1 ). for (i =1 . i <days . scanf (“%d”. The general concept behind the bubble sort. you must explicity copy each element separately. } printf (“Minimum temperture : %d\n”. This is a little like bubbles in a tank of water with each bubble. max) . } As stated earlier. for (i =1 . avg / days ) . i<days . i++ ) a1 [i] =i . for (i=0 . a2 [10]. this program loads a1 with the numbers 1 through 10 and then copies them into a2 . seeking its own level. For example. is the repeated comparisons and. return 0.for (i =0 . indeed how it got its name. 129 . printf (“Average temperature : %d \n “. exchanges of adjacent elements. for (i =0 . The sorting algorithm is the bubble sort. i< 11. a2[i] ) . int i . i++) avg += temp [i] . in turn.

--b ) { /* compare adjacent elements */ if (item [b-1] > item [b] ) { /* exchange elements */ t = item [b-1].h” #include “stdlib. t . /* read in numbers */ printf(“How many numbers? “). b. &item [a]). a <count . for (a=0 .#include “stdio. scanf(“%d”. int count . b>=a . a <count . /* now. t++ ) printf (“%d”. a++ ) scanf (“%d”. sort them using a bubble sort */ for (a=1 . } } /* display sorted list */ for (t =0 . item [b-1] = item [b]. int a .h” int main() { int item [100]. itemp [t]) . } 130 . t<count . return 0. a++ ) for (b= count –1. & count ). item [b] = t.

call it using the name of a character array without any index. a null is 0. which requires the STDIO. C supports strings using one dimensional character arrays.Use Strings String is an array of characters A null character detrmines the end of string Some string functions Strcpy Strcat Strcmp strlen The most common use of the one-dimensional array in C is the string. but is replaced by null.H header file. The carriage return is not stored. The fact that you must define the array that is going to hold a string to be one byte lager than the largest string it will be required to hold. which terminates the string. In C. this program reads and writes a string entered at the keyboard.h” int main() { 131 . The gets() function reads characters until you press RETURN. #include “stdio. For example. gets(). Unlike most other computer language C has built in string data type. To read a string from the keyboard you must use another C’s standard library function. to make room for the null. A string constant is also null terminated by the compiler automatically. A string is defined as a null terminated array. To use gets(). Instead.

Here is the previous program rewritten. /* output the string */ return 0. The gets() function performs no bounds checking. gets(str) . In the user was output to the screen a character at a time. The C standard library supplies many string related strcmp(). printf(“Enter a string (less then 80 chars ): \n”). If you wanted to output a newline.char star[80] . i++ ) printf(“%c”. int i . } Notice how the program uses the fact that a null is false to control the loop that outputs the string. str[i] . printf (str). you could output str like this : printf( ‘%s\n “.H.h” int main() { char star[80] . These functions require the header file STRING. printf(“Enter a string (less then 80 chars ): \n”). There is however. a much easier way to display a string. return 0. Let’s look at each now. gets(str) . str ) : This method uses %s format specifier followed by the newline character and uses the array as a second argument to be matched by the %s specifier . be sure to call it with an array large enough to hold the expected input. 132 . and strlen(). using printf (). so it is possible for the user to enter more characters than the string that gets() is called with can hold. Therefore. str [i] ). for (i =0 . #include “stdio. you simply use str without any index as the first argument to printf(). } Since the first argument to printf () is a string.

s2). from). “hello”). “there ). The contents of from are unchanged. The strcmp() function compares two strings. This fragment prints 0. char str [80] .The strcpy() function has this general form. so you must make sure that the array on the receiving end is large enough to hold what is being copied. 133 . because the strings are the same. strcpy(str. Therefore. Also. that is. It copies the contents of from to to. str). This fragment displays hello there. this fragment copies the string “hello str and displays it on the screen. the comparison is case sensitive. printf(“%s”. in dictionary order. It performs no bounds checking. It returns 0 if the strings are the same. Its general form is strcat(to. strcpy (str. strcpy (to. It adds the contents of from to the contents of to. For example. The strings are compared lexicographically. This is called concatenation. including the null terminator . printf (str). a string is less then another when it would appear before the other. The strcpy() function performs no bounds checking. strcat(str. so you much make sure that to is large enough to hold its current contents plus what it will be receiving. lowercase characters being greater than uppercase. from). char str [80]. strcmp(s1. The strcat() function adds the contents of one string to another. “hello”). It returns less then 0 if s1 is less s2 and greater then 0 if s1 is greater than s2. The comparison is not based upon the length of the string. It takes the general form.

str2 ). str2 ). #include “string. The strlen() function returns the length. strlen(str1)) . str2 . This program requests input of two strings. strlen(str2)). else if(i< 0) printf (“%s is less than %s\n “. str1 . str2 ). strcmp(“one “. This means that if strlen() is called using the string “test”. printf(“Enter the first string : “) .\n”). in characters. str2 ) . str1). printf(“%s is %d chars long \n “. Its general form is strlen(str) . str1. str1. “one”)).h” int main() { char str1[80] .h” #include “stdio. str1. The strlen() function does not count the null terminator. str2). else printf (“%s is greater than %s\n “. gets ( str2). of a string. 134 . printf(“Enter the second string : “). /* Concatenate str2 to end of str1 if there is enough room */ if (strlen (str1 ) + strlen (str2 )< 80 ) { strcat (str1.printf(“%d”. str2 [80] . str2). } /* copy str2 to str1 */ strcpy (str1. int i. gets(str1). it will return 4 . printf(“%s \n”. if (!i) printf(“the strings are equal . /* compare the string */ i = strcmp (str1. printf(“%s\n”. /* see how long the strings are */ printf(“%s is %d chars long \n “. then demonstrates the four string function with them.

j= atoi (temp). multiply. perform the operation */ if (! strcmp (command. else if (!strcmp (command. and then does what the command requests. subtract. It allows the user to Add. printf (“Enter second number : “) .h” int main() { char command[80] . “add”)) printf(“%d\n “.return 0. gets (command). or divide. i/j ). it uses a command line interface. int i . printf(“Enter first number: “). temp [80] . i-j ). “multiply”)) printf(“%d\n “. . ) { printf(“Operation ? “).h” #include “stdlib. /* see if user wants to stop */ if (!strcmp (command. 135 . /* Now. but does not use a menu. Instead. i+j ). “quit”)) break. “devide”)) { if (j) printf(“%d\n “. Many operating system use command line interfaces. The following program is similar to a program developed in previously. “ subtract”)) printf(“%d\n “. for example. } else if (!strcmp (command. else if (!strcmp (command. j. Unlike a menu. a command-based interface displays a prompting message. which allows the user to make a selection. } One common use of strings is to support a command-based interface. #include “string. i*j ). gets(temp). i= atoi (temp).h” #include “stdio. gets(temp). for ( . waits for the user to enter a command.

\n “). For example. “”). The atoi() function returns the integer equivalent of the number represented its string argument.H. } return 0. The atoi () function uses the header file STDLIB. Such a string is called a null string. 136 . atoi(“100”) returns the value 100.else printf( “ unknown command. It contains only one element : the null terminator . using a strcpy() statement like this : strcpy(str. } Notice that this example also introduces another of C’s standard library function: atoi(). You can create a string of length 0.

to add a dimension. Assuming this rightmost index will change most quickly when the array is accessed sequentially from the lowest to highest memory address. As you can see in the example. int count [10] [12]. For example.Create Multidimensional Arrays Array may be multidimensional Two dimension array decleration has the general form Type varName[RowSize][ColSize]. to create a 10x12 two dimensional integer array called count. you can think of it looking like that shown in the following figure. 0 1 2 3 4 0 1 2 3 137 . Array element can be determined by two indexes varName[Row][Col] An array of strings is a two dimension array of characters In addition to one-dimensional arrays. For example. given a 4x5 integer array called two_d. you simply specify its size inside square brackets. column format. you create arrays of two or more dimension. A two dimensional array is essentially an array of one-dimensional arrays and is most easily thought of in a row. you would use this statement.

} return 0. A good use of a two dimensional array is to manage lists of numbers. the following statement creates a 10x12x8 three dimensional array. then displays the array in row. i < 4 . i ++ ) { for (j= 0. column format . grouped by month . For example. float values [10] [12] [8] . twod [i] [j]) . this program loads a 4x5 arrays with the products of the indices. for (i= 0. for (i= 0 . i++) twod [i] [j] = i * j . simply add the additional.h” int main() { int twod [4] [5] . A three dimensional array is essentially an array of two-dimensional arrays. #include “stdio. you could use this two dimensional array to hold the noontime temperature for each day of the year. i < 4. } The program output looks like this: 00000 01234 02468 036912 To create arrays of three dimensions and greater. j. printf (“\n”) . For example. i < 5. int i.Two-dimensional arrays are used like one-dimensional ones. 138 . j++) printf (“%d “ . For example. j < 5. i++) for (i= 0.

The first constant will be placed in the first position of the array the constant in the second position. i++) for (j=0. int i. j. In the following example. printf (“Enter number of points : “ ). scanf (“%d “. i+1 . printf (“%d\n”. i < 5. j++) { printf(“Quarter %d. player %d. } return 0. player %d.float yeartemp [12] [31] .h” int main() { int bba11 [5] [4] . i++) for (i= 0. The general form of array initialization for one dimensional arrays is shown here: Type array name [size] = {value-list } . i++) { printf (“Quarter %d. & bba11 [i] [j] . #include “stdio. } Initialize Arrays Like other types of variables. In the same vein. for (i= 0. i<4 . “. 139 . j+1 ). Note that a semicolon follows the }. a five element integer array is initialized with the squares of the numbers 1 through 5 . j+1 ). This is accomplished by specifying a list of values the array elements will have. you can give the elements of arrays initial values. j < 5. the following program can be used to keep track of the number of points scored per quarter by each member of a basketball team. The value-list is a comma-separated list of constants that are type compatible with the base type of the array. “. i < 4. bba11 [i] [j] . i+1 . and so on. } /* display results */ for ( i=0 .

64. 16 . even though “Herb” is only 4. 6. sqr[0] [1] to contain 2. 8. and so forth. char name [5] = “Herb”. sqr [0] [2] to hold 3. 8. you can initialize the array using a quoted string. the compiler simply counts the number of initialization constants and uses that value as the size of the array. This means that I [0] will have the value 1 and I [4] will have the value 25. When a string constant is used. 25 }. int pwr[] = {1. 4 . ‘B’. If the character array is going to hold a string . Multidimensional arrays are initialized in the same way as one sqr is initialized with the values 1 through 9 . 9 }. You can initialize character arrays two ways. you must make sure that the array you declare is long enough to include the null. Because strings in C must end with a null. you need not specify the size of the array simply put nothing inside the square brackets. and ‘C’ . you simply specify each character using a comma-separated list. 4. First. 128}. 5. ‘B’ . 4. 7. This is why name is 5 character long. Notice that no curly braces surround the string. 9. 16. this initializes a with the letter ‘A’ . 2. if you don’t specify the size. For example. For example. ‘C’ } . If you are initializing a one-dimensional array. the compiler automatically supplies the null terminator. if the array is not holding a null terminated string. as shown here . 32. using row order . They are not used in this form of initialization. char a [3] = {‘A’ . 2. Int sqr [3] [3] = { 1. 3. 140 .int I [5] = { 1. This initialization causes sqr[0] [0] to have the value 1.

8. For example. The advantage to this declaration over the sized version is that tables may be lengthened or shortened without changing the array dimensions. the declaration of sqr as an unsized array is shown here . For multidimensional array you must specify all but the leftmost dimensional to allow C to index the array properly. Int sqr[ ] [3] = { 1. 7. In this way you may build tables of varying lengths with the compiler allocating enough storage for them automatically. 9 }. 5. and the second element contains its average speed rating. 6. at a later date. char prompt[ ] = “enter your name : “ . Array that don’t have their dimensions explicitly specified are called unsized arrays. For example. The program allows a user to enter the number of a processor. This helps avoid counting errors on long lists.Causes the compiler to create an initialized array eight elements long. An unsized array is useful because it is easier for you to change the size of the initialization list without having to count it and then change the array dimension. an unsized array is used to hold a prompting message. you wanted to change the prompt to “Enter your last name: “ you would not have to count the characters and then change the array size. A common use of an initialized array is to crate a lookup table. in this program a 5x2 two-dimensional array is initialized so that the first element in each row is the number of a CPU. 141 . Unsized array initializations are not restricted to only singly dimensioned array. If. Here. which is especially important when initializing string. and then it looks it up the table and reports its average speed. 2. 3. 4.

int i . 80386. break . i ++ ) if (processor == cpu [i] [0] ) { printf (“Average speed is %d mhz . & processor ) . #include “stdio. } Even though an array has been given an initial value. printf (“Enter the number of the processor : “) . 4. “hello”) . 40 }. } /* report error if not found */ if (i == 5 ) printf(“processor not found .h” #include “string. scanf(“%d”. \n “) . i < 5 . \n “.#include “stdio. /* look it up in the table */ for (i =0 . 80486. 4. 20.h” int main ( ) { long cpu [5] [2] = { 8088. its contents may be changed . return 0. 80286. cpu [i] ).h” int main( ) { char str [80] = “ I like C” . printf(str ) . 10. return 0. 8086. for example this program prints hello on the screen . } 142 . strcpy (str. long processor .

What do you think it defines? char names [10] [40]. printf( names [0]). the way you think about it will be slightly different. use this statement. here is a small string table. For example. one at a time. This statement specifies a table that can contain 10 strings. char animals [3] [5] [80]. For example. and each string can hold 80 characters. to output the first string. use this printf ( ) statement . To stop the program. To access a string within this table. enter a negative number . For example. specify animals [2] [1]. specify only the first index. to access the second string in the third list. By the same token. 143 . A twodimensional string table is created like any other two dimensional array. you must specify the first two dimensions. each up to 40 character long (including the null terminator). are very common in C programming. To access a specific string in this situation. to read a string from the keyboard into the third string in names. This program lets you enter ten strings. often called string tales. in any order you choose . gets(names [2]) . Each list is five string long. then lets you display them.Build Arrays of Strings Arrays of strings. The declaration that follows creates a three dimensional table with three lists of strings . However.

“Kind”.h” int main( ) { char text [10] [80] . “”. i++){ printf (“%d : “. “house “. gets (text [i]). return 0. 144 . /* adjust value to match array index */ if (i >=0 && i < 10) printf (“%s\n”. “ fahren “. “Jahr”. for (i =0 . “year”. “drive “. “zu”. i <10. scanf(“%d”. “Hund”. /*English to German Translator. i + 1 ). “” }. “nein”. the following program uses an initialized string table to translate between German and English. “no”.#include “stdio. The only time they are not needed is when a single string is being initialized. text [i] ). “Ich”. “child”. i --.h” int main( ) { char words [ ] [2][40] = { “dog”. */ #include “stdio. “to”. } do { printf (“Enter number of string (1-10): “) .h” #include “string. “I”. int i . } while (i>0) . &i). “Haus”. Notice that curly braces are needed to surround the list. For example. } You can initialize a string table as you would any other type of array.

For example. } You can access the individual characters that comprise a string table by using the rightmost index. printf(“Enter English word: “) . #include “stdio. “course “. } if (!strcmp (words [i] [0] . } return 0. “” )) { if (!strcmp (english . return 0. “human “ . “” )) printf (“Not in dictionary \n “ ) . break . /* now . } i++ . j. i=0. “of “. /* Search while null string not yet encountered */ while (strcmp (words [i] [0] . text [i] [j] . “in”. int i. display them */ for ( i = 0 . “” }. gets (english ).char english [80] . } 145 . “the “. the following program prints the string in the table one character at a time. int i . j++) printf(“%c”. words [i] [1] ) . words [i] [0] )) { printf (“German translation : %s “.h” int main( ) { char text [] [80] = { “when “. “events “ . text [i] [j] ) . text [i] [0] . i++) { for ( j = 0 . printf (“ “).

field_i is the name of the ith field of the structure and its type is type_i. For the same reason.Structures A Structure decleration is of the following form: struct structure_name { type_1 field_1. However. • • 146 . : : type_n field_n: }. To copy the value of one structure variable to another. a field may have the same name as some variable in the program. one can use the assignment operator. structure_name is the name of the structure. Here struct specifies that the following decleration is a structure. two different structure types may share a field name. type_2 field_2. It is possible that a field of a structure is of another structure type. Some important points about structures: • • • The field names of a structure must all be distinct. No ambiguity arises since we specify the structures type also while accessing any field.

Unit 6 147 .

you will be introduced to using pointers as parameters to functions. One reason that pointers are so important is that much of the power of the C language is derived from the unique way in which they are implemented in C. A pointer is basically the address of an object. 148 . You will learn about the special pointer operators. Also. and how arrays and pointers are related. pointer arithmetic.Dynamic Allocation Pointers is C variable Type Pointers carries an address of another variable or defined memory location Some Arithmatic operations can act on a pointer A special relation between pointers and arrays This unit covers one of C's most important and sometimes its most troublesome feature: the pointer.

Here. 149 . if a variable called p contains the address of another variable called q. This tells the computer that a pointer variable is being created. For example. then p would have the value 100. type is the base type of the pointer. C contains two special pointer operators: * and &. type *var name. Therefore if q is at location 100 in memory. then p is said to point to q. For example the following statement creates a pointer to an integer int *p. The base type specifies the type of the object that the pointer can point to. Notice that an asterisk precedes the variable name.Understand Pointer Basics Pointer decleration type *varName. The & operator returns the address of a variable The * operator returns the value stored at the address Pointers can deal with only the addition and subtraction operations. To declare a pointer variable/ use this general form. A pointer is a variable that holds the memory address of another object.

the process is called indirection is possible to use the *operator on the left side of an assignment statement in order to assign a variable a new value using a pointer to it. and q. p is assigned the address of q. the value is displayed using the * operator applied to p." Therefore this line can be read as "assign p the address of q. When a variable's value is referenced through a pointer. For example this program assigns q a value indirectly using the pointer p." Therefore. Next. The * operator can be verbalized as "at address. #include "stdio. *p). Lets see why. which uses the same symbol. First. which is declared as an integer pointer. In the next line.The & operator returns the address of the variable it precedes. The * operator returns the value stored at the address that it precedes. Defines two variables: p. #include "stdio. q." Finally. You can verbalize the & operator as "address of.h" int main( ) { int *p. the line int *p.h" int main( ) { 150 . /* assign p the address of q */ printf("%d”. /* display q's value using pointer */ return 0. /* assign q 100 */ p = &q. (The * pointer operator has no relationship to the multiplication operator. q is assigned the value 100. } This program prints 100 on the screen. q. q = 100.) For example examine this short program. which is an integer. the printf() statement can be read as "print the value at address q" which is 100.

consider the following fragment. int q. q. 151 . Never use a pointer to one type to point to an object of a different type. However. That is. the assignment statement uses the 2 bytes allocated to q as well as two adjacent bytes. thus causing an error. for example. which will most likely be where fp is stored. this fragment is wrong.23. or how many bytes to compare if an indirect comparison is made. the C compiler uses the base type to. Although not syntactically incorrect. . The base type of a pointer is very importantAlthough C allows any type of pointer to point anywhere in memory. float *fp. The pointer fp is assigned the address of an integer. ints are shorter than floats. q) . In general. Pointers are used to support linked lists and binary trees. it is the base type that determines how the object pointed to will be treated. This is how C knows how many bytes to copy when an indirect assignment is made. return 0. fp = &q. } In the two simple example programs just shown. /* what does this line do? •*-/ *fp = 100. To understand the importance of this. Therefore. and this assignment statement causes memory adjacent to q to be overwritten. it is very important that you always use the proper base type for a pointer. you will understand why pointers are important. /* get q's address */ *p = 199.int *p. p = &q. This address is then used on the left side of an assignment statement to assign a floating-point value. there is no reason to use a pointer. assuming 2-byte ints and 4-byte floats. determine how many bytes are in the object pointed to by the pointer. However. /* assign q a value using a pointer */ printf("q's value is %d". as you learn more about C.

Hence. To graphically illustrate how indirection works. q. the compiler will still let you use a null pointer.If you attempt to use a pointer before it has been assigned the address of a variable. trying to indirectly assign a value using p is meaningless and dangerous As pointers are defined in C. by convention. memory looks like this 152 . usually with disastrous results. Further assume that q is located at memory address 102 and that p is right before it. *p == 10.p is not pointing to anything */ As the comment notes. After this statement p = &q. the pointer p contains the value 102. after this assignment. It does not give it any meaningful initial value. 0 is. However. a pointer that contains a null value (0) is assumed to be unused and pointing at nothing. This is why the following fragment is incorrect. Therefore. main( ) {int *p. assumed to be an invalid memory address. In C. memory looks like this: Location 100 102 After the statement *p = 1000. assume these declarations int *p. declaring a pointer variable simply creates a variable capable of holding a memory address. /* incorrect . your program will probably crash. at location 100. the pointer p is not pointing to any known object. Remember. Contents 102 unknown executes.

h" int main( ) ( int *p. /* attempt to assign q a value */ q = *p. To illustrate why you must make sure that the base type of a pointer is the same as the object it points to. but harmless. you need to understand a few rules and restrictions 153 . temp.34. float q. Since p is an integer pointer.34F. pointers may be used like other variables. Fails to copy the number because only 2 bytes (assuming 2-byte integers) will be transferred. to which the indirection operators may be applied. /* this will not print 1234. indeed. temp = 1234. /* using indirection through an integer pointer */ printf("%f". q). } Even though p points to temp. which does. It simply holds q's address.Location 100 102 Contents 102 1000 Remember. the assignment q = *p. the value of p has nothing to do with the value of q. hold the value 1234. p = &temp.34 */ return 0. try this incorrect but benign program /* This program is wrong. However.*/ #include "stdio. it cannot be used to transfer a 4-byte quantity (assuming 4-byte floats) Restrictions to Pointer Expressions In general.

Further. int *p . It is possible to apply the increment and decrement operators to either the pointer itself or the object to which it points. as defined by its base type. For example. This statement causes p to point to the 200th integer past the one to which p was currently pointing. By the same token. Each time a pointer is incremented. and --. . assuming integers are two bytes long. assume that an integer pointer called p contains the address 200. divide. you may not perform any other type of arithmetic operations you may not multiply. Because characters are one byte long. and a decrement decreases its value by one. p will have the value 202. there are only four other operators that may be applied to pointer variables: the arithmetic operators +. p = p + 200.. then the resultant value contained in p would have been 204. Executes. . it will point to the next item. assume that p points to an integer that contains the value 1. What do you think the following statement will do? 154 . add a floating-point number to a pointer. You may add or subtract any integer quantity you want to or from a pointer. beyond the one currently pointed to. you may add or subtract only integer quantities You cannot. For example. Pointer arithmetic differs from "normal" arithmetic in one very important way: it is performed relative tom the base type of the pointer. However. an increment increases the pointer's value by one. ++. for example. Aside from addition and subtraction of an integer. you must be careful when attempting to increment the object pointed to by a pointer. the following is a valid fragment. or take the modulus of a pointer. if p had been a float pointer (assuming 4-byte floats). . After the statement p++. The only pointer arithmetic that appears as "normal" occurs when char pointers are used. or example.In addition to the * and & operators.

fp = &f. Contrary to what you might think.*p++. ip. ip++ . i. Shortly you will see an example of pointer comparisons. We can use this printf capability to illustrate several aspects of pointer arithmetic. The parentheses cause the value pointed to by p to be incremented. for example. 155 . double *dp. /* print the current values */ printf("%p %p %p %p\n". shows how all pointer arithmetic is relative to the base type of the pointer. You will shortly see. dp = &d. pointer comparisons only make sense if the pointers relate to each other if they both point to the same object. You may compare two pointers using the relational operators. f. /* now increment them by one */ cp++. cp. fp. At this point you might be wondering what use there is for pointer arithmetic. int *ip. You can use printf() to display the memory address contained in a pointer by using the %p format specifier. dp). fp++.h" int main( ) { char *cp. ip = &i. To increment what is pointed to by a pointer. #include "stdio. cp = &ch. d. However. ch. The following Program. this statement first increments p and then obtains the value at the new location. dp++ .. float *fp. you must use a form like this: (*p)++. for example. however that it is one of the most valuable components of the C language.

q. cp. return 0. fp. q. dp). but p has been incremented. However.h" int main( ) { int *p. The others will be incremented by the number of bytes in their base types. p) . q. } After this program has executed. } Although the values contained in the pointer variables in this program will vary widely between compilers and even between versions of the same compiler. q. (*p)++. printf("%p ". q = 1. ip.h" int main( ) { int *p. /* now q is incremented and p is unchanged •*/ printf("%d %p". return 0. p)./* print their new values */ printf("%p %p %p %p\n". typically 2 for ints.. p = &q. you will see that the address pointed to by ch will be incremented by one byte. q still has the value. /* this will not increment q */ printf("%d %p". q = 1. p) .. print£("%p ". if the program is written like this #include "stdio. p = &q. and 8 for doubles. The following program illustrates the need for parentheses when you want to increment the object pointed to by a pointer instead of the pointer itself. #include "stdio. *p++. return 0. p) . } q is incremented to 2 and p is unchanged 156 . 4 for floats.

The gets() function uses the pointer to load the array it points to with the characters you enter at the keyboard. this is exactly what you can do. but a pointer. In fact. It is this relationship between the two that makes their implementation both unique and powerful. When you use an array name without an index. This is why no indexes are used when you read a string using gets(). for example.However. This important point was not mentioned in the preceding Unit on arrays because you had not yet learned about pointers. You will see how this is done later. you may only pass a pointer to the array. this fact is crucial to understanding the C language. And. #include "stdio. you are generating a pointer to the start of the array. in fact. they are often interchangeable.Use Pointers with Arrays Relation between pointers and arrays name without an index is a pointer to the start of the array Using pointer arithmetic you can access array elements Pointers to String Constants Arrays of Pointers Multiple Indirection In C. What is being passed to gets() is not an array. pointers and arrays are closely related.h" int main( ) { 157 . you cannot pass an array to a function in C. Consider this program. In fact. Since an array name without an index is a pointer to the start of the array. it stands to reason that you can assign that value to another pointer and access the array using pointer arithmetic.

The following program. /* assign p the address of start of a */ /* this prints a's first/ second and third elements */ printf("%d %d %d\n". Generally. int *p. 158 . Now you should be able to fully understand why pointer arithmetic is done relative to the base type it allows arrays and pointers to relate to each other. 7/ 8. You might be surprised to learn that you can index a pointer as if it were an array. p = str. i++) printf("%c". 5. p[i]) . both printf() statements display the same thing. 6. *p. return 0. you must multiply the row number by the number of elements in the row and then add the number of the element within the row. p[i]. To use a pointer to access multidimensional arrays. 4. 10}. p = a. /* loop until null is found */ for(i=0. with multidimensional arrays it is easier to use array indexing rather than pointer arithmetic. in this array float balance [10] [5]. Pointers and arrays are linked by more than the fact that by using pointer arithmetic you can access array elements. Therefore.int a[10] = {1. (assume p is a float pointer) you must use a fragment like this * (p + (3*5) + 1) To reach the desired element. for example. each row is five elements long. 9. is perfectly valid. /* this does the same thing using a */ printf("%d %d %d". you must manually do what the compiler does automatically. 2. a[2]). *(p+2)). 3. int i.h" int main( ) { char str[ ] = "Pointers are fun". #include "stdio. a[1]. *(p+1). The parentheses in expressions such as *(p+2) are necessary because the * has a higher precedence than the + operator. } Here. a[0]. to access balance[3][l] using a pointer. char *p. For example.

int i. *(str+3) = ‘c’. #include "stdio. Although you can index a pointer as if it were an array. assuming the previous program. 159 . printf ("%c". using pointer arithmetic is faster than using array indexing. i++) p[i] = 'A'+i.} Keep one point firmly in mind. For example. /* wrong */ for(i=0. you should only index a pointer when that pointer points to an array. *(str+3)) . however. For example. p = &ch. The reason is that. in general. if you tried to execute it. you would probably crash your computer. modify the value of the pointer generated by using an array name. Since ch is not an array it cannot be meaningfully indexed. } You cannot.h" int main( ) { char str[80]. use pointer arithmetic rather than array indexing to access elements of the array. it is wrong. i<10. For somewhat complex reasons a C compiler will generally create faster executable code for an expression such as *(p+3) than it will for the comparable array index p[3J Because an array name without an index is a pointer to the start of the array. you will seldom want to do this. char *p ch. While the following fragment is syntactically correct. you can if you choose. this program is perfectly valid and prints c on the screen. this is an invalid statement: str ++.

printf("Enter a string: "). For tolower(). p = str. are called using a character argument.h" #include "stdio. otherwise the character is returned unchanged. The following program requests a string from the user and then prints the string. i++) str[i] = tolower(str[i] ) .H. if the character is a lowercase letter. These functions use the header file CTYPE.The pointer that is generated by str must be thought of as a constant that always points to the start of the array. printf ("%s\n". 160 . #include "ctype. int i . str). printf ("%s\n". a pointer is used to access the string.h" int main( ) { char str[80]. the uppercase equivalent is returned.h" int main ( ) { char str [80]. } The same program is shown below. Therefore.h" #include "stdio. i++) str[i] = toupper(str[i]). *p. it is invalid to modify it and the compiler will report an error. Two of C's library functions/ toupper() and tolower(). first in uppercase letters and then in lowercase. str[i]. In the case of toupper(). only this time. otherwise the character is returned unchanged. printf("Enter a string: ") . if the character is an uppercase letter. /* lowercase string */ return 0. #include "ctype. str[i]. gets(str) .This version uses array indexing to access the characters in the string so they can be converted into the appropriate case. the lowercase equivalent is returned. str). This second approach is the way you would see this program written by professional C programmers because incrementing a pointer is generally faster than indexing an array. /* uppercase string */ for(i=0. gets (str) . for(i=0.

a small digression is in order. } printf("%s\n". *p2. str). the following program uses a pointer to copy the contents of one string into another in reversed order.1. /* reset p */ while(*p) { *p = tolower(*p) . The routine while(*p) { *p = toupper (*p) . } Before leaving this example. *p1. /* null terminate str2 */ 161 . } will generally be written like this by experienced programmer while(*p) *p++ = toupper(*p). p++. } printf("%s\n". Because the ++ follows the p. char str2 [80]. /* make p1 point to end of strl */ p1 = strl + strlen(strl) . you can decrement a pointer as well. although most of examples have been incrementing pointers. #include "stdio. p2 = str2. while(p1 >= strl) *p2++ = *p1--. p++. /* lowercase string */ return 0. For example.h" #include "string.while(*p) { *p = toupper(*p). /* uppercase string */ p = str. the value pointed to by p is first obtained and then p is incremented to point to the next element Remember that. str).h" int main( ) { char strl[ ] = "Pointers are fun to use". p++.

Also. } Use Pointers to String Constants As you know. It then copies the contents of strl into str2 in reverse order. str2) . First. When the compiler encounters such a string. 162 . p is declared as a character pointer. it stores it in the program's string table and generates a pointer to the string. Therefore. and p2 to the start of str2. C allows string constants enclosed between double quotes to be used in a program. printf("%s %s". p = "one two three". } This program works by setting p1 to point to the end of str1. This means that it may point to an array of characters. Notice the pointer comparison in the while loop. It is used to stop the copying process when the start of strl is reached. return 0 } Let's see how this program works. the following program is correct and prints one two three on the screen. printf(p) . The loop is the equivalent of this one. #include "stdio. p2++. notice the use of the compacted forms *p2++ and *pl--. return 0. as shown here. while (pi >= strl) { *p2 = *pl. p1--. one two three is displayed on the screen. This program can be written more efficiently. When the compiler compiles the line p = "one two three".h" int main ( ) { char *p. For this reason. when p is used in the printf() statement.' it stores the string in the program's string table and assigns to p the address of the string in the table. strl.*p2 = '\0' .

Create Arrays of Pointers Pointers may be arrayed like any other data type. printf(p) . For example. To save typing. #include "stdio. 163 . the following statement declares an integer pointer array that has 20 elements.h" #include "string. gets (str) . printf(p) . char str[80] . return 0. } while(strcmp(p.#include "stdio. This program continues to read strings until you enter stop. return 0. and all references to it will reflect the change. you might elect to initialize a pointer to the string and then simply use the pointer when the message needed to be displayed. str)) . for example: char *p = "Insert disk into drive A. printf (p) . For example. } Here. Another advantage to this approach is that to change the prompt. int *pa[20].h" int main ( ) { char *p = "one two three". suppose that you had a program that at various different points would prompt the user to insert a diskette into drive A. p is initialized to point to the string. do{ printf("Enter a string: ") .h" int main( ) { char *p = "stop". you only need to change it once. } Using pointers to string constants can be very helpful when those constants are quite long. then press ENTER".

h" char *p[][2] = { "Red Delicious". "Disk full". To use the program.". void error (int err_num) { printf(p[err_num]) . To assign the integer pointed to by the third element of pa the value 100. the only value that the array elements may hold are the addresses of integer variables. Because pa is an array of pointers. enter the name of the apple. char *p[ ] = { "Input exceeds field width". #include "stdio. For example. "red. Probably the single most common use of arrays of pointers is to create string tables in much the same way that unsized arrays were used in the previous Unit. "Gala". "yellow". } The following program uses a two-dimensional array of pointers to create a string table that links apple varieties with their colors. "Disk write error" }. 164 . "Printer not turned on". "reddish orange". and the program will tell you its color. "red".h" #include "string. "Paper out". this function displays an error message based upon the value of its parameter err_.num. use the statement: *pa[2] = 100. "Winesap". "Golden Delicious". "Out of range".The address of an integer variable called myvar is assigned to the ninth element of the array as follows: pa[8] = Smyvar.

For example. but rather a pointer to a character pointer. This is called multiple indirection. "Mutsu". "green". /* get address of ch */ mp = &p. int main ( ) { int i. char **mp. p[i][0] ) ) printf("%s is %s\n"/ apple. gets(apple) . Become Acquainted with Multiple Indirection It is possible in C to have a pointer point to another pointer. *p[i][0]. this declaration tells the compiler that mp is a pointer to a character pointer . "yellow". for(i=0. Since null strings terminate the list. the first pointer contains the address of the second pointer.char **mp. this value will be 0 (false) when the end of the table is reached. In all other cases it will be non-0. "red"."Lodi". For example. ch. To declare a pointer to a pointer an additional asterisk is placed in front of the pointer's name. "Cortland". } return 0. p = &ch. } Look carefully at the condition controlling the for loop. *p. printf("enter name of apple: "). which points to the location containing the object. It is important to understand that mp is not a pointer to a character. Accessing the target value indirectly pointed to by a pointer to a pointer requires that the asterisk operator be applied twice. p[i][1]). When a pointer points to another pointer. i++) { if{!strcmp(apple. char apple[80]. /* get address of p */ 165 . "Jonathan". "red". "". The expression *p[il[0] gets the value of the first byte of the ith string. and the loop will repeat. “” /* terminate the table with null strings*/ }.

**mfp = 123. ch is assigned a value indirectly by using two pointers. **mfp. p = str. **mp. mfp = &fp. #include "stdio. then through the use of multiple indirection. pr.h" int main( ) { char *p. multiple indirection beyond a pointer to a pointer is very difficult to follow and is not recommended. str[80]. /* assign ch the value A using multiple indirection */ As the comments suggest. gets (*mp): printf (“ Hi %s”. } Notice that when mp is used as an argument to both gets() and printf ( ) . #include "stdio. mfp) . However.h" return main( ) { float *fp. val. only one * is used. printf (‘Enter your name: “). Multiple indirection is not limited to merely "a pointer to a pointer.**mp = 'A'. mp -= &p. 166 . val.903. } This program shows how you can input a string using gets() by using a pointer to a pointer to the string. The following program assigns val a value using multiple indirection. mp ). fp = &val." You can apply the * as often as needed. It first displays the value directly.i.ntf("%f %f". This is because both of these functions require a pointer to a string for their operation. return 0.

**mp is a pointer to p. p is a pointer to the string str. Therefore. *mp is a pointer to str. 167 . However.Remember.

The program that follows creates its own version of puts() called myputs( ). for example .This is why functions like strcpy ( ).This means that the function can change the variable used to call the function. it must be passed a pointer to that argument. Examples Another of C's standard library functions is called puts( ). the code inside that function has access to the variable pointed to by the parameter. the function must be declared as receiving a pointer of the same type. Because it is passed pointers. when you call a function like strlen() with the name of a string. When you pass a pointer to a function. This is why you need to precede a variable's name with an & when using scanf( ).Use Pointers and Function Parameters Pointers as function parameters Call-By-Value and Call-By-Reference Arrays as Arguments Pointers may be passed to functions.. this is a character pointer. it writes its string argument to the screen followed by a newline. In the case of strlen(). For example. you are actually passing a pointer to a function. When you pass a pointer to a function. the function is able to modify the array that receives the string. 168 . In order for scanf ( ) to modify the value of one of its arguments.can work.

int main ( ) { myputs("this is a test") . /* null terminates the string */ } Call-By-Value and Call-By-Reference 169 .h" void myputs(char *p). mystrcpy (str. and the parameter p must be declared as a character pointer in order to receive it. printf(str) . the myputs( ) function is actually called with a character pointer. "this is a test"). Therefore. } printf("\n") .h" void mystrcpy (char *to. } void myputs(char *p) { while(*p) { printf("%c". When the compiler encounters a string constant. return 0. it places it into the program's string table and generates a pointer to it. *p) . } void mystrcpy (char *to. *to = '\0'. char *from) { while(*from) *to++ = *from++. p++. int main( ) { char str [80] . return 0. called mystrcpy(). #include "stdio. The following program shows one way to implement the strcpy( ) function.#include "stdio. } This program illustrates a very important. char *from).

int b=93. z=*y-*x. rather than its value. the variable in the calling program is not altered. return(z). In a call-by-reference. This approach requires less program memory than a call-by-value. more than one value can be returned by the function. The arguments are now passed as a call-by-reference. the address of the argument. Additionally. the variables in the calling program can be altered. /* * C program to illustrate a call-by-reference. you achieve a call-by-reference by using a pointer as an argument.&b). } int subtractor(int *x. */ #include <stdio. a copy of the variable's value is actually passed to the function. Since a copy is passed. c). printf(“The difference is: %d\n”. When you use a call-byreference. int c.h> int subtractor(int *x. int main() { int a=5. In C. int *y) { int z. return (0). c=subtractor(&a. The major limitation to the call-by-value technique is that typically only one value is returned by the function. } Arrays as Arguments 170 .int *y).When variables are passed to function. but more on that later. Calling a function by value is a popular means of passing information to a function and is the default method in C. is passed to the function. The next example uses the subtracter function from the previous Unit.

int main() { int myarray[5]={5. The information in myarray is transferred by passing the address of the first element.21. by specifying the name of the array.8. only the name myarray is specified.h> void printer(int *data). you can pass an array by specifying a pointer of the element type. 171 . /* * C program will call a function with an array. return (0). * Function uses a pointer to pass array information*/ #include <stdio.data[i]).i<5. for(i=0. as you can see in the C example.20.78}. } Notice that when the function is called. You can also pass the address information by using an unsized array.In the following example. printer(myarray). In this case. printf(“Send information to function. Actually. \n"). the address of the first array element is passed via a pointer. } void printer(int *data) { int i. Since myarray is an array of integers.i++) printf(“The result is %d \n”. the contents of an array are passed to a function as a call-by-reference. you are providing the address of the first element in the array.

0. // #include <stdio.0. printf(“Send information to averaging function.i<10. int main() { float myarray [10] ={70. 1. // Function passes array information.h> void average(float data[ ]). i+1.14.8.3.2. for(i=0. avg). average(myarray). } avg=total/i.25. printf (“\nThe average is %f\n“. \n”). float avg.1. } The average is determined by summing each of the terms together and dividing by the total number of terms.67.23.5.0.141.234}.i++) { total+=data[i]. 172 .78.0. printf(“number %d is %f \n“.4. float total=0. } void average(float data[ ]) { int i. and calculates // the average of the numbers.0.// // C program will call a function with an array. data[i]). return (0).0.

y = "this is a constant string" . ..Dynamic storage allocation Static allocation and dynamic allocation malloc function free function We have met four classes of data: external. (Of course. . y = (char *)malloc(200 * sizeof(char)). duration and the forms allowed for initializations. which defines its scope rules. char *z = " arbitrary string".. the pointers themselves can be stored by any of the stated mechanisms. y = (char *)malloc(20 * sizeof(char*)). static. use yet another storage mechanism.) We illustrate the way the heap operates in terms of the following code segment: int main() { char *y. free(y). auto and register. which is memory that can be dynamically allocated at runtime and is accessed using pointers.. malloc and realloc. The standard functions. 173 . the heap. Each has an associated storage mechanism. char A[4]..

We do this later in main with the statement y = (char *)malloc(200 * sizeof(char)). You can also allocate and deallocate heap memory using the standard functions. which means that an identifier is associated with the same storage throughout the program execution. By contrast. At the point where main does the assignment y = " this is a constant string". the register data exists only while the function in which it is declared remains active and the same registers are also heavily used by the code otherwise generated by the compiler.) The compiler generates code that allocates storage for constant strings and also initializes it. In addition to the data on the stack. malloc. After using this space. the stack grows as each function is invoked and shrinks as it completes execution. The different memory mechanisms are that external and static forms exist throughout the program's execution.…. 174 . where malloc allocates space for 200 characters on the heap. So the pointers y and z and the array A are stored on the stack. you cannot rely on its initial value. Finally. the constant strings are stored in a persistent memory area (just like external and static data. Now the data declared in main is stored in the stack. We also classify the heap as a persistent form of storage because the same locations are allocated from the time of the malloc call until the storage is explicitly freed by the programmer (using a call to free or realloc) or the program completes. all that actually happens is that y takes the value of the address of the first letter in the constant string. we use free to make that space available for reuse in future calls to malloc. realloc and free. Since malloc does not initialize the memory it allocates. It is quite possible that the 20 locations allocated on our second call to malloc may reuse some of the 200 that were allocated on the first call.

Unit 7 175 .

<= in Though C supplies the standard qsort() function as part of the standard library. and the sorting of sequential disk files. First. Specifically. because qsort() is parameterized to operate on a wide variety of data.Sorting Sorting categories Sorting arrays Sorting sequential disk files Classes of Sort Algorithms By exchange By selection By insertion Judging Sorting Algorithms Sorting is the process of arranging a set of similar information into an increasing or decreasing order. the Quicksort algorithm (used by qsort()). (The generalization process inherently increases run time because of the extra processing time needed to handle various data types. it will run slower than a similar sort that operates on only one type of data. given a sorted list i of n elements then : i1 <= i2 <=…. Although very good for the general case. for three maim reasons. Second. The two general categories of sorting algorithms are the sorting of arrays (both in memory and in random access disk files). 176 . a generalized function like qsort() cannot be applied to all situations. may not be the best type of sort for specialized situations. the study and understanding of sorting is important.) Finally.

To sort the cards using insertion. To sort the cards using exchange. any element may be compared or exchanged with any other element at any time. The deck would be sorted when you had no cards in your hand. select the lowest-value card. you would place them into a new deck on the table always inserting them in the correct position.The main difference between sorting arrays and storing sequential files is that each element of the array is available all the time. only one: element is available at any one time. Generally. when information {such as a mailing list) is sorted. sorting techniques differ greatly between the two. Then you would select from the remaining cards on the table the lowest card and place it behind the one already in your hand. And hold it in your hand. a deck of cards. imagine. you would spread the cords on the table. As you took cards from the deck. With a sequential file. only a portion of that information is used as the sort key. That is. on a table and then proceed to exchange out-of-order cards until the deck is ordered. To sort by selection. face up. you would hold the cards in your hand and would take one at a time. Judging Sorting Algorithms 177 . but when an exchange is made the entire data structure is swapped. Because you always select the lowest card from those remaining on the table. and take it out of the deck. This key is used in comparisons. This process would continue until all the cards were in your hand. you would spread the cards. In a mailing list for example. Because of this difference. the cards in your hand would be sorted when the process was complete. but the entire address is sorted Classes of Sort Algorithms The three general methods that can be used to sort arrays are • • • By exchange By selection By insertion To understand these three methods. the zip code field might be used as the key.

Bubble Sort The best-known (and most infamous) sort is the bubble. exchanges of adjacent elements. In the following section representative sorts from each class of sorting algorithms are analyzed to judge their efficiency.Many different algorithms exist for each of the three sorting methods. the main key and the last name within the same ZIP code as the subkey. The general concept behind the Bubble sort is the repealed comparisons and. Later. and hardest when a list is in inverse order. Its name 178 . imagine a database that is sorted on a main key and a sub-key. and the list sorted again. but a terrible worst case A sort is said to exhibit natural behavior if it works least when the list is already in order. if necessary. but the general criteria for judging a sorting algorithm are based on the following questions: • • • • How fast. for example. can it sort information in an average case? How fast is its best and worst case? Does it exhibit natural or unnatural behavior? Does it rearrange elements with equal keys? How fast a particular algorithm sorts is of great concern. improved sorting methods are studied. this is one of the worst sorting ever conceived. The Bubble sort uses the exchange method of sorting. The best and worst-case run times are important if you expect to encounter one of these situations frequently. The. a sort must not exchange main keys of equal value . harder as the list becomes less ordered. simplicity. that its popularity is derived from its catchy name and its. When a new address is added to the list. The speed with which an array can be sorted is directly related to the number of comparisons and the number of exchanges (exchanges take more time). last names within ZIP codes) to be rearranged. Each algorithm has its merits. An exchange happens when two elements are swapped in the array. For reasons that well become evident. To guarantee this. A comparison occurs when one array element is compared to another. you do not want the subkeys (that is. To understand the importance of rearranging elements with equal keys. How hard a sort works is based on the number of comparisons and moves that must be executed. Later you will see that some sorts require an exponential amount of time per element to sort and some require logarithmic time. Often a sort will have a good average case. a mailing list with the Zip code as.

) This version of the Bubble sort can be used to sort a character array into ascending order.Bubble sort is driven by two loops Given that there are count elements in the array. printf( “the sorted string is : %s \n “ . return 0. a <count. int main () /* sort a string from the keyboard */ { char s[80. item [b-1] = item [b] . gets (s) . int count) /* bubble sort */ { register int a. bubble (s . this short program sorts a string typed in from the keyboard: void bubble(char *item. the outer loop causes the array to be scanned count-1 times This ensures that. ++a ) for (b=count . 179 /* exchange elements */ .comes from the method's similarity to bubbles in a tank of water. item [b] =t . --b ) { if(item [b-1 ] > item [b] ) { t= item [b-1] . b >= a. (A slightly optimized version of the Bubble sort will terminate if no exchanges occur. but this also adds another comparison to each pass through the inner loop. In this simplest form of the Bubble sort void bubble(char *item. for(a=1 . The. int count). strlen (s) ) . For example. } } } item is a pointer to the character array to be sorted and count is the number of elements in the array. every element is in its proper position when the function terminates. register char t . b . whore each bubble seeks its own level.1 .s ). in the worst case. The inner loop performs the actual comparisons and exchanges.] printf( “enter a string “ ) .

The number of exchange.} To illustrate how the Bubble sort works.001 seconds . the number of elements that are out of order approaches the number of comparisons. here are the passes used to sort dcab . sorting 100 elements will take about 5 seconds. whether or not the list is initially ordered. average and worst case.000. With the Bubble sort.) The Bubble sort is sort is said to be an squared algorithm because its execution time is a multiple if the square of the number of elements. then sorting 10 elements will take about 0. The numbers are .000 second or about 1400 hours—about two months of continuous sorting. is.3/4 (n2n) for the average case and 3/2(n2-n} for the worst case. 0 for the best case -an already sorted list. as you can see that as the list becomes less ordered. A Bubble sort. (Remember. the number of comparisons is always the same because the two for loops will still repeat the specified number of times.05 seconds. is bad for a large number of elements because execution time is directly related the number of comparisons and exchanges. This formula is derived from the FACT that the outer loop executes n-1 times and the inner loop n/2 times. there are three exchanges in a Bubble sort for every element out of order. Initial pass 1 pass 2 pass 3 dcab adcb abdc abcd When analyzing any sort. This means that the Bubble sort will always perform ½ ( n2-n ) comparisons where n is the number of elements to be sorted. you must determine how many comparisons and exchanges will be performed for the best.000-element sort (the size of a small telephone book) would take about 5. if you ignore the time it takes to exchange any out-of-position element and if each comparison takes 0. and sorting 1000 elements will take about 500 seconds. You can make same alight improvements to the Bubble sort to speed it up and to help its image. Multiplying these together gives the formula. A 100. For example. For example. the Bubble sort has one peculiarity an out-of-order element at the large end (such as the a in the decab array 180 . .

item [a-1 ] = item [a] . b = a. b=a. item [a] = t . } } c=b +1. b= count . a >= c. This suggests an improvement to the Bubble sort. but a misplaced element in the small end (such as the d) will rise very slowly to its proper place. Greatly out-of-place elements will travel more quickly to their correct positionsShown here. an improved bubble sort */ { register int a. ++a) { if (item [a-1] > item [a] ) { t = item [a-1]. for(a = c. b.1. item [a-1] = item [a] .example) will go to its proper position in one pass. c. item [a] = t. char t. d . } } 181 . int count) /* shaker sort.1. --a ) { if (item [a-1 ] > item [a] ) { t = item [a-1]. do { for (a = d. c = 1. a < d+1. Instead of always reading the array in the same direction. d = count . subsequent passes could reverse direction. this version of the Bubble sort is called the Shaker sort because of its shaking motion over the array: void shaker (char *item.

Although the Shaker sort is better than the Bubble sort. c . b<count.Then from the remaining n-1 elemints. up to the last two elements For example. } } item[c] = item [a] . better sort do exist. for(a=0. each pass would look like this: Initial Pass 1 Pass 2 Pass 3 The basic Selection sort is shown here: void select(char* item.d = b-1. ++ a) { c=a . } while (c <= d). item [a] = t . for(b = a + 1. int count) { register int a. } Although the Shaker sort does improve the Bubble sort. it still executes on the order of n2 because the number of comparisons is unchanged. if the selection method were to be used on the array b d a c.and because the number of exchanges has only been reduced by a relatively small constant. Sorting by Selection A Selection sort selects the element with the lowest value and exchange that with the first element. char t . t= item [a]. 182 bdac adbc abdc abcd /* selection sort */ . b. a < count –1 . ++b) { if(item[b] <t) { c=b. t = item [b] . and so forth. the element with the least key is found and exchange with the second element.

++a ) { t= item [a] .loop 1/2(n) times. For example. The average case is is n(ln n+y) where y is Euler's constant(about 0. To slow for a larger number of items The number of exchanges for the best case is 3(n-l) and for the worst case is n2/4+3(n-1). Although the number of comparisons for both the Bubble sort and the Selection sort. Then the fourth element is inserted into the list of three elements. This means that. b = a . given the array d c a b. int count ) /* sorting by insertion */ { register int a. The process continues until all-elements have been sorted. the outer loop executes n . Next.577216).1. the algorithm inserts the third member into its sorted position in relation to the first two members. Initial pass 1 pass 3 pass 4 dcab cdab acdb abcd A version of the Insertion sort is shown here: void insert (char* item . the number of exchanges in the average case is far less for the Selection sort. a < count .1 items and The inner. For the best case. each pass of the insertion sort would look like this. for (a=1. like the Bubble sort. which makes it. and each move requires three exchanges. if the list is ordered. char t . 183 . then only n-1 elements need to be moved. is the flame. The worst case approximates the number of comparison.} } Unfortunately. This means that the Selection sort requires 1/2(n2-n) comparisons.b . Sorting by Insertion The insertion sort is the last of the simple sorting algorithms the Insertion sort initially sorts the first two member of the array.

while (b>=0 && t < item [b] ) { item [b+1] = item [b] . First. } item [b+1] =t . i). If the list is in order. howevsr. then it remains sorted for both keys. } } Unlike the Bubble sort and the Selection sort. Second. Even though the comparisons may be fairly good for certain sets of data.4) Therefore. with the least exchanges occurring for an almost sorted list and the most exchanges for an inversely order array Improved Sorts 184 . the Insertion sort still behaves naturally. behaves naturally it works the least when the array is already sorted and the hardest when the array is sorted in inverse order. after an Insertion sort. The Insertion sort does have two advantages. If the list is in inverse order. then the number of comparisons is n-1. the fact that the array must always he shifted over each rime an element is placed in its. However:. proper location means that the number of moves can he very significant. the number for the worst. case is as bad as those for the Bubble and Selection sort and for the average case it is only slightly better. while its average number of comparisons is l/4(n2+n-2 ) The number of exchanges for each case is as follows: Best average 2(n-I) 1/4(n2+9n . This makes the Insertion sort useful for lists that are almost in order. b--. it leaves the order of equal keye unchanged: if a list is sorted using two keys. then the number of comparisons is l/2(n2+n)-1. the number of comparisons that occur while the Insertion sort is used will depend on how the list is initially ordered.10) worst l/2(n2+ 3n .

if the underlying algorithm is bad the sort will be slow no matter. that if you blink. two excellent aorta are developed. These sorts run so . derived from the Insertion sort. and the second is the Quicksort. in fact at some point.how optimal the coding. The Shell Sort The Shell sort is named after its inventor. However.All of the algorithms thus far bad the fatal flaw of executing in n2 time. the name seems to have stuck because its method of operation resembles sea shells piled upon one another. changes exponentially. Shell However. all elements that are three positions apart. In this section. Remember. First.L. too slow to use. when the run time of a routine is relative to n2 increasing speed of the coding or of the computer will only cause a slight improvement because the rate at which the run time increases. The first is the Shell sort.For large amounts of data.fast. 185 . it may be the fault of the underlying algorithm. which is generally considered the best routine. all those adjacent to each other are sorted. is based on diminishing increment. When a sort takes too long. Previous figure gives a diagram of a Shell sort on the array f d a c b e. The general method. you will miss them. are sorted Then all elements that are two positions apart are sorted-Finally. D. the sorts would be slow.

This algorithm is efficient because each sorting pass involves relatively few elements. both. 3. a [1]=5. } while (x<item [j] && j>=0 && j <=count) { item [j+k]=item [j]. 5. s++.w. therefore each pass increases the order of the data. i<count . Avoid sequences that are power of 2 because. s=-k. w++) { k=a [w] . for(i=k. char x. j=i-k. if (!s) { s= -k. the sequence 9. a[3]=2. For sample. or even that it will sort the array. but it does. item [s]=x. 1 works well and is used in the Shell sort shown here. } item [j+k] = x. a[5] . a[2]=3. for (w=0. } } } 186 . or elements that are already in reasonable order.k. w<5. they reduce the efficiency of the sorting algorithm void shell (char* item.j.s. The only rule is that the last increment must be 1. 2. ++i) { x=item[i] . for mathematically comply reasons. int count) /* a shell sort */ { register int i.It may not be obvious that this method yields good results. j=j-k. a[4]=1 . The exact sequence for the increments can be changed. a[0]=9.

This is surprising if you consider the terrible performance of the Bubble sort.You may have noticed that the inner while loop has three test. from overrunning the boundary of the array item These extra checks degrade the performance of Shell sort to some extent. the first pass of the Quicksort would rearrange the array like this: initial pass. quicksort. In this way the boundary checks are unnecessary. given the array f e d a c b and using the value d. The process is essentially recursive. Slightly different versions of the shell sort employ special array elements. conditions. However using sentinels requires a specific knowledge of the data. The Quicksort is built on the idea of partitions. invented and named by C. The. the cleanest implementations of Quicksort are recursive algorithms The selection of the middle comparand value can be accomplished two ways. The tests j>=0 and j<-=count are used to keep the sort. It is based on the exchange method of sorting.A. The x<item[j] is a comparison necessary for the sorting process. is generally considered the best. The general procedure is to select a value (called the comparand) and then to partition the array into two parts with all elements greater than or equal to the partition value on One side and those less than the partition value on the other.R. called sentinels which are not actually part of the array to be sorted. Even in the worst case the value Chosen is at one extremity—quicksort still performs well 187 . 1 fedacb bcadef This process is then repeated for each half (b c a and d e f). sorting algorithm currently available. For example. This process is then repeated for each remaining part until the array is sorted. indeed.Hoare. The quicksort. which is also based on the exchange method. which limits the generality of the sort function. Sentinels hold special termination values that indicate the least and the greatest possible elements. The value can be chosen either at random or by averaging a small sat of values taken from the array for the optimal sorting it is desirable to select a value that is precisely in the middle of value range however this not easy to do for most sets of data.

the following version of Quicksort selects the middle element of the array. Although this may not always result in a good choice, the sort still performs correctly. void quick (char* item, int count ) */qutcksort set up */ { qs(item , 0, count –1); } void qs (char* item , int left , int right ) /* quicksort */ { register int i, j; char x,y; i = left; j = right ; x = item [(left+ right) /2] ; do { while (item [i] <x && i < right ) i++ ; while (x < item[j] && j < left) j--; if (i<=j) { y= item [i]; item [i]=item [j]; item [j]=y; i++; j -- ; } } while (i<=j); if (left <j) qs (item ,left, j); if (i <right) qs (item ,i, right ); } In this version, the function quick() sets up a call to main sorting function, called qs() While this maintains the same common interface of item and count, it is not essential because qs() count have been called directly using three arguments The number of comparisons is n log n and that the number of exchanges is approximately n/6 log n- These are significantly better than any of the previous sorts discussed so far. This means, for example, that if 100 elements were to be sorted, Quicksort would require 100 * 2, or 200, comparisons because log 100 is 2. Compared with the Bubble sort's 910 comparisons, this number is quite good.

188

You should be aware of one particularly nasty aspect to Quicksort. If the comparand value for each partition happens to be the largest value, then Quicksort degenerates into "slowsort” with an n2- run time. Generally, however, this does not happen. You must carefully choose a method of determining the value of the comparand. Often the value is determined by the actual data you are sorting. In large mailing lists where sorting is often by zip code, the selection is simple, because the zip codes are fairly evenly distributed and a simple algebraic function can determine a suitable comparand. However, in certain databases, the sort keys may be so close in value (with many being the same value) that a. random is often the best method available. A common and fairly effective method is to sample three elements from a partition and take the middle value

Choosing a Sort
Generally, the Quicksort is the sort of choice because it is so fast. However, when only very small lists of data are to be sorted (less than 100), the overhead created by Quicksort's recursive calls may offset the benefits of a superior algorithm. In rare cases like this, one of the simpler sorts (perhaps even the bubble sort) will be quicker.

189

Sorting Other Data Structures

Sorting Strings Sorting Structures

Until now, you have only been sorting arrays of characters. This has made it easy to present each of the sorting routines. Obviously, arrays of any of the built-in data types can be sorted simply by changing the data types of the parameters and variables to the sort function. However, generally complex data -typed like strings, or groupings of information like structures, need to be sorted. Most, sorting involves a key and information linked to that key. To adapt the algorithms to sort other structures, you need to alter either the comparison section or the exchange section, or bothThe algorithm itself will remain unchanged. Because Quicksort is one of the- best general-purpose routines available at this time, it will be used in the following, examples. The same techniques will apply to any of the sorts described earlier. Sorting strings The easiest way to sort strings is to create an array of character pointers to those strings. This allows you to maintain easy indexing and keeps the basic Quicksort algorithm unchanged. The string version of Quicksort shown here will accept an array of char pointers that point to the strings to be sorted. The sort rearranges the pointers to the strings not the actual strings in memory. This version sorts the strings in alphabetical order, void quick_string (char *item[], int count)

190

{ qs_string (item , 0 , count –1); } void qs_string (char* item[], int left , int right ) // quick sort for strings { register int i , j ; char *x,*y ; i = left ; j = right ; x= item[ (left + right ) / 2] ; do { while (strcmp (item [i] ,x ) <0 && i<right ) i++; while (strcmp (item [j] ,x )>0 && j > left ) j--; if (i <= j) { y = item[i]; item [i] = item [j]; item[j] = y; i++, j--; } } while (i<=j); if (left <j) qs_string( item , left ,j ) ; if (i <right) qs_string( item, i, right ) ; } The comparison step has been changed to use the function strcmp(), which returns a negative number if the first string is lexicographically less than the second, 0 if the strings are equal, and a positive number if the first string is lexicographically greater than the second. The exchange part the routine has been left unchanged because only the pointers are- being exchanged not the actual strings. To exchange the actual strings, you would have to use the function strcpy(). The use of strcmp() will slow down the sort for reasons. First, it involves a function call, which always takes time second, the strcmp() Function itself performs several comparisons to determine the relationship of the two strings It speed is absolutely critical the code strcmp() can be duplicated in line inside the routine, However, there is no way to avoid comparing the strings since this is by definition what. the task involves. Sorting structures Most application programs that require a sort will need to have a grouping of

data sorted. A mailing list is an excellent example because a name, street, city, state, and ZIP code are all linked together. When this conglomerate unit of data is sorted, a sort key is used, but

191

j ).i .zip . char *x. while (strcmp (item [j]. as an array of structures assume for this example that the sort routine sorts an array of structures of type address. Since it is reasonable to arrange a mailing list. i = left . if (i <= j) { swap_all_fields (item . j-. do { while (strcmp (item [i]. x)> 0 && j<left) j--. a separate function. char city [20] . int count ) // quick sort for structures { qs_struct(item. } } while (i<= j) . 0. void quick_struct (struct address item[]. if (left <j ) qs_struct (item . To see how this is done. swap_all_fields().the mailing-list example. } Notice that both the comparison code and the exchange code needed to be altered. The state is three characters long and zip is ten characters long because a string array always needs to be one character longer than the maximum length of any string in order to store the null terminator. as shown here. char state [3] . i. }.right ) . x)< 0 && i<right ) i++.the entire structure is exchanged. if (i<right ) qs_struct (item .. j . char street[40] . a convenient structure is struct address { char name [40] .zip . For. was created to do 192 .left . char zip[10] . i++.zip . Because so many fields needed to be exchanged. } void qs_struct(struct address item[] .j ). int left . j =right . int right ) /* quick sort for structres */ { register int i. *y. count-1). x = item [(left + right )/2]. you first need to create a structure.

193 . You will need to create swap_all_fields() in accordance with the nature of the structure being sorted.this.

Unit 8 194 .

However. This method must be used on unsorted data. 195 . if the data has been sorted. as with sorting general-purpose routines sometimes are simply too inefficient for use in demanding situations because of the extra overheads created by the generalization . The following function searches a character array of known length until a match is found with the specified key.Searching Searching Methods The Sequential Search The binary search Databases of information exist so that. and another for a sorted file or array. Many compilers supply search functions as part of the standard library. There is only one method of finding information in an unsorted file or array. a user can locate a record by knowing its key. but can also be applied to sorted data. which greatly speeds up any search. Searching Methods Finding information in an unsorted array requires a sequential search starting at the first element and stopping either when a match is found or when the end of the array is reached. The Sequential Search The sequential search is easy to code. then a binary search can be used. from time to time.

char key ) { register int t .sequential_search(char* item . t < count . 196 . can be used to find a match. This is less than 4. or 12345 In this example. return –1. this is the only method available. For example. the binary search would first test the middle. int count . The binary search If the data to be searched is in sorted order. for (t =0 . A straight sequential search will. but if the data is unsorted. If the information is stored on disk. it. the search time can be vary long. it will test only one element and in the worst case n elements. if the element is lager than the key. or there are no more elements to test. called the binary search. then a superior method. on the average. the search would continue with the first half. teat n/2 elements. to find the number 4 in the array 1 2 3 4 5 6 7 6 9. Since this is greater than 4. which is 5. /* no match */ } This function will return the index number of the matching entry if there is one. The method uses the “divide-and-conquer” approach. In the best case. so the first half is discarded and the search continues with 45 This time the match is found. This process is repeated until either a match is found. or -1 if there is not. the middle element is 3. Test the middle element of the second half. It first tests the middle element. it then tests the middle element of the first half. otherwise.++t ) if (key == item [t]) return t .

else if (key > item [mid]) low=mid+1. int count. /* found */ } return –1 . You can make this search any arbitrary data structure by changing the comparison portion of the routine. the number is 1. in the best case.In the binary search. low =0. With average cases. while (low <= high ) { if (key <item [mid]) high= mid-1. } 197 . the number is somewhat better. the number of comparisons given the worst case is log2n. A binary search function for character arrays is shown here. high = count –1. high. mid. binary (char* item. char key) { int low. else return mid.

Unit 9 198 .

How closely the logical concept of an item of data is bound with its physical machine representation is in inverse correlation to its abstraction. In this case. which are organized collections of the simple data types. That is. are not quite as tightly bound as the simple types themselves because an array may not appear in memory the way the programmer thinks of it. Choosing and implementing a data structure are as important as the routines that manipulate the data. as a programmer. the value that an integer has in its machine representation closely approximates that which the programmer conceives of it having. the way the programmer thinks of them bears an ever-decreasing resemblance to the way they are actually represented in memory. The way that information is organized and accessed is usually determined by the nature of the programming problem. simple types such as char and int are tightly bound to their machine representation. Less tightly bound yet are floats because the actua1 representation inside the machine is unlike the average programmer's conception of a floating-point number. you must have in your "bag of tricks" the right storage and retrieval method for a variety of situations. Therefore. as data types become more complex. Simple arrays.Data Structures Data structure is information organization The four types of data engines Qeue Sack Linked list Bnary tree Programs consist of algorithms and data structure.The good program is a blend of both. For example. The 199 .

The final level of abstraction transcends the mere physical aspects of the data and concentrates instead on the sequence in which the data will be accessed (that is.structure. 200 . in which an item is one informational unit. The methods share two operations. In essence. store an item and retrieve an item. stored and retrieved). The four types of these engines are • • • • A queue A stack A Linked list A binary tree Each method provides a solution to a class of problems each is essentially a "device" that performs a specific storage and retrieval operation on the given information according to the requests it receives. the physical data is linked with a "data engine” that controls the way information can be accessed by your program. which is a conglomerate data type accessed under one name is even more abstracted from the machine representation.

qstore() places an item onto the end of the queue and qretrieve( ) removes the first item from the queue and returns its value Keep in mind that a retrieve operation removes an item from the queue. a queue may be empty because all of its items have been removed. To visualize how a queue works. This order is the only means of storage and retrieval. and if it is not stored elsewhere. The second item put in is the second item retrieved. even though the program is still active. lines at a bank or a fast-food restaurant are queues. Queues are used in many types of programming. The first item placed on the queue is the first item retrieved.Queues A queue is a linear list of information The queue is accessed in FIFO order The retrival process is destructive retrival Queue may be linear or circular one A queue is a linear list of information that is accessed in first-in. and I/O buffering.event or appointment scheduling (such as in a PERT or Gant chart). first-out order (sometimes called FIFO). a queue does not allow random access of any specific item. Therefore. consider-two-functions: qstore() and qretrieve(). 201 . Queues are very common in everyday life. and so on. For example. destroys it.situations such as simulations.

As each appointment is performed it is taken off the list. For the sake of simplicity. consider a simple appointment-scheduler program that allows you to enter a number of events. qretrieve() takes events off the queue as they occur. } These functions require two global variables: spos. and with each appointment removed. The function qstore() places pointers to new events on the end of the list and checks whether the list is full. The next figure shows the way this may appear in 202 . which holds the index of the next free storage location. You might use a program like this to organize a day's appointments. rpos is incremented in essence. here are the functions qstore() and qretriev() that will be used for the simple scheduling program: /*sort an appointment */ void qstore (char* q) { if (spos==MAX ) { printf(“list full\n”) . the program uses an array of pointers to the event strings. rpos "chases" spos through the queue. return. } /* retrive an appointmen */ char *qretrieve () { if (rpos==spos) { printf(“no (more ) appointments. spos ++. } p[spos]=q. \n”) . It limits each appointment description to 256 characters and the number of entries to 100. It is possible to use these functions to maintain a queue of other data types by simply changing the base type of the array on which they operate. and rpos. which holds the index of the next item to retrieve. spos is incremented. With each new appointment scheduled.For example. First. return NULL } rpos++ . return p[rpos-1].

Here is the entire program for this simple appointment schedule.h” #define MAX 100 char * p[MAX]. void enetr(). #include “stdlib. it can never be accessed again and is in effect destroyed. int rpos.h” #include “stdio.h” #include “ctype. void qstore(char*). char * qretrieve ().h” #include “string.memory as the program executes. void review (). 203 . no events are left in the schedule. Keep in mind that even though the information stored in the queue is not actually destroyed by the qretrieve() function. int spos. You may want to enhance this program for your own use. if rpos and spos are equal.

gets (s).void delete(). do { printf(“enter appointment %d : “. if (*s == 0) break . ++t) p[t] = NULL. break. *p . case ‘q’: exit (0) . } } return 0. int main() //Mini appointment – scheduler { char s[80]. if (!p) { 204 . /*no entry */ p = (char*) malloc(strlen(s)). .remove . t < MAX . ) { printf(“enter . case ‘R’: delete ().quit : “). } /* enter appointments */ void enter () { char s [256] . register int t . case ‘L’: review (). spos+1). gets (s) . break. switch (*s) { case ‘E’ : enter(). for (t=0. break. rpos = 0. *s = toupper (*s). spos = 0. for (.left .

} /* retrieve an appointment */ char *qretrive () { if (rpos == spos ) { printf(“no (more ) appointments . return . return.t+1 . for (t = rpos . } /* see what’s in the queue */ void review () { register int t . } 205 .\n”) . } /* store an appointment */ void qstore (char* q) { if (spos == MAX ) { printf(“list full\n”) . } strcpy (p. spos ++ .t <spos . } p[spos]=q. if (! (p=qretrieve () )) return .p). %s \n”.printf(“out of memory .++t) printf (“%d. if (*s) qstore (p). } /* delete an appointment from the queue */ void delete () { char *p . \n” ) . printf(“%s\n “. s) . return NULL.p [t] ). } while (*s) .

quit :R Jon at 9 about the phone system Enter . as shown here: void qstore (char* q) 206 .Ted at 10:30 – want that raise …. This method of implementing a queue is called a circular queue because it uses its storage array as if it were a circle a instead of a linear list. quit : L 1. remove . return p [rpos-1]. remove . remove . } A sample run of the appointment scheduler is shown here: Enter .remove . quit :q The Circular Queue In studying the appointment-scheduler program in the previous section.lunch with Mary and Tom at Harry’s Enter . This would allow any number of items to be placed on the queue. 3. list .list . list .humm 3. list .Jon at 9 about the phone system 2. the qstore() and qretrieve() functions need to be changed. remove . Instead of having the program stop when the limit of the array used to store the queue was reached. 3: lunch with Mary and Tom at Harry’s 4: <cr> Enter . quit : L 2. as long as items were also being taken off. an improvement may have occurred to you.rpos ++ . list . quit : E Enter appointment Enter appointment Enter appointment Enter appointment 1: Jon at 9 about the phone system 2: Ted at 10:30 – wants that raise …humm . To create a circular queue for use in the appointment-scheduler program.lunch with Mary and Tom at Harry’s enter . you could have both the store index (spos) and the retrieve index (rpos) loop back to the start of the array.Ted at 10:30 – want that raise …humm.

However. the queue is only full when both the store index and the retrieve index are equal. } rpos ++ return p[rpos –1 ]. } p[spos] =q . the retrieve index (rpos) must not be set to 0.\n “) .*/ if (spos +1 == rpos || (spos + 1 == MAX && ! rpos ) ) { printf (“ list full \n ) . It is important to note that the. retutn . the queue has room for another event. this means that when the program starts. but rather to MAX so that the first call to qstore() does not produce the queue full message. return NULL . if (spos == MAX ) spos =0 . /* loop back */ } char * qretrieve ( ) { if (rpos == MAX ) rpos =0 . /* loop back */ if (rpos == spos ) { printf (“No (more ) appointments . a brief period elapses during which what is being typed is not displayed until after the other process the program is working on is completed. Many word processors do this when they reformat a paragraph or justify a line. spos ++ . To accomplish this. If 207 .queue will hold only MAX-1 elements because rpos and spos must always be at least one element apart.{ /* the queue is full if either spos is one less then rpos or if spos is at the end of the queue array and rpos is at the beginning . Another common use of the circular queue is in real-time application programs that must continue to process information while buffering I/O requests. the application program must continue to check for keyboard entry during the execution of the other process. otherwise it would be impossible to know whether the queue was full or empty. otherwise. Perhaps the most common use of a circular queue is in operating systems that buffer the information read from and written to disk files or the console. } In essence.

keyboard buffer */ { register char ch . kbhit ()). and the process continues. if (kbhit ()) { ch=getch (). for (ch =’ ‘. } printf(“%d”. int rspos=MAX. The second process places characters in a circular queue as they are typed. ++t) { printf (“%d”.a key has been typed. The short program shown here works with the IBM PC and uses kbhit() to determine the keyboard status and getch() to read a character without echoeing it to the screen. which contains two processes. the characters are retrieved from the queue. t). without echoing them on the screen until a semicolon is struck. 80 208 . } while ((ch = qretrieve ()) != NULL ) putchar (ch). buf [80] = NULL. Once the process is complete. The first process in the program will print the numbers 1 through 32. t=0. void qstore(char cg) . int spos = 0 .000 on the screen. qstore (ch). the characters in the queue are retrieved and printed. consider the simple program presented next. /* display buf */ return 0. t < 32000 && ch != ‘. it is quickly placed in the queue.h” #define MAX char buf [MAX +1] . The characters you type will not be displayed because the first process is given priority over the screen at this time.’. int t . #include “stdio. After the semicolon has been struck.h” #include “conio. int main() /* circular queue example . char qretrieve () . To see how this can be done.

/* loop back */ } /* retrieve a character */ char qretrieve () { if (rpos == MAX ) rpos =0 . /* loop back */ if (rpos == spos ) { return NULL. } rpos ++ . if (spos == MAX ) spos =0 . } 209 . spos ++.} /* store character in queue */ void qstore (char q) { if (spos+1 == rpos || (spos+1 == MAX && !rpos)) { printf (“list full\n”). } buf[spos] = q . return buf[rpos –1 ] . return .

The bottom plate in the stack is the last to be used. In fact. 210 . Stacks are used a great deal in system software including compilers and interpreters.stacks and pop(). the two basic operations—store and retrieve — are usually called push and pop. Therefore. or you could allocate a region of memory using C's dynamic memory allocation functions Like the queue.the retrieval function takes a value off the list and. respectively. The general forms of push() and pop() using an integer array are shown here. if the value is not stored elsewhere. to implement a stack you need two functions: push() which places a. C uses the computer's stack when passing arguments in functions. and the top plate (the last plate placed on the stack) is the first to be used.Stacks A stack linear list of information The stackccessed in LFO order The retrival process is destructive retrival A stack is the opposite of a queue because it uses last-in. region of memory to use as the stack you could either use an array. destroys it. which retrieves a value from the stack. you also need a. You may maintain stacks of' other data types by changing the base type of the array on which the push() and pop() functions operate. first-out accessing (sometimes called LIFO). For historical reasons. Imagine a stack of plates. value on the.

and press the equal-sign key.which takes the general form operand. you would enter 100 than press + enter 200. However. tos ++.. The advantage of the postfix form is that the calculator without much code can evaluate expressions easily. you would first enter 100. An excellent sample of the use of a slack is a four-function calculator. For example. int tos =0 . } else { stack [tos] =i . to add 100 to 200. For example. two operands are removed from the stack. used a form of expression evaluation called postfix notation in which both operands are entered before the operator is entered. they are placed on a stack. and the result is pushed back on the stack. } return stack [tos] . } The variable tos is the index of the next open stack location. 211 .int stack [MAX ]. Most calculators today accept a standard form of expression called infix notation. always remember to prevent overflow and underflow. the stack is full. As operands are entered. } } int pop () /* retrieve top element from the stack */ { tos -. return HUGH_VAL . using postfix notation to add 100 to 200. if tos equals 0 the stack is empty. many early calculators in an attempt to save memory. when an operator is entered. and then press the + key. if (tos <0) { printf (“stack underf low –n”) . if tos is greater than the last storage function.then enter 200. When implementing these functions. In theses routines. /* top of stack */ void push (int i) /* place element on the stack */ { if (tos> =MAX ) { printf(“stack full \n “).

minus. 212 . times. /* points to bottom of stack */ void push (int i) /* place element on the stack */ { if (p> bos ) { printf (“stack full\n”) . p++. you need to modify the basic push() and pop() functions C.. } return *p. return NULL. } *p =i. if (p<tos) { printf (“stack underflow \n “). /* points to top of stack */ int *bos . return . as used in the calculator example later.These functions. you must allocate a region of free memory using malloc(). } int pop () /* retrieve top element from the stack */ { p-.Before developing the full four-function calculator for postfix expressions. and divide. You must also assign the address of the beginning of that region to tos and assign the address of the end to bos. The entire calculator program is shown here. /*will point to a region of free memory */ int *tos . } Before you can use these functions. are shown here: int *p. you may also enter a period. which causes the current value on the top of the stack to be displayed. In addition to the operators plus.'s dynamic allocation routines provide memory for the stack.

push(a*b).h” #define MAX 100 int *p. a-b ) . bos =p +MAX –1 . /* points to bettom of stack */ void push (int i) ./* a simple four –function calculator */ #include “stdlib.b. p= (int *) malloc (MAX * sizeof (int )) . push(a-b). } tos =p . case ‘*’: a = pop(). int main () { int a. printf (“%d \n “. case ‘-’: a = pop(). switch(*s) { case ‘+’ : a = pop(). int pop(void). /* will point to a region of free memory */ int *tos . break. b = pop(). do { printf (“:”). /* points to top of stack */ int *bos . break. char s [80] . printf (“%d \n “. a+b ) . b = pop().h” #include “stdio. printf(“four function calculater \n”) . gets(s) . b = pop(). printf (“%d \n “. a*b ) . case ‘/’: 213 . exit (1) . /* get stack memory */ if (!p) { printf (“allocation failure \n”) . break. push (a+b).

} int pop (void) /* retrieve top element from the stack */ { p--. return 0. break.’ : /* show contents of top of stack */ a=pop () .a = pop(). } } while (* s !=’q’) . push (a) . if (a==0){ printf (“divide by 0\n “) . return 0. p++ . } 214 . return . case ‘. } *p=i. } printf(“%\n” . break. } void push (int i) /* place element on the stack */ { if (p>bos ) { printf (“stack full\n”) . } return *p. default : push(atoi(s)).b/a). b = pop(). push (b/a). printf (“current value on top of stack . if (p< tos) { printf(“Stack underflow”). %d\n “. break. a) .

+<cr> 20 :5<cr> : /cr> 4 : .A sample session at. the calculator is shown here: Four Function Calculator : 10<cr> : 10<cr> . <cr> Currnt value on top at of stack : 4 :q <cr> 215 .

Second. The linked list allows you to insert and delete items quickly and 216 . consumptive that is. accessing an item in a stak or queue requires its removal. but if you do not know the actual size of a. you must use a linked list.Linked Lists Each piece of information carries with it a link to the next data A linked list may access its storage in a random fashion A linked list retrieval is no n-destructive Dynamic arrays can be constructed using the linked list Linked list can be single or double list Queues and stacks share two common traits. whereas a stack or queue can operate on both simple and complex data item. list. both have strict rules for referencing the data stored in them. A linked list requires complex data structure. The First purpose is to create arrays of unknown size in memory.retrieval operations are. at least conceptually. A linked-list retrieval operation does not remove and destroy an item from the list. unless stored elsewhere. First. because each piece of information carries with it a link to the next data. item in the chain. by nature. The second main usage is for disk-file storage of databases. a specific deletion operation must be added to do this. Its destruction both stacks and queues also require. the. and. Linked lists are used for two main purpose. a contiguous region of memory to operate Unlike a stack or a queue a linked list may access its storage in a random fashion. If you know the amount of storage in advance. you can use an array.

the case of a database. the list can be reconstructed using the other link. Three primary operations can be performed on a doubly linked list: in-start a new first element. 217 . These operations are shown in the following figure. if one link becomes invalid. insert a new middle element. linked lists are used extensively in database managers. A singly linked list contains a link to the next data item A doubly linked list contains link to both next and the previous element in the list The type you use depends upon your application. Linked lists can be either singly linked or doubly linked. First. Doubly Linked Lists Doubly linked lists consist of data and links to both the next item and the preceding item. because either a forward link or a backward link can read the entire list. allows a user to scan the list in either direction.easily without rearranging. Previous figure shows how these links are arranged. the list can be read in either direction. For these reasons. and insert a new last element. Second. This not only simplifies sorting the list but also. A list that has two links instead of just one has two major advantages.the entire disk file. This is meaningful only in the case of equipment failure.

}. int Age. float Salary. here to accommodate this: struct Employee { int Code. float Deduct.Building a doubly linked list is similar to building a. struct Employee *pNext. except that the structure must have room to maintain two links. struct Employee *pPrevious. singly linked list. float OTime. char Name[20]. char Address[40]. 218 .

struct Employee *pLast. The following function searches for a specified employee code. } 219 . pItem = pStart. } return pItem. struct Employee * SearchList(int Code) { struct Employee * pItem. while(pItem && pItem->Code != Code) { pItem = pItem->pNext. pItem->pPrevious = pLast. pItem->pNext = NULL. } else { pLast->pNext = pItem. the AddList() function builds a doubly linked list void AddList(struct Employee *pItem) { if (!pStart) { pItem->pNext = NULL. pLast = pItem. } } This function places each new entry on the end of the list. Using structure employee as the basic data item. pItem->pPrevious = NULL.struct Employee *pStart. pStart = pLast = pItem.

There are three cases to consider when deleting an element from a doubly linked list: deleting the first item. } else { if (pStart == pLast) { pStart = pLast = NULL. and deleting the last item. The following function will delete an item of type Employee from a doubly linked list. The following figure how the links are rearranged. int RetFlag = 1. int DeleteList(int Code) { struct Employee *pEmp. deleting a middle item. } else if(pEmp == pStart) 220 . if (!pEmp) { RetFlag = 0. pEmp = SearchList(Code).

} else { pEmp->pPrevious->pNext = pEmp->pNext. } else if(pEmp == pLast) { pLast = pLast->pPrevious.{ pStart = pStart->pNext. pLast->pNext = NULL. while(pStart) { pItem = pStart. pStart->pPrevious = NULL. void FreeList(void) { struct Employee * pItem. free(pItem). } In order to remove the linked list from memory you have to write the following function. pStart = pStart->pNext. } free(pEmp). pEmp->pNext->pPrevious = pEmp->pPrevious. } return RetFlag. } 221 . } pLast = NULL.

Although there can be many different types of trees binary trees are special because. 222 . and deletions. Each item in a binary tree consists of information with a link to the left member and a link to the right member. insertions. The following figure shows a small tree.Binary Trees Each item in a binary tree consists of information with a link to the left member and a link to the right member Binary trees are used in rapid search The root is the first item in the tree Tree is a recursive data structure The retrieval operation is nondestructive The fourth data structure is the binary tree. when they are sorted. they lend themselves to rapid searches.

Although trees are easy to visualize. which is linear in form. but code For them is much more difficult to understand 223 . the retrieval operation is nondestructive. that is. The height of the tree equals the number of layers deep that its root grows. each subtree is a tree. deleted. and accessed in any order. The root is the first item in the tree. The binary tree is a special form of linked list. Therefore the routines that are developed are recursive as well.Items can be inserted. think of binary trees as appearing in memory as they do on paper. Throughout this discussion. they present some very difficult programming problems that this section will only introduce.The special terminology needed to discuss trees is a classic case of mixed metaphors. Each data item is called a node (sometimes called a leaf) of the tree. A node that has no subtrees attached to it is called a terminal node. Also. but remember that a tree is only a way to structure data in memory. Most functions that use trees are recursive because the tree itself is a recursive data structure. and any piece of thy tree is called a subtree. Non-recursive versions of these functions do exist.

and then visit the right subtree. and postorder. What constitutes a sorted tree depends on how you will be traversing the tree. and then the root. and then the right subtree. Using inorder. using each method. The order of access for the tree just shown. stree() builds a sorted binary tree: 224 . With postorder. then the right subtree. The following function. you visit the left subtree. you visit the left subtree. The examples in the rest of this section access the tree inorder. then the left subtree. In a sorted binary tree. preorder. you visit the root.The process of accessing each node in a tree is called a tree traversal Consider the following tree: There are three ways to traverse a tree: inorder. In preorder. most uses require it.The order of a tree depends on how the tree is going to be referenced. the subtree on the left contains nodes that are less than or equal to the root. visit the root. is as follows: inoder preorder postorder abcdefg dbacfeg acbegfd Although a tree need not be sorted. while those on the right are greater than the root.

To use this function you need a global variable that holds the root of the tree. info ) . info). but you can substitute any simple or complex data type you like. } if (info <r-> info ) stree(r. /* first entry */ if (info < root -> info ) root -> left =r . r-> info = info . else stree (rt . info ) . else root -> right =r . and a pointer to the root will be assigned on the first call to stree(). exit (0) . return r . The same routine would be several times longer if straight iterative methods were employed The function must be called with a pointer to the root.r -> left . only a single character is used here as the information. } r-> left =NULL . else if (info > r. if (!root) return r. struct tree *r. the left or right node. going left of right based on the info field. char info ) { if (!r) { r = (struct tree *) malloc(sizeof(struct tree )).rt .> info ) stree (r –r -> right .rt . If you assume the name of this global is rt then to call the stree() function. r-> right=NULL .strcut tree stree (struct tree root. The stree() function is a recursive algorithm. info ). 225 . in this way both the first and subsequent elements can be inserted correctly. if(!r) { printf (“out of memory \n “) . Subsequent calls will not need to reassign the root. and information. This global must be set initially to NULL. you would use /* call stree () */ if (!rt) rt= stree (rt . For simplicity. } This algorithm simply follows the links through the tree. as are most tree routines.

} 226 . if (root == null ) break . postrder (root -> left ). preoder (root -> right). postrder (root -> right ). char key ) { if (!root ) return root . otherwise it returns NULL: struct tree *search_tree (struct tree root . The functions to traverse the tree in preorder and in postorder are shown here void preorder (struct tree* root ) { if (!root ) return . and to print the Info field of each node. printf(“% c “. you could use the inorder() function shown here: void inorder (struct tree* root) { if (! root ) return . printf (“%c “. /*empty tree */ while (root -> info !=key ){ if (key <root -> info ) root =root -> left . root -> info ). else root = root->right. root -> info ) . printf (“%c “. } This recursive function returns when it encounters a terminal node (a null pointer). The following function returns a pointer to the node in the tree that matches the key.To traverse the tree built using stree() inorder . } Search functions are easy to implement for binary trees. inorder (root -> right ). root -> info ). preoder (root -> left ). inorder (root -> left ). } void postorder (struct root* root) { if (!root ) return . } return root .

The node may also have from zero to two subtrees attached to it. or a right node. deleting a node from a tree is not as simple as searching the tree. The deleted node may be either the root. while(p->left) p = p->left.in the rest of your program. struct tree dtree(struct tree root . } } if (root -> info <key ) root -> right =dtree (root -> right . return NULL } /* or if one subtree is NULL */ else if (root -> left == NULL ) { p=root->right.Unfortunately. The process of rearranging the pointers lends itself to a recursive algorithm. } else if (root -> right == NULL ) { p= root -> left . return p2 . *p2 . else root -> left = dtree (root -> left . a. as the next program shows. free (root ) . 227 . } /* or both tree present */ else { p2= root -> right . key ). free (root) . return p. left node. } Remember to update the pointer to the root. p->left = root -> left. key ). return p. return root . free (root). char key) { struct tree *p . because the node deleted could be the root of the tree. if (root -> info == key ) { /* delete root */ /* this means an empty tree */ if (root -> left == root -> right ){ free (root ) . p= root->right.

flexibility. which must rely on a sequential search. and efficiency when used with database management programs because the information for these data-bases must reside on disk and because access times are important Because a balanced binary tree has. as a worst cases. 228 . log2n comparisons in searching it performs for better than a linked list.Binary trees offer tremendous power.

Unit 10 229 .

not all environments may be able to adapt to the UNIX-like system. a file on tape. Although files differ in form and capabilities. Most C compilers supply two complete sets of disk I/O functions. As C defines the term “file” it can refer to a disk file. the screen. This file system is not defined by the ANSI standard. The ANSI standard only defines one file system because the two file systems are redundant. Oue course objectives covers only the buffered file system. all streams are the same.like file system (sometimes called the unbuffered file system). a port. Further. In its most common form a stream is a logical interface to a file. The second file system is based upon the original UNIX operating environment and is called the UNIX. The stream provides a consistent interface.C and Persistence What is streams? File-System Basics Open file Close File Read from file Write to file Although C does not have any built-in method of performing file I/O. 230 . The advantage to this approach is that any hardware device will look much like any other. This file system is defined by the ANSI C standard. the keyboard. Streams In C the stream is a common logical interface to the various devices that comprise the computer. and so on. One is called the ANSI file system (sometimes called the buffered file system). the C standard library contains a very rich set of I/O functions.

char *mode). A text stream is used with ASCII characters. is the location in a file where the next file access will occur. The string pointed to by mode determines how the file may be accessed. The current location. which is the current location. A binary stream may be used with any type of data. The legal values for mode are shown in the following table Mode r w a rb Meaning Open a text file for reading Create a text file for writing Append to a text file Open a binary file for reading 231 . uses the header STDIO. the next read operation will occur at byte 50. as defined by the operating system. The fopen() function. some character translations may take place. For example. it is converted into a carriage-return/linefeed sequence. One final concept we need to declare is that of the current location. there may not be a one-to-one correspondence between what is sent to the stream and what is written to the file. For this reason. Its prototype is. For example. A stream is disassociated from a file using a close operation. When a text stream is being used. like all the file-system functions. FILE* fopen(char fname. when the newline character is output.H. also referred to as the current position. No character translations will occur. use fopen(). File-System Basics The file system basics cover the following: • • • • Open file Close File Read from file Write to file To open a file and associate it with a stream. The name of the file to open is pointed to by fname.A stream is linked to a file using an open operation. if a file is 100 bytes long and half the file has been read. and there is a one-to-one correspondence between what is sent to the stream and what is actually contained in the file. There are two types of streams: text and binary. It must be a valid file name.

the proper way to open a file called myfile for text input is shown in this fragment. It is a structure that holds various information about the file. EOF is returned. use fclose(). which must be a valid file pointer previously obtained using fopen(). FILE *fp. For example. whose prototype is int fclose(FILE *fp). FILE *fp)'. Once a file has been opened. "r"))==NULL) { printf("Error opening file\n"). The type FILE is defined in STDIO. you may read and/or write bytes to or from it using these two functions. most file system implementations write data to disk one sector at a time. 232 . When you call fclose(). The fclose() function returns 0 if successful. If an error occurs. exit(1). This is often referred to as flushing the buffer. int fgetc(FILE *fp). depending upon its mode. int fputc(int ch. and disassociates the stream from the file. } To close a file. Create a binary file for writing Append to a binary file Open a text file for read/write Create a text file for read/write Append or create a text file for read/write Open a binary file for read/write Create a binary file for read /write Append a binary file for read/write If the open operation is successful. if((fp = fopen("myfile". The fclose() function closes the file associated with fp.wb ab r+ w+ a+ r+b w+b a+b . If the fopen() function fails. it returns a null pointer.H. data is buffered until a sector's worth of information has been output before the buffer is physically written to disk. it automatically writes any information remaining in a partially full buffer to disk. Therefore. fopen() returns a valid file pointer. In order to improve efficiency.

} fclose(fp) . exit (1) . Although ch is defined as an int. while (*p) { if(fputc(*p. /* open myfile for input */ if((fp = fopen("myfile". which is an integer value. The following program demonstrates the basics of file system.h" void main(void) { FILE *fp. int i. The fputc() function returns the character written if successful or EOF if an error occurs. fp)==EOF) { printf("Error writing file\n") . you may call it using simply a char. The fgetc() function also returns EOF when the end of the file is reached. The fputc() function writes the byte contained in ch to the file associated with fp as an unsigned char. Your routine can assign the fgetc(}'s return value to a char. The reason that it returns an integer is that if an error occurs. char str[80] = "This is a file system test". "w"))==NULL) { printf("Cannot open file\n") . fgetc() returns EOF. exit (1) .The fgetc() function reads the next byte from the file described by fp as an unsigned char and returns it as an integer. } 233 . exit (1) .h" #include "stdlib. #include "stdio. "r"))==NULL) { printf ("Cannot open file\n") . /* open myfile for output */ if((fp = fopen("myfile". } p = str. } p++. char *p. which is the common procedure.

} The following program takes two command-line arguments. char *argv[]) { FILE *fp. /* Search specified file for specified character. The first is the name of a file. exit(1) . Notice how it uses argv to access the file name and the character for which to search. The program searches the specified file. putchar(i) . exit(1) .h" #include "stdlib. it reports this fact. char ch. "r"))==NULL) { printf ("Cannot open file\n") . } fclose (fp) . if (i == EOF) break.) { i = fgetc (fp) . } /* look for character */ while((ch = fgetc(fp)) != EOF} if(ch == *argv[2] ) { 234 . /* see if correct number of command line arguments */ if(argc!=3) { printf("Usage: find. looking for the character. ./*• read back the file */ for(. */ #include "stdio. If the file contains at least one of these characters. } /* open file for input */ if((fp = fopen(argv[1]. <filename> <ch>\n").h" void main(int argc. the second is a character.

break. } 235 . ch) .printf ("%c found". } fclose (fp) .

int num.). Their prototypes are int fputs(char *str. FILE *fp). These functions operate exactly like printf() and scanf() except that they work with files.. char* fgets(char *str. They are fprint() and fscanf(). The function returns str if successful and a null pointer if an error occurs.. FILE *fp). The fgets() function reads characters from the file associated with fp into the string pointed to by str until num-1 characters have been read. FILE *fp). a newline character is encountered.. char* fgets(char *str. int num. Also unlike its related function puts() it does not automatically append a carriage-return/ linefeed sequence. C provides four functions which make file operations easier. Their 236 . Unlike its related function gets(). In any case.Other Text Functions Text file functions int fputs(char *str. the newline character is retained. The fputs() function writes the string pointed to by str to the file associated with fp... FILE *fp). the string is null-terminated. The first two are called fputs() and fgets(). which write a string and read a string from a file respectively. It returns EOF if an error occurs and a non-negative value if successful.. The C file system contains other two very powerful functions. char *control-string. char *control-string. or the end of the file is reached.). int fscanf(FILE *fp. When working with text files. int fprintf(FILE *fp. The null that terminates str is not written.

). exit(1) .h" #include "stdlib... exit(1) . #include "stdio. and the program uses fgets() to display the contents of the file. and the file is closed... the file is reopened for input. This following program demonstrates fputs() and fgets().. these functions operate on the file specified by fp. /* check for command line arg */ if(argc!=2) { printf("specify file name\n") .h" #include "string.). char *control-string. The advantage to fprintf() and fscanft) is that they make it very easy to write a wide variety of data to a file using a text format. Instead of directing their I/O operations to the console. char *argv[]) { FILE *fp. Otherwise their operations are the same as their console-based relatives. Next. "w"))==NULL) { printf("Cannot open file\n"). the input phase terminates.h" void main(int argc. } printf("Enter a blank line to stop\n"). int fscanf(FILE *fp. } /* open file for output */ if((fp = fopen(argv[1]. do { printf (" : " ) . When the user enters a blank line. It reads lines entered by the user and writes them to the file specified on the command line. 237 .prototypes are int fprintf(FILE *fp. gets(str) .. char *control-string. char str[80] .

for command line arg */ if(argc != 2) { printf("specify file name\n"). } 238 .h" void main(int argc. fclose(fp) . double ld. /* open file for input */ if((fp = fopen(argv[1]. It first writes a double. /* add newline */ if(*str != '\n') fputs(str. char str[80] . char *argv[]) { FILE *fp. } while(*str != '\n') . "\n").h" #include "stdlib. and a string to the file specified on the command line. printf(str) . fp) . exit(1) .strcat(str. exit(1) . #include "stdio. } while(!feof(fp) ) . fclose (fp) . int d. } This following program demonstrates fprintf() and fscanf(). "r"))==NULL) { printf ("Cannot open file\n") . an int. /* check. fp) .h" #include "string. } /* read back the file */ do { fgets(str. 79.

fclose (fp) . printf("%lf %d %s". fclose(fp) . } fprintf(fp. 1908. "w" ) ) ==NULL) { printf("Cannot open file\n"). "r")) == NULL) { printf("Cannot open file\n"). &ld.342. 12345. /* open file for input */ if((fp = fopen(argv[1]. } fscanf(fp. &d. d. } 239 ./* open file for output */ if((fp = fopen(argv[1] . str) . "%lf %d %s". "%lf %d %s". ld. exit (1) . exit(1) . "hello"). str).

FILE *fp).Their prototypes are size_t fread(void ^buffer.h" 240 . size_t size. size_t num. num number of objects. fread() and fwrite(). num number of objects. size_t num.Read and Write Binary Data Binary File functions size_t fread(void ^buffer. size_t size. from the buffer pointed to by buffer. no objects have been read/ and either the end of the file has been encountered or an error has occurred. binary representation. the following program writes an integer value to a file called MYFILE using its internal. size_t num. FILE *fp}. FILE *fp}.h" #include "stdlib. each object size bytes long. As a simple example. size_t fwrite(void ^buffer. into the buffer pointed to by buffer. The C file system includes two important functions. The fread() function reads from the file associated with fp. The fwrite() function is the opposite of fread(). It returns the number of objects actually read. If this value is 0. each object size bytes long. sizeJ: size. It writes to the file associated with fp. size_t num. These functions can read and write any type of data/ using any kind of representation. size_t fwrite(void ^buffer. This value will be less than num only if an output error has occurred. sizeJ: size. FILE *fp). #include "stdio. It returns the number of objects written.

1002. fp)!=1) { printf("Write error occurred").9. exit(1) . sizeof(int). 75.23.34.void main(void) { FILE *fp. 12. } printf("i is %d". } i = 100.0. } The following program fills a ten-element array with floating point numbers/ writes them to a file.h" #include "stdlib.45. 1. 1. 875. void main(void) 241 . } if(fread(&i. 1. exit(1) .23. exit (1) . fclose(fp) .897. and then reads them back. sizeof(int). /* open file for input */ if((fp = fopen("myfile". exit (1) . 0. #include "stdio. 0. if(fwrite(&i.01.875 }. 19. 11. The file must be opened for binary I/O operations. } fclose(fp) . i) .87. fp)!=1) { printf("Read error occurred"). /* open file for output */ if((fp = fopen("myfile".h" double d[10] = { 10. int i . "w"))==NULL) { printf("Cannot open file\n") . "r")) == NULL) { printf("Cannot open file\n") .

i++) printf ("\n%lf ". exit (1) . i++) d[i] = -1. exit (1) . 1. i<10. 1. exit (1) . exit (1). /* read the entire array in one step */ if(fread(d. } /* write the entire array in one step */ if(fwrite(d. "wb"))==NULL) { printf("cannot open file") . } fclose(fp) . sizeof (d). if((fp = fopen("myfile". d[i] ) . } fclose(fp) . fp)!=1) { printf("write error") . "rb"))==NULL) { printf ("cannot open file") . if((fp = fopen("myFile". FILE *fp. i<10.0. sizeof (d).{ int i . fp)!=1) { printf("read error") . } /* clear the array */ for(i=0. /* display the array */ for(i=0. } 242 .

The function that lets you do this is called fseek(). Origin must be one of these macros. The value of offset determines the number of bytes from origin to make the new current position. For example. if you wanted to make the current location "100 bytes from the start of the file/ then origin will be SEEK_SET and offset will be 100. If a failure 243 . long ftell(FILE *p). long offset. Its prototype is long ftell(FILE *p). Value of Origin Meaning SEEK_SET Seek from start of file SEEK_CUR Seek from current location SEEK_END Seek from end of file These macros are defined in STDIO. int origin). We can access any point in the file using another C's file system functions. another file system functions. int origin). fp is associated with the file being accessed.H. shown here with their meanings.Random Access Files in C can be accessed randomly using the functions int fseek(FILE *fp. The fseek() function returns 0 when successful and non-0 if a failure occurs You can determine the current location of a file using ftell(). and its prototype is int fseek(FILE *fp. It returns the location of the file position indicator within the file associated with fp. long offset.

} The following program uses ftell( ) and fseek() to copy the contents of one file into another in reverse order. it returns -1L. exit(1). if (argc !=2) { printf(“File name missing”). SEEK_SET)) { printf("seek error"). #include "stdio.h" #include "stdlib. you will want to use random access only on binary files. The following program uses fseek() to report the value of any byte within the file specified on the command line.occurs. char *argv[]) { long loc. fclose (fp) . FILE *fp. loc. } printf("Value at loc %ld is %d". fgetc(fp)). &loc) . exit(1). exit(1) . 244 . In general. } printf("Enter byte to seek to: ") . } if ((fp = fopen(argv[1]. if(fseek(fp. loc.h" void main(int argc. “rb”)) == NULL) { printf(“cannot open file”). scanf("%ld".

/* see if filename is specified */ if(argc!=3) { printf("File name missing"). fputc(ch. } if((in = fopen(argv[1]. exit (1) . loc = ftell(in) . "rb")) == NULL) { printf("cannot open file") . } if((out = fopen(argv[2]. FILE *in.h" #include "stdlib. exit (1) . } 245 . / * back up past end-of-file mark */ while (loc >= 0L) { fseek(in. /* copy file in reverse order */ loc = loc-2. } /* find end of source file */ fseek(in. SEEK_SET) . 0L. } fclose (in) . ch = fgetc (in) . "wb")) ==NULL) { printf("cannot open file"). loc--. out) .#include "stdio. *out.h" void main(int argc. loc. char ch. char *argv[]) { long loc. SEEK_END). exit(1). fclose (out) .

Sign up to vote on this title
UsefulNot useful

Master Your Semester with Scribd & The New York Times

Special offer: Get 4 months of Scribd and The New York Times for just $1.87 per week!

Master Your Semester with a Special Offer from Scribd & The New York Times