You are on page 1of 106

Programming with C

1. Introduction to Problem Solving Flow charts, Tracing flow charts, Problem solving methods, Need for computer Languages, Sample Programs written in C 2. C Language preliminaries: C character set, Identifiers and keywords, Data types, Declarations, Expressions, statements and symbolic constants 3. Input-Output: getchar, putchar, scanf, printf, gets, puts, functions. 4. Pre-processor commands: #include, #define, #ifdef 5. Preparing and running a complete C program 6. Operators and expressions: Arithmetic, unary, logical, bit-wise, assignment and conditional operators 7. Control statements: While, do-while, for statements, nested loops, if else, switch, break, Continue, and goto statements, comma operators 8. Storage types: Automatic, external, register and static variables. 9. Functions Defining and accessing, passing arguments, Function prototypes, Recursion, Library functions, Static functions 10. Arrays: Defining and processing, Passing arrays to a function, Multi dimensional arrays. 11. Strings Defining and operations on strings. 12. Pointers Declarations, Passing pointers to a function, Operations on pointers, Pointer Arithmetic, Pointers and arrays, Arrays of pointers function pointers. 13. Structures Defining and processing, Passing to a function, Unions, typedef, array of structure, and pointer to structure 14. File structures:
1

Definitions, concept of record, file operations: Storing, creating, retrieving, updating Sequential, relative, indexed and random access mode, Files with binary mode(Low level), performance of Sequential Files, Direct mapping techniques: Absolute, relative and indexed sequential files (ISAM) concept of index, levels of index, overflow of handling. 15. File Handling: File operation: creation, copy, delete, update, text file, binary file. Syllabus for MCA First Year Semester I (with effect from the academic year 2007-2008) Term work/ Practical: Each candidate will submit a journal in which at least 12 practical assignments based on the above syllabus along with the flow chart and program listing will be submitted with the internal test paper. Test graded for 10 marks and Practical graded for 15 marks. List of Practical Two programs based on functions. Two programs based on pointers. Four programs based on Remaining portion eg. Control statements, Structures and Unions etc. Three programs based on Different File Operations (File Handling) References : 1. Mastering C by Venugopal, Prasad TMH 2. Complete reference with C Tata McGraw Hill 3. C programming E.Balagurusamy Tata McGray Hill 4. How to solve it by Computer : Dromey, PHI 5. Schaums outline of Theory and Problems of programming with C : Gottfried 6. The C programming language : Kerninghan and Ritchie 7. Programming in ANSI C : Ramkumar Agarwal 8. Mastering C by Venugopal, Prasad TMH 9. Let Us C by kanetkar 10. An introduction to data structures with applications, Jean-Paul Trembly and Paul Sorenson, (2nd edition), 1884

Chapter 1 Contents Flow charts Tracing flow charts

Introduction to Problem Solving

Problem solving methods Need for computer Languages Sample Programs written in C

Flow Chart A Flow Chart is a diagrammatic representation that gives a stepby-step solution to a given problem. A Flowchart is a common type of diagram that :
a. represents an algorithm or process,

b. showing the steps as boxes of various kinds, and


c. Shows their order by connecting these with arrows.

Data is represented in these boxes, and arrows connecting them represent flow / direction of flow of data. A flow chart can therefore be used to: 1. Define and analyze processes; 2. Build a step-by-step picture of the process for analysis, discussion, or communication; and 3. Define, standardize or find areas for improvement in a process

Fig : A simple flowchart representing a process for dealing with a non-functioning TV Remote Flowchart Symbols Different flow chart symbols have different meanings. The most common flow chart symbols are:
1. Terminator: An oval flow chart shape indicating the start or end of

the process.
2. Process: A rectangular flow chart shape indicating a normal

process flow step.


3. Decision: A diamond flow chart shape indication a branch in the

process flow.
4. Connector: A small, labeled, circular flow chart shape used to

indicate a jump in the process flow.


5. Data: A parallelogram that indicates data input or output (I/O) for a

process.
4

6. Document: used to indicate a document or report (see image in

sample flow chart below). A really simplistic flow chart showing the flow chart symbols described above can be seen below:
START TERMINATOR

PROCESS NO
DECISIO N

YES DATA

DOCUMENT

END TERMINATOR

Need for Programming Languages


5

A programming language is an artificial language designed to express computations that can be performed by a machine, particularly a computer. Programming languages can be used to create programs that control the behavior of a machine, to express algorithms precisely, or as a mode of human communication. Many programming languages have some form of written specification of their syntax (form) and semantics (meaning). Some languages are defined by a specification document. For example, the C programming language is specified by an ISO Standard. Other languages, such as Perl, have a dominant implementation that is used as a reference. The earliest programming languages predate the invention of the computer, and were used to direct the behavior of machines such as Jacquard looms and player pianos. Thousands of different programming languages have been created, mainly in the computer field, with many more being created every year. Most programming languages describe computation in an imperative style, i.e., as a sequence of commands, although some languages, such as those that support functional programming or logic programming, use alternative forms of description.

Sample C Programs /*Hello world program*/ #include<stdio.h> #include<conio.h> void main() { printf(hello world); } /* addition of 2 numbers */ #include<stdio.h> #include<conio.h> void main() { int a, b,c; c=0; a=3; b=4; c = a + b: printf(result of addition = %d,c); }

CHAPTER 2 C LANGUAGE PRELIMINARIES CONTENTS


C character set Identifiers and keywords Data types Declarations Expressions Statements Symbolic constants

C CHARACTER SET
A character denotes any alphabet, digit or symbols to represent information. The character set in C Language can be grouped into the following categories. 1. 2. 3. 4. Letters Digits Special Characters White Spaces

White Spaces are ignored by the compiler until they are a part of string constant. White Space may be used to separate words, but are strictly prohibited while using between characters of keywords or identifiers. Digits: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 Alphabets: a, b, .z A, B, ...Z Arithmetic Operations: +, -, *, /, %(Mod) Special Characters:

( = \

) ! blan k

{ $ & -

} ? | _

[ . ^ /

] , ~ *

