You are on page 1of 124

(AMITY CENTER FOR e-LEARNING)

Computer Programming Using C Language

By:

Ashish Seth Kirti Seth

(AMITY CENTER FOR e-LEARNING)

Preface
The question you always might think before learning C language is that why should I learn this language? At present in the market, there are so many languages, using which you can meet most of the industry needs. For the past many years, the solution for the most of the raw needs of the industry has been C language? C is the heart of programming, one who learns this language can command over any language very easily. This book covers more than average discussions of C, It covers the features and functionality of the language in depth. Starting chapter helps the reader to grasp the basic and structure of the language, later chapter deals with the advance features of the language like pointers and file handling. In order to asses your learning the quiz section is appended at the end of each chapter. This assessment system is designed to evaluate the level of knowledge and skills as defined by learning objectives We have tried my best to make the book very useful for the students. Constructive, criticism, and suggestions for the improvement of book are most welcome It is pleasure to acknowledge my sincere gratitude to Prof. Dinesh Khurana (Amity International Business School), Amity University Uttar Pradesh for giving us an opportunity and motivation to write this book. Thanks to our parents who gave us shower of love and believed our ability. we would like to dedicate this work to our lovely daughters baby Verda and baby Vindhya. Finally, we thanks to the Almighty who helped us in disguise in each and every step

Ashish Seth Kirti Seth

(AMITY CENTER FOR e-LEARNING)

Index
Chapter No. Title Introduction to C Operators and Expressions Data Input/Output Functions Control Statements Functions Arrays Pointers Structures and Unions Data Files Key to End Chapter Quizzes Bibliography Page No. 1 15 37 48 64 88 106 126 138 150 152

1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.

(AMITY CENTER FOR e-LEARNING)

Chapter 1 Introduction to C
Contents: 1.1 Introduction 1.2 Data and Variables 1.2.1 Reserve words 1.2.2 Identifiers\ 1.3 Data Types 1.3.1 Integer Number Variables 1.3.2 Decimal Number Variables 1.3.3 Character Variables 1.4 Form of C Program

1.1 Introduction
C is considered as High Level Languages. It uses English type statements that are converted to machine statements which are executed by computers. C programs are simple text files containing program statements. As such, it is created using a text editor. This is called the source program. Once you have written the program, it must be compiled. The source program is compiled by a special program called a compiler, whose task is to convert the statements in the source code to either an intermediate format (called an object file), or an executable format which can be run on the computer. There are a number of free compilers available on the Internet. we briefly described the following stages in the development of a computer program:
(1) Define the problem. (2) Analyze the problem. (3) Develop an algorithm (a method) for solving the problem. (4) Write the computer program which implements the algorithm. (5) Test and debug (find the errors in) the program. (6) Document the program. (Explain how the program works and how to use it). (7) Maintain the program.

(AMITY CENTER FOR e-LEARNING)

1.2 Data and Variables


All computer programs, except the most trivial, are written to operate on data. For example: the data for an action game might be keys pressed or the position of the cursor when the mouse is clicked;
the data for a word processing program are the keys pressed while you are typing a letter;

the data for an accounting program would include, among other things, expenses and income; the data for a program that teaches Spanish could be an English word that you type in response to a question. For a program to be run, it must be stored in the computers memory. When data is supplied to a program, that data is also stored in memory. Thus we think of memory as a place for holding programs and data. One of the nice things about programming in a high-level language (like C or Java) is that you dont have to worry about which memory locations are used to store your data. But how do we refer to an item of data, given that there may be many data items in memory? Think of memory as a set of boxes (or storage locations). Each box can hold one item of data, for example, one number. We can give a name to a box, and we will be able to refer to that box by the given name. In our example, we will need two boxes, one to hold the side of the square and one to hold the area. We will call these boxes s and a, respectively. If we wish, we can change the value in a box at any time; since the values can vary, s and a are called variable names, or simply variables. Thus a variable is a name associated with a particular memory location or, if you wish, it is a label for the memory location. We can speak of giving a variable a value, or setting a variable to a specific value, such as 1, for instance. Important points to remember are: a box can hold only one value at a time; if we put in a new value, the old one is lost; we must not assume that a box contains any value unless we specifically store a value in the box. In particular, we must not assume that the box contains 0. Variables are a common feature of computer programs. It is very difficult to imagine what programming would be like without them. In everyday life, we often use variables. For example, we speak of an address. Here, address is a variable whose value depends on the person under consideration. Other common variables are telephone number, name of school, subject, size of population, type of car, television model, etc. (What are some possible values of these variables?) A variable is a data name that may be used to store a data value. Variable may take different values at different times during execution.

(AMITY CENTER FOR e-LEARNING)


Rules for declaring variable: 1. They must begin with a letter some systems permit underscore as the first character. 2. ANSI standard recognizes a length of 31 characters. However, the length should not be normally more than eight characters, since only the first eight characters are treated as significant by many compilers. 3. Uppercase & lowercase are significant .That is variable total is not the same as toTal or Total. 4. The variable name should not be a keyword. 5. White space is not allowed. C's Character Set C does not use, nor requires the use of, every character found on a modern computer keyboard. The only characters required by the C Programming Language are as follows:
A-Z a -z 0-9 space . , : ; ' $ " # % & ! _ {} [] () < > | +-/*=

1.2.1 Reserve words


The C language uses a number of keywords such as int, char and while. A keyword has a special meaning in the context of a C program and can be used for that purpose only. For example, int can be used only in those places where we need to specify that the type of some item is integer. All keywords are written in lowercase letters only. Thus int is a keyword but Int and INT are not. Keywords are reserved, that is, you cannot use them as your identifiers. As such, they are usually called reserved words. All keywords have fixed meanings and these meanings can not be changed. Keywords sever as basic building blocks for program statement. There are 32 keywords, Example break, case, char, do, if, else, int, float, for, goto, long, void,while

1.2.2 Identifiers
The C programmer needs to make up names for things such as variables, function names and symbolic constants (see next section). A name that he makes up is called a user identifier. There are a few simple rules to follow in naming an identifier:
6

(AMITY CENTER FOR e-LEARNING)


Name of a variable (or any other item you define in program) is called identifier identifier must start with a letter or underscore symbol (_), the rest of the characters should be letters, digits or underscores the following are valid identifiers: x x1 x_1 _abc sum Rate averagE the following are not legal identifiers. Why? 13 3X %change data-1 my.identifier a(3) C is case sensitive: MyVar and myvar are different identifiers What are good identifiers Careful selection of identifiers makes your program clearer Identifiers should be Short enough to be reasonable to type (single word is norm) Standard abbreviations are fine (but only standard abbreviations) Long enough to be understandable use abbreviations and underscores to separate the words, never use capital letters for variables

1.3 Data Types


Now we have to start looking into the details of the C language. How easy you find the rest of this section will depend on whether you have ever programmed before - no matter what the language was. There are a great many ideas common to programming in any language and C is no exception to this rule. So if you haven't programmed before, you need to take the rest of this section slowly and keep going over it until it makes sense. If, on the other hand, you have programmed before you'll be wondering what all the fuss is about It's a lot like being able to ride a bike! The first thing you need to know is that you can create variables to store values in. A variable is just a named area of storage that can hold a single value (numeric or character). C is very fussy about how you create variables and what you store in them. It demands that you declare the name of each variable that you are going to use and its type, or class, before you actually try to do anything with it. In this section we are only going to be discussing local variables. These are variables that are used within the current program unit (or function) in a later section we will looking at global variables - variables that are available to all the program's functions.
7

(AMITY CENTER FOR e-LEARNING)


There are five basic data types associated with variables:
int - integer: a whole number. float - floating point value: ie a number with a fractional part. double - a double-precision floating point value. char - a single character. void - valueless special purpose type which we will examine closely in later sections.

Ranges of data types: int -------- -32,768 to 32767 char ------ -128 to 127 float ------ 3.4e-38 to 3.4e+38 Size: int ----- 2 byte=16bit char --- 1 byte=8bit float --- 4 byte=32bit One of the confusing things about the C language is that the range of values and the amount of storage that each of these types takes is not defined. This is because in each case the 'natural' choice is made for each type of machine. You can call variables what you like, although it helps if you give them sensible names that give you a hint of what they're being used for - names like sum, total, average and so on. If you are translating a formula then use variable names that reflect the elements used in the formula. For example, 2 r (that should read as "2 pi r" but that depends upon how your browser has been set-up) would give local variables names of pi and r. Remember, C programmers tend to prefer short names! Note: all C's variables must begin with a letter or a "_" (underscore) character. 1.3.1 Integer Number Variables The first type of variable we need to know about is of class type int - short for integer. An int variable can store a value in the range -32768 to +32767. You can think of it as a largish positive or negative whole number: no fractional part is allowed. To declare an int you use the instruction: int variable name; For example: int a; declares that you want to create an int variable called a. To assign a value to our integer variable we would use the following C statement:
a=10;

The C programming language uses the "=" character for assignment. A statement of the form a=10; should be interpreted as take the numerical value 10 and store it in a memory location
8

(AMITY CENTER FOR e-LEARNING)


associated with the integer variable a. The "=" character should not be seen as an equality otherwise writing statements of the form:
a=a+10;

will get mathematicians blowing fuses! This statement should be interpreted as take the current value stored in a memory location associated with the integer variable a; add the numerical value 10 to it and then replace this value in the memory location associated with a. 1.3.2 Decimal Number Variables As described above, an integer variable has no fractional part. Integer variables tend to be used for counting, whereas real numbers are used in arithmetic. C uses one of two keywords to declare a variable that is to be associated with a decimal number: float and double. They are each offer a different level of precision as outlined below. float A float, or floating point, number has about seven digits of precision and a range of about 1.E-36 to 1.E+36. A float takes four bytes to store. double A double, or double precision, number has about 13 digits of precision and a range of about 1.E303 to 1.E+303. A double takes eight bytes to store. For example: float total; double sum; To assign a numerical value to our floating point and double precision variables we would use the following C statement: total=0.0; sum=12.50; 1.3.3 Character Variables C only has a concept of numbers and characters. It very often comes as a surprise to some programmers who learnt a beginner's language such as BASIC that C has no understanding of strings but a string is only an array of characters and C does have a concept of arrays which we shall be meeting later in this course. To declare a variable of type character we use the keyword char. - A single character stored in one byte.For example: char c;

(AMITY CENTER FOR e-LEARNING)


To assign, or store, a character value in a char data type is easy - a character variable is just a symbol enclosed by single quotes. For example, if c is a char variable you can store the letter A in it using the following C statement: c='A' Notice that you can only store a single character in a char variable. Later we will be discussing using character strings, which has a very real potential for confusion because a string constant is written between double quotes. But for the moment remember that a char variable is 'A' and not "A". Something To Declare Before you can use a variable you have to declare it. As we have seen above, to do this you state its type and then give its name. For example, int i; declares an integer variable. You can declare any number of variables of the same type with a single statement. For example:
int a, b, c;

declares three integers: a, b and c. You have to declare all the variables that you want to use at the start of the program. Later you will discover that exactly where you declare a variable makes a difference, but for now you should put variable declarations after the opening curly bracket of the main program. Here is an example program that includes some of the concepts outlined above.
/* Program#int.c Another simple program using int and printf */ #include <stdio.h> main() { int a,b,average; a=10; b=6; average = ( a+b ) / 2 ; printf("Here "); printf("is "); printf("the "); printf("answer... "); printf("\n");

10

(AMITY CENTER FOR e-LEARNING)


printf("%d.",average); }

More On Initialising Variables You can assign an initial value to a variable when you declare it. For example:
int i=1;

sets the int variable to one as soon as it's created. This is just the same as:
int i; i=l;

but the compiler may be able to speed up the operation if you initialise the variable as part of its declaration. Don't assume that an uninitialised variable has a sensible value stored in it. Some C compilers store 0 in newly created numeric variables but nothing in the C language compels them to do so. The form of a C Program All C programs will consist of at least one function, but it is usual (when your experience grows) to write a C program that comprises several functions. The only function that has to be present is the function called main. For more advanced programs the main function will act as a controlling function calling other functions in their turn to do the dirty work! The main function is the first function that is called when your program executes. C makes use of only 32 keywords which combine with the formal syntax to the form the C programming language. Note that all keywords are written in lower case - C, like UNIX, uses upper and lowercase text to mean different things. If you are not sure what to use then always use lowercase text in writing your C programs. A keyword may not be used for any other purposes. For example, you cannot have a variable called auto. The layout of C Programs The general form of a C program is as follows (don't worry about what everything means at the moment - things will be explained later): pre-processor directives global declarations main() { local variables to function main ; statements associated with function main ; } f1()
11

(AMITY CENTER FOR e-LEARNING)


{ local variables to function 1 ; statements associated with function 1 ; } f2() { local variables to function f2 ; statements associated with function 2 ; } . .
. etc

Note the use of the bracket set () and {}. () are used in conjunction with function names whereas {} are used as to delimit the C statements that are associated with that function. Also note the semicolon - yes it is there, but you might have missed it! a semicolon (;) is used to terminate C statements. C is a free format language and long statements can be continued, without truncation, onto the next line. The semicolon informs the C compiler that the end of the statement has been reached. Free format also means that you can add as many spaces as you like to improve the look of your programs. A very common mistake made by everyone, who is new to the C programming language, is to miss off the semicolon. The C compiler will concatenate the various lines of the program together and then tries to understand them - which it will not be able to do. The error message produced by the compiler will relate to a line of you program which could be some distance from the initial mistake.

12

(AMITY CENTER FOR e-LEARNING)

Chapter 2 Operators and Expressions


Contents: 2.1 Introduction 2.2 Precedence of C operators 2.3 Arithmetic operator 2.4 Relational and Logical Operators 2.5 Increment and Decrement operator 2.6 Assignment Operators and Expressions 2.6.1 Conditional Expressions 2.7 Bitwise operators 2.8 Miscellaneous Features 2.8.1 2.8.2 2.8.3 Casting C Shorthand Multiple Assignments

2.1 Introduction
Operators form expressions by joining individual constants, variables, and array. C includes a large number of operators which fall into different categories. In this lesson we will see how arithmetic operators, unary operators, relational and logical operators, assignment operators and the conditional operators are used to form expressions. The data items on which operators act upon are called operands. Some operators require two operands while others require only one operand. Most operators allow the individual operands to be expressions. A few operators permit only single variable as operand. Variables and constants can be used in conjunction with C operators to create more complex expressions. Table 2-1 presents the set of C operators.

Table 2-1 C Operators


Operator () [] Example
f() a[10]

Description/Meaning Function call Array reference

13

(AMITY CENTER FOR e-LEARNING)


-> . + [unary] - [unary] * [unary] & [unary] ~ ++ [prefix]
s->a s.a +a -a *a &a ~a ++a

Structure and union member selection Structure and union member selection Value of a Negative of a Reference to object at address a Address of a One's complement of a The value of a after increment The value of a before increment The value of a after decrement The value of a before decrement Size in bytes of object with type t1 Size in bytes of object having the type of expression e a plus b

++ [postfix] a++ - - [prefix]


-a

- - [postfix] asizeof sizeof sizeof (t1) sizeof e

+ [binary] - [binary] * [binary] /%

a a a a a

+ * / %

b b b b b

a minus b a times b a divided by b Remainder of a/b

>> <<

a >> b a << b

a, right-shifted b bits a, left-shifted b bits 1 if a < b; 0 otherwise

< > <= >= == !=

a a a a a a

< b > b <= b >= b == b != b

1 if a > b; 0 otherwise 1 if a <= b; 0 otherwise 1 if a >= b; 0 otherwise 1 if a equal to b; 0 otherwise 1 if a not equal to b; 0 otherwise

14

(AMITY CENTER FOR e-LEARNING)


& [binary] | ^ && || !
a & b a | b a ^ b

Bitwise AND of a and b Bitwise OR of a and b Bitwise XOR (exclusive OR) of a and b Logical AND of a and b (yields 0 or 1) Logical OR of a and b (yields 0 or 1) Logical NOT of a (yields 0 or 1) Expression e1 if a is nonzero;

a && b a || b !a

?:

a ? e1 : e2

Expression e2 if a is zero a, after b is assigned to it a plus b (assigned to a)

= += -= *= /= %= >>= <<= &= |= ^= ,

a minus b (assigned to a)
a = b a += b a -= b a *= b a /= b a %= b a >>= b a <<= b a &= b a |= b a ^= b e1,e2

a times b (assigned to a) a divided by b (assigned to a) Remainder of a/b (assigned to a) a, right-shifted b bits (assigned to a) a, left-shifted b bits (assigned to a) a AND b (assigned to a) a OR b (assigned to a) a XOR b (assigned to a) e2 (e1 evaluated first)

The C operators fall into the following categories: Postfix operators, which follow a single operand. Unary prefix operators, which precede a single operand. Binary operators, which take two operands and perform a variety of arithmetic and logical operations. The conditional operator (a ternary operator), which takes three operands and evaluates either the second or third expression, depending on the evaluation of the first expression. Assignment operators, which assign a value to a variable. The comma operator, which guarantees left-to-right evaluation of comma-separated expressions.
15

(AMITY CENTER FOR e-LEARNING)

2.2 Precedence of C Operators


Operator precedence determines the grouping of terms in an expression. This affects how an expression is evaluated. Certain operators have higher precedence than others; for example, the multiplication operator has higher precedence than the addition operator:
x = 7 + 3 * 2; /* x is assigned 13, not 20 */

The previous statement is equivalent to the following:


x = 7 + (3 * 2);

Using parenthesis in an expression alters the default precedence. For example:


x = (7 + 3) * 2; /* (7 + 3) is evaluated first */

In an unparenthesized expression, operators of higher precedence are evaluated before those of lower precedence. Consider the following expression:
A+B*C

The identifiers B and C are multiplied first because the multiplication operator (*) has higher precedence than the addition operator (+). Category Postfix Unary Additive Shift Relational Equality Bitwise AND Bitwise XOR Bitwise OR Logical AND Logical OR Conditional Assignment Comma Operator () [] -> . ++ - + - ! ~ ++ - - (type) * & sizeof +<< >> < <= > >= == != & ^ | && || ?: , Associativity Left to right Right to left Left to right Left to right Left to right Left to right Left to right Left to right Left to right Left to right Left to right Left to right Right to left Left to right
16

Multiplicative * / %

= += -= *= /= %= >>= <<= &= ^= |= Right to left

(AMITY CENTER FOR e-LEARNING)

Table 2-2 Precedence of C Operators


Associativity relates to precedence, and resolves any ambiguity over the grouping of operators with the same precedence. In the following statement, the rules of C specify that a * b is evaluated first:
y = a * b / c;

In a more complicated example, associativity rules specify that b ? c : d is evaluated first in the following example:
a ? b ? c : d : e;

The associativity of the conditional operator is right-to-left on the line. The assignment operator also associates right-to-left; for example:
int x = 0 , y = 5, z = 3; x = y = z; /* x has the value 3, not 5 */

Other operators associate left-to-right; for example, the binary addition, subtraction, multiplication, and division operators all have left-to-right associativity. Associativity applies to each row of operators in Table 2-2 and is right-to-left for some rows and left-to-right for others. The kind of associativity determines the order in which operators from the same row are evaluated in an unparenthesized expression. Consider the following expression:
A*B%C

This expression is evaluated as follows because the multiplicative operators (*, /, %) are evaluated from left to right:
(A*B)%C

Parentheses can always be used to control precedence and associativity within an expression

2.3 Arithmetic Operators


The binary arithmetic operators are +, -, *, /, and the modulus operator %. Integer division truncates any fractional part. The expression x%y produces the remainder when x is divided by y, and thus is zero when y divides x exactly. For example, a year is a leap year if it is divisible by 4 but not by 100, except that years divisible by 400 are leap years. Therefore

17

(AMITY CENTER FOR e-LEARNING)


if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) printf("%d is a leap year\n", year); else printf("%d is not a leap year\n", year); The % operator cannot be applied to a float or double. The direction of truncation for / and the sign of the result for % are machine-dependent for negative operands, as is the action taken on overflow or underflow. The binary + and - operators have the same precedence, which is lower than the precedence of *, / and %, which is in turn lower than unary + and -. Arithmetic operators associate left to right.

2.4 Relational and Logical Operators


The relational and logical operators are as follows:
Operator &gt &gt= < &lt= == !=
&amp&

Meaning
Greater than Greater than or equal to Less than Less than or equal to Equal Not equal logical AND logical OR logical NOT

|| !

The idea of true and false underlies the concepts of relational and logical operators. In C, true is any value other than zero and false is zero. All relational and logical operations produce a result of either 1 or 0.

18

(AMITY CENTER FOR e-LEARNING)


Although C does not contain an exclusive OR (XOR) operator, a function can easily be created to perform that task. Mostly used relational operators are > >= < <= They all have the same precedence. Just below them in precedence are the equality operators: == != Relational operators have lower precedence than arithmetic operators, so an expression like i < lim-1 is taken as i < (lim-1), as would be expected. More interesting are the logical operators && and ||. Expressions connected by && or || are evaluated left to right, and evaluation stops as soon as the truth or falsehood of the result is known. Most C programs rely on these properties. for (i=0; i < lim-1 && (c=getchar()) != '\n' && c != EOF; ++i) s[i] = c; Before reading a new character it is necessary to check that there is room to store it in the array s, so the test i < lim-1 must be made first. Moreover, if this test fails, we must not go on and read another character. Similarly, it would be unfortunate if c were tested against EOF before getchar is called; therefore the call and assignment must occur before the character in c is tested. The precedence of && is higher than that of ||, and both are lower than relational and equality operators, so expressions like i < lim-1 && (c=getchar()) != '\n' && c != EOF need no extra parentheses. But since the precedence of != is higher than assignment, parentheses are needed in (c=getchar()) != '\n' to achieve the desired result of assignment to c and then comparison with '\n'. By definition, the numeric value of a relational or logical expression is 1 if the relation is true, and 0 if the relation is false.

19

(AMITY CENTER FOR e-LEARNING)


The unary negation operator ! converts a non-zero operand into 0, and a zero operand in 1. A common use of ! is in constructions like if (!valid) rather than if (valid == 0) It's hard to generalize about which form is better. Constructions like !valid read nicely (``if not valid''), but more complicated ones can be hard to understand. Exercise. Write a loop equivalent to the for loop above without using && or ||.

2.5 Increment and Decrement Operators


C provides two unusual operators for incrementing and decrementing variables. The increment operator ++ adds 1 to its operand, while the decrement operator -- subtracts 1. We have frequently used ++ to increment variables, The increment operator "++" increments the named variable. For example, the statement "a++" is equivalent to "a= a+1" or "a+= 1". A statement that uses an increment operator has a value. For example, the statement
a= 3; printf("a=%d a+1=%d\n", a, ++a);

will display the text "a=3 a+1=4." If the increment operator comes after the named variable, then the value of the statement is calculated after the increment occurs. So the statement example 1,
a= 3; printf("a=%d a+1=%d\n", a, a++);

would display "a=3 a+1=3" but would finish with a set to 4. The decrement operator "--" is used in the same fashion as the increment operator. example 2,
if (c == '\n') ++nl;

20

(AMITY CENTER FOR e-LEARNING)


The unusual aspect is that ++ and -- may be used either as prefix operators (before the variable, as in ++n), or postfix operators (after the variable: n++). In both cases, the effect is to increment n. But the expression ++n increments n before its value is used, while n++ increments n after its value has been used. This means that in a context where the value is being used, not just the effect, ++n and n++ are different. If n is 5, then
x = n++;

sets x to 5, but
x = ++n;

sets x to 6. In both cases, n becomes 6. The increment and decrement operators can only be applied to variables; an expression like (i+j)++ is illegal. In a context where no value is wanted, just the incrementing effect, as in
if (c == '\n') nl++;

prefix and postfix are the same. But there are situations where one or the other is specifically called for. For instance, consider the function squeeze(s,c), which removes all occurrences of the character c from the string s.
/* squeeze: delete all c from s */ void squeeze(char s[], int c) { int i, j; for (i = j = 0; s[i] != '\0'; i++) if (s[i] != c) s[j++] = s[i]; s[j] = '\0'; }

Each time a non-c occurs, it is copied into the current j position, and only then is j incremented to be ready for the next character. This is exactly equivalent to
if (s[i] != c) { s[j] = s[i]; j++; }

As another example, consider the standard function strcat(s,t), which concatenates the string t to the end of string s. strcat assumes that there is enough space in s to hold the combination. As we have written it, strcat returns no value; the standard library version returns a pointer to the resulting string. /* strcat: concatenate t to end of s; s must be big enough */
void strcat(char s[], char t[]) { int i, j; i = j = 0; while (s[i] != '\0') /* find end of s */ i++; while ((s[i++] = t[j++]) != '\0') /* copy t */

21

(AMITY CENTER FOR e-LEARNING)


; }

As each member is copied from t to s, the postfix ++ is applied to both i and j to make sure that they are in position for the next pass through the loop. Exercise. Write an alternative version of squeeze(s1,s2) that deletes each character in s1 that matches any character in the string s2. Exercise. Write the function any(s1,s2), which returns the first location in a string s1 where any character from the string s2 occurs, or -1 if s1 contains no characters from s2. (The standard library function strpbrk does the same job but returns a pointer to the location.)

2.6 Assignment Operators and Expressions


An expression such as i=i+2 in which the variable on the left side is repeated immediately on the right, can be written in the compressed form i += 2 The operator += is called an assignment operator. Most binary operators (operators like + that have a left and right operand) have a corresponding assignment operator op=, where op is one of + - * / % << >> & ^ | If expr1 and expr2 are expressions, then expr1 op= expr2 is equivalent to expr1 = (expr1) op (expr2) except that expr1 is computed only once. Notice the parentheses around expr2: x *= y + 1 means x = x * (y + 1) rather than x=x*y+1 As an example, the function bitcount counts the number of 1-bits in its integer argument.
/* bitcount: count 1 bits in x */ int bitcount(unsigned x) { int b; for (b = 0; x != 0; x >>= 1)

22

(AMITY CENTER FOR e-LEARNING)


if (x & 01) b++; return b; }

Declaring the argument x to be an unsigned ensures that when it is right-shifted, vacated bits will be filled with zeros, not sign bits, regardless of the machine the program is run on. Quite apart from conciseness, assignment operators have the advantage that they correspond better to the way people think. We say ``add 2 to i'' or ``increment i by 2'', not ``take i, add 2, then put the result back in i''. Thus the expression i += 2 is preferable to i = i+2. In addition, for a complicated expression like yyval[yypv[p3+p4] + yypv[p1]] += 2 the assignment operator makes the code easier to understand, since the reader doesn't have to check painstakingly that two long expressions are indeed the same, or to wonder why they're not. And an assignment operator may even help a compiler to produce efficient code. We have already seen that the assignment statement has a value and can occur in expressions; the most common example is while ((c = getchar()) != EOF) ... The other assignment operators (+=, -=, etc.) can also occur in expressions, although this is less frequent. In all such expressions, the type of an assignment expression is the type of its left operand, and the value is the value after the assignment. Exercise In a two's complement number system, x &= (x-1) deletes the rightmost 1-bit in x. Explain why. Use this observation to write a faster version of bitcount.

2.6.1 Conditional Expressions


The statements if (a > b) z = a; else z = b;
23

(AMITY CENTER FOR e-LEARNING)


compute in z the maximum of a and b. The conditional expression, written with the ternary operator ``?:'', provides an alternate way to write this and similar constructions. In the expression expr1 ? expr2 : expr3 the expression expr1 is evaluated first. If it is non-zero (true), then the expression expr2 is evaluated, and that is the value of the conditional expression. Otherwise expr3 is evaluated, and that is the value. Only one of expr2 and expr3 is evaluated. Thus to set z to the maximum of a and b, z = (a > b) ? a : b; /* z = max(a, b) */ It should be noted that the conditional expression is indeed an expression, and it can be used wherever any other expression can be. If expr2 and expr3 are of different types, the type of the result is determined by the conversion rules discussed earlier in this chapter. For example, if f is a float and n an int, then the expression (n > 0) ? f : n is of type float regardless of whether n is positive. Parentheses are not necessary around the first expression of a conditional expression, since the precedence of ?: is very low, just above assignment. They are advisable anyway, however, since they make the condition part of the expression easier to see. The conditional expression often leads to succinct code. For example, this loop prints n elements of an array, 10 per line, with each column separated by one blank, and with each line (including the last) terminated by a newline. for (i = 0; i < n; i++) printf("%6d%c", a[i], (i%10==9 || i==n-1) ? '\n' : ' '); A newline is printed after every tenth element, and after the n-th. All other elements are followed by one blank. This might look tricky, but it's more compact than the equivalent if-else. Another good example is printf("You have %d items%s.\n", n, n==1 ? "" : "s"); Exercise. Rewrite the function lower, which converts upper case letters to lower case, with a conditional expression instead of if-else.

2.7 Bitwise Operators

Since C was designed to take the place of assembly language for most programming tasks, it needed to be able to support assembler-like operations. Bitwise operations refer to testing, setting or shifting the actual bits in a byte or word (byte and word corresponding to the types char and int and their variants). C provides six operators for bit manipulation; these may only be applied to integral operands, that is, char, short, int, and long, whether signed or unsigned. & bitwise AND
24

(AMITY CENTER FOR e-LEARNING)


| ^ << >> ~ bitwise inclusive OR bitwise exclusive OR left shift right shift one's complement (unary)