< : ` %

> ; # @

CONSTANTS & VARIABLES


7

Constants
A constant value is the one which does not change during the execution of a program. C supports several types of constants. 1. 2. 3. 4. Integer Constants Real Constants Single Character Constants String Constants

Integer Constants An integer constant is a sequence of digits. There are 3 types of integers namely decimal integer, octal integers and hexadecimal integer. Decimal Integers consists of a set of digits 0 to 9 preceded by an optional + or - sign. Spaces, commas and non digit characters are not permitted between digits. Example for valid decimal integer constants are 123, -3, 0, 562321, + 78 Some examples for invalid integer constants are 15 750, 20,000, Rs. 1000 Octal Integers constant consists of any combination of digits from 0 through 7 with a O at the beginning. Some examples of octal integers are O26, O, O347, O676 Hexadecimal integer constant is preceded by OX or Ox, they may contain alphabets from A to F or a to f. The alphabets A to F refers to 10 to 15 in decimaldigits. Example of valid hexadecimal integers are OX2, OX8C, OXbcd, Ox 1. Real Constants Real Constants consists of a fractional part in their representation. Integer constants are inadequate to represent quantities that vary continuously. These quantities are represented by numbers containing fractional parts like 26.082. Example of realconstants are 0.0026, -0.97, 435.29, +487.0 Real Numbers can also be represented by exponential notation. The general form for exponential notation is mantissa exponent. The mantissa is either a real number expressed in decimal notation or an integer. The exponent is an integer number with an optional plus or minus sign.

Single Character Constants A Single Character constant represent a single character which is enclosed in a pair of quotation symbols. Example for character constants are 8

'5', 'x', ';', ' ' All character constants have an equivalent integer value which is called ASCII Values.

String Constants A string constant is a set of characters enclosed in double quotation marks. The characters in a string constant sequence may be an alphabet, number, special character and blank space. Example of string constants are "VISHAL", "1234", "God Bless", "!.....?"

Variables
A variable is a value that can change any time. It is a memory location used to store a data value. A variable name should be carefully chosen by the programmer so that its use is reflected in a useful way in the entire program. Variable names are case sensitive. Example of variable names are Sun, number, Salary, Emp_name, average1

IDENTIFIERS AND KEYWORDS


Every word in C language is a keyword or an identifier/variable. Keywords in C language cannot be used as a variable name. They are specifically used by the compiler for its own purpose and they serve as building blocks of a c program.

Identifiers:
Identifiers are the names given to variables, classes, methods and interfaces. It must be a whole word and starts with either an alphabet or an underscore. They are case sensitive. No commas or blanks are allowed in it No special symbol other than an underscore can be used in it. Ex.: marks grace

sem1_rollno alpha

Keywords: Keywords are words that have special meaning to the C compiler. 9

An identifier cannot have the same spelling and case as a C keyword. C makes use of only 32 keywords or reserved words which combine with the formal syntax to the form the C programming language. All keywords in C are written in lower case. A keyword may not be used as a variable name. Ex.:
auto break case char const continue default do double else enum extern float for goto if int long register return short signed sizeof static struct switch typedef union unsigned void volatile while

Data types & Declarations


In c, there are three types of data In C language the system has to know before-hand, the type of numbers or characters being used in the program. These are data types. There are many data types in C language. A C programmer has to use appropriate data type as per his requirement. C language data types can be broadly classified as a. Primary data type b. Derived data type c. User-defined data type

DATA

PRIMARY DATA

SECONDARY DATA

USER DEFINED

CHAR INT FLOAT DOUBLE

ARRAY FUNCTION POINTER STRUCTUR E UNION

TYPEDEF ENUM

Fig: Data Types in C


Integer Data Type Integers are numbers without decimal point Integers are whole numbers with a range of values, range of values are machine dependent. 10

Generally an integer occupies 2 bytes memory space and its value range limited to -32768 to +32767 (that is, -215 to +215-1). A signed integer use one bit for storing sign and rest 15 bits for number. To control the range of numbers and storage space, C has three classes of integer storage namely short int, int and long int. All three data types have signed and unsigned forms. A short int requires half the amount of storage than normal integer. Unlike signed integer, unsigned integers are always positive and use all the bits for the magnitude of the number. Therefore, the range of an unsigned integer will be from 0 to 65535. The long integers are used to declare a longer range of values and it occupies 4 bytes of storage space. Syntax: int <variable name>; int num1; short int num2; long int num3; Example: 5, 6, 100, 2500.

Integer Data Type Memory Allocation:

11

Floating Point Data Type The float data type is used to store fractional numbers (real numbers) with 6 digits of precision. Floating point numbers are denoted by the keyword float. When the accuracy of the floating point number is insufficient, we can use the double to define the number. The double is same as float but with longer precision and takes double space (8 bytes) than float. To extend the precision further we can use long double which occupies 10 bytes of memory space. Syntax: float <variable name>; float num1; double num2; long double num3; Example: 9.125, 3.1254.

Floating Point Data Type Memory Allocation:

Character Data Type Character type variable can hold a single character and are declared by using the keyword char. As there are singed and unsigned int (either short or long), in the same way there are signed and unsigned chars; both occupy 1 byte each, but having different ranges. Unsigned characters have values between 0 and 255, signed characters have values from 128 to 127. Syntax: char <variable name>; char ch = a; Example: a, b, g, S, j.

12

Arithmetic Expressions
An expression is a combination of variables constants and operators written
according to the syntax of C language. In C every expression evaluates to a value i.e., every expression results in some value of a certain type that can be assigned to a variable. Some examples of C expressions are shown in the table given below.
Algebraic Expression
axbc (m + n) (x + y) (m + n) * (x + y) C Expression a*bc (ab / c) a*b/c

Evaluation of Expressions Expressions are evaluated using an assignment statement of the form Variable = expression; Variable is any valid C variable name. When the statement is encountered, the expression is evaluated first and then replaces the previous value of the variable on the left hand side. All variables used in the expression must be assigned values before evaluation is attempted.

Example of evaluation statements are x=a*bc y=b/c*a z = a b / c + d;

13

Statements
Each instruction in a C program is written as a separate statement. Therefore a complete C program would comprise of a series of statements. The statements in a program must appear in the same order in which we wish them to be executed; unless of course the logic of the problem demands a deliberate jump or transfer of control to a statement, which is out of sequence. Blank spaces may be inserted between two words to improve the readability of the statement. However, no blank spaces are allowed within a variable, constant or keyword. All statements are entered in small case letters. C has no specific rules for the position at which a statement is to be written. Thats why it is often called a free-form language. Every C statement must end with a (semicolon) ; Thus ; acts as a statement terminator.

Example # include <stdio.h> # include <conio.h> void main() { printf(hello world); }


printf(hello world); is an statement that ends with a semicolon.

Symbolic constants
C allows the definition of symbolic constants - names that will be replaced with their values when the program is compiled Symbolic constants are defined before main(), and the syntax is #define NAME value Example : #define ANGLE_MIN 0 #define ANGLE_MAX 360 would define ANGLE_MIN and ANGLE_MAX to the values 0 and 360, respectively. C distinguishes between lowercase and uppercase letters in variable names. It is customary to use capital letters in defining global constants.

14

CHAPTER 3 INPUT-OUTPUT
CONTENTS

getchar() putchar() scanf() printf() gets() puts()

One of the essential operations performed in a C language programs is to provide input values to the program and output the data produced by the program to a standard output device. We can assign values to variable through assignment statements such as x = 5 a = 0 ; and so on. Another method is to use the Input then scanf which can be used to read data from a key board. For outputting results we have used extensively the function printf which sends results out to a terminal. There exists several functions in C language that can carry out input output operations. These functions are collectively known as standard Input /Output Library. Each program that uses standard input / output function must contain the statement. # include < stdio.h > at the beginning.

Single character input output

The basic operation done in input output is to read characters from the standard input device such as the keyboard and to give output or writing it to the output unit usually the screen. The getchar function can be used to read a character from the standard input device. The scanf can also be used to achieve the function.

The getchar has the following form. Variable name = getchar(); Variable name is a valid C variable, that has been declared already and that possess the type char. Example program : # include < stdio.h > program void main ( ) program. // assigns stdio-h header file to wer // Indicates the starting point of the 15

{ char C, // variable declaration printf (Type one character:) ; // message to user C = getchar () ; // get a character from key board and stores it in variable C. printf ( The character we typed is = %c, C) ; // output } // Statement which displays value of C on // Standard screen. The putchar function which is analogous to getchar function can be used for writing characters one at a time to the output terminal. The general form is putchar (variable name); where variable is a valid C type variable that has already been declared Ex:putchar ( ); displays the value stored in variable C to the standard screen. Program shows the use of getchar function in an interactive environment. Example: #include < stdio.h > // Inserts stdio.h header file into the Pgm void main ( ) // Beginning of main function. { char in; // character declaration of variable in. printf ( please enter one character); // message to user in = getchar ( ) ; // assign the keyboard input value to in. putchar (in); // output in value to standard screen. } String input and output

The gets function receives the string from standard input device while puts outputs the string to the standard output device. A string is an array or set of characters. The function gets accepts the name of the string as a parameter, and fills the string with characters that are input from the keyboard till newline character is encountered. (That is till we press the enter key). At the end function gets appends a null terminator as must be done to any string and returns. The puts function displays the contents stored in its parameter on the standard screen. The standard form of the gets function is gets (str) Here "str" is a string variable. The standard form for the puts character is puts (str) Where str is a string variable.

Example:
# include < stdio.h > void main ( ) { char s [80]; printf (Type a string less than 80 characters:);

16

gets (s); printf (The string types is:); puts(s); }

Formatted Input For scanf:

The formatted input refers to input data that has been arranged in a particular format. Input values are generally taken by using the scanf function. The scanf function has the general form. scanf (control string, arg1, arg2, arg3 .argn); The format field is specified by the control string and the arguments arg1, arg2, .argn specifies the address of location where address is to be stored. The control string specifies the field format which includes format specifications and optional number specifying field width and theconversion character % and also blanks, tabs and newlines. The Blanks tabs and newlines are ignored by compiler. The conversion character % is followed by the type of data that is to be assigned to variable of the assignment. The field width specifier is optional. The general format for reading a integer number is %xd Here percent sign (%) denotes that a specifier for conversion follows and x is an integer number which specifies the width of the field of the number that is being read. The data type character d indicates that the number should be read in integer mode. Example : scanf (%3d %4d, &sum1, &sum2); If the values input are 175 and 1342 here value 175 is assigned to sum1 and 1342 to sum 2. Suppose the input data was follows 1342 and 175. The number 134 will be assigned to sum1 and sum2 has the value 2 because of %3d the number 1342 will be cut to 134 and the remaining part is assigned to second variable sum2. If floating point numbers are assigned then the decimal or fractional part is skipped by the computer. To read the long integer data type we can use conversion specifier % ld & % hd for short integer.

Input specifications for real number

Field specifications are not to be used while representing a real number therefore real numbers are specified in a straight forward manner using % f specifier. The general format of specifying a real number input is 17

scanf (% f , &variable); Example: scanf (%f %f % f, &a, &b, &c); With the input data 321.76, 4.321, 678 The values 321.76 is assigned to a , 4.321 to b & 678 to C. If the number input is a double data type then the format specifier should be % lf instead of %f. Input specifications for a character. Single character or strings can be input by using the character specifiers. The general format is % xc or %xs Where C and S represents character and string respectively and x represents the field width. The address operator need not be specified while we input strings. Example : scanf (%C %15C, &ch, nname): Here suppose the input given is a, Robert then a is assigned to ch and name will be assigned to Robert.

Printing One Line: printf();

The most simple output statement can be produced in C Language by using printf statement. It allows we to display information required to the user and also prints the variables we can also format the output and provide text labels. The simple statement such as printf (Enter 2 numbers); prompts the message enclosed in the quotation to be displayed.

A simple program to illustrate the use of printf statement:#include < stdio.h > main ( ) { printf (Hello!); printf (Welcome to the Institute of Distance & Open Learning!); } Output: Hello! Welcome to IDOL. 18

Both the messages appear in the output as if a single statement. If we wish to print the second message to the beginning of next line, a new line character must be placed inside the quotation marks. Example : printf (Hello!\n); OR printf (\n Welcome to the Institute of Distance & Open Learning); Conversion Strings and Specifiers: The printf ( ) function is quite flexible. It allows a variable number of arguments, labels and sophisticated formatting of output. The general form of the printf ( ) function is printf (conversion string, variable list); The conversion string includes all the text labels, escape character and conversion specifiers required for the desired output. The variable includes all the variable to be printed in order they are to be printed. There must be a conversion specifies after each variable. Specifier Meaning %c Print a character %d Print a Integer %i Print a Integer %e Print float value in exponential form. %f Print float value %g Print using %e or %f whichever is smaller %o Print actual value %s Print a string %x Print a hexadecimal integer (Unsigned) using lower case a F %X Print a hexadecimal integer (Unsigned) using upper case A F %a Print a unsigned integer. %p Print a pointer value %hx hex short %lo octal long %ld long

19

CHAPTER 4 PRE-PROCESSOR COMMANDS


CONTENTS #include

#define #ifdef

Introduction The C preprocessor is exactly what its name implies. It is a program that processes our source program before it is passed to the compiler. Preprocessor commands (often known as directives) form what can almost be considered a language within C language. We can certainly write C programs without knowing anything about the preprocessor or its facilities. But preprocessor is such a great convenience that virtually all C programmers rely on it. The preprocessor offers several features called preprocessor directives. Each of these preprocessor directives begin with a # symbol. The directives can be placed anywhere in a program but are most often placed at the beginning of a program, before the first function definition. We would learn the following preprocessor directives here: (a) Macro expansion (b) File inclusion (c) Conditional Compilation

Macro Expansion Example: #define UPPER 25 main( ) { int i ; for ( i = 1 ; i <= UPPER ; i++ ) printf ( "\n%d", i ) ; } In this program instead of writing 25 in the for loop we are writing it in the form of UPPER, which has already been defined before main( ) through the statement, #define UPPER 25 This statement is called macro definition or more commonly, just a macro. During preprocessing, the preprocessor replaces every occurrence of UPPER in the program with 25.

20

File Inclusion The second preprocessor directive well explore in this chapter is file inclusion. This directive causes one file to be included in another. The preprocessor command for file inclusion looks like this: #include "filename" and it simply causes the entire contents of filename to be inserted into the source code at that point in the program It can be used in two cases: (a) If we have a very large program, the code is best divided into several different files, each containing a set of related functions. It is a good programming practice to keep different sections of a large program separate. These files are #included at the beginning of main program file. (b) There are some functions and some macro definitions that we need almost in all programs that we write. These commonly needed functions and macro definitions can be stored in a file, and that file can be included in every program we write, which would add all the statements in this file to our program as if we have typed them in. It is common for the files that are to be included to have a .h extension. This extension stands for header file, possibly because it contains statements which when included go to the head of our program. The prototypes of all the library functions are grouped into different categories and then stored in different header files. For example prototypes of all mathematics related functions are stored in the header file math.h, prototypes of console input/output functions are stored in the header file conio.h, and so on. Actually there exist two ways to write #include statement. These are: #include "filename" #include <filename> The meaning of each of these forms is given below: #include "goto.c" This command would look for the file goto.c in the current directory as well as the specified list of directories as mentioned in the include search path that might have been set up. This command would look for the file goto.c in the specified list of directories only.
21

#include <goto.c>

Conditional Compilation We can, if we want, have the compiler skip over part of a source code by inserting the preprocessing commands #ifdef and #endif, which have the general form: #ifdef macroname statement 1 ; statement 2 ; statement 3 ; #endif If macroname has been #defined, the block of code will be processed as usual; otherwise not. main( ) { #ifdef OKAY statement 1 statement 2 statement 3 statement 4 #endif statement 5 statement 6 statement 7 }

; ; /* detects virus */ ; ; /* specific to stone virus */ ; ; ;

Here, statements 1, 2, 3 and 4 would get compiled only if the macro OKAY has been defined, and we have purposefully omitted the definition of the macro OKAY. At a later date, if we want that these statements should also get compiled all that we are required to do is to delete the #ifdef and #endif statements. Sometimes, instead of #ifdef the #ifndef directive is used. The #ifndef (which means if not defined) works exactly opposite to #ifdef. The above example if written using #ifndef, would look like this:

22

CHAPTER 5 PREPARING AND RUNNING A COMPLETE C PROGRAM Contents Planning a C program Writing a C program Writing a Program into the computer Compiling and executing Detecting Errors Debugging Techniques

Planning a C Program

A C program should be written using a top-down approach. It means than the overall program strategy should be set first and then proceed with the general logic of the program.

A program outline called pseudocode is made. It contains minimal program logic and more of program components such as header files, function headings, starting and closing braces, etc.

Example: Addition of two numbers is given by C=A+B

The steps required to write a program for adding two numbers is as follows: 1. 2. 3. 4. Declare variables, A, B & C Read values for A & B Add A & B, store result in C Display the value of C

Here is the program outline in the form of pseudocode /* Addition of two numbers*/ void main() { /* declare variables a, b & c*/ /* Read values for a & b*/ /* calculate value of c*/ /*display the value of c */ } Writing a C program
23

If the program strategy is well planned then this should be a very simple straightforward step. Caution should be taken to make sure that the sequence of statements is correct. Example: calculating the value of c before reading the value of a & b is a common mistake

Use proper indentation wherever required because it is the key that will help we to understand wer program when it becomes too large. Comment wer program wherever possible so that it reflects the program logic and makes it more readable A C program should not only execute successfully and give we results but also be readable and understandable. Example: /* Addition of two numbers*/ #include <stdio.h> #include <conio.h> void main() { int a, b, c; /* declare variables a, b & c*/ c = 0; /* initialize variable c */ scanf(%d%d,&a,&b); /* Read values for a & b*/ c = a + b; /* calculate value of c*/ printf(Result of Addition = %f,c); /*display the value of c */ }

Writing a Program into the computer Now the next step is to compile and execute the program. The process of Compilation and Execution is done in the software / Compiler, usually a Borland Turbo C/C++ compiler is widely used. The program can the typed and then executed in the compiler or it can be written in the compiler itself using its screen editor C programs are saved by the .c extension and c++ programs by .cpp. Example: Filenames could be Addition.c, idol.c, bscit.c
24

Compiling and executing

Now that the program is open in the compiler we are ready to compile it. Compilation is the process that tests the programs for errors. In our TC editor we can either use the keyboard shortcut Ctrl + c, or using the mouse directly click Compile in the menu bar.

If the compilation is successful then, we get a message 0 warnings & 0 errors, if not then the errors are listed line by line in a sequential order with a possible reason or mistake.

Once the program is successfully compiled and is found to be error free the next step is to execute it. It could be done either by using the key board shortcut CTRL + r, or using the mouse to directly click on Run in the menu bar

Detecting Errors All errors are difficult to be spotted before compiling, and are mostly detected when compiled. Compiling reveals the presence of syntactical or grammatical errors in a program and generates diagnostic messages Example: Common errors that are detected during compilation are Variable not defined, undefined symbol, function prototype missing

25

Chapter 6 Operators and expressions Contents

Arithmetic Unary Logical bit-wise assignment conditional operators

Operators An operator is a symbol that instructs C to perform some operation, or action, on one or more operands. An operand is something that an operator acts on. In C, all operands are expressions. C operators fall into several categories: The assignment operator Mathematical operators Relational operators Logical operators The Assignment Operator The assignment operator is the equal sign (=). Its use in programming is somewhat different from its use in regular math. If we write x = y; in a C program, it doesn't mean "x is equal to y." Instead, it means "assign the value of y to x." In a C assignment statement, the right side can be any expression, and the left side must be a variable name. Thus, the form is as follows: variable = expression; When executed, expression is evaluated, and the resulting value is assigned to variable. Mathematical Operators C's mathematical operators perform mathematical operations such as addition and subtraction. C has two unary mathematical operators and five binary mathematical operators. The unary mathematical operators are so named because they take a single operand. C has two unary mathematical operators, listed in Table below

Table: C's unary mathematical operators.


26

Operator Increment Decrement

Symbol ++ --

Action Increments the operand by one Decrements the operand by one

Examples ++x, x++ --x, x--

The increment and decrement operators can be used only with variables, not with constants. The operation performed is to add one to or subtract one from the operand. In other words, the statements ++x; --y; are the equivalent of these statements: x = x + 1; y = y - 1; we should note from above Table that either unary operator can be placed before its operand (prefix mode) or after its operand (postfix mode). These two modes are not equivalent. They differ in terms of when the increment or decrement is performed: When used in prefix mode, the increment and decrement operators modify their operand before it's used. When used in postfix mode, the increment and decrement operators modify their operand after it's used An example should make this clearer. Look at these two statements: x = 10; y = x++; After these statements are executed, x has the value 11, and y has the value 10. The value of x was assigned toy, and then x was incremented. In contrast, the following statements result in both y and x having the value 11.x is incremented, and then its value is assigned to y. x = 10; y = ++x; Remember that = is the assignment operator, not a statement of equality. As an analogy, think of = as the "photocopy" operator. The statement y = x means to copy x into y. Subsequent changes to x, after the copy has been made, have no effect on y.

Binary Mathematical Operators C's binary operators take two operands. The binary operators, which include the common mathematical operations found on a calculator, are listed in Table below.

27

Table: C's binary mathematical operators. Operator Addition Subtraction Multiplication Division Modulus Symbo l + * / % Action Adds two operands Subtracts the second operand from the first operand Multiplies two operands Divides the first operand by the second operand Gives the remainder when the first operand is divided by the second operand Example x+y x-y x*y x/y x%y

Relational Operators C's relational operators are used to compare expressions, asking questions such as, "Is x greater than 100?" or "Is y equal to 0?" An expression containing a relational operator evaluates to either true (1) or false (0). C's six relational operators are listed in Table below Operator Equal Greater than Less than Greater than or equal to Less than or equal to Not equal Symbo l == > < >= <= != Question Asked Is operand 1 equal to operand 2? Is operand 1 greater than operand 2? Is operand 1 less than operand 2? Is operand 1 greater than or equal to operand 2? Is operand 1 less than or equal to operand 2? Is operand 1 not equal to operand 2? Example x == y x>y x<y x >= y x <= y x != y

Table: Relational operators in use. Expression How It Reads 5 == 1 Is 5 equal to 1? 5>1 Is 5 greater than 1? 5 != 1 Is 5 not equal to 1? (5 + 10) == (3 * 5) Is (5 + 10) equal to (3 * 5)?

What It Evaluates To 0 (false) 1 (true) 1 (true) 1 (true)

28

Table: C's logical operators. Operator Symbol AND && OR || NOT !

Example exp1 && exp2 exp1 || exp2 !exp1

Table: C's logical operators in use. Expression What It Evaluates To (exp1 && exp2) True (1) only if both exp1 and exp2 are true; false (0) otherwise (exp1 || exp2) True (1) if either exp1 or exp2 is true; false (0) only if both are false (!exp1) False (0) if exp1 is true; true (1) if exp1 is false We can see that expressions that use the logical operators evaluate to either true or false, depending on the true/false value of their operand(s). Table below shows some actual code examples. Table: Code examples of C's logical operators. Expression (5 == 5) && (6 != 2) (5 > 1) || (6 < 1) (2 == 1) && (5 == 5) !(5 == 4) What It Evaluates To True (1), because both operands are true True (1), because one operand is true False (0), because one operand is false True (1), because the operand is false

Compound Assignment Operators C's compound assignment operators provide a shorthand method for combining a binary mathematical operation with an assignment operation. For example, say we want to increase the value of x by 5, or, in other words, add 5 to x and assign the result to x. We could write x = x + 5; Using a compound assignment operator, which we can think of as a shorthand method of assignment, we would write x += 5; In more general notation, the compound assignment operators have the following syntax (where op represents a binary operator): exp1 op= exp2 This is equivalent to writing exp1 = exp1 op exp2;
29

We can create compound assignment operators using the five binary mathematical operators Table: Examples of compound assignment operators. When We Write This... x *= y y -= z + 1 a /= b x += y / 8 y %= 3 It Is Equivalent To This x=x*y y=y-z+1 a=a/b x=x+y/8 y=y%3

The Conditional Operator The conditional operator is C's only ternary operator, meaning that it takes three operands. Its syntax is exp1 ? exp2 : exp3; If exp1 evaluates to true (that is, nonzero), the entire expression evaluates to the value of exp2. If exp1 evaluates to false (that is, zero), the entire expression evaluates as the value of exp3. For example, the following statement assigns the value 1 to x if y is true and assigns 100 to x if y is false: x = y ? 1 : 100; Likewise, to make z equal to the larger of x and y, we could write z = (x > y) ? x : y; Perhaps we've noticed that the conditional operator functions somewhat like an if statement. The preceding statement could also be written like this: if (x > y) z = x; else z = y; The conditional operator can't be used in all situations in place of an if...else construction, but the conditional operator is more concise. The conditional operator can also be used in places we can't use an if statement, such as inside a single printf() statement: printf( "The larger value is %d", ((x > y) ? x : y) );
30

Bitwise Operators One of Cs powerful features is a set of bit manipulation operators. These permit the programmer to access and manipulate individual bits within a piece of data. Operator ~ >> << & | ^ Ones Complement Operator On taking ones complement of a number, all 1s present in the number are changed to 0s and all 0s are changed to 1s. For example ones complement of 1010 is 0101. Similarly, ones complement of 1111 is 0000. Thus, ones complement of 65 means ones complement of 0000 0000 0100 0001, which is binary equivalent of 65. Ones complement of 65 therefore would be, 1111 1111 1011 1110 Ones complement operator is represented by the symbol main( ) { int j, k ; for ( j = 0 ; j <= 3 ; j++ ) { printf ( "\nDecimal %d is same as binary ", j ) ; showbits ( j ) ; k = ~j ; printf ( "\nOnes complement of %d is ", j ) ; showbits ( k ) ; } } And here is the output of the above program... Decimal 0 is same as binary 0000000000000000 Ones complement of 0 is 1111111111111111 Decimal 1 is same as binary 0000000000000001 Ones complement of 1 is 1111111111111110 Decimal 2 is same as binary 0000000000000010 Ones complement of 2 is 1111111111111101 Decimal 3 is same as binary 0000000000000011 Ones complement of 3 is 1111111111111100
31

Meaning Ones Complement Operator Right Shift Operator Left Shift Operator Bitwise AND Operator Bitwise OR Operator Bitwise XOR Operator

Right Shift Operator The right shift operator is represented by >>. It needs two operands. It shifts each bit in its left operand to the right. The number of places the bits are shifted depends on the number following the operator (i.e. its right operand). Thus, ch >> 3 would shift all bits in ch three places to the right. Similarly, ch >> 5 would shift all bits 5 places to the right. For example, if the variable ch contains the bit pattern 11010111, then, ch >> 1 would give 01101011 and ch >> 2 would give 00110101. As the bits are shifted to the right, blanks are created on the left. These blanks must be filled somehow. They are always filled with zeros. main( ) { int i = 5225, j, k ; printf ( "\nDecimal %d is same as binary ", i ) ; showbits ( i ) ; for ( j = 0 ; j <= 5 ; j++ ) { k = i >>j ; printf ( "\n%d right shift %d gives ", i, j ) ; showbits ( k ) ; } } The output of the above program would be... Decimal 5225 is same as binary 0001010001101001 5225 right shift 0 gives 0001010001101001 5225 right shift 1 gives 0000101000110100 5225 right shift 2 gives 0000010100011010 5225 right shift 3 gives 0000001010001101 5225 right shift 4 gives 0000000101000110 5225 right shift 5 gives 0000000010100011

Left Shift Operator This is similar to the right shift operator, the only difference being that the bits are shifted to the left, and for each bit shifted, a 0 is added to the right of the number.
32

main( ) { int i = 5225, j, k ; printf ( "\nDecimal %d is same as ", i ) ; showbits ( i ) ; for ( j = 0 ; j <= 4 ; j++ ) { k = i <<j ; printf ( "\n%d left shift %d gives ", i, j ) ; showbits ( k ) ; } } The output of the above program would be... Decimal 5225 is same as binary 0001010001101001 5225 left shift 0 gives 0001010001101001 5225 left shift 1 gives 0010100011010010 5225 left shift 2 gives 0101000110100100 5225 left shift 3 gives 1010001101001000 5225 left shift 4 gives 0100011010010000 Bitwise AND Operator This operator is represented as &. It is different than &&, the logical AND operator. The & operator operates on two operands. While operating upon these two operands they are compared on a bit-by-bit basis. Hence both the operands must be of the same type (either char or int). The second operand is often called an AND mask. The & operator operates on a pair of bits to yield a resultant bit. First bit 0 0 1 1 Second bit 0 1 0 1 Resultant bit 0 0 0 1

The example given below shows more clearly what happens while ANDing one operand with another. This operand when ANDed bitwise 1 0 1 0 1 0 1 0 With this operand yields 1 1 0 this result 1 0 0 Bitwise OR Operator 0 0 0 0 0 0 1 1 1 0
33

Another important bitwise operator is the OR operator which is represented as |. The rules that govern the value of the resulting bit obtained after ORing of two bits is shown in the truth table below. First bit 0 0 1 1 Second bit 0 1 0 1 Resultant bit 0 1 1 1

Using the Truth table confirm the result obtained on ORing the two operands as shown below. 11010000 Original bit pattern 00000111 OR mask ------------11010111 Resulting bit pattern Bitwise XOR Operator The XOR operator is represented as ^ and is also called an Exclusive OR Operator. The OR operator returns 1, when any one of the two bits or both the bits are 1, whereas XOR returns 1 only if one of the two bits is 1. The truth table for the XOR operator is given below First bit 0 1 Second bit 0 1 Resultant bit 1 0

XOR operator is used to toggle a bit ON or OFF. A number XORed with another number twice gives the original number

34

Chapter 7 Control statements Contents While do-while for statements nested loops if else, switch break, continue and goto statements comma operators
The while Statement The while statement, also called the while loop, executes a block of statements as long as a specified condition is true. The while statement has the following form: while (condition) statement condition is any C expression, and statement is a single or compound C statement. When program execution reaches a while statement, the following events occur: 1. The expression condition is evaluated. 2. If condition evaluates to false (that is, zero), the while statement terminates, and execution passes to the first statement following statement 3. If condition evaluates to true (that is, nonzero), the while statement terminates, and execution passes to the first statement following statement. 4. Execution returns to step 1 Figure. The operation of a while statement.

35

/* Demonstrates a simple while statement */ #include <stdio.h> int count; int main() { /* Print the numbers 1 through 20 */ count = 1; while (count <= 20) { printf("%d\n", count); count++; } return 0; } Output: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 The do...while Loop C's loop construct is the do...while loop, which executes a block of statements as long as a specified condition is true. The do...while loop tests the condition at the end of the loop rather than at the beginning, as is done by the for loop and the while loop. The structure of the do...while loop is as follows: do statement while (condition); condition is any C expression, and statement is a single or compound C statement. When program execution reaches a do...while statement, the following events occur: 1. The statements in statement are executed. 2. condition is evaluated. If it's true, execution returns to step 1. If it's false, the loop terminates 36

The statements associated with a do...while loop are always executed at least once. This is because the test condition is evaluated at the end, instead of the beginning, of the loop. In contrast, for loops and while loops evaluate the test condition at the start of the loop, so the associated statements are not executed at all if the test condition is initially false. Example: /* Demonstrates a simple do...while statement */ #include <stdio.h> int get_menu_choice( void ); main() { int choice; choice = get_menu_choice(); printf("We chose Menu Option %d\n", choice ); return 0; } int get_menu_choice( void ) { int selection = 0; do { printf("\n" ); printf("\n1 - Add a Record" ); printf("\n2 - Change a record"); printf("\n3 - Delete a record"); printf("\n4 - Quit"); printf("\n" ); printf("\nEnter a selection: " ); scanf("%d", &selection ); }while ( selection < 1 || selection > 4 ); return selection; 37

} 1 2 3 4 - Add a Record - Change a record - Delete a record Quit

Enter a selection: 8 1 - Add a Record 2 - Change a record 3 - Delete a record 4 - Quit Enter a selection: 4 We chose Menu Option 4 The for Statement for (initial; condition; increment) statement(s); initial is any valid C expression. It is usually an assignment statement that sets a variable to a particular value condition is any valid C expression. It is usually a relational expression. When condition evaluates to false (zero), the for statement terminates, and execution passes to the first statement following statement(s); otherwise, the C statement(s) in statement(s) are executed. increment is any valid C expression. It is usually an expression that increments a variable initialized bythe initial expression. Statement(s) are the C statements that are executed as long as the condition remains true. A for statement is a looping statement. It can have an initialization, test condition, and increment as parts of its command. The for statement executes the initial expression first. It then checks the condition. If the condition is true, the statements execute. Once the statements are completed, the increment expression is evaluated. The for statement then rechecks the condition and continues to loop until the condition is false. Example: /* Prints the value of x as it counts from 0 to 9 */ int x; for (x = 0; x <10; x++) printf( "\nThe value of x is %d", x ); Example: /*Obtains values from the user until 99 is entered */ int nbr = 0; for ( ; nbr != 99; ) scanf( "%d", &nbr );

Example: /* Lets user enter up to 10 integer values */ /* Values are stored in an array named value. If 99 is */ 38

/* entered, the loop stops */ int value[10]; int ctr,nbr=0; for (ctr = 0; ctr < 10 && nbr != 99; ctr++) { puts("Enter a number, 99 to quit "); scanf("%d", &nbr); value[ctr] = nbr; } Nesting for Statements A for statement can be executed within another for statement. This is called nesting. Nested for statements. /* Demonstrates nesting two for statements */ #include <stdio.h> void draw_box( int, int); main() { draw_box( 8, 35 ); return 0; } void draw_box( int row, int column ) { int col; for ( ; row > 0; row--) { for (col = column; col > 0; col--) printf("X"); printf("\n"); } } XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX When we run this program, 280 Xs are printed on-screen, forming an 8*35 square. The program has only one command to print an X, but it is nested in two loops. In this listing, a function prototype for draw_box() is declared. This function takes two type intvariables, row and column, which contain the dimensions of the box of Xs to be drawn. main() calls draw_box() and passes the value 8 as the row and the value 35 as the column. Looking closely at the draw_box() function, we might see a couple things we don't readily understand. The first is why the local variable col was declared. The 39

second is why the second printf() was used. Both of these will become clearer after we look at the two for loops.

The if Statement Relational operators are used mainly to construct the relational expressions used in if and while statements, how relational operators are used to make program control statements. Statements in a C program normally execute from top to bottom, in the same order as they appear in wer source code file. A program control statement modifies the order of statement execution. Program control statements can cause other program statements to execute multiple times or to not execute at all, depending on the circumstances. The if statement is one of C's program control statements. In its basic form, the if statement evaluates an expression and directs program execution depending on the result of that evaluation. The form of an if statement is as follows: if (expression) statement; If expression evaluates to true, statement is executed. If expression evaluates to false, statement is not executed. In either case, execution then passes to whatever code follows the if statement. We could say that execution of statement depends on the result of expression. Note that both the line if (expression) and the line statement; are considered to comprise the complete if statement; they are not separate statements. An if statement can control the execution of multiple statements through the use of a compound statement, or block. As defined earlier in this chapter, a block is a group of two or more statements enclosed in braces. A block can be used anywhere a single statement can be used. Therefore, we could write an if statement as follows: if (expression) { statement1; statement2; /* additional code goes here */ statementn; }

Example: Demonstrates if statements. /* Demonstrates the use of if statements */ #include <stdio.h> 40

int x, y; main() { /* Input the two values to be tested */ printf("\nInput an integer value for x: "); scanf("%d", &x); printf("\nInput an integer value for y: "); scanf("%d", &y); /* Test values and print result */ if (x == y) printf("x is equal to y\n"); if (x > y) printf("x is greater than y\n"); if (x < y) printf("x is smaller than y\n"); return 0; } Input an integer value for x: 100 Input an integer value for y: 10 x is greater than y Input an integer value for x: 10 Input an integer value for y: 100 x is smaller than y Input an integer value for x: 10 Input an integer value for y: 10 x is equal to y The else Clause An if statement can optionally include an else clause. The else clause is included as follows: if (expression) statement1; else statement2; If expression evaluates to true, statement1 is executed. If expression evaluates to false, statement2 is executed. Both statement1 and statement2 can be compound statements or blocks. Example: An if statement with an else clause. /* Demonstrates the use of if statement with else clause */ #include <stdio.h> int x, y; main() { /* Input the two values to be tested */ printf("\nInput an integer value for x: "); scanf("%d", &x); printf("\nInput an integer value for y: "); scanf("%d", &y); /* Test values and print result */ if (x == y) 41

printf("x is equal to y\n"); else if (x > y) printf("x is greater than y\n"); else printf("x is smaller than y\n"); return 0; } Input an integer value for x: 99 Input an integer value for y: 8 x is greater than y Input an integer value for x: 8 Input an integer value for y: 99 x is smaller than y Input an integer value for x: 99 Input an integer value for y: 99 x is equal to y The if Statement : Different forms Form 1 if( expression ) statement1; next_statement; This is the if statement in its simplest form. If expression is true, statement1 is executed. If expression is not true, statement1 is ignored. Form 2 if( expression ) statement1; else statement2; next_statement; This is the most common form of the if statement. If expression is true, statement1 is executed; otherwise, statement2 is executed. Form 3 if( expression1 ) statement1; else if( expression2 ) statement2; else statement3; next_statement; This is a nested if. If the first expression, expression1, is true, statement1 is executed before the program continues with the next_statement. If the first expression is not true, the second expression, expression2, is checked. If the first expression is not true, and the second is true, statement2 is executed. If both expressions are false, statement3 is executed. Only one of the three statements is executed. Example 1 if( salary > 45,0000 ) tax = .30; else tax = .25; 42

Example 2 if( age < 18 ) printf("Minor"); else if( age < 65 ) printf("Adult"); else printf( "Senior Citizen"); The switch Statement C's most flexible program control statement is the switch statement, which lets wer program execute different statements based on an expression that can have more than two values. Earlier control statements, such as if, were limited to evaluating an expression that could have only two values: true or false. To control program flow based on more than two values, we had to use multiple nested if statements, as shown in Listing 13.4. The switch statement makes such nesting unnecessary. The general form of the switch statement is as follows: switch (expression) { case template_1: statement(s); case template_2: statement(s); ... case template_n: statement(s); default: statement(s); } In this statement, expression is any expression that evaluates to an integer value: type long, int, or char. The switch statement evaluates expression and compares the value against the templates following each case label, and then one of the following happens: If a match is found between expression and one of the templates, execution is transferred to the statement that follows the case label. If no match is found, execution is transferred to the statement following the optional default label. If no match is found and there is no default label, execution passes to the first statement following the switch statement's closing brace.

Using the switch statement. /* Demonstrates the switch statement. */ #include <stdio.h> main() { int reply; puts("Enter a number between 1 and 5:"); scanf("%d", &reply); switch (reply) { case 1: puts("We entered 1."); 43

case 2: puts("We entered 2."); case 3: puts("We entered 3."); case 4: puts("We entered 4."); case 5: puts("We entered 5."); default: puts("Out of range, try again."); } return 0; } Enter a number between 1 and 5: 2 We entered 2. We entered 3. We entered 4. We entered 5. Out of range, try again. It looks as though the switch statement finds the first matching template and then executes everything that follows (not just the statements associated with the template). That's exactly what does happen, though. That's how switch is supposed to work. In effect, it performs a goto to the matching template. To ensure that only the statements associated with the matching template are executed, include a break statement where needed. Listing 13.6 shows the program rewritten with break statements. Now it functions properly. Correct use of switch, including break statements as needed. /* Demonstrates the switch statement correctly. */ #include <stdio.h> main() { int reply; puts("\nEnter a number between 1 and 5:"); scanf("%d", &reply); switch (reply) { case 0: break; case 1: { puts("We entered 1.\n"); break; } case 2: { puts("We entered 2.\n"); break; } case 3: 44

{ puts("We entered 3.\n"); break; } case 4: { puts("We entered 4.\n"); break; } case 5: { puts("We entered 5.\n"); break; } default: { puts("Out of range, try again.\n"); } } /* End of switch */ } Enter a number between 1 and 5: 1 We entered 1. Enter a number between 1 and 5: 6 Out of range, try again.

The break Statement The break statement can be placed only in the body of a for loop, while loop, or do...while loop. (It's valid in a switch statement too, but that topic isn't covered until later in this chapter.) When a break statement is encountered, execution exits the loop. The following is an example: for ( count = 0; count < 10; count++ ) { if ( count == 5 ) break; } Left to itself, the for loop would execute 10 times. On the sixth iteration, however, count is equal to 5, and the break statement executes, causing the for loop to terminate. Execution then passes to the statement immediately following the for loop's closing brace. When a break statement is encountered inside a nested loop, it causes the program to exit the innermost loop only. Example: Using the break statement. /* Demonstrates the break statement. */ 45

#include <stdio.h> char s[] = "This is a test string. It contains two sentences."; main() { int count; printf("\nOriginal string: %s", s); for (count = 0; s[count]!='\0'; count++) { if (s[count] == `.') { s[count+1] = `\0'; break; } } printf("\nModified string: %s\n", s); return 0; } Original string: This is a test string. It contains two sentences. Modified string: This is a test string. The continue Statement Like the break statement, the continue statement can be placed only in the body of a for loop, a while loop, or a do...while loop. When a continue statement executes, the next iteration of the enclosing loop begins immediately. The statements between the continue statement and the end of the loop aren't executed. The operation of continue is also shown in Figure 13.1. Notice how this differs from the operation of a break statement. Following example uses the continue statement. This program accepts a line of input from the keyboard and then displays it with all lowercase vowels removed. Example: Using the continue statement. 1: /* Demonstrates the continue statement. */ 2: 3: #include <stdio.h> 4: 5: main() 6: { 7: /* Declare a buffer for input and a counter variable. */ 8: 9: char buffer[81]; 10: int ctr; 11: 12: /* Input a line of text. */ 13: 14: puts("Enter a line of text:"); 15: gets(buffer); 16: 17: /* Go through the string, displaying only those */ 46

18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36:

/* characters that are not lowercase vowels. */ for (ctr = 0; buffer[ctr] !='\0'; ctr++) { /* If the character is a lowercase vowel, loop back */ /* without displaying it. */ if (buffer[ctr] == `a' || buffer[ctr] == `e' || buffer[ctr] == `i' || buffer[ctr] == `o' || buffer[ctr] == `u') continue; /* If not a vowel, display it. */ putchar(buffer[ctr]); } return 0; }

Enter a line of text: This is a line of text Ths s ln f txt Although this isn't the most practical program, it does use a continue statement effectively. Lines 9 and 10 declare the program's variables. buffer[] holds the string that the user enters in line 15. The other variable, ctr, increments through the elements of the array buffer[], while the for loop in lines 20 through 34 searches for vowels. For each letter in the loop, an if statement in lines 26 through 28 checks the letter against lowercase vowels. If there is a match, a continue statement executes, sending control back to line 20, the for statement. If the letter isn't a vowel, control passes to the if statement, and line 33 is executed. Line 33 contains a new library function, putchar(), which displays a single character onscreen. The continue Statement continue; continue is used inside a loop. It causes the control of a program to skip the rest of the current iteration of a loop and start the next iteration. Example int x; printf("Printing only the even numbers from 1 to 10\n"); for( x = 1; x <= 10; x++ ) { if( x % 2 != 0 ) /* See if the number is NOT even */ continue; /* Get next instance x */ printf( "\n%d", x ); }

The goto Statement

47

The goto statement is one of C's unconditional jump, or branching, statements. When program execution reaches a goto statement, execution immediately jumps, or branches, to the location specified by the goto statement. This statement is unconditional because execution always branches when a goto statement is encountered; the branch doesn't depend on any program conditions (unlike if statements, for example). A goto statement and its target must be in the same function, but they can be in different blocks. Take a look at Listing 13.3, a simple program that uses a goto statement. Example: Using the goto statement. 1: /* Demonstrates the goto statement */ 2: 3: #include <stdio.h> 4: 5: main() 6: { 7: int n; 8: 9: start: ; 10: 11: puts("Enter a number between 0 and 10: "); 12: scanf("%d", &n); 13: 14: if (n < 0 ||n > 10 ) 15: goto start; 16: else if (n == 0) 17: goto location0; 18: else if (n == 1) 19: goto location1; 20: else 21: goto location2; 22: 23: location0: ; 24: puts("We entered 0.\n"); 25: goto end; 26: 27: location1: ; 28: puts("We entered 1.\n"); 29: goto end; 30: 31: location2: ; 32: puts("We entered something between 2 and 10.\n"); 33: 34: end: ; 35: return 0; 36: } Enter a number between 0 and 10: 1 We entered 1. Enter a number between 0 and 10: 9 We entered something between 2 and 10. 48

This is a simple program that accepts a number between 0 and 10. If the number isn't between 0 and 10, the program uses a goto statement on line 15 to go to start, which is on line 9. Otherwise, the program checks on line 16 to see whether the number equals 0. If it does, a goto statement on line 17 sends control to location0 (line 23), which prints a statement on line 24 and executes another goto. The goto on line 25 sends control to end at the end of the program. The program executes the same logic for the value of 1 and all values between 2 and 10 as a whole. The target of a goto statement can come either before or after that statement in the code. The only restriction, as mentioned earlier, is that both the goto and the target must be in the same function. They can be in different blocks, however. We can use goto to transfer execution both into and out of loops, such as a for statement, but we should never do this. In fact, I strongly recommend that we never use the goto statement anywhere in wer programs. There are two reasons:We don't need it. No programming task requires the goto statement. We can always write the needed code using C's other branching statements. The goto Statement goto location; location is a label statement that identifies the program location where execution is to branch. A label statement consists of an identifier followed by a colon and a C statement: location: a C statement; If we want the label by itself on a line, we can follow it with the null statement (a semicolon by itself): location: ;

The Comma Operator The comma is frequently used in C as a simple punctuation mark, serving to separate variable declarations, function arguments, and so on. In certain situations, the comma acts as an operator rather than just as a separator. We can form an expression by separating two subexpressions with a comma. The result is as follows: Both expressions are evaluated, with the left expression being evaluated first. The entire expression evaluates to the value of the right expression. For example, the following statement assigns the value of b to x, then increments a, and then increments b: x = (a++ , b++); Because the ++ operator is used in postfix mode, the value of b--before it is incremented--is assigned to x. Using parentheses is necessary because the comma operator has low precedence, even lower than the assignment operator. As we'll learn in the next chapter, the most common use of the comma operator is in for statements. DO use (expression == 0) instead of (!expression). When compiled, these two expressions evaluate the same; however, the first is more readable. DO use the logical operators && and || instead of nesting if statements. DON'T confuse the assignment operator (=) with the equal to (==) operator. 49

50

Chapter 8 Storage types


Contents: Automatic, external, register and static variables. From C compilers point of view, a variable name identifies some physical location within the computer where the string of bits representing the variables value is stored. There are basically two kinds of locations in a computer where such a value may be kept Memory and CPU registers. It is the variables storage class that determines in which of these two locations the value is stored. Moreover, a variables storage class tells us: (a) Where the variable would be stored. (b) What will be the initial value of the variable, if initial value is not specifically assigned.(i.e. the default initial value). (c) What is the scope of the variable; i.e. in which functions the value of the variable would be available. (d) What is the life of the variable; i.e. how long would the variable exist. There are four storage classes in C: (a) Automatic storage class (b) Register storage class (c) Static storage class (d) External storage class Let us examine these storage classes one by one.

Automatic Storage Class


The features of a variable defined to have an automatic storage class are as under: Storage Memory. Default initial value An unpredictable value, which is often called a garbage value. Scope Local to the block in which the variable is defined. Till the control remains within the block in which the variable is defined.

Life

51

Scope and life of an automatic variable is illustrated in the following program.


main( ) { auto int i = 1 ; { { { printf ( "\n%d ", i ) ; } printf ( "%d ", i ) ; } printf ( "%d", i ) ; } }

The output of the above program is:


111

Register Storage Class


The features of a variable defined to be of register storage class are as under: Storage CPU registers. Default initial value Scope Garbage value. Local to the block in which the variable is defined. Till the control remains within the block in which the variable is defined.

Life

A value stored in a CPU register can always be accessed faster than the one that is stored in memory. Therefore, if a variable is used at many places in a program it is better to declare its storage class as register. A good example of frequently used variables is loop counters. We can name their storage class as register.
main( ) { register int i ; for ( i = 1 ; i <= 10 ; i++ ) printf ( "\n%d", i ) ; }

Here, even though we have declared the storage class of i as register, we cannot say for sure that the value of i would be stored in a CPU register. Because the number of CPU registers are limited, and they may be busy doing some other task. What happens in such an event... the variable works as if its storage class is auto.

Not every type of variable can be stored in a CPU register.

52

For example, if the microprocessor has 16-bit registers then they cannot hold a float value or a double value, which require 4 and 8 bytes respectively. However, if we use the register storage class for a float or a double variable we wont get any error messages. All that would happen is the compiler would treat the variables to be of auto storage class.

Static Storage Class


The features of a variable defined to have a static storage class are as under: Storage Default initial value Scope Memory. Zero. Local to the block in which the variable is defined. Value of the variable persists between different function calls.

Life

Example:
main() { increment( ) ; increment( ) ; increment( ) ; } increment( ) { static int i = 1 ; printf ( "%d\n", i ) ; i=i+1; }

Like auto variables, static variables are also local to the block in which they are declared. The difference between them is that static variables dont disappear when the function is no longer active. Their values persist. If the control comes back to the same function again the static variables have the same values they had last time around. In the above example, i is static, it is initialized to 1 only once. It is never initialized again. During the first call to increment( ), i is incremented to 2. Because i is static, this value persists. The next time increment( ) is called, i is not re-initialized to 1; on the contrary its old value 2 is still available. This current value of i (i.e. 2) gets printed and then i = i + 1 adds 1 to i to get a value of 3. When increment( ) is called the third time, the current value of i (i.e. 3) gets printed and once again i is incremented. In short, if the storage class is static then the statement static int i = 1 is executed only once, irrespective of how many times the same function is called. In the above 53

External Storage Class


The features of a variable whose storage class has been defined as external are as follows: Storage Default initial value Scope Life Memory. Zero. Global. As long as the programs execution doesnt come to an end.

that their scope is global, not local. External variables are declared outside all functions, yet are available to all functions that care to use them. Example:
int i ; main( ) { printf ( "\ni = %d", i ) ; increment( ) ; increment( ) ; decrement( ) ; decrement( ) ; } increment( ) { i=i+1; printf ( "\non incrementing i = %d", i ) ; } decrement( ) { i=i-1; printf ( "\non decrementing i = %d", i ) ; }

The output would be:


i=0 on incrementing i = 1 on incrementing i = 2 on decrementing i = 1 on decrementing i = 0

As is obvious from the above output, the value of i is available to the functions increment( ) and decrement( ) since i has been declared outside all functions.

We can make a few ground rules for usage of different storage classes in different programming situations with a view to:
54

(a) economise the memory space consumed by the variables (b) improve the speed of execution of the program The rules are as under: Use static storage class only if we want the value of a variable to persist between different function calls. Use register storage class for only those variables that are being used very often in a program. Reason is, there are very few CPU registers at our disposal and many of them might be busy doing something else. Make careful utilization of the scarce resources. A typical application of register storage class is loop counters, which get used a number of times in a program. Use extern storage class for only those variables that are being used by almost all the functions in the program. This would avoid unnecessary passing of these variables as arguments when making a function call. Declaring all the variables as extern would amount to a lot of wastage of memory space because these variables would remain active throughout the life of the program. If we dont have any of the express needs mentioned above, then use the auto storage class. In fact most of the times we end up using the auto variables, because often it so happens that once we have used the variables in a function we dont mind loosing them.

55

Chapter 9 Functions Contents Defining and accessing Passing arguments Function prototypes Recursion Library functions

Function: A function is a self-contained block of statements that perform a coherent task of some kind. Every C program can be thought of as a collection of these functions. Using a function is something like hiring a person to do a specific job. Sometimes the interaction with this person is very simple; sometimes its complex. Example: main() { message( ) ; printf ( "\nCry, and we stop the monotony!" ) ; } message( ) { printf ( "\nSmile, and the world smiles with we..." ) ; } And heres the output...
Smile, and the world smiles with we... Cry, and we stop the monotony!

Here, main( ) itself is a function and through it we are calling the function message( ). when we say that main( ) calls the function message( ), We mean that the control passes to the function message( ). The activity of main( ) is temporarily suspended; it falls asleep while the message( ) function wakes up and goes to work. When the message( ) function runs out of statements to execute, the control returns to main( ), which comes to life again and begins executing its code at the exact point where it left off. Thus, main( ) becomes the calling function, whereas message( ) becomes the called function.

56

From this program a number of conclusions can be drawn: Any C program contains at least one function. If a program contains only one function, it must be main( ). If a C program contains more than one function, then one (and only one) of these functions must be main( ), because program execution always begins with main( ). There is no limit on the number of functions that might be present in a C program. Each function in a program is called in the sequence specified by the function calls in main( ). After each function has done its thing, control returns to main( ).When main( ) runs out of function calls, the program ends. Passing Arguments The mechanism used to convey information to the function is the argument. We have unknowingly used the arguments in the printf( ) and scanf( ) functions; the format string and the list of variables used inside the parentheses in these functions are arguments. The arguments are sometimes also called parameters. Consider the following program. In this program, in main( ) we receive the values of a, b and c through the keyboard and then output the sum of a, b and c. However, the calculation of sum is done in a different function called calsum( ). If sum is to be calculated in calsum( ) and values of a, b and c are received in main( ), then we must pass on these values to calsum( ), and once calsum( ) calculates the sum we must return it from calsum( ) back to main( ).
/* Sending and receiving values between functions */ main( ) { int a, b, c, sum ; printf ( "\nEnter any three numbers " ) ; scanf ( "%d %d %d", &a, &b, &c ) ; sum = calsum ( a, b, c ) ; printf ( "\nSum = %d", sum ) ; } calsum ( x, y, z ) int x, y, z ; { 57

int d ; d=x+y+z; return ( d ) ; } And here is the output... Enter any three numbers 10 20 30 Sum = 60

There are a number of things to note about this program: (a) In this program, from the function main( ) the values of a, b and c are passed on to the function calsum( ), by making a call to the function calsum( ) and mentioning a, b and c in the parentheses: sum = calsum ( a, b, c ) ; In the calsum( ) function these values get collected in three variables x, y and z: calsum ( x, y, z ) int x, y, z ; (b) The variables a, b and c are called actual arguments, whereas the variables x, y and z are called formal arguments. Any number of arguments can be passed to a function being called. However, the type, order and number of the actual and formal arguments must always be same. (c) The return statement serves two purposes: (1) On executing the return statement it immediately transfers the control back to the calling program. (2) It returns the value present in the parentheses after return, to th3e calling program. In the above program the value of sum of three numbers is being returned.

Function Declaration and Prototypes main()


{ float square ( float ) ; // function prototype float a, b ; printf ( "\nEnter any number " ) ; scanf ( "%f", &a ) ; b = square ( a ) ; // function call printf ( "\nSquare of %f is %f", a, b ) ; } float square ( float x ) // function definition { float y ; y=x*x; return ( y ) ; } And here is the output... 58

Enter any Square of Enter any Square of

number 1.5 1.5 is 2.250000 number 2.5 2.5 is 6.250000

The function square( ) must be declared in main( ) as float square ( float ) ; This statement is often called the prototype declaration of the square( ) function. It means square( ) is a function that receives a float and returns a float. We have done the prototype declaration in main( ) because we have called it from main( ).

Recursion
In C, it is possible for the functions to call themselves. A function is called recursive if a statement within the body of a function calls the same function. Sometimes called circular definition, recursion is thus the process of defining something in terms of itself. Example: Suppose we want to calculate the factorial value of an integer. As we know, the and that number. For example, 4 factorial is 4 * 3 * 2 * 1. This can also be expressed as 4! = 4 * 3! where ! stands for factorial. Thus factorial of a number can be expressed in the form of itself. Hence this can be programmed using recursion. However, before we try to write a recursive function for calculating factorial let us take a look at the non-recursive function for calculating the factorial value of an integer.
main( ) { int a, fact ; printf ( "\nEnter any number " ) ; scanf ( "%d", &a ) ; fact = factorial ( a ) ; printf ( "Factorial value = %d", fact ) ; } factorial ( int x ) { int f = 1, i ; for ( i = x ; i >= 1 ; i-- ) f=f*i; return ( f ) ; } And here is the output... Enter any number 3 Factorial value = 6

59

Library Functions A library function is a function that can be called by a program to perform some task, but it is not part of the program itself. Typically library functions are collected together into libraries, which comprise suites of functions that are loosely related in some way. An example might be a collection of functions that deal with dates and times and how they can be formatted or represented. Libraries save programmers the bother of writing code to do the same tasks time and time again; in short, libraries encourage code reuse. Example : printf(), scanf();

60

Chapter 10 Arrays
Contents Defining and processing Passing arrays to a function Multi-dimensional arrays.

The C language provides a capability that enables the user to define a set of ordered data items known as an array. Suppose we had a set of grades that we wished to read into the computer and suppose we wished to perform some operations on these grades, we will quickly realize that we cannot perform such an operation until each and every grade has been entered since it would be quite a tedious task to declare each and every student grade as a variable especially since there may be a very large number. In C we can define variable called grades, which represent not a single value of grade but a entire set of grades. Each element of the set can then be referenced by means of a number called as index number or subscript.

Declaration of arrays:
Like any other variable arrays must be declared before they are used. The general form of declaration is: type variable-name[50]; The type specifies the type of the elements that will be contained in the array, such as int float or char and the size indicates the maximum number of elements that can be stored inside the array for ex: float height[50]; Declares the height to be an array containing 50 real elements. Any subscripts 0 to 49 are valid. In C the array elements index or subscript begins with number zero. So height [0] refers to the first element of the array. (For this reason, it is easier to think of it as referring to element number zero, rather than as referring to the first element). As individual array element can be used anywhere that a normal variable with a statement such as g = grade [50]; The statement assigns the value stored in the 50th index of the array to the variable g. More generally if I is declared to be an integer variable, then the statement g=grades [I]; Will take the value contained in the element number I of the grades array to 61

assign it to g. so if I were equal to 7 when the above statement is executed, then the value of grades [7] would get assigned to g. A value stored into an element in the array simply by specifying the array element on the left hand side of the equals sign. In the statement grades [100]=95; The value 95 is stored into the element number 100 of the grades array. The ability to represent a collection of related data items by a single array enables us to develop concise and efficient programs. For example we can very easily sequence through the elements in the array by varying the value of the variable that is used as a subscript into the array. So the for loop for(i=0;i < 100;++i); sum = sum + grades [i]; Will sequence through the first 100 elements of the array grades (elements 0 to 99) and will add the values of each grade into sum. When the for loop is finished, the variable sum will then contain the total of first 100 values of the grades array (Assuming sum were set to zero before the loop was entered) In addition to integer constants, integer valued expressions can also be inside the brackets to reference a particular element of the array. So if low and high were defined as integer variables, then the statement next_value=sorted_data[(low+high)/2]; would assign to the variable next_value indexed by evaluating the expression (low+high)/2. If low is equal to 1 and high were equal to 9, then the value of sorted_data[5] would be assigned to the next_value and if low were equal to 1 and high were equal to 10 then the value of sorted_data[5] would also be referenced. Just as variables arrays must also be declared before they are used. The declaration of an array involves the type of the element that will be contained in the array such as int, float, char as well as maximum number ofelements that will be stored inside the array. The C system needs this latter information in order to determine how much memory space to reserve for the particular array. The declaration int values[10]; would reserve enough space for an array called values that could hold up to 10 integers. Refer to the below given picture to conceptualize the reserved storage space.

62

values[0] values[1] values[2] values[3] values[4] values[5] values[6] values[7] values[8] values[9] The array values stored in the memory. Initialization of arrays: We can initialize the elements in the array in the same way as the ordinary variables when they are declared. The general form of initialization off arrays is: type array_name[size]={list of values}; The values in the list care separated by commas, for example the statement int number[3]={0,0,0}; Will declare the array size as a array of size 3 and will assign zero to each element if the number of values in the list is less than the number of elements, then only that many elements are initialized. The remaining elements will be set to zero automatically. In the declaration of an array the size may be omitted, in such cases the compiler allocates enough space for all initialized elements. For example the statement int counter[]={1,1,1,1}; Will declare the array to contain four elements with initial values 1. This approach works fine as long as we initialize every element in the array. The initialization of arrays in c suffers two draw backs 1. There is no convenient way to initialize only selected elements. 2. There is no shortcut method to initialize large number of elements. /* Program to count the no of positive and negative numbers*/

#include< stdio.h >


void main( ) 63

{ int a[50],n,count_neg=0,count_pos=0,I; printf(Enter the size of the arrayn); scanf(%d,&n); printf(Enter the elements of the arrayn); for I=0;I < n;I++) scanf(%d,&a[I]); for(I=0;I < n;I++) { if(a[I] < 0) count_neg++; else count_pos++; } printf(There are %d negative numbers in the arrayn,count_neg); printf(There are %d positive numbers in the arrayn,count_pos); }

Multi dimensional Arrays Often there is a need to store and manipulate two dimensional data structure such as matrices & tables. Here the array has two subscripts. One subscript denotes the row & the other the column. The declaration of two dimension arrays is as follows: data_type array_name[row_size][column_size]; int m[10][20] ; Here m is declared as a matrix having 10 rows( numbered from 0 to 9) and 20 columns(numbered 0 through 19). The first element of the matrix is m[0][0] and the last row last column is m[9][19] Elements of multi dimension arrays: A 2 dimensional array marks [4][3] is shown below figure. The first element is given by marks [0][0] contains 35.5 & second element is marks [0][1] and contains 40.5 and so on. marks [0][0] Marks [0][1] 40.5 35.5 marks [1][0] Marks [1][1] 55.5 50.5 marks [2][0] Marks [2][1] Marks [0][2] 45.5 Marks [1][2] 60.5 Marks [2][2]

64

marks [3][0] Marks [3][1]

Marks [3][2]

Initialization of multidimensional arrays: Like the one dimension arrays, 2 dimension arrays may be initialized by following their declaration with a list of initial values enclosed in braces Example: int table[2][3]={0,0,0,1,1,1}; Initializes the elements of first row to zero and second row to 1. The initialization is done row by row. The above statement can be equivalently written as int table[2][3]={{0,0,0},{1,1,1}} By surrounding the elements of each row by braces. C allows arrays of three or more dimensions. The compiler determines the maximum number of dimension. The general form of a multidimensional array declaration is: date_type array_name[s1][s2][s3]..[sn]; Where s is the size of the ith dimension. Some examples are: int survey[3][5][12]; float table[5][4][5][3]; Survey is a 3 dimensional array declared to contain 180 integer elements. Similarly table is a four dimensional array containing 300 elements of floating point type. /* example program to add two matrices & store the results in the 3rd matrix */ #include< stdio.h > #include< conio.h > void main() { int a[10][10],b[10][10],c[10][10],i,j,m,n,p,q; clrscr(); printf(enter the order of the matrixn); scanf(%d%d,&p,&q); if(m==p && n==q) { printf(matrix can be addedn); printf(enter the elements of the matrix a); for(i=0;i < m;i++) for(j=0;j < n;j++) scanf(%d,&a[i][j]); printf(enter the elements of the matrix b); for(i=0;i < p;i++) for(j=0;j < q;j++) scanf(%d,&b[i][j]); printf(the sum of the matrix a and b is); 65

for(i=0;i < m;i++) for(j=0;j < n;j++) c[i][j]=a[i][j]+b[i][j]; for(i=0;i < m;i++) { for(j=0;j < n;j++) printf(%dt,&a[i][j]); printf(n); } } Passing arrays to a function (as parameter) At some moment we may need to pass an array to a function as a parameter. In C it is not possible to pass a complete block of memory by value as a parameter to a function, but we are allowed to pass its address. In practice this has almost the same effect and it is a much faster and more efficient operation. In order to accept arrays as parameters the only thing that we have to do when declaring the function is to specify in its parameters the element type of the array, an identifier and a pair of void brackets []. For example, the following function: void procedure (int arg[]) accepts a parameter of type "array of int" called arg. In order to pass to this function an array declared as: int myarray [40]; it would be enough to write a call like this: procedure (myarray); #include<stdio.h> #include<conio.h> void read(int *,int); void dis(int *,int); void main() { int a[5],b[5],c[5],i; printf("Enter the elements of first list \n"); read(a,5); printf("The elements of first list are \n"); dis(a,5); } void read(int c[],int i) { int j; for(j=0;j<i;j++) scanf("%d",&c[j]); fflush(stdin); } void dis(int d[],int i) { 66

int j; for(j=0;j<i;j++) printf("%d ",d[j]); printf("\n"); } Output Enter the elements of first list 1 2 3 4 5 The elements of first list are 12345