The bitwise AND operator & is often used to mask off some set of bits, for example n = n & 0177; sets to zero all but the low-order 7 bits of n. The bitwise OR operator | is used to turn bits on: x = x | SET_ON; sets to one in x the bits that are set to one in SET_ON. The bitwise exclusive OR operator ^ sets a one in each bit position where its operands have different bits, and zero where they are the same. One must distinguish the bitwise operators & and | from the logical operators && and ||, which imply left-to-right evaluation of a truth value. For example, if x is 1 and y is 2, then x & y is zero while x && y is one. The shift operators << and >> perform left and right shifts of their left operand by the number of bit positions given by the right operand, which must be non-negative. Thus x << 2 shifts the value of x by two positions, filling vacated bits with zero; this is equivalent to multiplication by 4. Right shifting an unsigned quantity always fits the vacated bits with zero. Right shifting a signed quantity will fill with bit signs (``arithmetic shift'') on some machines and with 0-bits (``logical shift'') on others. The unary operator ~ yields the one's complement of an integer; that is, it converts each 1-bit into a 0-bit and vice versa. For example x = x & ~077 sets the last six bits of x to zero. Note that x & ~077 is independent of word length, and is thus preferable to, for example, x & 0177700, which assumes that x is a 16-bit quantity. The portable form involves no extra cost, since ~077 is a constant expression that can be evaluated at compile time.
25

(AMITY CENTER FOR e-LEARNING)


As an illustration of some of the bit operators, consider the function getbits(x,p,n) that returns the (right adjusted) n-bit field of x that begins at position p. We assume that bit position 0 is at the right end and that n and p are sensible positive values. For example, getbits(x,4,3) returns the three bits in positions 4, 3 and 2, right-adjusted. /* getbits: get n bits from position p */ unsigned getbits(unsigned x, int p, int n) { return (x >> (p+1-n)) & ~(~0 << n); } The expression x >> (p+1-n) moves the desired field to the right end of the word. ~0 is all 1-bits; shifting it left n positions with ~0<<n places zeros in the rightmost n bits; complementing that with ~ makes a mask with ones in the rightmost n bits. Exercise. Write a function setbits(x,p,n,y) that returns x with the n bits that begin at position p set to the rightmost n bits of y, leaving the other bits unchanged. Exercise. Write a function invert(x,p,n) that returns x with the n bits that begin at position p inverted (i.e., 1 changed into 0 and vice versa), leaving the others unchanged. Exercise. Write a function rightrot(x,n) that returns the value of the integer x rotated to the right by n positions.
Clearing a Bit - Bitwise AND (&amp)

Bitwise ANDing is frequently used for &quotmasking"operations, i.e., the operator may be used to set specific bits to zero. Any bit that is 0 in either operand causes the corresponding bit to be set to 0. For example, the following resets a parity bit to 0: return (ch & 127); Note that the number 127 has bit 8 set to 0. Here is what happens: parity bit set parity bit unset

1 0 0 1 0 1 0 1 0 1 1 1 1 1 1 1 0 0 0 1 0 1 0 1

0 0 0 1 0 1 0 1 0 1 1 1 1 1 1 1 0 0 0 1 0 1 0 1

ch 127 result

26

(AMITY CENTER FOR e-LEARNING)


Setting a Bit - Bitwise OR (|) Similarly, the bitwise OR may be used to set a bit. Any bit which is set to 1 in either operand causes the outcome to be set to 1. For example, the following is 128 | 3: 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 3 in binary 128 in binary result

Exclusive OR (^) Exclusive OR (XOR) sets a bit only if the bits being compared are different. One interesting property of XOR is that any value XOR'd with itself produces 0. This is useful in assembly programming. Swapping Values. An interesting application of XOR is that it can be used to exchange two values without the need for an extra memory location, e.g.: a ^= b; b ^= a; a ^= b; Shift Operators (&lt&lt and &gt&gt) Shift operators move all bits left or right as specified. As bits are shifted off one end, zeroes are brought in at the other. A shift is not a rotate; the bits shifted off one end are lost. Left shifting has the effect of multiplying the shifted value by two. For right shifts, what is shifted in on the left depends on the sign of the value being shifted and also on how the operation is implemented on the particular machine. If the sign is 0 (positive), then zeroes will be shifted in. If the sign is 1 (negative), on some machines 1s will be shifted in and on others, 0s. The former is known as an arithmetic right shift; the latter is known as a logical right shift. C does not guarantee a defined result if a value is shifted by an amount greater or less than the number of bits in the data item.

27

(AMITY CENTER FOR e-LEARNING)


One's Complement Operator (~) The One's Complement operator reverses the state of each bit in the specified variable. Note that two complements in a row return the byte to its original value.

The ? Operator The ternary operator ? replaces certain statements of the if-then-else form. In the following: y = x >10 ? 100 : 200 the first expression is evaluated. If it evaluates to true, y is made equal to 100. If it evaluates to false, y is made equal to 200.

The &amp and * Operators Preamble. A pointer is the memory address of a variable. A pointer variable is a variable specifically declared to hold a pointer. Pointers: provide a fast means of referencing array elements, allow C functions to modify their calling parameters, and support linked lists and other dynamic data structures. A pointer is of sufficient size to hold an address as defined by the architecture of the computer. Pointer Operators. The following operators are used to manipulate pointers:

The & Operator The & operator returns the memory address of its operand. For example: m = &count; places the address of count into m. & can be thought of as "address of".

28

(AMITY CENTER FOR e-LEARNING)


The * Operator The * operator is the complement of &amp. It returns the value of the variable at the address which follows it. For example, in the following extension of the preceding code fragment: q = *count; the value of count is placed in q. * can be thought of as "address".

The Compile-Time Operator sizeof sizeof is a unary compile time operator which returns the length, in bytes, of the variable or parenthesized type specifier that precedes it. Usage is illustrated in the following: printf(&quot%f&quot, sizeof f); printf(&quot%d&quot, sizeof(int));

The Comma Operator The comma operator may be used to string together several expressions. For example, in: x - (y = 3, y + 1); the left side of the comma operator is evaluated as void, which means that y is first assigned the value 3 and then x is assigned the value 4.

The . and -> Operators The . and -> operators reference individual elements in structures and unions. The . operator is used when working with the actual structure or union, e.g.: employee.wage = 123.23; The -&gt is used when working with a pointer to the structure or union, e.g.: emp_ptr->wage = 123.23;
29

(AMITY CENTER FOR e-LEARNING)

2.8 Miscellaneous Features


2.8.1 Casting

An expression can be forced to be of a particular type by using a cast. Casts are often considered to be operators. As an operator, casts are unary, and have the same precedence as other unary operators. An example of a cast which ensures that an expression evaluates to type float is as follows: x = (float) x / 2; In the following example, a fractional number is truncated to a whole number: double x = 3.141592654; double y; y = (short) x; // resulting value of y is 3.0 In the following example, casting is used to round to the nearest integer: double x, y; x = 4.67; y = (short) (x + 0.5); // resulting value of y is 5.0 x = 4.45; y = (short) (x +.05); // resulting value of y is 4.0
2.8.2 C Shorthand

C has a special shorthand which simplifies the coding of certain assignments. For example: x = x + 10; can be written as x += 10; x = x * 10; can be written as x *= 10; Some further examples using the bitwise operators are as follows:

30

(AMITY CENTER FOR e-LEARNING)


Operator &gt&gt= &lt&lt=< &amp= ^= |=
2.8.3 Multiple Assignments

Usage

Result in a After Operation

a &gt&gt= b a shifted right by b bits a &lt&lt= b a &amp= b a ^= b a |= b a shifted left by b bits a ANDed with b a exclusive ORed with b a ORed with b

The assignment of a value to many variables is possible using multiple assignment, eg: x = y = z = 0;

Chapter 3 Data Input / Output Functions


Contents: 3.1 Introduction 3.2 Standard input output 3.3 Character Input / Output 3.3.1 getchar 3.3.2 putchar 3.4 Formatted input /output 3.4.1 printf 3.4.2 scanf 3.5 whole lines of input and output
31

(AMITY CENTER FOR e-LEARNING)


3.5.1 gets 3.5.2 puts

3.1 Introduction
One of the reasons that has prevented many programming languages from becoming widely used for real programming is their poor support for I/O, a subject which has never seemed to excite language designers. C has avoided this problem, oddly enough, by having no I/O at all! The C language approach has always been to do I/O using library functions, which ensures that system designers can provide tailored I/O instead of being forced to change the language itself. As C has evolved a library package known as the Standard I/O Library or stdio, has evolved with it and has proved to be both flexible and portable. This package has now become part of the Standard. The old stdio package relied heavily on the UNIX model of file access, in particular the assumption that there is no distinction between unstructured binary files and files containing readable text. Many operating systems do maintain a distinction between the two, and to ensure that C programs can be written portably to run on both types of file model, the stdio package has been modified. There are changes in this area which affect many existing programs, although strenuous efforts were taken to limit the amount of damage.

3.2 The standard Input Output File.


To perform, input and output to files or the terminal, UNIX supplies a standard package. To use them, this contains most of the functions which will be introduced in this section, along with definitions of the data types required. Your program must include these definitions by adding the line to use these facilities. #include near start of the program file. If you do not do this, the compiler may complain about undefined data types or functions.

32

(AMITY CENTER FOR e-LEARNING)

3.3 Character Input / Output


If you will not press the return key then theyll not start reading any input, and theyll not print characters on the terminal until there is a whole line to be printed. This is the lowest level of output and input. It provides very precise control, but is usually too fiddly to be useful also. Most computers perform buffering of inputs and outputs. These include:
1. getchar

2. putchar

3.3.1 getchar
getchar always returns the next character of keyboard input as an int. The EOF (end of file) is returned,if there is an error . It is usual to compare this value against EOF before using it. So error conditions will not be handled correctly,if the return value is stored in a char, it will never be equal to EOF. The following program is used to count the number of characters read until an EOF is encountered. EOF can be generated by typing Control - d. #include main() { int ch, i = 0; while((ch = getchar()) != EOF) i ++; printf(%d\n, i); }

3.3.2 putchar
The putchar() function writes ch to STDOUT. The code putchar( ch );
33

(AMITY CENTER FOR e-LEARNING)


is the same as putc( ch, STDOUT );

The return value of putchar() is the written character, or EOF if there is an error putchar puts its character argument on the standard output (usually the screen). The following example program converts any typed input into capital letters.It applies the function toupper from the character conversion library ctype.h to each character in turn to do this.

#include /* For definition of toupper */ #include /* For definition of getchar, putchar, EOF */ main() { int ch; while((ch = getchar()) != EOF) putchar(toupper(ch)); }

3.4 Formatted Input / Output


They are closest to the facilities offered by Pascal or Fortran, and usually the easiest to use for input and output. The versions offered under C are a little more detailed, offering precise control of layout. These includes following: 1. printf 2. scanf

3.4.1 printf

34

(AMITY CENTER FOR e-LEARNING)


This offers more structured output than the putchar. Its arguments are, in order; a control string, which controls what get printed, followed by a list of values to be substituted for entries in the control string.The printf() function prints output to STDOUT, according to format and other arguments passed to printf(). The string format consists of two types of items - characters that will be printed to the screen, and format commands that define how the other arguments to printf() are displayed. Basically, you specify a format string that has text in it, as well as "special" characters that map to the other arguments of printf().

The %s means, "insert the first argument, a string, right here." The %d indicates that the second argument (an integer) should be placed there. There are different %-codes for different variable types, as well as options to limit the length of the variables and whatnot.

Code ---%c %d %i %e %E %f %g %G %o %s %u %x

Format -----character signed integers signed integers scientific notation, with a lowercase "e" scientific notation, with a uppercase "E" floating point use %e or %f, whichever is shorter use %E or %f, whichever is shorter octal a string of characters unsigned integer unsigned hexadecimal, with lowercase letters

35

(AMITY CENTER FOR e-LEARNING)


%X %p unsigned hexadecimal, with uppercase letters a pointer

%n the argument shall be a pointer to an integer into which is placed the number of characters written so far %% a '%' sign

An integer placed between a % sign and the format command acts as a minimum field width specifier, and pads the output with spaces or zeros to make it long enough. If you want to pad with zeros, place a zero before the minimum field width specifier. You can use a precision modifier, which has different meanings depending on the format code being used. With %e, %E, and %f, the precision modifier lets you specify the number of decimal places desired. For example, %12.6f will display a floating number at least 12 digits wide, with six decimal places. With %g and %G, the precision modifier determines the maximum number of significant digits displayed. With %s, the precision modifer simply acts as a maximum field length, to complement the minimum field length that precedes the period.

All of printf()'s output is right-justified, unless you place a minus sign right after the % sign. For example,
%-12.4f

will display a floating point number with a minimum of 12 characters, 4 decimal places, and left justified. You may modify the %d, %i, %o, %u, and %x type specifiers with the letter l and the letter h to specify long and short data types (e.g. %hd means a short integer). The %e, %f, and %g type specifiers can have the letter l before them to indicate that a double follows. The %g, %f, and %e type specifiers can be preceded with the character '#' to ensure that the decimal point will be present, even if there are no decimal digits. The use of the '#' character with the %x type

36

(AMITY CENTER FOR e-LEARNING)


specifier indicates that the hexidecimal number should be printed with the '0x' prefix. The use of the '#' character with the %o type specifier indicates that the octal value should be displayed with

a 0 prefix.

You can also include constant escape sequences in the output string.The return value of printf() is the number of characters printed, or a negative number if an error occurred. Example: char name[20] = "Bob"; int age = 21; printf( "Hello %s, you are %d years old\n", name, age ); OUTPUT: Hello Bob, you are 21 years old

3.4.1 scanf
To grab things from input,scanf() is used. Beware though; scanf isnt greatest function that C has to offer. Some people brush off the scanf as a broken function that shouldnt be used often. The prototype for scanf is: int scanf( const char *format, );

To read of data from the keyboard scanf allows formatted. Like printf it has a control string, followed by the list of items to be read. However scanf wants to know the address of items to be read, since it is a function which will change that value. Therefore the names of variables are preceded by the & sign. Character strings are an exception to this. Since a string is already a character pointer, we give the names of the string variables unmodified by a leading &. Control string entries which match values to be read are preceded by the percentage sign in a similar way to their printf equivalent. Looks similar to printf, but doesnt completely behave like the printf does. Take the example:

scanf(%d, x);

37

(AMITY CENTER FOR e-LEARNING)


The following is the example which shows the use of scanf:

int x, args; for ( ; ; ) { printf(Enter an integer bub: ); if (( args = scanf(%d, &x)) == 0) { printf(Error: not an integer\n); continue; } else { if (args == 1) printf(Read in %d\n, x); else break; } }

3.5 whole lines of input and output


Where we are not too interested in the format of our data, or perhaps we cannot predict its format in advance, we can read and write whole lines as character strings. This approach allows us to read in a line of input, and then use various string handling functions to analyse it at our leisure

3.5.1 puts
The function puts() writes str to STDOUT. puts() returns non-negative on success, or EOF on failure. Explanation: This function, puts, will output the string pointed to by astring. It will then add a newline character. This is built in to the function. It returns a nonnegative integer if it was successful. It returns EOF if there was an error Syntax: #include <stdio.h>
38

(AMITY CENTER FOR e-LEARNING)


int puts( char *str );

//Example outputs "Hello, World" with a newline #include <cstdio> using namespace std; int main() { puts("Hello World"); }

3.5.2 gets
The gets() function reads characters from STDIN and loads them into str, until a newline or EOF is reached. The newline character is translated into a null termination. The return value of gets() is the read-in string, or NULL if there is an error. Syntax: #include <stdio.h>

Chapter 4 Control Statements


Contents:

4.1 Preliminaries 4.1.1 Branching 4.1.1.1 4.1.1.2 4.1.2 If-else Switch-case

Looping 4.1.2.1 4.1.2.2 4.1.2.3 For loop While do while Break - continue

39

(AMITY CENTER FOR e-LEARNING)


4.1

Preliminaries

C provides two styles of flow control: Branching Looping These branching and looping in C can be achieved with the help of following keywords If-Else While For Break / Continue Switch-Case We will discuss each of these one by one to understand their syntax and their application in programming language

4.1.1Branching
Branching is deciding what actions to take and looping is deciding how many times to take a certain action.Branching is so called because the program chooses to follow one branch or another

4.1.1.1 if statement
This is the simplest form of the branching statements. It takes an expression in parenthesis and an statement or block of statements. if the expression is true then the statement or block of statements gets executed otherwise these statements are skipped. Programs need to make decisions. Should this statement be executed or that one? Are these parameters correct and so on. This is done using the if statement. The syntax is pretty easy.
if ( conditional expression ) statement; This can be extended with else.

40

(AMITY CENTER FOR e-LEARNING)

If-Else
The if else statement is used to make decisions. The syntax is: if (expression) statement-1 else statement-2 expression is evaluated; if it is not equal to zero (e.g., logic true), then statement-1 is executed. The else clause is optional. If the if part of the statement did not execute, and the else is present, then statement-2 executes.
if ( conditional expression ) statement1; else statement2; So if the expression is true, statement1 is executed, otherwise statement2 is executed.

NOTE: Expression will be assumed to be true if its evaulated values is non-zero. if , if-else , if-elseif-else statements take the following form: if (expression) statement; or if (expression) { Block of statements; } or if (expression) { Block of statements; } else { Block of statements; }

41

(AMITY CENTER FOR e-LEARNING)


or if (expression) { Block of statements; } else if(expression) { Block of statements; } else { Block of statements; }

Here are some examples: if ( a==3 ) b=a;

if ( b==0 ) { b=1; a += 2; } else { b=0; a=1; }

Be

Careful

that

you

don't

write

when

you

mean

==

Can you see the problem with this code? if (a=1) { 42

(AMITY CENTER FOR e-LEARNING)


b =9; } This will always set b to 9 as (a=1) is always true. It assigns a value of 1 to a instead of comparing a with 1. The corrected line should be this. if (a==1) This is a common mistake amongst beginners.

4.1.1.2 switch statement


The switch statement is much like a nested if .. else statement. Its mostly a matter of preference which you use, switch statement can be slightly more efficient and easier to read. switch( expression ) { case constant-expression1: [case constant-expression2: [case constant-expression3: [default : statements4;] } statements1; statements2;] statements3;]

When there are many choices, a switch statement may be better than an if. The syntax of a switch statement is: switch ( expression) { case a: statement1; break; case b: statement2; case d: statement3; break; default: statement4; } Notes: Expression should be an int or a char type. e.g. switch (character) { case 'B': 43

(AMITY CENTER FOR e-LEARNING)


case 'b': statement1; break; case 'c': statement2; case 'd': statement3; break; default: statement4; } If the character is 'B' or 'b' then statement1 is executed, but if the character is 'c' then statement2 and statement3 are both executed. With 'd' though, only statement3 is executed. For all other characters statement4 is executed. When a case matches, all statements from that case on, including those that follow are executed until a break is found. This is known as 'Fall Through'. switch (value) { case 3:statement3; case 2:statement2; case 1:statement1; default: break; } In this example, I've exploited 'fall through' so that for any number 1-5, statements n; n-1 down to 1 are executed. Eg if value ==3, statement3, statement2 and statement1 are executed (in that order). Notes about Switch Each case can have one or more statements without needing to be enclosed by curly brackets. The default case can occur anywhere. Good Practice to use default, perhaps to trap errors.

4.1.2 Looping
Loops provide a way to repeat commands and control how many times they are repeated. C provides a number of looping way.

44

(AMITY CENTER FOR e-LEARNING)

4.1.2.1 The For Loop


There are several ways of doing loops in C.

The syntax of a for loop is the following: for (expr-1;expr-2;expr-3) statement


OR for ( initial statement; conditional expression; loop statement ) main statement;

Note This is the one place where there is no need to put brackets around a conditional expression. This executes the initial statement once, then while the conditional expression is true, the loop statement and the main statement are executed. All three sections are optional so the following is allowed. It is an infinite loop as the conditional expression is always true if absent.

for ( ;; ) mainstatement; This will keep executing main statement for ever. The conditional expression is the most important of the three sections. As long as it is true the main statement is always run. Once the expression is false, the loop exits. for (index=1 ;index <= 10;index++ ) printf("The value of i is %i\n\r",i) ; This outputs ten lines The value of i is 1 The value of i is 2 .. The value of i is 10

45

(AMITY CENTER FOR e-LEARNING)


index++ is shorthand for adding 1 to index. You could write index = index + 1 or index +=1 but index++ is more concise.

4.1.2.2 while and do-while while loop


The most basic loop in C is the while loop.A while statement is like a repeating if statement. Like an If statement, if the test condition is true: the statments get executed. The difference is that after the statements have been executed, the test condition is checked again. If it is still true the statements get executed again.This cycle repeats until the test condition evaluates to false. Basic syntax of while loop is as follows: while ( expression ) { Single statement or Block of statements; }

while

begins by evaluating expression. If it is false, then statement is skipped. If it is true, then

statement is evaluated. Then the expression is evaluated again, and the same check is performed. The loop exits when expression becomes zero. One can easily create an infinite loop in C using the while statement: while (1) statement
There are two loop statements that use while.

46

(AMITY CENTER FOR e-LEARNING)


First is the while statement which has this syntax. while (expression) statement As long as the expression is true, the statement is executed. int total =0; int index =0; while (total < 100) { index++; total+=index; printf("Sum of 1 to %i is %i",index,total) ; } Looping doesn't get much simpler than while. The most important thing to know with while loops is that the control expression is evaluated before the statement is run. If the expression is false, the statement is not run. So a while loop may never execute a statement. Also because c allows a statement to be an expression it is possible to write complicated code like this int c=10; int a =0; while (c--) { printf("Value of a is %i",a++) ; } c-- subtracts one from c.

Do While
do ... while is just like a while loop except that the test condition is checked at the end of the loop rather than the start. This has the effect that the content of the loop are always executed at least once.Less popular than the while statement is the do while statement. This puts the expression at the end.
47

(AMITY CENTER FOR e-LEARNING)


Basic syntax of do...while loop is as follows: do { Single statement or Block of statements; }while(expression);

A while loop might never execute a statement if the expression is false but a do while will always execute the statement at least once. Here is an example of a do while loop. int count =0; int index =9; do if (value[ index] ==999) count++; index--; while ( index >= 0) ; Break and Continue work equally well with for, while and do while loops. Note For and while can be used for same purpose

for loop is similar to while, it's just written differently. for statements are often used to proccess lists such a range of numbers: The syntax of a for loop is the following: for (expr-1;expr-2;expr-3) statement
48

(AMITY CENTER FOR e-LEARNING)


This is equivalent to the following construct using while: expr-1; while (expr-2) { statement expr-3; } Typically, expr-1 is an assignment, expr-2 is a relational expression, and expr-3 is an increment or decrement of some manner. For example, the following code counts from 0 to 99, printing each number along the way: int i; for (i= 0; i < 100; i++) printf("%d\n", i);

4.1.2.3 break and continue statements


C provides two commands to control how we loop:
break -- exit form loop or switch. continue -- skip 1 iteration of loop.

Break
Use of the break provides an early exit from a while or a for loop. If a condition is met in switch case then execution continues on into the next case clause also if it is not explicitly specified that the execution should exit the switch statement. This is achieved by using break keyword.
Here's an example:

49

(AMITY CENTER FOR e-LEARNING)


int markerpos=-1; for (index=0 ;index < 10;index++ ) { if (values[index] ==-999 ) { markerpos = index; ; break; } } if (markerpos== 999) printf("-1 Not located in array"; else printf("-1 Found at index %i\n\r",markerpos) ; That's a more complicated example. It searches the 10 element array values looking for a 999 value. The variable markerpos holds the position if a 999 is found. It is initialized to -1 and after the search this value is examined to see if a 999 was found.

Continue
This does the opposite of break; Instead of terminating the loop, it immediately loops again, skipping the rest of the code So lets sum that integer array again, but this time we'll leave out elements with an index of 4 and 5. int value =0; for (index=0 ;index < 10;index++ ) { if (index==4 || index==5) continue; value += numbers[index];

50

(AMITY CENTER FOR e-LEARNING)


} printf("Value = %i",value) ; You probably won't use continue very often but it's useful on the odd occasion. You already have seen example of using break statement. Here is an example showing usage of continue statement. #include

main() { int i; int j = 10;

for( i = 0; i <= j; i ++ ) { if( i == 5 ) { continue; } printf("Hello %d\n", i ); } } This will produce following output: Hello 0 Hello 1 Hello 2 Hello 3 Hello 4
51

(AMITY CENTER FOR e-LEARNING)


Hello 6 Hello 7 Hello 8 Hello 9 Hello 10

52

(AMITY CENTER FOR e-LEARNING)

Chapter 5 Functions
Contents:

5.1 What is a function? 5.2 Structure of the function 5.2.1 5.2.2 5.2.3 function header function body function prototype

5.3 Need of function 5.4 Parts of function 5.5 Types of function 5.6 Categories of function 5.7 Call by value 5.8 Call by reference 5.9 Recursive function

5.1 What is a Function?


A function is a block of code that has a name and it has a property that it is reusable i.e. it can be executed from as many different points in a C Program as required. Function groups a number of program statements into a unit and gives it a name. This unit can be invoked from other parts of a program. A computer program cannot handle all the tasks by it self. Instead its requests other program like entities - called functions in C - to get its tasks done. A function is a self contained block of statements that perform a coherent task of same kind The name of the function is unique in a C Program and is Global. It neams that a function can be accessed from any location with in a C Program. We pass information to the function called arguments specified when the function is called. And the function either returns some value to the point it was called from or returns nothing. We can divide a long C program into small blocks which can perform a certain task. A function is a self contained block of statements that
53

(AMITY CENTER FOR e-LEARNING)


perform a coherent task of same kind.Almost all programming languages have some equivalent of the function. You may have met them under the alternative names subroutine or procedure. Some languages distinguish between functions which return variables and those which don't. C assumes that every function will return a value. If the programmer wants a return value, this is achieved using the return statement. If no return value is required, none should be used when calling the function

5.2 Structure of a Function


There are two main parts of the function. The function header and the function body. int sum(int x, int y) { int ans = 0; ans = x + y; return ans } Function Header In the first line of the above code int sum(int x, int y) It has three main parts
1. 2. 3. The name of the function i.e. sum The parameters of the function enclosed in paranthesis Return value type i.e. int

//holds the answer that will be returned //calculate the sum //return the answer

Function Body What ever is written with in { } in the above example is the body of the function. Function Prototypes The prototype of a function provides the basic information about a function which tells the compiler that the function is used correctly or not. It contains the same information as the function header contains. The prototype of the function in the above example would be like
54

(AMITY CENTER FOR e-LEARNING)


int sum (int x, int y); The only difference between the header and the prototype is the semicolon ; there must the a semicolon at the end of the prototype.

5.3 Need of functions


The basic philosophy of function is divide and conquer by which a complicated tasks are successively divided into simpler and more manageable tasks which can be easily handled. A program can be divided into smaller subprograms that can be developed and tested successfully. A function is a complete and independent program which is used (or invoked) by the main program or other subprograms. A subprogram receives values called arguments from a calling program, performs calculations and returns the results to the calling program. There are many advantages in using functions in a program they are: 1. It facilitates top down modular programming. In this programming style, the high level logic of the overall problem is solved first while the details of each lower level functions is addressed later. 2. the length of the source program can be reduced by using functions at appropriate places. This factor is critical with microcomputers where memory space is limited. 3. It is easy to locate and isolate a faulty function for further investigation. 4. A function may be used by many other programs this means that a c programmer can build on what others have already done, instead of starting over from scratch. 5. A program can be used to avoid rewriting the same sequence of code at two or more locations in a program. This is especially useful if the code involved is long or complicated. 6. Programming teams does a large percentage of programming. If the program is divided into subprograms, each subprogram can be written by one or two team members of the team rather than having the whole team to work on the complex program
55

(AMITY CENTER FOR e-LEARNING)


7. We can understand the flow of program, and its code easily since the readability is enhanced while using the functions

5.4 Parts of a function


Each function used in a program must be

Declared : it is like registering the function to make itself known for use Defined : related with actual working or functionality of fuinction

Called : to make function in use

Function Declaration
Just as you cant use a variable without first telling the compler what it is, you also cant use a funciotns without teling the compiler about it, There are two ways to do this . The approach we show here ist o declare the funtion before it is called. The other approach is to define it before its called. ; well examine that next.) in the Table program, the functions starline() is declared in the line. Void starline ( ); The declaration tells the compiler that at some later point we plan to present a function called starline. The keyword void specifies that the function has no return value, and the empty parentheses indicate that it takes no arguments. Notice that the functions declarations is terminated with a semicolon It is a complete statement in itself. Function declarations are also called prototypes, since they provide a model or blueprint for the function. They tell the compiler, a function that looks like this is coming up later in the program, so its all right if you see references to it before you see the function itself.

Calling the Function

56

(AMITY CENTER FOR e-LEARNING)


The function is called (or invoked) three times from main (). Each of the three calls look like this: Starline(): This is all we need to call a function name, followed by parentheses. The syntax of the call is very similar to that of declaration, except that the return type is not used. A semicolon terminates the call. Executing the call statement causes the function to execute; that is, control is transferred to the function, the statement in the function definition are executed, and then control returns to the statement following the function call.

Function definition
[ data type] function name (argument list) argument declaration; { local variable declarations; statements; [return expression] } Example : mul(a,b) int a,b; { int y; y=a+b; return y; } When the value of y which is the addition of the values of a and b. the last two statements ie, y=a+b; can be combined as
57

(AMITY CENTER FOR e-LEARNING)


return(y) return(a+b);

5.5 Types of Function


There are basically two types of functions 1. 2. Library functions Ex. printf ( ), scanf ( ) etc. User defined function e.g the function message mentioned above.

C support the use of library functions and use defined functions. The library functions are used to carry out a number of commonly used operations or calculations. The user-defined functions are written by the programmer to carry out various individual tasks The following point must be noted about functions (i) (ii) C program is a collection of one or more functions A function gets called when the function name is followed by a semicolon for e.g. main ( ) { message ( ); } 3. Function is defined when function name is followed by a pair of braces in which one or more statements may be present for e.g. message ( ) { statement 1;

58

(AMITY CENTER FOR e-LEARNING)


statement2; statement 3; } 4. Any function can be called from any other function even main ( ) can be called from other functions. for e.g. main ( )
{

message ( ); } message ( ) { printf ( \n Hello); main ( ); } 5. A function can be called any number of times for eg. main () { message ( ); message ( ); }
59