67

Chapter 11 Strings
Contents Defining and operations on strings.

A string is a sequence of characters. Any sequence or set of characters defined within double quotation symbols is a constant string. In c it is required to do some meaningful operations on strings they are: 1. 2. 3. 4. 5. Reading string displaying strings Combining or concatenating strings Copying one string to another. Comparing string & checking whether they are equal Extraction of a portion of a string

Strings are stored in memory as ASCII codes of characters that make up the string appended with \0(ASCII value of null). Normally each character is stored in one byte, successive characters are stored in successive bytes. characte r ASCII Code M 7 7 C 6 7 A 6 5 S 3 8 2 3 E 6 9 M 7 7 3 2 1 4 9 3 2 I 7 3 D 6 8 O 7 9 L 7 6 \ 0 0

The last character is the null character having ASCII value zero. Initializing Strings Following the discussion on characters arrays, the initialization of a string must the following form which is simpler to one dimension array. char month1[ ]={j,a,n,u,a,r,y}; Then the string month is initializing to January. This is perfectly valid but C offers a special way to initialize strings. The above string can be initialized char month1[]=January; The characters of the string are enclosed within a part of double quotes. The compiler takes care of string enclosed within a pair of a double quotes. The compiler takes care of storing the ASCII codes of charactersof the string in the memory and also stores the null terminator in the end.

/*String.c string variable*/ #include < stdio.h > main() { char month[15]; 68

printf (Enter the string); gets (month); printf (The string entered is %s, month); } In this example string is stored in the character variable month the string is displayed in the statement. printf(The string entered is %s, month); It is one dimension array. Each character occupies a byte. A null character (\0) that has the ASCII value 0 terminates the string. The figure shows the storage of string January in the memory recall that \0 specifies a single character whose ASCII value is zero. J A N U A R Y \0

Character string terminated by a null character \0. A string variable is any valid C variable name & is always declared as an array. The general form of declaration of a string variable is char string_name[size]; The size determines the number of characters in the string name. Example: char month[10]; char address[100]; The size of the array should be one byte more than the actual space occupied by the string since the complier appends a null character at the end of the string. Reading Strings from the terminal: The function scanf with %s format specification is needed to read the character string from the terminal.

69

Example: char address[15]; scanf(%s,address); scanf statement has a draw back it just terminates the statement as soon as it finds a blank space, suppose if we type the string new york then only the string new will be read and since there is a blank space after word new it will terminate the string. Note that we can use the scanf without the ampersand symbol before the variable name. In many applications it is required to process text by reading an entire line of text from the terminal. The function getchar can be used repeatedly to read a sequence of successive single characters and store it in the array. We cannot manipulate strings since C does not provide any operators for string. For instance we cannot assign one string to another directly. For example: String=xyz; String1=string2; Are not valid. To copy the chars in one string to another string we may do so on a character to character basis. Writing strings to screen: The printf statement along with format specifier %s to print strings on to the screen. The format %s can be used to display an array of characters that is terminated by the nullcharacter for example printf(%s,name); can be used to display the entire contents of the array name. Arithmetic operations on characters: We can also manipulate the characters as we manipulate numbers in c language. When ever the system encounters the character data it is automatically converted into a integer value by the system. We can represent a character as a interface by using the following method. X=a; printf(%d\n,x); Will display 97 on the screen. Arithmetic operations can also be performed on characters for example x=z-1; is a valid statement. The ASCIIvalue of z is 122 the statement the therefore will assign 121 to variable x. It is also possible to use character constants in relational expressions for example ch>a && ch < = z will check whether the character stored in variable ch is a lower case letter. A character digit can also be converted into its equivalent integer value suppose un the expression a=character-1; where a is defined as an integer variable & character contains value 8 then a= ASCII value of 8 ASCII value 1=56-49=7.