(AMITY CENTER FOR e-LEARNING)


message ( ) { printf (\n Hello); } 6. The order in which the functions are defined in a program and the order in which they get called need not necessarily be same for e.g. main ( ); { message 1 ( ); message 2 ( ); } message 2 ( ) { printf (\n I am learning C); } message 1 ( ) { printf ( \n Hello ); } 7. A function can call itself such a process as called recursion.
60

(AMITY CENTER FOR e-LEARNING)


8. A function can be called from other function, but a function cannot be defined in an-other function. The following program code would be wrong, since Argentina is being defined inside another function main ( ). main ( ) { printf (\n I am in main); argentina ( ) { printf {\n I am in argentina); } } 9. 10. 11. Any C program contains at least one function. If a program contains only one function, it must be main( ). In a C program if there are more than one functional present then one of these func-tional must be main( ) because program execution always begins with main( ). 12. 13. 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( ) 14. After each function has done its thing, control returns to the main( ), when main( ) runs out of function calls, the program ends. Functions declaration and prototypes Any function by default returns an int value. If we desire that a function should return a value other than an int, then it is necessary to explicitly mention so in the calling functions as well as in the called function. for e.g main ( )
61

(AMITY CENTER FOR e-LEARNING)


{ float a,b, printf ("\n Enter any number"); scanf ("\% f", &a ); b = square (a) printf ("\n square of % f is % f", a,b); } square (float X) { float y; Y = x * x; return (y); } the sample run of this program is Enter any number 2.5 square of 2.5 is 6.000000 Here 6 is not a square of 2.5 this happened because any C function, by default, always returns an integer value. The following program segment illustrates how to make square ( ) capable of returning a float value. main ( ) { float square ( ); float a, b; printf ("\n Enter any number "); scanf ("%f" &a); b = square (a); printf ("\n square of % f is % f, " a, b); }

62

(AMITY CENTER FOR e-LEARNING)


float square (float x) { float y; y= x *x; return ( y); }

5.6 Categories of functions


A function may belong to any one of the following categories: 1. Functions with no arguments and no return values. 2. Functions with arguments and no return values. 3. Functions with arguments and return values.
Functions with no arguments and no return values:

Let us consider the following program /* Program to illustrate a function with no argument and no return values*/ #include main() { staetemtn1(); starline(); statement2(); starline(); } /*function to print a message*/ statement1() { printf(\n Sample subprogram output);
63

(AMITY CENTER FOR e-LEARNING)


} statement2() { printf(\n Sample subprogram output two); } starline() { int a; for (a=1;a<60;a++) printf(%c,*); printf(\n); } In the above example there is no data transfer between the calling function and the called function. When a function has no arguments it does not receive any data from the calling function. Similarly when it does not return value the calling function does not receive any data from the called function. A function that does not return any value cannot be used in an expression it can be used only as independent statement.
Functions with arguments but no return values:

The nature of data communication between the calling function and the arguments to the called function and the called function does not return any values to the calling function this shown in example below: Consider the following: Function calls containing appropriate arguments. For example the function call value (500,0.12,5) Would send the values 500,0.12 and 5 to the function value (p, r, n) and assign values 500 to p, 0.12 to r and 5 to n. the values 500,0.12 and 5 are the actual arguments which become the values of the formal arguments inside the called function. Both the arguments actual and formal should
64

(AMITY CENTER FOR e-LEARNING)


match in number type and order. The values of actual arguments are assigned to formal arguments on a one to one basis starting with the first argument as shown below:

main() { function1(a1,a2,a3an) } function1(f1,f2,f3.fn); { function } here a1,a2,a3 are actual arguments and f1,f2,f3 are formal arguments. The no of formal arguments and actual arguments must be matching to each other suppose if actual arguments are more than the formal arguments, the extra actual arguments are discarded. If the number of actual arguments are less than the formal arguments then the unmatched formal arguments are initialized to some garbage values. In both cases no error message will be generated. The formal arguments may be valid variable names, the actual arguments may be variable names expressions or constants. The values used in actual arguments must be assigned values before the function call is made. When a function call is made only a copy of the values actual arguments is passed to the called function. What occurs inside the functions will have no effect on the variables used in the actual argument list. Let us consider the following program /*Program to find the largest of two numbers using function*/ #include main() { int a,b;
65

body;

(AMITY CENTER FOR e-LEARNING)


printf(Enter the two numbers); scanf(%d%d,&a,&b); largest(a,b) } /*Function to find the largest of two numbers*/ largest(int a, int b) { if(a>b) printf(Largest element=%d,a); else printf(Largest element=%d,b); } in the above program we could make the calling function to read the data from the terminal and pass it on to the called function. But function foes not return any value.
Functions with arguments and return values:

The function of the type Arguments with return values will send arguments from the calling function to the called function and expects the result to be returned back from the called function back to the calling function. To assure a high degree of portability between programs a function should generally be coded without involving any input output operations. For example different programs may require different output formats for displaying the results. Theses shortcomings can be overcome by handing over the result of a function to its calling function where the returned value can be used as required by the program. In the above type of function the following steps are carried out: 1. The function call transfers the controls along with copies of the values of the actual arguments of the particular function where the formal arguments are creates and assigned memory space and are given the values of the actual arguments.

66

(AMITY CENTER FOR e-LEARNING)


2. The called function is executed line by line in normal fashion until the return statement is encountered. The return value is passed back to the function call is called function. 3. The calling statement is executed normally and return value is thus assigned to the calling function. Note that the value return by any function when no format is specified is an integer.
Return value data type of function:

A C function returns a value of type int as the default data type when no other type is specified explicitly. For example if function does all the calculations by using float values and if the return statement such as return (sum); returns only the integer part of the sum. This is since we have not specified any return type for the sum. There is the necessity in some cases it is important to receive float or character or double data type. To enable a calling function to receive a noninteger value from a called function we can do the two things: 1. The explicit type specifier corresponding to the data type required must be mentioned in the function header. The general form of the function definition is

Type_specifier function_name(argument list) Argument declaration; { function statement; } The type specifier tells the compiler, the type of data the function is to return. 2. The called function must be declared at the start of the body in the calling function, like any other variable. This is to tell the calling function the type of data the function is actually returning. The program given below illustrates the transfer of a floating-point value between functions done in a multiple function program.

67

(AMITY CENTER FOR e-LEARNING)


main() { float x,y,add(); double sub(0; x=12.345; y=9.82; printf(%f\n add(x,y)); printf(%lf\nsub(x,y); } float add(a,b) float a,b; { return(a+b); } double sub(p,q) double p,q; { return(p-q); } We can notice that the functions too are declared along with the variables. These declarations clarify to the compiler that the return type of the function add is float and sub is double.
Void functions:

The functions that do not return any values can be explicitly defined as void. This prevents any accidental use of these functions in expressions.

5.7 CALL BY VALUE


In the preceding examples we have seen that whenever we called a function we have always passed the values of variables to the called function. Such function calls are called calls by
68

(AMITY CENTER FOR e-LEARNING)


value by this what it meant is that on calling a function we are passing values of variables to it. The example of call by value is shown below; sum = calsum (a, b, c); f = factr (a); In this method the value of each of the actual arguments in the calling function is copied into corresponding formal arguments of the called function. With this method the changes made to the formal arguments in the called function have no effect on the values of actual argument in the calling function. The following program illustrates this: main ( ) { int a = 10, b=20; swapy (a,b); printf ("\na = % d b = % d", a,b); } swapy (int x, int y) { int t; t = x; x = y; y = t; printf ( "\n x = % d y = % d" , x, y); } The output of the above program would be; x = 20 y = 10 a =10 b =20

5.8 CALL BY REFERENCE


In the second method the addresses of actual arguments in the calling function are copied in to formal arguments of the called function. This means that using these addresses we would have an access to the actual arguments and hence we would be able to manipulate them the following program illustrates this.
69

(AMITY CENTER FOR e-LEARNING)


main ( ) { int a = 10, b =20, swapv (&a, &b); printf ("\n a = %d b= %d", a, b); } swapr (int **, int * y) { int t; t = *x *x = *y; *y = t; } The output of the above program would be a = 20 b =10

5.9 Recursive Functions


A recursive function is one which calls itself. This is another complicated idea which you are unlikely to meet frequently. We shall provide some examples to illustrate recursive functions. Recursive functions are useful in evaluating certain types of mathematical function. You may also encounter certain dynamic data structures such as linked lists or binary trees. Recursion is a very useful way of creating and accessing these structures. Here is a recursive version of the Fibonacci function. int fib(int num) /* Fibonacci value of a number */ { switch(num) { case 0: return(0); break;
70

(AMITY CENTER FOR e-LEARNING)


case 1: return(1); break; default: /* Including recursive calls */ return(fib(num - 1) + fib(num - 2)); break; } }
We met another function earlier called power. Here is an alternative recursive version.

double power(double val, unsigned pow) { if(pow == 0) /* pow(x, 0) returns 1 */ return(1.0); else return(power(val, pow - 1) * val); } Notice that each of these definitions incorporates a test. Where an input value gives a trivial result, it is returned directly, otherwise the function calls itself, passing a changed version of the input values. Care must be taken to define functions which will not call themselves indefinitely, otherwise your program will never finish. The definition of fib is interesting, because it calls itself twice when recursion is used. Consider the effect on program performance of such a function calculating the fibonacci function of a moderate size number.

71

(AMITY CENTER FOR e-LEARNING)

If such a function is to be called many times, it is likely to have an adverse effect on program performance. Don't be frightened by the apparent complexity of recursion. Recursive functions are sometimes the simplest answer to a calculation. However there is always an alternative nonrecursive solution available too. This will normally involve the use of a loop, and may lack the elegance of the recursive solution. As the definition specifies, there are two types of recursive functions. Consider a function which calls itself: we call this type of recursion immediate recursion. One can view this mathematically in a directed call graph. A -- -| ^ | | | |---- | void A() { A(); return; } A() is a recursive function since it directly calls itself. The second part of the defintion refers to a cycle (or potential cycle if we use conditional statements) which involves other functions. Consider the following directed call graph

72

(AMITY CENTER FOR e-LEARNING)


A ---------> B ^ | | | | | |---- C <----| This can be viewed in the following three functions: void C() { A(); return; } void B() { C(); return; } void A() { B(); return; } Recursive functions are an inefficient means of solving problems in terms of run times but are interesting to study nonetheless. For our purposes we will only consider immediate recursion since this will cause enough difficulty.

Writing Recursive Functions


A recursive function has the following general form (it is simply a specification of the general function we have seen many times): ReturnType Function( Pass appropriate arguments ) { if a simple case, return the simple value // base case / stopping condition else call function with simpler version of problem } For a recursive function to stop calling itself we require some type of stopping condition. If it is not the base case, then we simplify our computation using the general formula.

73

(AMITY CENTER FOR e-LEARNING)

Chapter 6 Arrays
Contents:

6.1 Introduction 6.2 Need of an array 6.3 Declaration of Arrays 6.4 Initialization of an arrays 6.5 More operations on array 6.5.1 6.5.2 6.5.3 Create an array Printing an array Copying an array

6.6 Multidimensional Array 6.6.1 6.6.2 initialization of multidimensional array more on multidimensional array

6.1 Introduction
The C language provides a capability that enables the user to define a set of ordered data items known as an array. Alternatively, array is a collection of homogeneous element, ,homogeneous means elements of same data type .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 represents 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.

6.2 Need of an Array


To understand the need , Let's start by looking at a single variable used to store a person's age.

74

(AMITY CENTER FOR e-LEARNING)


1: #include <stdio.h> 2: 3: int main() 4: { 5: short age; 6: age=23; 7: printf("%d\n", age); 8: return 0; 9: } Not much to it. The variable age is created at line (5) as a short. A value is assigned to age. Finally, age is printed to the screen. Now let's keep track of 4 ages instead of just one. We could create 4 separate variables, but 4 separate variables have limited appeal. (If using 4 separate variables is appealing to you, then consider keeping track of 93843 ages instead of just 4). Rather than using 4 separate variables, we'll use an array. Hence the need

6.3

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 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;

75

(AMITY CENTER FOR e-LEARNING)


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 of elements 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. values[0]

values[1]

values[2]

values[3]

76

(AMITY CENTER FOR e-LEARNING)


values[4]

values[5]

values[6]

values[7]

values[8]

values[9]

The array values stored in the memory.

6.4

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.
77

(AMITY CENTER FOR e-LEARNING)

6.5 More operations on array


6.5.1 Create an Array in C Step 1 Understand that every element of an array (or any other kind of list) will be the same kind of data. For example, a list of test scores will be an array of integers, since each test score is an integer. For more complex data, you will need to define a structure. Step 2 Decide what the largest size your array can ever reach will be, because arrays have a fixed length. You'll want to strike a balance between having your program able to handle unusually long data sets, and having it require (and waste) a lot of memory. Step 3 Create the array the same way you would create a single variable, but add the maximum size in square brackets after the name, as in these examples: int test_scores[50]; char first_name[20]; employee_record employees[1000]; Step 4 Create a second variable that keeps track of how many elements you've added to the array so far. Step 5 Create an array with multiple dimensions simply making an array of arrays, like this: int test_answers[10][20]; char student_names[50][20]; Use the Array Step 7 Access the array's elements using the index in square brackets, like this: test_scores[12] = 50; printf("Test score: %d\n", test_scores[i]);

78

(AMITY CENTER FOR e-LEARNING)


Step 8 Pass arrays to functions, if you so choose. You don't need to (and should not) specify the size in the function definition. This is what the function definition and call would look like: function subtotal(int test_scores[]); test_subtotal = subtotal(test_scores); 6.5.2 Printing arrays Here is the same program with an attempt to print the array to the screen: 1: #include <stdio.h> 2: 3: int main() 4: { 5: short age[4]; 6: age[0]=23; 7: age[1]=34; 8: age[2]=65; 9: age[3]=74; 10: 11: printf("%x\n", age); 12: return 0; 13: } Line (11) is meant to print the 4 ages to the screen. But instead of printing out the four short variables, what appears to be nonsense prints out instead. The important point to come away with is that simply providing the name of the array in an output statement will not print out the elements of the array. How about printing out each of the values separately? Try this: 1: #include <stdio.h> 2:
79

(AMITY CENTER FOR e-LEARNING)


3: int main() 4: { 5: short age[4]; 6: age[0]=23; 7: age[1]=34; 8: age[2]=65; 9: age[3]=74; 10: printf("%d\n", age[0]); 11: printf("%d\n", age[1]); 12: printf("%d\n", age[2]); 13: printf("%d\n", age[3]); 14: return 0; 15: } Lines (10) through line (13) produce the output we are expecting. There is no single statement in the language that says "print an entire array to the screen". Each element in the array must be printed to the screen individually. 6.5.3 Copying arrays Suppose that after filling our 4 element array with values, we need to copy that array to another array of 4 short's? Try this:

1: #include <stdio.h> 2: 3: int main() 4: { 5: short age[4]; 6: short same_age[4];

80

(AMITY CENTER FOR e-LEARNING)


7: age[0]=23; 8: age[1]=34; 9: age[2]=65; 10: age[3]=74; 11: 12: same_age=age; 13: 14: printf("%d\n", same_age[0]); 15: printf("%d\n", same_age[1]); 16: printf("%d\n", same_age[2]); 17: printf("%d\n", same_age[3]); 18: return 0; 19: } Line (12) tries to copy the age array into the same_age array. What happened when you tried to compile the program above? Let's try copying arrays using a technique similar to the technique used to print arrays (that is, one element at a time): 1: #include <stdio.h> 2: 3: int main() 4: { 5: short age[4]; 6: short same_age[4]; 7: 8: age[0]=23; 9: age[1]=34; 10: age[2]=65; 11: age[3]=74; 12:
81

(AMITY CENTER FOR e-LEARNING)


13: same_age[0]=age[0]; 14: same_age[1]=age[1]; 15: same_age[2]=age[2]; 16: same_age[3]=age[3]; 17: 18: printf("%d\n", same_age[0]); 19: printf("%d\n", same_age[1]); 20: printf("%d\n", same_age[2]); 21: printf("%d\n", same_age[3]); 22: return 0; 23: } This technique for copying arrays works fine. Two arrays are created: age and same_age. Each element of the age array is assigned a value. Then, in order to copy of the four elements in age into the same_age array, we must do it element by element. Like printing arrays, there is no single statement in the language that says "copy an entire array into another array". The array elements must be copied individually. The technique used to copy one array into another is exactly the same as the technique used to copy 4 separate variables into 4 other variables. So what is the advantage to using arrays over separate variables? One significant advantage of an array over separate variables is the name. In our examples, using four separate variables requires 4 unique names. The 4 short variables in our array have the same name, age. The 4 short's in the array are identical except for an index number used to access them. This distinction allows us to shorten our code in a way that would be impossible with 4 variables, each with unique names: 1: #include <stdio.h> 2: 3: int main() 4: { 5: short age[4]; 6: short same_age[4]; 7: int i, j;
82

(AMITY CENTER FOR e-LEARNING)


8: age[0]=23; 9: age[1]=34; 10: age[2]=65; 11: age[3]=74; 12: 13: for(i=0; i<4; i++) 14: 15: 16: for(j=0; j<4; j++) 17: printf("%d\n", same_age[j]); same_age[i]=age[i];

18: return 0; 19: }