70

We can also get the support of the c library function to converts a string of digits into their equivalent integer values the general format of the function in x=atoi(string) here x is an integer variable & string is a character array containing string of digits.
String operations (string.h) C language recognizes that string is a different class of array by letting us input and output the array as a unit and are terminated by nullcharacter . C library supports a large number of string handling functions that can be used to array out many o f the string manipulations such as: Length (number of characters in the string). Concatentation (adding two are more strings) Comparing two strings. Substring (Extract substring from a given string) Copy(copies one string over another) To do all the operations described here it is essential to include string.h library header file in the program.

strlen() function: This function counts and returns the number of characters in a string. The length does not include a null character. Syntax: n=strlen(string); Where n is integer variable. Which receives the value of length of the string. Example length=strlen(Hollywood); The function will assign number of characters 9 in the string to a integer variable length. /*writr a c program to find the length of the string using strlen() function*/ #include < stdio.h > include < string.h > void main() { char name[100]; int length; printf(Enter the string); gets(name); length=strlen(name); printf(\nNumber of characters in the string is=%d,length); }

71

strcat() function: when we combine two strings, we add the characters of one string to the end of other string. This process is called concatenation. The strcat()function joins 2 strings together. It takes the following form strcat(string1,string2) string1 & string2 are character arrays. When the function strcat is executed string2 is appended to string1. the string at string2 remains unchanged. Example strcpy(string1,sri); strcpy(string2,Bhagavan); printf(%s,strcat(string1,string2); From the above program segment the value of string1 becomes sribhagavan. The string at str2 remains unchanged as bhagawan. strcmp function In c we cannot directly compare the value of 2 strings in a condition like if(string1==string2) Most libraries however contain the strcmp() function, which returns a zero if 2 strings are equal, or a non zero number if the strings are not the same. The syntax of strcmp() is given below: strcmp(string1,string2) ; String1 & string2 may be string variables or string constants. String1, & string2 may be string variables or string constants some computers return a negative if the string1 is alphabetically less than the second and a positive number if the string is greater than the second.

Example: strcmp(Newyork,Newyork) will return zero because 2 strings are equal. strcmp(their,there) will return a 9 which is the numeric difference between ASCII i and ASCII r. strcmp(The, the) will return 32 which is the numeric difference between ASCII T & ASCII t. strcmp() function This function is same as strcmp() which compares 2 strings but not case sensitive. Example strcmp(THE,the); will return 0. strcpy() function C does not allow we to assign the characters to a string directly as in the statement name=Robert; Instead use the strcpy() function found in most compilers the syntax of the function is illustrated below. strcpy(string1,string2); 72

Strcpy function assigns the contents of string2 to string1. string2 may be a character array variable or a string constant. strcpy(Name,Robert); In the above example Robert is assigned to the string called name. strlwr () function This function converts all characters in a string from uppercase to lowercase. syntax strlwr(string); For example: strlwr(IDOL) converts to Idol. strrev() function This function reverses the characters in a string. Syntax strrev(string); For ex strrev(program); reverses the characters in a string into margrop. strupr() function This function converts all characters in a string from lower case to uppercase. Syntax strupr(string); For example: strupr(idol); will convert the string to IDOL. /* Example program to use string functions*/ #include < stdio.h > #include < string.h > void main() { char s1[20],s2[20],s3[20]; int x,l1,l2,l3; printf(Enter the strings); scanf(%s%s,s1,s2); x=strcmp(s1,s2); if(x!=0) {printf(\nStrings are not equal\n); strcat(s1,s2); } else printf(\nStrings are equal); strcpy(s3,s1); l1=strlen(s1); l2=strlen(s2); l3=strlen(s3); printf(\ns1=%s\t length=%d characters\n,s1,l1); printf(\ns2=%s\t length=%d characters\n,s2,l2); printf(\ns3=%s\t length=%d characters\n,s3,l3); }

73

Chapter 12 Pointers Contents Declarations Passing pointers to a function Operations on pointers, Pointer Arithmetic Pointers and arrays Arrays of pointers function pointers

In c a pointer is a variable that points to or references a memory location in which data is stored. Each memory cell in the computer has an address that can be used to access that location so a pointer variable points to a memory location we can access and change the contents of this memory location via the pointer. Pointer declaration: A pointer is a variable that contains the memory location of another variable. The syntax is as shown below. We start by specifying the type of data stored in the location identified by the pointer. The asterisk tells the compiler that we are creating a pointer variable. Finally we give the name of the variable. type * variable name; Example: int *ptr; float *string; Address operator: Once we declare a pointer variable we must point it to something we can do this by assigning to the pointer the address of the variable we want to point as in the following example: ptr=&num; This places the address where num is stores into the variable ptr. If num is stored in memory 21260 address then the variable ptr has the value 21260. /* A program to illustrate pointer declaration*/ main() { int *ptr; int sum; sum=45; ptr=sum; printf (\n Sum is %d\n, sum); printf (\n The sum pointer is %d, ptr); } we will get the same result by assigning the address of num to a regular(non pointer) variable. The benefit is that we can also refer to the pointer variable as *ptr the asterisk tells to the computer that we are not interested in the value 74

21260 but in the value stored in that memory location. While the value of pointer is 21260 the value of sum is 45 however we can assign a value to the pointer * ptr as in *ptr=45. This means place the value 45 in the memory address pointer by the variable ptr. Since the pointer contains the address 21260 the value 45 is placed in that memory location. And since this is the location of the variable num the value also becomes 45. this shows how we can change the value of pointer directly using a pointer and the indirection pointer. Pointer expressions & pointer arithmetic: Like other variables pointer variables can be used in expressions. For example if p1 and p2 are properly declared and initialized pointers, then the following statements are valid. y=*p1**p2; sum=sum+*p1; z= 5* - *p2/p1; *p2= *p2 + 10; C allows us to add integers to or subtract integers from pointers as well as to subtract one pointer from the other. We can also use short hand operators with the pointers p1+=; sum+=*p2; etc., we can also compare pointers by using relational operators the expressions such as p1 >p2 , p1==p2 and p1!=p2 are allowed. /*Program to illustrate the pointer expression and pointer arithmetic*/ #include< stdio.h > main() { int ptr1,ptr2; int a,b,x,y,z; a=30;b=6; ptr1=&a; ptr2=&b; x=*ptr1+ *ptr2 6; y=6*- *ptr1/ *ptr2 +30; printf(\nAddress of a +%u,ptr1); printf(\nAddress of b %u,ptr2); printf(\na=%d, b=%d,a,b);

printf(\nx=%d,y=%d,x,y); ptr1=ptr1 + 70; ptr2= ptr2; printf(\na=%d, b=%d,a,b); }


Pointers and function: The pointer are very much used in a function declaration. Sometimes only with a pointer a complex function can be easily represented and success. The usage of the pointers in a function definition may be classified into two groups. 75

1. Call by reference 2. Call by value. Call by value: We have seen that a function is invoked there will be a link established between the formal and actual parameters. A temporary storage is created where the value of actual parameters is stored. T he formal parameters picks up its value from storage area the mechanism of data transfer between actual and formal parameters allows the actual parameters mechanism of data transfer is referred as call by value. The corresponding formal parameter represents a local variable in the called function . The current value of corresponding actual parameter becomes the initial value of formal parameter. The value of formal parameter may be changed in the body of the actual parameter. The value of formal parameter may be changed in the body of the subprogram by assignment or input statements. This will not change the value of actual parameters.

/* Include< stdio.h > void main() { int x,y; x=20; y=30; printf(\n Value of a and b before function call =%d %d,a,b); fncn(x,y); printf(\n Value of a and b after function call =%d %d,a,b); } fncn(p,q) int p,q; { p=p+p; q=q+q; } Call by Reference: When we pass address to a function the parameters receiving the address should be pointers. The process of calling a function by using pointers to pass the address of the variable is known as call by reference. The function which is called by reference can change the values of the variable used in the call. /* example of call by reference*? /* Include< stdio.h > void main() 76

{ int x,y; x=20; y=30; printf(\n Value of a and b before function call =%d %d,a,b); fncn(&x,&y); printf(\n Value of a and b after function call =%d %d,a,b); } fncn(p,q) int p,q; { *p=*p+*p; *q=*q+*q; } Pointer to arrays: an array is actually very much like pointer. We can declare the arrays first element as a[0] or as int *a because a[0] is an address and *a is also an address the form of declaration is equivalent. The difference is pointer is avariable and can appear on the left of the assignment operator that is lvalue. The array name is constant and cannot appear as the left side of assignment operator.

/* A program to display the contents of array using pointer*/ main() { int a[100]; int i,j,n; printf(\nEnter the elements of the array\n); scanf(%d,&n); printf(Enter the array elements); for(I=0;I< n;I++) scanf(%d,&a[I]); printf(Array element are); for(ptr=a,ptr< (a+n);ptr++) printf(Value of a[%d]=%d stored at address %u,j+=,*ptr,ptr); } The way there can be an array of ints or an array of floats, similarly there can be an array of pointers. Since a pointer variable always contains an address, an array of pointers would be nothing but a collection of addresses. The addresses present in the array of pointers can be addresses of isolated variables or addresses of array elements or any other addresses. All rules that apply to an ordinary array apply to the array of pointers as well. I think a program would clarify the concept. main( ) { int *arr[4] ; /* array of integer pointers */ int i = 31, j = 5, k = 19, l = 71, m ; arr[0] = &i ; arr[1] = &j ; arr[2] = &k ;

arr[3] = &l ; 77

for ( m = 0 ; m <= 3 ; m++ ) printf ( "%d ", * ( arr[m] ) ) ; }

Pointer to Function A useful technique is the ability to have pointers to functions. Their declaration is easy: write the declaration as it would be for the function, say int func(int a, float b); and simply put brackets around the name and a * in front of it: that declares the pointer. Because of precedence, if we don't parenthesize the name, we declare a function returning a pointer: /* function returning pointer to int */ int *func(int a, float b); /* pointer to function returning int */ int (*func)(int a, float b); Once we've got the pointer, we can assign the address of the right sort of function just by using its name: like an array, a function name is turned into an address when it's used in an expression. We can call the function using one of two forms: (*func)(1,2); /* or */ func(1,2); The second form has been newly blessed by the Standard. Here's a simple example. #include <stdio.h> #include <stdlib.h> void func(int); main() { void (*fp)(int); fp = func; (*fp)(1); fp(2); exit(EXIT_SUCCESS); } void func(int arg) { printf("%d\n", arg); } 78

Chapter 13 Structures Contents Defining and processing Passing to a function Unions typedef array of structure Pointer to structure

Definition A structure is a convenient method of handling a group of related data items of different data types. Arrays are used to store large set of data and manipulate them but the disadvantage is that all the elements stored in an array are to be of the same data type. If we need to use a collection of different data type items it is not possible using an array. When we require using a collection of different data items of different data types we can use a structure. Structure is a method of packing data of different types.

Defining & accessing Structure structure definition: struct tag_name { data type member1; data type member2; } Example: struct lib_books { char title[20]; char author[15]; int pages; float price; }; the keyword struct declares a structure to holds the details of four fields namely title, author pages and price. These are members of the structures. Each member may belong to different or same data type. The tag name can be used to define objects that have the tag names structure. The structure we just declared is not a variable by itself but a template for the structure. We can declare structure variables using the tag name any where in the 79

program. For example the statement, struct lib_books book1,book2,book3; declares book1,book2,book3 as variables of type struct lib_books each declaration has four elements of the structure lib_books. The complete structure declaration might look like this struct lib_books { char title[20]; char author[15]; int pages; float price; }; struct lib_books, book1, book2, book3; structures do not occupy any memory until it is associated with the structure variable such as book1. The template is terminated with a semicolon. While the entire declaration is considered as a statement, each member is declared independently for its name and type in a separate statement inside the template. The tag name such as lib_books can be used to declare structure variables of its data type later in the program. We can also combine both template declaration and variables declaration in one statement, the declaration struct lib_books { char title[20]; char author[15]; int pages; float price; } book1,book2,book3; is valid. The use of tag name is optional for example struct { } book1, book2, book3 declares book1,book2,book3 as structure variables representing 3 books but does not include a tag name for use in the declaration. A structure is usually defines before main along with macro definitions. In such cases the structure assumes global status and all the functions can access the structure. Giving values to members As mentioned earlier the members themselves are not variables they should be linked to structure variables in order to make them meaningful members. 80

The link between a member and a variable is established using the member operator . Which is known as dot operator or period operator. For example: Book1.price is the variable representing the price of book1 and can be treated like any other ordinary variable. We can use scanf statement to assign values like scanf(%s,book1.file); scanf(%d,& book1.pages); Or we can assign variables to the members of book1 strcpy(book1.title,basic); strcpy(book1.author,Balagurusamy); book1.pages=250; book1.price=28.50;

/* Example program for using a structure*/ #include< stdio.h > void main() { int id_no; char name[20]; char address[20]; char combination[3]; int age; }newstudent; printf(Enter the student information); printf(Now Enter the student id_no); scanf(%d,&newstudent.id_no); printf(Enter the name of the student); scanf(%s,&new student.name); printf(Enter the address of the student); scanf(%s,&new student.address); printf(Enter the cmbination of the student); scanf(%d,&new student.combination); printf(Enter the age of the student); scanf(%d,&new student.age); printf(Student information\n); printf(student id_number=%d\n,newstudent.id_no); printf(student name=%s\n,newstudent.name); printf(student Address=%s\n,newstudent.address); printf(students combination= %s\n,newstudent.combination); printf(Age of student=%d\n,newstudent.age); } 81

Initializing structure: Like other data type we can initialize structure when we declare them. As for initialization goes structure obeys the same set of rules as arrays we initialize the fields of a structure by the following structure declaration with a list containing values for fileds as with arrays these values must be evaluate at compile time. Example: struct student newstudent { 12345, kapildev Pes college; Cse; 19; }; this initializes the id_no field to 12345, the name field to kapildev, the address field to pes college the field combination to cse and the age field to 19.