Since the only difference between each of the short's in the arrays is their index, a loop and a counter can be used to more easily copy all of the elements. The same technique is used to shorten the code that prints the array to the screen. Even though arrays give us some convenience when managing many variables of the same type, there is little difference between an array and variables declared individually. There is no single statement to copy an array, there is no single statement to print an array. If we want to perform any action on an array, we must repeatedly perform that action on each element in the array.

6.6 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]

83

(AMITY CENTER FOR e-LEARNING)


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] Marks [0][2] 35.5 40.5 45.5

marks [1][0] Marks [1][1] Marks [1][2] 50.5 55.5 60.5

marks [2][0] Marks [2][1] Marks [2][2]

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

6.6.1 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,01,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:
84

(AMITY CENTER FOR e-LEARNING)


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 matrix\n); scanf(%d%d,&p,&q); if(m==p && n==q) { printf(matrix can be added\n); 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); for(i=0;i < m;i++) for(j=0;j < n;j++)

85

(AMITY CENTER FOR e-LEARNING)


c[i][j]=a[i][j]+b[i][j]; for(i=0;i < m;i++) { for(j=0;j < n;j++) printf(%d\t,&a[i][j]); printf(\n); } }

6.6.2 More on Multi-Dimensional Arrays


consider #define ROWS 5 #define COLS 10 int multi[ROWS][COLS]; we can access individual elements of the array multi using either: multi[row][col] or *(*(multi + row) + col) To understand more fully what is going on, let us replace *(multi + row) with X as in: *(X + col) Now, from this we see that X is like a pointer since the expression is de-referenced and we know that col is an integer. Here the arithmetic being used is of a special kind called "pointer arithmetic" is being used. That means that, since we are talking about an integer array, the address pointed to by (i.e. value of) X + col + 1 must be greater than the address X + col by and amount equal to sizeof(int). Since we know the memory layout for 2 dimensional arrays, we can determine that in the expression multi + row as used above, multi + row + 1 must increase by value an amount equal to that needed to "point to" the next row, which in this case would be an
86

(AMITY CENTER FOR e-LEARNING)


amount equal to COLS * sizeof(int). That says that if the expression *(*(multi + row) + col) is to be evaluated correctly at run time, the compiler must generate code which takes into consideration the value of COLS, i.e. the 2nd dimension. Because of the equivalence of the two forms of expression, this is true whether we are using the pointer expression as here or the array expression multi[row][col]. Thus, to evaluate either expression, a total of 5 values must be known: 1. The address of the first element of the array, which is returned by the expression multi, i.e., the name of the array. 2. The size of the type of the elements of the array, in this case sizeof(int). 3. The 2nd dimension of the array 4. The specific index value for the first dimension, row in this case. 5. The specific index value for the second dimension, col in this case. Given all of that, consider the problem of designing a function to manipulate the element values of a previously declared array. For example, one which would set all the elements of the array multi to the value 1.

void set_value(int m_array[][COLS]) { int row, col; for (row = 0; row < ROWS; row++) { for (col = 0; col < COLS; col++) { m_array[row][col] = 1; } } }

And to call this function we would then use:


87

(AMITY CENTER FOR e-LEARNING)


set_value(multi); Now, within the function we have used the values #defined by ROWS and COLS that set the limits on the for loops. But, these #defines are just constants as far as the compiler is concerned, i.e. there is nothing to connect them to the array size within the function. row and col are local variables, of course. The formal parameter definition permits the compiler to determine the characteristics associated with the pointer value that will be passed at run time. We really dont need the first dimension and, as will be seen later, there are occasions where we would prefer not to define it within the parameter definition, out of habit or consistency, I have not used it here. But, the second dimension must be used as has been shown in the expression for the parameter. The reason is that we need this in the evaluation of m_array[row][col] as has been described. While the parameter defines the data type (int in this case) and the automatic variables for row and column are defined in the for loops, only one value can be passed using a single parameter. In this case, that is the value of multi as noted in the call statement, i.e. the address of the first element, often referred to as a pointer to the array. Thus, the only way we have of informing the compiler of the 2nd dimension is by explicitly including it in the parameter definition. In fact, in general all dimensions of higher order than one are needed when dealing with multidimensional arrays. That is if we are talking about 3 dimensional arrays, the 2nd and 3rd dimension must be specified in the parameter definition.

88

(AMITY CENTER FOR e-LEARNING)

Chapter 7 Pointers
Contents: 7.1 Introduction 7.2 Pointer types and Arrays 7.3 Pointers and Strings 7.4 Pointers to Arrays 7.5 Dynamic Allocation of Memory

7.1 introduction
One of those things beginners in C find difficult is the concept of pointers. The purpose of this chapter is to provide an introduction to pointers and their use to these beginners. I have found that often the main reason beginners have a problem with pointers is that they have a weak or minimal feeling for variables, (as they are used in C). Thus we start with a discussion of C variables in general.A variable in a program is something with a name, the value of which can vary. The way the compiler and linker handles this is that it assigns a specific block of memory within the computer to hold the value of that variable. The size of that block depends on the range over which the variable is allowed to vary. For example, on 32 bit PC's the size of an integer variable is 4 bytes. On older 16 bit PCs integers were 2 bytes. In C the size of a variable type such as an integer need not be the same on all types of machines. Further more there is more than one type of integer variable in C. We have integers, long integers and short integers which you can read up on in any basic text on C. This document assumes the use of a 32 bit system with 4 byte integers. If you want to know the size of the various types of integers on your system, running the following code will give you that information. #include <stdio.h>
89

(AMITY CENTER FOR e-LEARNING)


int main() { printf("size of a short is %d\n", sizeof(short)); printf("size of a int is %d\n", sizeof(int)); printf("size of a long is %d\n", sizeof(long)); } When we declare a variable we inform the compiler of two things, the name of the variable and the type of the variable. For example, we declare a variable of type integer with the name k by writing:
int k;

On seeing the "int" part of this statement the compiler sets aside 4 bytes of memory (on a PC) to hold the value of the integer. It also sets up a symbol table. In that table it adds the symbol k and the relative address in memory where those 4 bytes were set aside. Thus, later if we write:
k = 2;

we expect that, at run time when this statement is executed, the value 2 will be placed in that memory location reserved for the storage of the value of k. In C we refer to a variable such as the integer k as an "object". In a sense there are two "values" associated with the object k. One is the value of the integer stored there (2 in the above example) and the other the "value" of the memory location, i.e., the address of k. Some texts refer to these two values with the nomenclature rvalue (right value, pronounced "are value") and lvalue (left value, pronounced "el value") respectively. In some languages, the lvalue is the value permitted on the left side of the assignment operator '=' (i.e. the address where the result of evaluation of the right side ends up). The rvalue is that which is on the right side of the assignment statement, the 2 above. Rvalues cannot be used on the left side of the assignment statement. Thus: 2 = k; is illegal. Actually, the above definition of "lvalue" is somewhat modified for C. According to K&R II "An object is a named region of storage; an lvalue is an expression referring to an object."
90

(AMITY CENTER FOR e-LEARNING)


However, at this point, the definition originally cited above is sufficient. As we become more familiar with pointers we will go into more detail on this. Okay, now consider:
int j, k; k = 2; j = 7; k = j; <-- line 1 <-- line 2

In the above, the compiler interprets the j in line 1 as the address of the variable j (its lvalue) and creates code to copy the value 7 to that address. In line 2, however, the j is interpreted as its rvalue (since it is on the right hand side of the assignment operator '='). That is, here the j refers to the value stored at the memory location set aside for j, in this case 7. So, the 7 is copied to the address designated by the lvalue of k. In all of these examples, we are using 4 byte integers so all copying of rvalues from one storage location to the other is done by copying 4 bytes. Had we been using two byte integers, we would be copying 2 bytes. Now, let's say that we have a reason for wanting a variable designed to hold an lvalue (an address). The size required to hold such a value depends on the system. On older desk top computers with 64K of memory total, the address of any point in memory can be contained in 2 bytes. Computers with more memory would require more bytes to hold an address. The actual size required is not too important so long as we have a way of informing the compiler that what we want to store is an address. Such a variable is called a pointer variable (for reasons which hopefully will become clearer a little later). In C when we define a pointer variable we do so by preceding its name with an asterisk. In C we also give our pointer a type which, in this case, refers to the type of data stored at the address we will be storing in our pointer. For example, consider the variable declaration:
int *ptr;

ptr is the name of our variable (just as k was the name of our integer variable). The '*' informs the compiler that we want a pointer variable, i.e. to set aside however many bytes is required to store an address in memory. The int says that we intend to use our pointer variable to store the
91

(AMITY CENTER FOR e-LEARNING)


address of an integer. Such a pointer is said to "point to" an integer. However, note that when we wrote int k; we did not give k a value. If this definition is made outside of any function ANSI compliant compilers will initialize it to zero. Similarly, ptr has no value, that is we haven't stored an address in it in the above declaration. In this case, again if the declaration is outside of any function, it is initialized to a value guaranteed in such a way that it is guaranteed to not point to any C object or function. A pointer initialized in this manner is called a "null" pointer. The actual bit pattern used for a null pointer may or may not evaluate to zero since it depends on the specific system on which the code is developed. To make the source code compatible between various compilers on various systems, a macro is used to represent a null pointer. That macro goes under the name NULL. Thus, setting the value of a pointer using the NULL macro, as with an assignment statement such as ptr = NULL, guarantees that the pointer has become a null pointer. Similarly, just as one can test for an integer value of zero, as in if(k == 0), we can test for a null pointer using if (ptr == NULL). But, back to using our new variable ptr. Suppose now that we want to store in ptr the address of our integer variable k. To do this we use the unary & operator and write: ptr = &k; What the & operator does is retrieve the lvalue (address) of k, even though k is on the right hand side of the assignment operator '=', and copies that to the contents of our pointer ptr. Now, ptr is said to "point to" k. Bear with us now, there is only one more operator we need to discuss. The "dereferencing operator" is the asterisk and it is used as follows: *ptr = 7; will copy 7 to the address pointed to by ptr. Thus if ptr "points to" (contains the address of) k, the above statement will set the value of k to 7. That is, when we use the '*' this way we are referring to the value of that which ptr is pointing to, not the value of the pointer itself. Similarly, we could write: printf("%d\n",*ptr); to print to the screen the integer value stored at the address pointed to by ptr;.

92

(AMITY CENTER FOR e-LEARNING)


One way to see how all this stuff fits together would be to run the following program and then review the code and the output carefully. #include <stdio.h> int j, k; int *ptr; int main(void) { j = 1; k = 2; ptr = &k; printf("\n"); printf("j has the value %d and is stored at %p\n", j, (void *)&j); printf("k has the value %d and is stored at %p\n", k, (void *)&k); printf("ptr has the value %p and is stored at %p\n", ptr, (void *)&ptr); printf("The value of the integer pointed to by ptr is %d\n", *ptr); return 0; }

7.2 Pointer types and Arrays


Okay, let's move on. Let us consider why we need to identify the type of variable that a pointer points to, as in: int *ptr; One reason for doing this is so that later, once ptr "points to" something, if we write: *ptr = 2; the compiler will know how many bytes to copy into that memory location pointed to by ptr. If ptr was declared as pointing to an integer, 4 bytes would be copied. Similarly for floats and doubles the appropriate number will be copied. But, defining the type that the pointer points to permits a number of other interesting ways a compiler can interpret code. For example, consider a block in memory consisting if ten integers in a row. That is, 40 bytes of memory are set aside
93

(AMITY CENTER FOR e-LEARNING)


to hold 10 integers. Now, let's say we point our integer pointer ptr at the first of these integers. Furthermore lets say that integer is located at memory location 100 (decimal). What happens when we write: ptr + 1; Because the compiler "knows" this is a pointer (i.e. its value is an address) and that it points to an integer (its current address, 100, is the address of an integer), it adds 4 to ptr instead of 1, so the pointer "points to" the next integer, at memory location 104. Similarly, were the ptr declared as a pointer to a short, it would add 2 to it instead of 1. The same goes for other data types such as floats, doubles, or even user defined data types such as structures. This is obviously not the same kind of "addition" that we normally think of. In C it is referred to as addition using "pointer arithmetic", a term which we will come back to later. Similarly, since ++ptr and ptr++ are both equivalent to ptr + 1 (though the point in the program when ptr is incremented may be different), incrementing a pointer using the unary ++ operator, either pre- or post-, increments the address it stores by the amount sizeof(type) where "type" is the type of the object pointed to. (i.e. 4 for an integer). Since a block of 10 integers located contiguously in memory is, by definition, an array of integers, this brings up an interesting relationship between arrays and pointers. Consider the following: int my_array[] = {1,23,17,4,-5,100}; Here we have an array containing 6 integers. We refer to each of these integers by means of a subscript to my_array, i.e. using my_array[0] through my_array[5]. But, we could alternatively access them via a pointer as follows: int *ptr; ptr = &my_array[0];

/* point our pointer at the first integer in our array */

And then we could print out our array either using the array notation or by dereferencing our pointer. The following code illustrates this:

94

(AMITY CENTER FOR e-LEARNING)


#include <stdio.h>

int my_array[] = {1,23,17,4,-5,100}; int *ptr; int main(void) { int i; ptr = &my_array[0]; printf("\n\n"); for (i = 0; i < 6; i++) { printf("my_array[%d] = %d ",i,my_array[i]); /*<-- A */ printf("ptr + %d = %d\n",i, *(ptr + i)); } return 0; } Compile and run the above program and carefully note lines A and B and that the program prints out the same values in either case. Also observe how we dereferenced our pointer in line B, i.e. we first added i to it and then dereferenced the new pointer. Change line B to read: printf("ptr + %d = %d\n",i, *ptr++); and run it again... then change it to: printf("ptr + %d = %d\n",i, *(++ptr)); and try once more. Each time try and predict the outcome and carefully look at the actual outcome. In C, the standard states that wherever we might use &var_name[0] we can replace that with var_name, thus in our code where we wrote: ptr = &my_array[0]; we can write:
95

/* point our pointer to the first element of the array */

/*<-- B */

(AMITY CENTER FOR e-LEARNING)


ptr = my_array; to achieve the same result. This leads many texts to state that the name of an array is a pointer. I prefer to mentally think "the name of the array is the address of first element in the array". Many beginners (including myself when I was learning) have a tendency to become confused by thinking of it as a pointer. For example, while we can write ptr = my_array; we cannot write my_array = ptr; The reason is that while ptr is a variable, my_array is a constant. That is, the location at which the first element of my_array will be stored cannot be changed once my_array[] has been declared. Earlier when discussing the term "lvalue" I cited K&R-2 where it stated: "An object is a named region of storage; an lvalue is an expression referring to an object". This raises an interesting problem. Since my_array is a named region of storage, why is my_array in the above assignment statement not an lvalue? To resolve this problem, some refer to my_array as an "unmodifiable lvalue". Modify the example program above by changing ptr = &my_array[0]; to ptr = my_array; and run it again to verify the results are identical. Now, let's delve a little further into the difference between the names ptr and my_array as used above. Some writers will refer to an array's name as a constant pointer. What do we mean by that? Well, to understand the term "constant" in this sense, let's go back to our definition of the term "variable". When we declare a variable we set aside a spot in memory to hold the value of the appropriate type. Once that is done the name of the variable can be interpreted in one of two ways. When used on the left side of the assignment operator, the compiler interprets it as the
96

(AMITY CENTER FOR e-LEARNING)


memory location to which to move that value resulting from evaluation of the right side of the assignment operator. But, when used on the right side of the assignment operator, the name of a variable is interpreted to mean the contents stored at that memory address set aside to hold the value of that variable. With that in mind, let's now consider the simplest of constants, as in: int i, k; i = 2; Here, while i is a variable and then occupies space in the data portion of memory, 2 is a constant and, as such, instead of setting aside memory in the data segment, it is imbedded directly in the code segment of memory. That is, while writing something like k = i; tells the compiler to create code which at run time will look at memory location &i to determine the value to be moved to k, code created by i = 2; simply puts the 2 in the code and there is no referencing of the data segment. That is, both k and i are objects, but 2 is not an object. Similarly, in the above, since my_array is a constant, once the compiler establishes where the array itself is to be stored, it "knows" the address of my_array[0] and on seeing:
ptr = my_array;

it simply uses this address as a constant in the code segment and there is no referencing of the data segment beyond that.

7.3 Pointers and Strings


The study of strings is useful to further tie in the relationship between pointers and arrays. It also makes it easy to illustrate how some of the standard C string functions can be implemented. Finally it illustrates how and when pointers can and should be passed to functions. In C, strings are arrays of characters. This is not necessarily true in other languages. In BASIC, Pascal, Fortran and various other languages, a string has its own data type. But in C it does not. In C a string is an array of characters terminated with a binary zero character (written as '\0'). To start off our discussion we will write some code which, while preferred for illustrative purposes, you would probably never write in an actual program. Consider, for example:

97

(AMITY CENTER FOR e-LEARNING)


char my_string[40]; my_string[0] = 'T'; my_string[1] = 'e'; my_string[2] = 'd': my_string[3] = '\0'; While one would never build a string like this, the end result is a string in that it is an array of characters terminated with a nul character. By definition, in C, a string is an array of characters terminated with the nul character. Be aware that "nul" is not the same as "NULL". The nul refers to a zero as defined by the escape sequence '\0'. That is it occupies one byte of memory. NULL, on the other hand, is the name of the macro used to initialize null pointers. NULL is #defined in a header file in your C compiler, nul may not be #defined at all. Since writing the above code would be very time consuming, C permits two alternate ways of achieving the same thing. First, one might write: char my_string[40] = {'T', 'e', 'd', '\0',}; But this also takes more typing than is convenient. So, C permits:
char my_string[40] = "Ted";

When the double quotes are used, instead of the single quotes as was done in the previous #include <stdio.h>

char strA[80] = "A string to be used for demonstration purposes"; char strB[80];

int main(void) { char *pA; char *pB; /* a pointer to type character */ /* another pointer to type character */

puts(strA); /* show string A */ pA = strA; puts(pA); /* point pA at string A */ /* show what pA is pointing to */
98

(AMITY CENTER FOR e-LEARNING)


pB = strB; putchar('\n'); /* point pB at string B */ /* move down one line on the screen */

while(*pA != '\0') /* line A (see text) */ { *pB++ = *pA++; /* line B (see text) */ } *pB = '\0'; puts(strB); return 0; } In the above we start out by defining two character arrays of 80 characters each. Since these are globally defined, they are initialized to all '\0's first. Then, strA has the first 42 characters initialized to the string in quotes. Now, moving into the code, we declare two character pointers and show the string on the screen. We then "point" the pointer pA at strA. That is, by means of the assignment statement we copy the address of strA[0] into our variable pA. We now use puts() to show that which is pointed to by pA on the screen. Consider here that the function prototype for puts() is: int puts(const char *s); For the moment, ignore the const. The parameter passed to puts() is a pointer, that is the value of a pointer (since all parameters in C are passed by value), and the value of a pointer is the address to which it points, or, simply, an address. Thus when we write puts(strA); as we have seen, we are passing the address of strA[0]. Similarly, when we write puts(pA); we are passing the same address, since we have set pA = strA; Given that, follow the code down to the while() statement on line A. Line A states: While the character pointed to by pA (i.e. *pA) is not a nul character (i.e. the terminating '\0'), do the following: Line B states: copy the character pointed to by pA to the space pointed to by pB, then increment pA so it points to the next character and pB so it points to the next space. /* line C (see text) */ /* show strB on screen */

99

(AMITY CENTER FOR e-LEARNING)


When we have copied the last character, pA now points to the terminating nul character and the loop ends. However, we have not copied the nul character. And, by definition a string in C must be nul terminated. So, we add the nul character with line C. It is very educational to run this program with your debugger while watching strA, strB, pA and pB and single stepping through the program. It is even more educational if instead of simply defining strB[] as has been done above, initialize it also with something like: strB[80] = "12345678901234567890123456789012345678901234567890" where the number of digits used is greater than the length of strA and then repeat the single stepping procedure while watching the above variables. Give these things a try! Getting back to the prototype for puts() for a moment, the "const" used as a parameter modifier informs the user that the function will not modify the string pointed to by s, i.e. it will treat that string as a constant. Of course, what the above program illustrates is a simple way of copying a string. After playing with the above until you have a good understanding of what is happening, we can proceed to creating our own replacement for the standard strcpy() that comes with C. It might look like: char *my_strcpy(char *destination, char *source) { char *p = destination; while (*source != '\0') { *p++ = *source++; } *p = '\0'; return destination; }

100

(AMITY CENTER FOR e-LEARNING)


In this case, I have followed the practice used in the standard routine of returning a pointer to the destination. Again, the function is designed to accept the values of two character pointers, i.e. addresses, and thus in the previous program we could write: int main(void) { my_strcpy(strB, strA); puts(strB); } I have deviated slightly from the form used in standard C which would have the prototype: char *my_strcpy(char *destination, const char *source); Here the "const" modifier is used to assure the user that the function will not modify the contents pointed to by the source pointer. You can prove this by modifying the function above, and its prototype, to include the "const" modifier as shown. Then, within the function you can add a statement which attempts to change the contents of that which is pointed to by source, such as: *source = 'X'; which would normally change the first character of the string to an X. The const modifier should cause your compiler to catch this as an error. Try it and see. Now, let's consider some of the things the above examples have shown us. First off, consider the fact that *ptr++ is to be interpreted as returning the value pointed to by ptr and then incrementing the pointer value. This has to do with the precedence of the operators. Were we to write (*ptr)++ we would increment, not the pointer, but that which the pointer points to! i.e. if used on the first character of the above example string the 'T' would be incremented to a 'U'. You can write some simple example code to illustrate this. Recall again that a string is nothing more than an array of characters, with the last character being a '\0'. What we have done above is deal with copying an array. It happens to be an array of characters but the technique could be applied to an array of integers, doubles, etc. In those cases, however, we would not be dealing with strings and hence the end of the array would not be marked with a special value like the nul
101

(AMITY CENTER FOR e-LEARNING)


character. We could implement a version that relied on a special value to identify the end. For example, we could copy an array of positive integers by marking the end with a negative integer. On the other hand, it is more usual that when we write a function to copy an array of items other than strings we pass the function the number of items to be copied as well as the address of the array, e.g. something like the following prototype might indicate: void int_copy(int *ptrA, int *ptrB, int nbr); where nbr is the number of integers to be copied. You might want to play with this idea and create an array of integers and see if you can write the function int_copy() and make it work. This permits using functions to manipulate large arrays. For example, if we have an array of 5000 integers that we want to manipulate with a function, we need only pass to that function the address of the array (and any auxiliary information such as nbr above, depending on what we are doing). The array itself does not get passed, i.e. the whole array is not copied and put on the stack before calling the function, only its address is sent. This is different from passing, say an integer, to a function. When we pass an integer we make a copy of the integer, i.e. get its value and put it on the stack. Within the function any manipulation of the value passed can in no way effect the original integer. But, with arrays and pointers we can pass the address of the variable and hence manipulate the values of the original variables.

7.4 Pointers to Arrays


Pointers, of course, can be "pointed at" any type of data object, including arrays. While that was evident when we discussed program 3.1, it is important to expand on how we do this when it comes to multi-dimensional arrays. To review, that given an array of integers we could point an
integer pointer at that array using:

int *ptr; ptr = &my_array[0]; /* point our pointer at the first integer in our array */

As we stated there, the type of the pointer variable must match the type of the first element of the array. In addition, we can use a pointer as a formal parameter of a function which is designed to manipulate an array. e.g.
102

(AMITY CENTER FOR e-LEARNING)


Given: int array[3] = {1, 5, 7}; void a_func(int *p); Some programmers might prefer to write the function prototype as: void a_func(int p[]); which would tend to inform others who might use this function that the function is designed to manipulate the elements of an array. Of course, in either case, what actually gets passed is the value of a pointer to the first element of the array, independent of which notation is used in the function prototype or definition. Note that if the array notation is used, there is no need to pass the actual dimension of the array since we are not passing the whole array, only the address to the first element. We now turn to the problem of the 2 dimensional array. As stated in the last chapter, C interprets a 2 dimensional array as an array of one dimensional arrays. That being the case, the first element of a 2 dimensional array of integers is a one dimensional array of integers. And a pointer to a two dimensional array of integers must be a pointer to that data type. One way of accomplishing this is through the use of the keyword "typedef". typedef assigns a new name to a specified data type. For example: typedef unsigned char byte; causes the name byte to mean type unsigned char. Hence byte b[10]; would be an array of unsigned characters. Note that in the typedef declaration, the word byte has replaced that which would normally be the name of our unsigned char. That is, the rule for using typedef is that the new name for the data type is the name used in the definition of the data type. Thus in: typedef int Array[10]; Array becomes a data type for an array of 10 integers. i.e. Array my_arr; declares my_arr as an array of 10 integers and Array arr2d[5]; makes arr2d an array of 5 arrays of 10 integers each. Also note that Array *p1d; makes p1d a pointer to an array of 10 integers. Because *p1d points to the same type as arr2d, assigning the address of the two dimensional array arr2d to p1d, the

103

(AMITY CENTER FOR e-LEARNING)


pointer to a one dimensional array of 10 integers is acceptable. i.e. p1d = &arr2d[0]; or p1d = arr2d; are both correct. Since the data type we use for our pointer is an array of 10 integers we would expect that incrementing p1d by 1 would change its value by 10*sizeof(int), which it does. That is, sizeof(*p1d) is 20. You can prove this to yourself by writing and running a simple short program. Now, while using typedef makes things clearer for the reader and easier on the programmer, it is not really necessary. What we need is a way of declaring a pointer like p1d without the need of the typedef keyword. It turns out that this can be done and that int (*p1d)[10]; is the proper declaration, i.e. p1d here is a pointer to an array of 10 integers just as it was under the declaration using the Array type. Note that this is different from int *p1d[10]; which would make p1d the name of an array of 10 pointers to type int.

7.5 Dynamic Allocation of Memory


There are times when it is convenient to allocate memory at run time using malloc(), calloc(), or other allocation functions. Using this approach permits postponing the decision on the size of the memory block need to store an array, for example, until run time. Or it permits using a section of memory for the storage of an array of integers at one point in time, and then when that memory is no longer needed it can be freed up for other uses, such as the storage of an array of structures.
When memory is allocated, the allocating function (such as malloc(), calloc(), etc.) returns a pointer. The type of this pointer depends on whether you are using an older K&R compiler or the newer ANSI type compiler. With the older compiler the type of the returned pointer is char, with the ANSI compiler it is void.

104

(AMITY CENTER FOR e-LEARNING)


If you are using an older compiler, and you want to allocate memory for an array of integers you will have to cast the char pointer returned to an integer pointer. For example, to allocate space for 10 integers we might write: int *iptr; iptr = (int *)malloc(10 * sizeof(int)); if (iptr == NULL) { .. ERROR ROUTINE GOES HERE .. } If you are using an ANSI compliant compiler, malloc() returns a void pointer and since a void pointer can be assigned to a pointer variable of any object type, the (int *) cast shown above is not needed. The array dimension can be determined at run time and is not needed at compile time. That is, the 10 above could be a variable read in from a data file or keyboard, or calculated based on some need, at run time. Because of the equivalence between array and pointer notation, once iptr has been assigned as above, one can use the array notation. For example, one could write: int k; for (k = 0; k < 10; k++) iptr[k] = 2;
to set the values of all elements to 2.