Passing to a function We can pass structures as arguments to functions. Unlike array names however, which always point to the start of the array, structure names are not pointers.

As a result, when we change structure parameter inside a function, we dont effect its corresponding argument.
A structure may be passed into a function as individual member or a separate variable. A program example to display the contents of a structure passing the individual elements to a function is shown below. # include < stdio.h > void main() { int emp_id; char name[25]; char department[10]; float salary; }; static struct emp1={125,sampath,operator,7500.00}; /* pass only emp_id and name to display function*/ display(emp1.emp_id,emp1.name); } /* function to display structure variables*/ display(e_no,e_name) int e_no,e_name; 82

{ printf(%d%s,e_no,e_name); in the declaration of structure type, emp_id and name have been declared as integer and character array. When we call the function display() using display(emp1.emp_id,emp1.name); we are sending the emp_id and name to function display(0); it can be immediately realized that to pass individual elements would become more tedious as the number of structure elements go on increasing a better way would be to pass the entire structure variable at a time. Passing entire structure to functions: In case of structures having to having numerous structure elements passing these individual elements would be a tedious task. In such cases we may pass whole structure to a function as shown below:

# include stdio.h> { int emp_id; char name[25]; char department[10]; float salary; }; void main() { static struct employee emp1= { 12, sadanand, computer, 7500.00 }; /*sending entire employee structure*/ display(emp1); } /*function to pass entire structure variable*/ display(empf) struct employee empf { printf(%d%s,%s,%f, empf.empid,empf.name,empf.department,empf.salary); } Array of structure It is possible to define a array of structures for example if we are maintaining information of all the students in the college and if 100 students are studying in 83

the college. We need to use an array than single variables. We can define an array of structures as shown in the following example: structure information { int id_no; char name[20]; char address[20]; char combination[3]; int age; } student[100]; An array of structures can be assigned initial values just as any other array can. Each element is a structure that must be assigned corresponding initial values as illustrated below. #include< stdio.h > { struct info { int id_no; char name[20]; char address[20]; char combination[3]; int age; } struct info std[100]; int I,n; printf(Enter the number of students); scanf(%d,&n); printf( Enter Id_no,name address combination age\m); for(I=0;I < n;I++) scanf(%d%s%s%s %d,&std[I].id_no,std[I].name,std[I].address,std[I].combinatio n,&std[I].age); printf(\n Student information); for (I=0;I< n;I++) printf(%d%s%s%s%d\n, ,std[I].id_no,std[I].name,std[I].address,std[I].combination,std [I].age); } Structure within a structure: A structure may be defined as a member of another structure. In such structures the declaration of the embedded structure must appear before the declarations of other structures. struct date { int day; int month; 84

int year; }; struct student { int id_no; char name[20]; char address[20]; char combination[3]; int age; structure date def; structure date doa; }oldstudent, newstudent; the sturucture student constains another structure date as its one of its members. Unions Unions like structure contain members whose individual data types may differ from one another. However the members that compose a union all share the same storage area within the computers memory whereas each member within a structure is assigned its own unique storage area. Thus unions are used to observe memory. They are useful for application involving multiple members where values need not be assigned to all the members at any one time. Like structures union can be declared using the keyword union as follows: union item { int m; float p; char c; } code; this declares a variable code of type union item. The union contains three members each with a different data type. However we can use only one of them at a time. This is because if only one location is allocated for union variable irrespective of size. The compiler allocates a piece of storage that is large enough to access a union member we can use the same syntax that we use to access structure members. That is code.m code.p code.c

are all valid member variables. During accessing we should make sure that we are accessing the member whose value is currently stored. For example a statement such as 85

code.m=456; code.p=456.78; printf(%d,code.m); Would produce erroneous result. In effect a union creates a storage location that can be used by one of its members at a time. When a different number is assigned a new value the new value supersedes the previous members value. Unions may be used in all places where a structure is allowed. The notation for accessing a union member that is nested inside a structure remains the same as for the nested structure.

typedef

A typedef declaration lets we define wer own identifiers that can be used in place of type specifiers such as int, float, and double. A typedef declaration does not reserve storage. The names we define using typedef are not new data types, but synonyms for the data types or combinations of data types they represent. The name space for a typedef name is the same as other identifiers. The exception to this rule is if the typedef name specifies a variably modified type. In this case, it has block scope. When an object is defined using a typedef identifier, the properties of the defined object are exactly the same as if the object were defined by explicitly listing the data type associated with the identifier. typedef int LENGTH; LENGTH length, width, height;

typedef can be used to define a class type (structure, union, or C++ class). For example: typedef struct { int scruples; int drams; int grains; } WEIGHT; The structure WEIGHT can then be used in the following declarations: WEIGHT chicken, cow, horse, whale;

86

Chapter 14 File structures Contents


Definitions concept of record file operations: Storing, creating, retrieving, updating Sequential, relative, indexed and random access mode, Files with binary mode(Low level)p Performance of Sequential Files Direct mapping techniques: Absolute, relative and indexed sequential files (ISAM) concept of index, levels of index, overflow of handling.

Definition

A file is a collection of bytes stored on a secondary storage device, which is generally a disk of some kind. The collection of bytes may be interpreted, for example, as characters, words, lines, paragraphs and pages from a textual document; fields and records belonging to a database; or pixels from a graphical image. The meaning attached to a particular file is determined entirely by the data structures and operations used by a program to process the file. It is conceivable (and it sometimes happens) that a graphics file will be read and displayed by a program designed to process textual data. The result is that no meaningful output occurs (probably) and this is to be expected. A file is simply a machine decipherable storage media where programs and data are stored for machine usage.

Files are of two different forms: sequential files & random access files. 1. Sequential files are great for data we read or write all at once For example, a typical text fileis usually a sequential file. Usually the text editor will read or write the entire file at once. 2. Random access files work best for data we read and write in pieces A database file, on the other hand, requires random access since the application can read data from anywhere in the file in response to a query. Concept of record A good view of a file is as a list of records. The file is broken down into a sequential string of records that share a common structure. A list is simply an open-ended single dimensional array of items, so we can view a file as an array of records. As such, we can index into
87

the file and select record number zero, record number one, record number two, etc. Using common file access operations, it is quite possible to skip around to different records in a file. The principle difference between a sequential file and a random access file is the organization of the records and how easy it is to locate a specific record within the file. The easiest file organization to understand is the random access file. A random access file is a list of records whose lengths are all identical (i.e., random access files require fixed length records). If the record length is n bytes, then the first record appears at byte offset zero in the file, the second record appears at byte offset n in the file, the third record appears at byte offset n*2 in the file, etc. This organization is virtually identical to that of an array of records in main memory; we use the same computation to locate an "element" of this list in the file as we would use to locate an element of an array in memory; the only difference is that a file doesn't have a "base address" in memory, we simply compute the zero-based offset of the record in the file. This calculation is quite simple, and using some file I/O functions we will learn about a little later, we can quickly locate and manipulate any record in a random access file. Sequential files also consist of a list of records. However, these records do not all have to be the same length. If a sequential file does not use fixed length records then we say that the file uses variable-length records. If a sequential file uses variable-length records, then the file must contain some kind of marker or other mechanism to separate the records in the file. Typical sequential files use one of two mechanisms: a length prefix or some special terminating value. These two schemes should sound quite familiar to those who have read the chapter on strings. Character strings use a similar scheme to determine the bounds of a string in memory. A text file is the best example of a sequential file that uses variablelength records. Text files use a special marker at the end of each record to delineate the records. In a text file, a record corresponds to a single line of text. Under Windows, the line feed character marks the end of each record. Other operating systems may use a different sequence; e.g., Windows uses a carriage return/line feed sequence while the Mac OS uses a single carriage return. Since we're working with Windows here, we'll adopt the line feed end of line marker. Accessing records in a file containing variable-length records is problematic. Unless we have an array of offsets to each record in a variable-length file, the only practical way to locate record n in a file is to read the first n-1 records. This is why variable-length files are sequential-access - we have the read the file sequentially from the start in order to locate a specific record in the file. This will be much slower than accessing the file in
88

a random access fashion. Generally, we would not use a variablelength record organization for files we need to access in a random fashion.

Performance It would seem that fixed-length random access files offer all the advantages here. After all, we can access records in a file with fixedlength records much more rapidly than files using the variablelength record organization. However, there is a cost to this: fixed-length records have to be large enough to hold the largest possible data object we want to store in a record. To store a sequence of lines in a text file, for example, record sizes would have to be large enough to hold the longest possible input line. This could be quite large. Each record in the file will consume this many bytes even if the record uses substantially less data. For example, an empty line only requires one or a single byte (for the line feed character). If the record size is 256 bytes, then we're wasting 255 or 255 bytes for that blank line in the file. If the average line length is around 60 characters, then each line wastes an average of about 200 characters. This problem, known as internal fragmentation, can waste a tremendous amount of space on the disk, especially as the files get larger or we create lots of files. File organizations that use variable-length records generally don't suffer from this problem.

File operations: Storing, creating, retrieving, updating Sequential, relative, indexed and random access mode, C supports a number of functions that have the ability to perform basic file operations, which include: 1. Naming a file 2. Opening a file 3. Reading from a file 4. Writing data into a file 5. Closing a file

89

Commonly used File operation functions in C:

Function Name fopen() Fclose getc()


putc() fprintf() fscanf() getw()

Operation Creates a new file for use Opens a new existing file for use Closes a file which has been opened for use Reads a character from a file
Writes a character to a file Writes a set of data values to a file Reads a set of data values from a file Reads a integer from a file

putw() fseek() ftell() rewind()

Writes an integer to the file Sets the position to a desired point in the file Gives the current position in the file Sets the position to the begining of the file

File organization and access methods are separate but related concepts, organization refers to the internal structure, access method is an "allowed method" to read/write from/to the file. It may be possible to access a file in an access method other than the "natural" one. Possible file organizations are: 1) Sequential - The info in file can be accessed only in the order it was written. The writing order defines the "natural" order of data, in simple cases the data will reside on the disk in consecutive locations.

90

2) Relative - The file is a sequence of equal-sized "data cells", we can access any "cell" we want using its serial number, and the system will calculate the offset. Relative files are just like arrays [of structures], but instead of residing in main memory, they are recorded on a magnetic media. 3) Indexed - The file is made of "data cells", not necessarily of the same size, and contain "indexes", lists of "pointers" to these cells arranged by some order. Standard FORTRAN 77 doesn't require that indexed files are to be implemented, but some vendors supply this nice extension. Access methods are classified by the way they find the location of the data on the disk: 1) By physical address - The real hardware address, composed of three components (at least): the number of the magnetic head used, number of the track and number of the sector. 2) By physical/logical/virtual block number - This is the serial number of the required disk block ("atomic" unit of disk area), the three variants are different numbering methods. 3) Sequential - First data item is at the start of the file, other items follow one after the other. 4) Direct - Data item location is calculated from its serial number and the constant "cell size", this gives an offset from the file's beginning. 5) Keyed - First one or more indexes are consulted (in a complex process), they yield the address of the data item. 6) Memory mapping - The operating system creates an association between the data in the file and a part of the main memory. the system supports accesses to the "mapped" main memory as if they were accesses to the file's data. We can think of this process as if the system copied all of the file contents to a large array residing in main memory, but in order to conserve physical memory it is paging it in and out as necessary. 7) Byte stream - The system buffers file accesses and let's we read a specified number of bytes at a time.

91

Compatibility of different organizations and access methods: Access \ Organization Sequential Relative Indexed ----------------------------- --------------- ------------ ----------Sequential + + + Direct ? + ? Keyed + Physical address + + + By block number + + + Memory mapping + + + Byte stream + + + The two basic types of file-systems ----------------------------------There are two major types of file-systems, characterized by the way they implement file I/O: Byte-oriented file systems In this type of file-system, a file is considered as a sequence of bytes, the operating system supplies routines that can read/write a specified number of bytes. To have any structure in a file, system and application programs accessing the file must adopt some convention that has to respected by all programs. For example, a line-feed (ASCII 10) character in a file containing text may denote an end-of-line. Record-oriented file systems In these file-systems a file is a sequence of records of the same type. A record is a sequence of data bytes together with control information about the record's size and maybe some attributes. The unit of I/O operations is one or more record(s). This structure is imposed by consistently interpreting the data and control information kept in the records, by system routines we call in order to perform file I/O. Having all records in a file share the same type, makes it reasonable to use files and records terms interchangeably. ISAM ISAM (Indexed Sequential Access Method) is a file management system developed that allows records to be accessed either sequentially (in the order they were entered) or randomly (with an index).
92

Each index defines a different ordering of the records. An employee database may have several indexes, based on the information being sought. For example, a name index may order employees alphabetically by last name, while a department index may order employees by their department. A key is specified in each index. For an alphabetical index of employee names, the last name field would be the key.

93

Chapter 15 File Handling Contents File operation: creation, copy, delete, update, text file, binary file

Creating a file and output some data In order to create files we have to learn about File I/O i.e. how to write data into a file and how to read data from a file. We begin as before with the include statement for stdio.h, then define some variables for use in the example including a rather strange looking new type. /* Program to create a file and write some data the file */ #include <stdio.h> #include <stdio.h> main( ) { FILE *fp; char stuff[25]; int index; fp = fopen("TENLINES.TXT","w"); /* open for writing */ strcpy(stuff,"This is an example line."); for (index = 1; index <= 10; index++) fprintf(fp,"%s Line number %d\n", stuff, index); fclose(fp); /* close the file before ending program */ } The type FILE is used for a file variable and is defined in the stdio.h file. It is used to define a file pointer for use in file operations. Before we can write to a file, we must open it. It means that we must tell the system that we want to write to a file and what the file name is. We do this with the fopen() function illustrated in the first line of the program. The file pointer, fp in our case, points to the file and two arguments are required in the parentheses, the file name first, followed by the file type. The file name is any valid DOS file name, and can be expressed in upper or lower case letters, or even mixed if we so desire. It is enclosed in double quotes. For this example we have chosen the name TENLINES.TXT. This file should not exist on wer disk at this time. If we have a file with this name, we should change its name or move it because when we execute this program, its contents will be erased. If we dont have a file by this name, that is good because we will create one and put some data into it.
94

We are permitted to include a directory with the file name. The directory must, of course, be a valid directory otherwise an error will occur. Also, because of the way C handles literal strings, the directory separation character \\ must be written twice. For example, if the file is to be stored in the \PROJECTS sub directory then the file name should be entered as \\PROJECTS\\TENLINES.TXT. The second parameter is the file attribute and can be any of three letters, r, w, or a, and must be lower case.

Reading (r) When an r is used, the file is opened for reading, a w is used to indicate a file to be used for writing, and an a indicates that we desire to append additional data to the data already in an existing file. Most C compilers have other file attributes available Using the r indicates that the file is assumed to be a text file. Opening a file for reading requires that the file already exist. If it does not exist, the file pointer will be set to NULL and can be checked by the program. Example: Here is a small program that reads a file and display its contents on screen. /* Program to display the contents of a file on screen */ #include <stdio.h> void main() { FILE *fopen(), *fp; int c; fp = fopen("prog.c","r"); c = getc(fp) ; while (c!= EOF) { putchar(c); c = getc(fp); } fclose(fp); } Writing (w) When a file is opened for writing, it will be created if it does not already exist and it will be reset if it does, resulting in the deletion of any data already there. Using the w indicates that the file is assumed to be a text file. Example: Here is the program to create a file and write some data into the file. #include <stdio.h> int main()
95

{ FILE *fp; file = fopen("file.txt","w"); /*Create a file and add text*/ fprintf(fp,"%s","This is just an example :)"); /*writes data to the file*/ fclose(fp); /*done!*/ return 0; } Appending (a) When a file is opened for appending, it will be created if it does not already exist and it will be initially empty. If it does exist, the data input point will be positioned at the end of the present data so that any new data will be added to any data that already exists in the file. Using the a indicates that the file is assumed to be a text file. Example: Here is a program that will add text to a file which already exists and there is some text in the file. #include <stdio.h> int main() { FILE *fp file = fopen("file.txt","a"); fprintf(fp,"%s","This is just an example :)"); /*append some text*/ fclose(fp); return 0; } Outputting to the file The job of actually outputting to the file is nearly identical to the outputting we have already done to the standard output device. The only real differences are the new function names and the addition of the file pointer as one of the function arguments. In the example program, fprintf replaces our familiar printf function name, and the file pointer defined earlier is the first argument within the parentheses. The remainder of the statement looks like, and in fact is identical to, the printf statement. Closing a file To close a file we simply use the function fclose with the file pointer in the parentheses.
96

Actually, in this simple program, it is not necessary to close the file because the system will close all open files before returning to DOS, but it is good programming practice to close all files in spite of the fact that they will be closed automatically, because that would act as a reminder to we of what files are open at the end of each program. We can open a file for writing, close it, and reopen it for reading, then close it, and open it again for appending, etc. Each time we open it, we could use the same file pointer, or we could use a different one. The file pointer is simply a tool that we use to point to a file and we decide what file it will point to. Compile and run this program. When we run it, we will not get any output to the monitor because it doesnt generate any. After running it, look at wer directory for a file named TENLINES.TXT and type it; that is where wer output will be. Compare the output with that specified in the program; they should agree! Do not erase the file named TENLINES.TXT yet; we will use it in some of the other examples in this section. Reading from a text file Now for our first program that reads from a file. This program begins with the familiar include, some data definitions, and the file opening statement which should require no explanation except for the fact that an r is used here because we want to read it. #include <stdio.h> main( ) { FILE *fp; char c; funny = fopen("TENLINES.TXT", "r"); if (fp == NULL) printf("File doesn't exist\n"); else { do { c = getc(fp); /* get one character from the file */ putchar(c); /* display it on the monitor */ } while (c != EOF); /* repeat until EOF (end of file) */ } fclose(fp); } In this program we check to see that the file exists, and if it does, we execute the main body of the program. If it doesnt, we print a message and quit. If the file does not exist, the system will set the pointer equal to NULL which we can test.
97

The main body of the program is one do while loop in which a single character is read from the file and output to the monitor until an EOF (end of file) is detected from the input file. The file is then closed and the program is terminated. At this point, we have the potential for one of the most common and most perplexing problems of programming in C. The variable returned from the getc function is a character, so we can use a char variable for this purpose. There is a problem that could develop here if we happened to use an unsigned char however, because C usually returns a minus one for an EOF which an unsigned char type variable is not capable of containing. An unsigned char type variable can only have the values of zero to 255, so it will return a 255 for a minus one in C. This is a very frustrating problem to try to find. The program can never find the EOF and will therefore never terminate the loop. This is easy to prevent: always have a char or int type variable for use in returning an EOF. There is another problem with this program but we will worry about it when we get to the next program and solve it with the one following that. After we compile and run this program and are satisfied with the results, it would be a good exercise to change the name of TENLINES.TXT and run the program again to see that the NULL test actually works as stated. Be sure to change the name back because we are still not finished with TENLINES.TXT. Copy a File 1. #include<stdio.h> 2. #include<conio.h> 3. #include<stdlib.h> 4. 5. void main(int arg,char *arr[]) 6. { 7. FILE *fs,*ft; 8. char ch; 9. clrscr(); 10. if(arg!=3) 11. { 12. printf("Argument Missing ! Press key to exit."); 13. getch(); 14. exit(0); 15. } 16. 17. fs = fopen(arr[1],"r"); 18. if(fs==NULL) 19. { 20. printf("Cannot open source file ! Press key to exit."); 21. getch();
98

22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48.

exit(0); } ft = fopen(arr[2],"w"); if(ft==NULL) { printf("Cannot copy file ! Press key to exit."); fclose(fs); getch(); exit(0); } while(1) { ch = getc(fs); if(ch==EOF) { break; } else putc(ch,ft); } printf("File copied succesfully!"); fclose(fs); fclose(ft); }

Code Explanation This is an advanced kind of program, not for beginners. This is for those who have idea of file handling, function, pointer array etc. Line 5: This line is starting of the main function which accepts two arguments or parameters. First argument is an integer argument in the main function which stores the number of parameters provided at the runtime. In our program it has to be 3 (e.g. program_name source_file destination_file). Second argument in main function is a character array pointer, as we can see, which store the arguments. Line 7: This line declares two file pointer variables which we will need in our program. One file pointer variable will be used to read file and another will be used to write to file. Line 10-15: These line will check whether user has provided 3 arguments or not. If argument is less than 3 or greater than 3, then it will show error message. Line 17-23: In these lines we will open source file in read mode. To serve this purpose we will use fopen() function. This function requires two arguments, first is file name and second is file opening mode. It takes file name from main() functions character array pointer argument. If fopen() function can open file successfully then returns pointer else returns NULL. We are checking this, if file
99

is not found or file cannot be accessed due to security restriction then there is no need to execute program further. Line 25-32: In this block of code we are trying to create a new file. So we need to open this file in write mode. It also takes file name from main() functions character array pointer argument. If fopen() function returns NULL then we need to close source file stream and exit program. Line 34-43: As we can see here we have declared an infinite while loop and the loop continues until end of file is reached. The gets() function reads character from given stream and stores character in ch variable then increments file pointer to next character. In line 42 we are writing character stored in ch variable to new file (ft file pointer) with the help of putc() function. Line 46-47: These two lines contain two same functions whose job is to clearing the stream buffer and closing the stream buffer. Because we are using two file pointer, so we need to close both of them. Delete a file in C We can see in the given example that we want to remove the file HELLO.txt. For this, we have used the library function remove() which deletes the file HELLO.txt. In case if the file will not be deleted, the function perror() prints the error message on the console. Example : Deleting the File #include <stdio.h> #include <conio.h> void main() { if (remove("HELLO.txt") == -1) perror("Error in deleting a file"); getch(); } Text Files Text files in C are straightforward and easy to understand. All text file functions and types in C come from the stdio library. When we need text I/O in a C program, and we need only one source for input information and one sink for output information, we can rely on stdin (standard in) and stdout (standard out). We can then use input and output redirection at the command line to move different information streams through the program. There are six different I/O commands in <stdio.h> that we can use with stdin and stdout: printf - prints formatted output to stdout
100

scanf - reads formatted input from stdin puts - prints a string to stdout gets - reads a string from stdin putc - prints a character to stdout getc, getchar - reads a character from stdin The advantage of stdin and stdout is that they are easy to use. Likewise, the ability to redirect I/O is very powerful. For example, maybe we want to create a program that reads from stdin and counts the number of characters: #include <stdio.h> #include <string.h> void main() { char s[1000]; int count=0; while (gets(s)) count += strlen(s); printf("%d\n",count); } Enter this code and run it. It waits for input from stdin, so type a few lines. When we are done, press CTRL-D to signal end-of-file (eof). The gets function reads a line until it detects eof, then returns a 0 so that the while loop ends. When we press CTRL-D, we see a count of the number of characters in stdout (the screen). Now, suppose we want to count the characters in a file. If we compiled the program to an executable named xxx, we can type the following: xxx < filename Instead of accepting input from the keyboard, the contents of the file named filename will be used instead. We can achieve the same result using pipes: cat < filename | xxx We can also redirect the output to a file: xxx < filename > out This command places the character count produced by the program in a text file named out. Sometimes, we need to use a text file directly. For example, we might need to open a specific file and read from or write to it. We might want to manage several streams of input or output or create a program like a text editor that can save and recall data or configuration files on command. In that case, use the text file functions in stdio: fopen - opens a text file fclose - closes a text file feof - detects end-of-file marker in a file fprintf - prints formatted output to a file fscanf - reads formatted input from a file
101

fputs - prints a string to a file fgets - reads a string from a file fputc - prints a character to a file fgetc - reads a character from a file Text Files: Opening We use fopen to open a file. It opens a file for a specified mode (the three most common are r, w, and a, for read, write, and append). It then returns a file pointer that we use to access the file. For example, suppose we want to open a file and write the numbers 1 to 10 in it. We could use the following code: #include <stdio.h> #define MAX 10 int main() { FILE *f; int x; f=fopen("out","w"); if (!f) return 1; for(x=1; x<=MAX; x++) fprintf(f,"%d\n",x); fclose(f); return 0; } The fopen statement here opens a file named out with the w mode. This is a destructive write mode, which means that if out does not exist it is created, but if it does exist it is destroyed and a new file is created in its place. The fopen command returns a pointer to the file, which is stored in the variable f. This variable is used to refer to the file. If the file cannot be opened for some reason, f will contain NULL. The fprintf statement should look very familiar: It is just like printf but uses the file pointer as its first parameter. The fclose statement closes the file when we are done. Text Files: Reading To read a file, open it with r mode. In general, it is not a good idea to use fscanf for reading: Unless the file is perfectly formatted, fscanf will not handle it correctly. Instead, use fgets to read in each line and then parse out the pieces we need. The following code demonstrates the process of reading a file and dumping its contents to the screen:
102

#include <stdio.h> int main() { FILE *f; char s[1000]; f=fopen("infile","r"); if (!f) return 1; while (fgets(s,1000,f)!=NULL) printf("%s",s); fclose(f); return 0; } Binary Files Binary files are very similar to arrays of structures, except the structures are in a disk file rather than in an array in memory. Because the structures in a binary file are on disk, we can create very large collections of them (limited only by wer available disk space). They are also permanent and always available. The only disadvantage is the slowness that comes from disk access time. Binary files have two features that distinguish them from text files: 1. We can jump instantly to any structure in the file, which provides random access as in an array. 2. We can change the contents of a structure anywhere in the file at any time. Binary files also usually have faster read and write times than text files, because a binary image of the record is stored directly from memory to disk (or vice versa). In a text file, everything has to be converted back and forth to text, and this takes time. C supports the file-of-structures concept very cleanly. Once we open the file we can read a structure, write a structure, or seek to any structure in the file. This file concept supports the concept of a file pointer. When the file is opened, the pointer points to record 0 (the first record in the file). Any read operation reads the currently pointed-to structure and moves the pointer down one structure. Any write operation writes to the currently pointed-to structure and moves the pointer down one structure. Seek moves the pointer to the requested record. C thinks of everything in the disk file as blocks of bytes read from disk into memory or read from memory onto disk. C uses a file pointer, but it can point to any byte location in the file. We therefore have to keep track of things.

The following program illustrates these concepts:


103

#include <stdio.h> /* random record description - could be anything */ struct rec { int x,y,z; }; /* writes and then reads 10 arbitrary records from the file "junk". */ int main() { int i,j; FILE *f; struct rec r; /* create the file of 10 records */ f=fopen("junk","w"); if (!f) return 1; for (i=1;i<=10; i++) { r.x=i; fwrite(&r,sizeof(struct rec),1,f); } fclose(f); /* read the 10 records */ f=fopen("junk","r"); if (!f) return 1; for (i=1;i<=10; i++) { fread(&r,sizeof(struct rec),1,f); printf("%d\n",r.x); } fclose(f); printf("\n"); /* use fseek to read the 10 records in reverse order */ f=fopen("junk","r"); if (!f) return 1; for (i=9; i>=0; i--) { fseek(f,sizeof(struct rec)*i,SEEK_SET); fread(&r,sizeof(struct rec),1,f); printf("%d\n",r.x);
104

} fclose(f); printf("\n"); /* use fseek to read every other record */ f=fopen("junk","r"); if (!f) return 1; fseek(f,0,SEEK_SET); for (i=0;i<5; i++) { fread(&r,sizeof(struct rec),1,f); printf("%d\n",r.x); fseek(f,sizeof(struct rec),SEEK_CUR); } fclose(f); printf("\n"); /* use fseek to read 4th record, change it, and write it back */ f=fopen("junk","r+"); if (!f) return 1; fseek(f,sizeof(struct rec)*3,SEEK_SET); fread(&r,sizeof(struct rec),1,f); r.x=100; fseek(f,sizeof(struct rec)*3,SEEK_SET); fwrite(&r,sizeof(struct rec),1,f); fclose(f); printf("\n"); /* read the 10 records to insure 4th record was changed */ f=fopen("junk","r"); if (!f) return 1; for (i=1;i<=10; i++) { fread(&r,sizeof(struct rec),1,f); printf("%d\n",r.x); } fclose(f); return 0; } In this program, a structure description rec has been used, but we can use any structure description we want. We can see that fopen and fclose work exactly as they did for text files.
105

The new functions here are fread, fwrite and fseek. The fread function takes four parameters: a. A memory address b. The number of bytes to read per block c. The number of blocks to read d. The file variable
Thus, the line fread(&r,sizeof(struct rec),1,f); says to read 12 bytes

(the size of rec) from the file f (from the current location of the file pointer) into memory address &r. One block of 12 bytes is requested. It would be just as easy to read 100 blocks from disk into an array in memory by changing 1 to 100. The fwrite function works the same way, but moves the block of bytes from memory to the file. The fseek function moves the file pointer to a byte in the file. Generally, we move the pointer in sizeof(struct rec) increments to keep the pointer at record boundaries. We can use three options when seeking: SEEK_SET SEEK_CUR SEEK_END SEEK_SET moves the pointer x bytes down from the beginning of the file (from byte 0 in the file). SEEK_CUR moves the pointer x bytes down from the current pointer position. SEEK_END moves the pointer from the end of the file (so we must use negative offsets with this option). Several different options appear in the code above. In particular, note the section where the file is opened with r+ mode. This opens the file for reading and writing, which allows records to be changed. The code seeks to a record, reads it, and changes a field; it then seeks back because the read displaced the pointer, and writes the change back.

106

You might also like