Even with a reasonably good understanding of pointers and arrays, one place the newcomer to C is likely to stumble at first is in the dynamic allocation of multi-dimensional arrays. In general, we would like to be able to access elements of such arrays using array notation, not pointer notation, wherever possible. Depending on the application we may or may not know both dimensions at compile time. This leads to a variety of ways to go about our task. As we have seen, when dynamically allocating a one dimensional array its dimension can be determined at run time. Now, when using dynamic allocation of higher order arrays, we never need to know the first dimension at compile time. Whether we need to know the higher dimensions depends on how we go about writing the code. Here I will discuss various methods of dynamically allocating room for 2 dimensional arrays of integers.

105

(AMITY CENTER FOR e-LEARNING)

Chapter 8 Structures and Union


Contents:

8.1 What is structure? 8.2 Functions and Structures


8.2.1 8.2.2 8.2.3

Passing structure to elements to functions Passing entire function to functions Arrays of structure

8.3 Union
8.4 More on structures and Union

8.1 What is a Structure?


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. A structure is a convenient method of handling a group of related data items of different data types. We can summarize structure as

Structure is a method of packing the data of different types. When we require using a collection of different data items of different data types in that situation we can use a structure.
A structure is used as a method of handling a group of related data items of different data types.

Syntax of Using Structure


structure definition: general format:

struct tag_name {
106

(AMITY CENTER FOR e-LEARNING)


data type member1; data type member2; } Example of Using Structure:

struct lib_books { char title[20]; char author[15]; int pages; float price; }; To holds the details of four fields namely title, author pages and price,the keyword struct declares a structure. These are the members of the structures. Each member may belong to same or different data type. The tag name can be used to define the 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 the structure variables using the tag name any where in the program. For example the statement, struct lib_books book1, book2, book3; declares the 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 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;

8.2 Functions and structures


107

(AMITY CENTER FOR e-LEARNING)


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.
8.4.1

Passing structure to elements to functions

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; { 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

108

(AMITY CENTER FOR e-LEARNING)


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.

8.2.2 Passing entire function 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*/


109

(AMITY CENTER FOR e-LEARNING)


display(empf) struct employee empf { printf(%d%s,%s,%f, empf.empid,empf.name,empf.department,empf.salary); }

8.2.3 Arrays 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 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. Remember that each element is a structure that must be assigned corresponding initial values as illustrated below. #include< stdio.h > { struct info { int id_no;
110

(AMITY CENTER FOR e-LEARNING)


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].combination,&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); }

8.2.4 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; int year; }; struct student {
111

(AMITY CENTER FOR e-LEARNING)


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.
Important points about a structure

1)A structure allocates the total size of all elements in it. 2) Members inside a structure are always stored in separate memory locations throughout the lifetime and scope of the entire structure. Manipulations of one member will not affect the values of any of the others in any way unless they are operated on in code to do so.

8.3 Union
However the members that we compose a union all share the same storage area within the computers memory where as each member within a structure is assigned its own unique storage area. Thus unions are used to observe memory. They are useful for the application involving multiple members. Where values need not be assigned to all the members at any time. Unions like structure contain members whose individual data types may differ from one another also. Like structures union can be declared using the keyword union as follows: union item { int m; float p; char c; } code

112

(AMITY CENTER FOR e-LEARNING)


The notation for accessing a union member that is nested inside a structure remains the same as for the nested structure.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 to a new value the new value supercedes the previous members value. Unions may be used in all the places where a structure is allowed. Important points about a union: 1) A union only allocates as much memory as its largest element (member) requires. 2) The union will store one and only one actual value for one element at a time. If another element is stored before the first is retrieved, the first stored value is lost. This presents the programmer with extra responsibility when using a union to determine that the logic will properly store all values used in the union through a correct lifetime and scope.

8.4 More on Structures and Union


The difference between structure and union: 1. union allocates the memory equal to the maximum memory required by the member of the union but structure allocates the memory equal to the total memory required by the members. 2. In union, one block is used by all the member of the union but in case of structure, each member have their own memory space

Similarities between structure and union: 1) They both can accept the dot (.) operator to address a member from the object name, as struct.member or union.member. 2) They both use brace delimited declarations to create the template for the data object. Both accept tagname and name as well as explicit initialization as options. 3) They both can have their size correctly determined as maximum size in bytes by use of the sizeof() operator.

An example program is shown below. I hope it helps you understand. #include <stdio.h> #include <stdlib.h> /* Declares union */
113

(AMITY CENTER FOR e-LEARNING)


union one{ char one; int two; float three; };

/* Declares structure */ struct two{ char one; int two; float three; };

int main(void) { /* Uses tag names to create structure S and union U. */ struct two S; union one U;

/* Outputs object sizes to screen. */ printf("%d is the size of S, as structure.\n", sizeof(S)); printf("%d is the size of U, as union.\n\n", sizeof(U)); /* Loads values into S and U, as below. */ S.one = 'A'; S.two = 3645; S.three = 678.32; U.one = 'A'; U.two = 3645; U.three = 678.32;

114

(AMITY CENTER FOR e-LEARNING)

Chapter 9 Data Files


Contents:

9.1 Introduction 9.2 File Types 9.2.1 Text streams 9.2.2 Binary streams 9.3 Stdio.h header file 9.4 Oprations on file 9.4.1 Opening named files 9.4.2 Reading from a stream using fgetc 9.4.3 Writing to a stream using fputc 9.4.4 Closing files

9.1 Introduction
One of the reasons that has prevented many programming languages from becoming widely used for real programming is their poor support for I/O, a subject which has never seemed to excite language designers. C has avoided this problem, oddly enough, by having no I/O at all! The C language approach has always been to do I/O using library functions, which ensures that system designers can provide tailored I/O instead of being forced to change the language itself.As C has evolved, a library package known as the Standard I/O Library or stdio, has evolved with it and has proved to be both flexible and portable. This package has now become part of the Standard We frequently use files for storing information which can be processed by our programs. In order to store information permanently and retrieve it we need to use files Files are not only used for data. Our programs are also stored in files.The editor which you use to enter your program and save it, simply manipulate files for you.
115

(AMITY CENTER FOR e-LEARNING)

9.2 File Types


There are two types of file, text files and binary files, which, within a program, are manipulated as text streams and binary streams once they have been opened for I/O. The stdio package does not permit operations on the contents of files directly, but only by viewing them as streams.

9.2.1 Text streams


The Standard specifies what is meant by the term text stream, which essentially considers a file to contain lines of text. A line is a sequence of zero or more characters terminated by a newline character. It is quite possible that the actual representation of lines in the external environment is different from this and there may be transformations of the data stream on the way in and out of the program; a common requirement is to translate the \n line-terminator into the sequence \r\n on output, and do the reverse on input. Other translations may also be necessary. Data read in from a text stream is guaranteed to compare equal to the data that was earlier written out to the file if the data consists only of complete lines of printable characters and the control characters horizontal-tab and newline, no newline character is immediately preceded by space characters and the last character is a newline.It is guaranteed that, if the last character written to a text file is a newline, it will read back as the same. It is implementation defined whether the last line written to a text file must terminate with a newline character; this is because on some implementations text files and binary files are the same. Some implementations may strip the leading space from lines consisting only of a space followed by a newline, or strip trailing spaces at the end of a line! An implementation must support text files with lines containing at least 254 characters, including the terminating newline. Opening a text stream in update mode may result in a binary stream in some implementations.Writing on a text stream may cause some implementations to truncate the file at that pointany data beyond the last byte of the current write being discarded.

9.2.2. Binary streams


A binary stream is a sequence of characters that can be used to record a program's internal data, such as the contents of structures or arrays in binary form. Data read in from a binary stream will always compare equal to data written out earlier to the same stream, under the same implementation. In some circumstances, an implementation-defined number of NUL characters may be appended to a binary stream.The contents of binary files are exceedingly machine specific, and not, in general, portable.

116

(AMITY CENTER FOR e-LEARNING)

9.3 The stdio.h header file


To provide support for streams of the various kinds, a number of functions and macros exist. The <stdio.h> header file contains the various declarations necessary for the functions, together with the following macro and type declarations: FILE The type of an object used to contain stream control information. Users of stdio never need to know the contents of these objects, but simply manipulate pointers to them. It is not safe to copy these objects within the program; sometimes their addresses may be magic. fpos_t A type of object that can be used to record unique values of a stream's file position indicator. . BUFSIZ The size of the buffer used by the setbuf function. An integral constant expression whose value is at least 256. EOF A negative integral constant expression, indicating the end-of-file condition on a stream i.e. that there is no more input. SEEK_CUR SEEK_END SEEK_SET Integral constant expressions used to control the actions of fseek. stdin stdout stderr Predefined objects of type (FILE *) referring to the standard input, output and error streams respectively. These streams are automatically open when a program starts execution.

9.4 Operations on file


The primary difference between manipulating files and doing terminal I/O is that we must specify in our programs which files we wish to use. As you know, you can have many files on your disk. If you wish to use a file in your programs, then you must specify which file or files you wish to use. Specifying the file you wish to use is referred to as opening the file. When you open a file you must also specify what you wish to do with it i.e. Read from the file, Write to the file, or both. Because you may use a number of different files in your program, you must specify when reading or writing which file you wish to use. This is accomplished by using a variable called a file pointer. Every file you open has its own file pointer variable. When you wish to write to a file you specify the file by using its file pointer variable.You declare these file pointer variables as follows:
117

(AMITY CENTER FOR e-LEARNING)


FILE *fopen(), *fp1, *fp2, *fp3; The variables fp1, fp2, fp3 are file pointers. You may use any name you wish. The file <stdio.h> contains declarations for the Standard I/O library and should always be included at the very beginning of C programs using files. Constants such as FILE, EOF and NULL are defined in <stdio.h>.You should note that a file pointer is simply a variable like an integer or character. It does not point to a file or the data in a file. It is simply used to indicate which file your I/O operation refers to. A file number is used in the Basic language and a unit number is used in Fortran for the same purpose.

9.4.1 Opening named files


Named files are opened by a call to the fopen function, whose declaration is this: #include <stdio.h> FILE *fopen(const char *pathname, const char *mode); The pathname argument is the name of the file to open, such as that returned from tmpnam, or some program-specific filename.Files can be opened in a variety of modes, such as read mode for reading data, write mode for writing data, and so on. Note that if you only want to write data to a file, fopen will create the file if it does not already exist, or truncate it to zero length (losing its previous contents) if it did exist The function fopen is one of the Standard Library functions and returns a file pointer which you use to refer to the file you have opened e.g. fp = fopen( prog.c, r) ;

The above statement opens a file called prog.c for reading and associates the file pointer fp with the file. When we wish to access this file for I/O, we use the file pointer variable fp to refer to it. You can have up to about 20 files open in your program - you need one file pointer for each file you intend to use. If you attempt to read from an non-existent file, your program will crash!! The fopen function was designed to cope with this eventuality. It checks if the file can be opened appropriately. If the file cannot be opened, it returns a NULL pointer. Thus by checking the file pointer returned by fopen, you can determine if the file was opened correctly and take appropriate action e.g.

118

(AMITY CENTER FOR e-LEARNING)


fp = fopen (filename, r) ;

if ( fp == NULL) { printf(Cannot open %s for reading \n, filename ); exit(1) ; /*Terminate program: Commit suicide !!*/ } The above code fragment show how a program might check if a file could be opened appropriately.The function exit() is a special function which terminates your program immediately. exit(0) mean that you wish to indicate that your program terminated successfully whereas a nonzero value means that your program is terminating due to an error condition.Alternatively, you could prompt the user to enter the filename again, and try to open it again: fp = fopen (fname, r) ;

while ( fp == NULL) { printf(Cannot open %s for reading \n, fname ); printf(\n\nEnter filename : ); gets( fname ); fp = fopen (fname, r) ; } In this code fragment, we keep reading filenames from the user until a valid existing filename is entered.

9.4.2 Reading from a stream using fgetc


The fgetc function is used to read a character from a stream.

119

(AMITY CENTER FOR e-LEARNING)


int fgetc(FILE *fp); If successful, fgetc returns the next byte or character from the stream (depending on whether the file is "binary" or "text", as discussed under fopen above). If unsuccessful, fgetc returns EOF. (The specific type of error can be determined by calling ferror or feof with the file pointer.) The standard macro getc, also defined in <stdio.h>, behaves in almost the same way as fgetc, except that being a macro it may evaluate its arguments more than once.The standard function getchar, also defined in <stdio.h>, takes no arguments, and is equivalent to getc(stdin).

9.4.3 Writing to a stream using fputc


The fputc function is used to write a character to a stream. int fputc(int c, FILE *fp); The routine getc(fp) is similar to getchar() and putc(c,fp) is similar to putchar(c). Thus the statement c = getc(fp); reads the next character from the file referenced by fp and the statement putc(c,fp); writes the character c into file referenced by fp. /* file.c: Display 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 );
120

(AMITY CENTER FOR e-LEARNING)


}

fclose( fp ); } In this program, we open the file prog.c for reading. We then read a character from the file. This file must exist for this program to work. If the file is empty, we are at the end, so getc returns EOF a special value to indicate that the end of file has been reached. (Normally -1 is used for EOF) The while loop simply keeps reading characters from the file and displaying them, until the end of the file is reached

9.4.4 Closing files


An open file is closed using fclose. #include <stdio.h>

int fclose(FILE *stream); Any unwritten data buffered for stream is flushed out and any unread data is thrown away. If a buffer had been automatically allocated for the stream, it is freed. The file is then closed.Zero is returned on success, EOF if any error occurs The function fclose is used to close the file i.e. indicate that we are finished processing this file. We could reuse the file pointer fp by opening another file. /* Prompt user for filename and display file on screen */

#include <stdio.h>

void main() { FILE *fopen(), *fp; int c ; char filename[40] ;


121

(AMITY CENTER FOR e-LEARNING)


printf(Enter file to be displayed: ); gets( filename ) ; fp = fopen( filename, r);

c = getc( fp ) ;

while ( c != EOF ) { putchar(c); c = getc ( fp ); }

fclose( fp ); }

In this program, we pass the name of the file to be opened which is stored in the array called filename, to the fopen function. In general, anywhere a string constant such as prog,c can be used so can a character array such as filename. (Note the reverse is not true).The above programs suffer a major limitation. They do not check whether the files to be used exist or not.

Example usage
The following C program opens a binary file called myfile, reads five bytes from it, and then closes the file. #include <stdio.h> #include <stdlib.h> int main(void) {
122

(AMITY CENTER FOR e-LEARNING)


char buffer[5] = {0}; /* initialized to zeroes */ int i, rc; FILE *fp = fopen("myfile", "rb"); if (fp == NULL) { perror("Failed to open file \"myfile\""); return EXIT_FAILURE; } for (i = 0; (rc = getc(fp)) != EOF && i < 5; buffer[i++] = rc) ; fclose(fp); if (i == 5) { puts("The bytes read were..."); printf("%x %x %x %x %x\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]); } else fputs("There was an error reading the file.\n", stderr); return EXIT_SUCCESS; }

123

(AMITY CENTER FOR e-LEARNING)

BIBLIOGRAPHY
1. Programming in ANSI C, E Balagurusamy , TMH 2. Let Us C, Y Kanetkar , BPB 3. The C Programming Language, B.W. Kernigham & Ritchie, PHI 4. Programming in C , Gottrified, TMH

124

You might also like