Chapter 1: Introduction to Programming 1.1  What is problem solving ? We encounter a variety of problems in our daily lives, both ‘big’ and ‘small’. Some are exciting

Chapter 1: Introduction to Programming
1.1 What is problem solving ?
We encounter a variety of problems in our daily lives, both ‘big’ and ‘small’. Some are exciting
and challenging to solve. Some are dull and boring which we feel like postponing all the time
(like, mopping the house)... How do we solve them? Do we have any broad strategies for solving problems? At least some general guide lines? Let us start with a simple daily life problem... If I have to look into the dictionary for the word
'procrastinate', How do we do it ? Should I start from page 1? Keep going page by page ?
How do I find out the meaning ? What procedure should I adopt ? What is the best (fastest way)
to find the meaning of the word I want ? The same problem can also be viewed through a
different but a similar example. If I would like to find out the phone number of Mr Zimba. How should I go about in doing it? (We know that, almost all of us, involuntarily will go to the last few pages by skipping a big bunch of pages in the beginning. We internally know that, ‘Z’ starts only towards the end of the directory. The key question would be, how do we translate this involuntary action into a methodical and step­by­step approach ? What algorithm should we adopt? All these problems certainly would require procedural steps, that are less time consuming and more efficient.
1.1.1 Some aspects of problem solving
• Identify the problem. Then, clearly (not cleverly !) write down the problem definition.
• Get started with the problem by trying to understand the intricacies
• Look for possible (alternative solution strategies; choose specific examples!)
• Look for generalizations and similarities with other known problems (and their solutions)
• Select the best solution strategy
• Write down the solution procedure into simple and step by step set of instructions. We encounter a variety of problems in our daily lives. A vast number of them can be classified
as calculation oriented. For example think about buying groceries from Tashi store. The person servicing has to enter the code of an items which in turn will pickup the corresponding price of the item bought. If there are several such items, all of them are entered and the list of all the items bought is displayed. If a big note is given, the exact amount to be paid is deducted and the excess is returned. If there can be so many calculations associated with such a simple everyday example, then imagine the huge and complex number of calculations associated with huge systems like, banks, airlines, Revenue authorities, financial institutions etc... Solutions to many problems in science can also be cast into a calculation (more precisely, arithmetic calculation) based approaches.
1.2 Algorithms
In order to solve a problem it is necessary to evolve a detailed and precise step­by­step method of solution. An algorithm is a sequence of steps or instructions for solving a problem. Attributes of an Algorithm :
Precision: An algorithm should be precise and simple. Each step of the algorithm should be precisely defined, that is, the steps must be unambiguous. Uniqueness: An algorithmic step should have only one way (unique) to perform a task.
Finiteness : An algorithm should end in finite number of instructions. It should not prolong
infinitely. (We can’t program a statement like, Tell me the sum of values up to infinity, although
summing up to certain huge number is meaningful).
Input : It should have some initial data/inputs (they can be called input variables).
Output: An algorithm should focus on the end result (output)
Generality: An algorithm should be general. As a simple example, if the student is asked to
program 1+2+... + 10, It is highly recommended that, the student should program for the case of
1+2+...+N, where N can be 10. The same program can indeed be used later for any value of N.
Furthermore, N becomes the input and Sum of the values can be called as Output. Note that, N
can’t be infinity (the mathematical notion is fine. But, it should be representable on the machine
as a finite number). Looking for the above characteristics in every algorithm would give the
students the much needed confidence on how to write an algorithm.
Example 1.2.1 A Simple Real Life Example of an Algorithm : Let's say that you have a friend arriving at the bus stop in Trashigang, and your friend needs to get from the bus stop to your hostel in Sherubtse College, Kanglung. Here are three different algorithms that you might give your friend for getting to your hostel: •
•
•
The taxi algorithm: 1. Go to the taxi stand. 2. Get in a taxi. 3. Give the driver my hostel name.
The call­me algorithm: 1. When your bus arrives, call my cell phone. 2. Meet me at the bus stand. The bus algorithm: 1. Get on a bus. 2. Get off in college gate, call my cell phone. 3. Meet me at the college gate. All three of these algorithms accomplish exactly the same goal, but each algorithm does it in completely different way. Each algorithm also has a different cost and a different travel time. You choose the algorithm based on the circumstances. Example 1.2.2 I am hungry. I would like to buy coffee from a coffee shop? What should I do ? (What are the algorithmic steps for buying coffee from a coffee shop?)
The approach:
What are the inputs ? (money)
What is the output ? (Hot coffee from the coffee)
Then, how should the steps be written in a sequence ?
The Algorithmic steps :
Step 1: Locate a coffee shop.
Step 2: Ask a coffee from a service person.
Step 3: Pay money.
Step : get your coffee and enjoy
Example 1.2.3 Algorithm to add two integer numbers
Inputs: two numbers
Output: sum of two number
Sequential steps:
Step 1: Read the first number
Step 2: Read the second number
Step 3: Add first number and second number
Step 4: Print result (sum)
Quick Exercise
1. Write down the algorithmic steps to prepare Ema Datse (What are the inputs ? What is the
output ? What are the sequential steps ? )
2. Write down the algorithmic steps to find the average of two integer numbers (What are the inputs ? What is the output ? What are the sequential steps ? )
1.3 Flow Charts
A flowchart is a graphical representation of an algorithm. These flowcharts play a vital role in the programming of a problem and are quite helpful in understanding the logic of complicated and lengthy problems. Once the flowchart is drawn, it becomes easy to write the program in any high level language. Often we see how flowcharts are helpful in explaining the program to others. Hence, it is correct to say that a flowchart is a must for the better documentation of a complex program.
Flowcharts are usually drawn using some standard symbols; however, Start or end of the program
Computational steps or processing function of a program
Input or output operation
Decision making and branching
Connector or joining of two parts of program
The following are some guidelines in flowcharting: a. In drawing a proper flowchart, all necessary requirements should be listed out in logical order. b. The flowchart should be clear, neat and easy to follow. There should not be any room for ambiguity in understanding the flowchart. c. The usual direction of the flow of a procedure or system is from left to right or top to bottom. d. Only one flow line should come out from a process symbol. or e. Only one flow line should enter a decision symbol, but two or three flow lines, one for each possible answer, should leave the decision symbol. Only one flow line is used in conjunction with terminal symbol. •
•
•
If the flowchart becomes complex, it is better to use connector symbols to reduce the number of flow lines. Avoid the intersection of flow lines if you want to make it more effective and better way of communication. Ensure that the flowchart has a logical start and finish. It is useful to test the validity of the flowchart by passing through it with a simple test data. Example 1.3.1
Problem : Write an algorithm and draw the flowchart for finding the average of two numbers
Algorithm:
Input: two numbers x and y
Output: the average of x and y
Steps: 1.
2.
3.
4.
5.
START
input x
input y
sum = x + y
average = sum /2
output average
Input x
Input y
Sum = x + y
Average = sum/2
Output Averag
Quick exercise
END
Problem : Write an algorithm for finding the area of a rectangle
Hints:
•
•
•
define the inputs and the outputs
define the steps draw the flowchart
1.4 Computer Systems
Having seen what is a problem solving all about and some of its facet. It is time for us to handle
the key question on how do we implement the solution on a computer ? Let us take a brief look
at the computer systems and some of their functionalities.
Computers are very simple minded (in fact, dumb is the most appropriate word) but, very
powerful machines. At the outset, the two words look contradictory but, there is truth in it.
Computer is like an indefatigable workaholic. Its ability comes from its speed. It can process
millions of calculations in split seconds, when it is appropriately programmed to do so.
However, it should be pointed out that, they are capable of performing only simple tasks. For
example, if we can go to the machine level (hardware level), they can obey simple commands
such as, add two numbers, assign a value to a location, compare two numbers etc... Such
instruction sets are called machine language. The most surprising part of these instructions is
that, they can be combined in a coherent and complex way to perform a rich set of useful
operations. Let us look at a few simple definitions.
Computer : A machine designed to perform operations (e.g. add two numbers, compare two numbers, etc.), when specified with a set of instructions called program
Software : Consists of all intangible forms (ideas, algorithms, programs). These programs control the computer and allow the user to perform useful tasks: Eg. word processor, accounting, library catalog, web browser, email)
Hardware : Consists of all tangible (visible) objects of the computer Ex: CPU, Mother Board,
Terminal (Monitor), Hard Disk, key board, mouse, printers etc.
Three Kinds of software:
1. Operating system: acts as interface between user programs or applications, and the hardware
• Examples: Windows, DOS, Unix, Linux, ...
• Example programs: copy file, save file, delete file, ...
2. Application software: someone else wrote it for you
• Examples: word processor, spreadsheet, web browser, ...
3. User programs: what you write
• e.g. write a C program to calculate the area of a circle with a given diameter
• you’ll see plenty of examples in this module!
Computer hardware architecture
Most computers have the same basic architecture:
May be, in a more simplistic sense, we can say : A typical human being has 2 eyes, 2 ears, 1
nose,1 heart, 1 brain etc... which can be called hardware. The ideas, the thought process
embedded in the brain, the nervous system is ‘software’. But, please note that the ‘software’ is
executed by the underlying ‘hardware’. In a bit advanced modules you are going to learn that,
both hardware and software are logically equivalent. Any operation performed by software can
in principle, be built into the hardware as well. Furthermore, any instruction which is executed
by the hardware, can also be simulated by the software. However, the decision to put certain
operations in hardware is indeed based on factors such as, cost, reliability, speed and frequency
of expected changes etc. There are no hard and fast rules and designers with different goals may
often make different decisions.
CPU, is the commonly used acronym for the Central Processing Unit. Well known examples are,
Pentium – III, Pentium IV, Celeron, etc. This guy, CPU is essentially the heart of the computer.
It consists of the processor and the ALU – The Arithmetic Logic Unit. The processor, is the part
which controls all the other parts of the computer. When we give an instruction through the
keyboard, it essentially does the following steps:
(1) It accepts input values, stores them in memory
(2) It interprets the instruction
(3) For example, if we want to add two numbers in memory, the processor will retrieve the
Values from memory and sends them to ALU
(4) ALU performs addition and the processor then, stores the result in memory. The
microprocessor is essentially, the CPU. It is contained in a single IC chip, which contains
Millions of components in a small area.
RAM : Random access memory (Or) Volatile memory. This is what we refer to when we
simply say memory. Something loaded into this memory space is simply lost when the computer
is switched off. RAM is the workspace of the computer. RAM is like a large work table on
which we place many different things.
There are lots of issues like, the internal design of the computer and the functionality of each of
the components etc... This field of study is known as computer architecture. However, it is
much more meaningful to focus on issues like how to make better use of the computer, which is
the objective of CS101. Quick Exercise
Categorize the following into either Hardware or Software
(a) MS POWER POINT (b) C Compiler
(c) CD Writer (d) Pentium Processor
(e) CISCO Router (f) ADOBE Acrobat Reader
(f) Modem (g) A file on the UNIX system
1.5 Computer Programming
To carry out some task, the computer must be told exactly what to do and how to do it. An algorithm is the series of steps involved in carrying out a particular task. To carry out these steps, the algorithm
must be expressed in a form that the computer can understand. An algorithm expressed in such a form is called a program. The user can then tell the computer to execute or run this program.
A computer program is written in a programming language. “Natural” languages are for communicating with people.
Programming languages are for communicating with computer
** Refer slides **
Chapter 2: Constants, Variables and Data Types
2.1 Constants
Constants in C refer to fixed values that do not change during the execution of a program. C
supports several types of constants; integer, real, single character and string constants.
Integer constants: refers to a sequence of digits. Eg. 45
Real constants: also called floating point constants refers to the number containing fractional parts.
Eg. 23.89
Single character constants: or simply character constant contains a single character enclosed
within a pair of single quote marks. Eg. '5' , 'X', ';', ' '
Note that the character constant '5' is not the same as the number 5.
String constants: is a sequence of characters enclosed in double quotes. The characters maybe
letters, numbers, special characters and blank space. Eg. “Hello” , “2356” , “well done” , “5+4”,
“X”
Remember that the character constant 'X' is not equivalent to the single character string constant
“X”.
Escape sequences : Certain non-printing characters, as well as the backslash (\), single (') and double
(“) can be expressed in terms of escape sequences. These are special character that are used in output
functions.
2.2 Keywords
Given below are the keywords (also called reserve words) of the C language. These words have
definite meaning associated with them. Keywords serve as building blocks for program statements. All
keywords must be written in lowercase. We will discuss the meaning of each of these words, only in an
appropriate context (we may not cover the
meaning of all words in our CS101 !).
2.3 Identifiers
Identifiers refer to the names of variables, functions and arrays. These are user-defined names and
consist of a sequence of letters and digits, with a letter as a first character. There are some rules in
constructing identifiers (It is always good to have some
rules to avoid meaningless names). As a matter of convention, our parents do not name us with
numbers like, 6, 28, although they are nice and perfect numbers in mathematics. Recently in
China, a father named his son as @. This was promptly rejected by the federal government. So,
we understand that even unwritten conventions are well followed.
Rules in choosing identifier names :
1. First character must be an alphabet ('a'..'z', 'A'..'Z') or underscore (_).
2. Must consist of only letters('a'..'z', 'A'..'Z'), digits ('0'..'9') or underscore (_).
3. C identifiers are case sensitive, so cs101, CS101 and cS101 are distinct identifiers.
4. Cannot use a keyword.
5. Must not contain white space.
There are several conventions and issues in choosing the right identifier names. Perhaps it is too
early to talk about those conventions and other good practices. But, for the time being, it is good
enough to know that choosing appropriate names (identifiers), which are relevant to the context
is an art, with a view on the program readability.
Some Legal/ Illegal identifiers
L2 norm →
Illegal (blank space not allowed)
Powerpoint → Legal
automobile-engine → Illegal (hyphen not allowed)
integer → Legal (only int is a keyword; But better to avoid )
vector_sum → Legal (using an underscore results in readable programs)
$ToPound → Illegal (can not have with a $ symbol)
Quick Exercise
Identify legal and illegal identifiers. Suggest an alternative if it is illegal.
(a) amino-acids
(b) 2nd_number
(c) sum6
(d) ATCG
(e) short
(f) graph
(g) main
(h) int
2.4 Variables
"Variable"s provide a mechanism to identify each data item with a name. This is just like our
names in real life. They have a location in memory.
Unlike constants that remain unchanged during the execution of a program, a variable may take
different values at different times during execution. In C programming, all variables should be
declared before their first use.
As mentioned earlier (in Identifier), variable names may consist of letters, digits and underscore (_)
characters. In addition to the rules of identifiers, variable length should not be more than eight
characters.
Some examples of valid variable names are:
a, avg, sum_ egg, n1, T_money.
Invalid variable names are:
1n, $avg, 132, sum egg.
2.5 Data Types
C supports several different types of data, each of which may be represented differently within the
computer's memory. The basic data types and typical memory requirements are listed in the table
below:
Data Type
Description
Format
Typical Memory Requirements
int
Integer quantity
%d
2 bytes (16 bits)
char
Single character
%c
1 byte (8 bits)
float
Floating-point number
%f
1 word (4 bytes=32 bits)
double
Double-precision floating-point
number
%lf
2 words (8 bytes = 64 bits)
2.6 Variable Declaration and Assignment of Values
All the variables must be declared before they are used in the program. Declaration does two things:
1. It tells the compiler what the variable name is.
2. It specifies what type of data that variable will hold.
The syntax for declaring a variable is:
data_type v1,v2,v3,..vn;
where data_type is the valid data types and v1,v2,v3,..vn are the names of variables. Variables are
separated by commas. A declaration must end with a semicolon.
Example: Valid declarations are:
int a, b, c;
float f1, f2;
char c;
a, b, and c are declared to be integer variables, f1 and f2 are floating point variables, c
is a char-type variable.
These declarations could also have been written as follows:
int a;
int b;
int c;
float f1;
float f2;
char c;
Example program: Declaration of variables
main() /*Program name */
{
/* Declaration */
int a, b, c;
float f1, f2;
char c;
}/*Program ends */
main()is the beginning of the program. The opening brace { signals the execution of the program.
Declaration of variables is usually done immediately after the opening brace of the program. The lines
beginning with / * and ending with */ are known as comment lines. These are used in the program to
enhance its readability and understanding. They help the programmers and other users in understanding
the various functions and operations of a program. Comment lines are not executable statements and
therefore anything between /* and */ is ignored by the compiler.
To assign values to the variable, assignment operator (=) is used. Assignment is of the form:
variable_name = value;
But before the assignment, the variable must be declared.
Examples:
int a,b;
a = 5;
b = 2;
It is also possible to assign a value to the variable at the time of declaration.
data_type variable_name = value;
Examples:
int a = 5;
char yes = 'y';
More than one variable can be assigned in one statement using multiple assignment operators.
Example:
int a,b;
a=b=5;
Example program: Assignments
main( )
{
/* declaration */
int a, b;
/* declaration and assignment */
int var = 5;
int a, b=6, c;
/* declaration and multiple assignment */
int p, q, r;
p = q = r = 6;
}
2.8 scanf( ) and printf( )
Both scanf( ) and printf( ) are library functions which requires the header file #include<stdio.h> before
main() function. scanf() is used for reading the input from the keyboard and printf() will write the
output on the screen.
scanf( )
The general format of input function is:
scanf(“format-string”, &var1, &var2, ...,&varn);
The format-string contains the format of data to be stored in the list of variables var1, var2, ...,varn .
The ampersand symbol & before each variable name is an operator that specifies the variable name's
address. We must always use this operator, otherwise unexpected results may occur.
Examples:
If there is a variable n1, declared as an int, we can read the variable as :
scanf("%d", &n1);
when this statement is encountered by the computer, the execution stops and waits for the value of the
variable n1 to be typed in. Since the format-string “%d” specifies that an integer value is to be read, we
have to type in the value in integer form. Once the number is typed in and the 'Return' key is pressed,
the computer then proceeds to the next statement. Thus the use of scanf provides an interactive feature
and makes the program 'user friendly'. The value is assigned to the variable n1.
We can also read more variables in the same statement using scanf() as follows :
int n1, n2, n3;
scanf("%d%d%d", &n1, &n2, &n3);
However, if our objective is to read real values using these variables, we should declare them as
float data type. Furthermore, the above statements should be written as follows:
float n1, n2, n3;
scanf("%f%f%f", &n1, &n2, &n3);
While, reading a mixture of integer and non-integer values through the keyboard, it could be
written as follows (notice the right sequence being used for the format descriptors):
int i1, i2 ;
float f1, f2 ;
scanf("%d%f%f%d", &i1, &f1, &f2, &i2);
printf( )
The general format of output function is:
printf(“format-string”, var1,var2,var3,...,varn);
This library function is useful for printing the values and other desired text on the screen. Format
string (in double quotes) and the variable names are the required inputs. With in the double
quotes, we use the appropriate format descriptors just like the scanf() function. But, for
printing the variable, we DO NOT use the address of (&) operator.
Example:
printf("Have you eaten lunch today? \n");
The printf( ) statement above will copy the contents Have you eaten lunch today? as
it is on to the screen. \n refers to skip to a new line.
Example:
int x ;
float y;
x=2;
y = 3.52;
printf ("x = %d\n", x); will write on the screen as: x = 2
printf ("x : %d, y : %f\n", x, y); will write on the screen as: x : 2, y : 3.520000
Four zeros after 3.52 could be a little puzzling, but %f specifier typically writes output upto 6
decimal places. To force only to 2 decimal places, we can write as follows:
printf ("x : %d, y : %.2f\n", x, y); Result would be : x : 2, y : 3.52
More examples:
int
i1, i2 ;
float f1, f2 ;
i1 = 3; i2 = 4; f1 = 7.1;
f2 = 1.2 ;
printf("%d,%f,%d,%f.", i1, f1, i2, f2);
Screen output will be : 3,4,7.100000,1.200000. Please notice the order of the format specifiers and the
commas – how they are exactly reproduced on the screen.
Example program: printf( ) and scanf( )
main( )
{
int n1;
float n2;
/* Input data from keyboard */
printf(“Enter an integer number:”);
scanf(“%d”, &n1);
printf(“\n Enter a floating point number:”);
scanf(“%f”, &n2);
/* output the data entered by the user */
printf (“Integer number = %d”, n1);
printf (“Floating point number = %f”, n2);
}
Quick exercise:
1. Write printf statements to output the following:
1. int a, b, c;
2. float x, y, z;
3. char c;
2. Write printf statements to print the following table:
Name
Average
Pass/Fail
Pema
30
Fail
Tashi
80
Pass
Lekey
45
Pass
3. Write scanf function to read two integers, one floating-point number, one character and a string.
2.9 Symbolic Constants
A symbolic constant is a name that substitutes for a sequence of characters. The characters may
represent a numeric constant, a character constant or a string constant. Thus, a symbolic
constant allows a name to appear in place of a numeric constant, a character constant or a string.
Symbolic constants are usually defined at the beginning of a program and does not end with
semicolon.
A symbolic constant is defined by:
#define symbolic-name constant-value
Example:
A C program contains the following symbolic constant definitions.
#define PI 3.141593
#define TAXRATE 0.23
#define TRUE 1
#define FALSE 0
#define FRIEND “Tshering”
Suppose the program contains the statement
area = PI * radius * radius;
During the compilation process, each occurrence of a symbolic constant will be
replaced by its corresponding value. Thus, the above statement will become
area = 3.141593 * radius * radius;
*********************************************************************************************
Please bring all the errors to my notice either by sending an email to mpelmo@gmail.com or in person. I will
appreciate your kind gesture!
**********************************************************************************************
Chapter 3: Operators and Expressions
3.1 Operators
Operator is a symbol that tells the computer to perform certain actions on variables (or)
expressions. An expression is a sequence of operands and operators that reduces to a
single value.
C operators can be classified into a number of categories. They include:
1. Arithmetic operators
2. Relational and Equality operators
3. Logical operators
4. Assignment operators
5. Increment and decrement operators
6. Conditional operators
3.1.1 Arithmetic Operators
The multiplication and division symbols are typically * and /. The meaning of + and –
follows the usual Math. Style. But, % is called the remainder (or) modulus operator. The
modulus operator produces the remainder of an integer division. All these operators are
explained below with the help of an example.
Name
Symbol
Expression
Addition
+
(x+y)
Subtraction
-
(x-y)
Multiplication
*
(x*y)
Division
/
(x/y)
Modulus
%
(x%y)
Examples:
If there are three variables x, y and z, which store integer values (declared as: int x,y,z;),
and if we have the following initial values : x = 5; y = 2; (This is called
initialization) then, different arithmetic operations are carried out on the two variables.
z = x+y;
/* z stores 7 */
z = x-y;
/* z stores 3 */
z = x*y;
/* z stores 10 */
z = x/y;
z = x%y ;
/* z stores 2 . Decimal part truncated */
/* z stores 1 */
In the statements above, there should be no confusion for addition(+), subtraction (-) and
multiplication(*). But, the serious question is with respect to the division operator( /). The
division between two integers results in truncated integer value and not a rounded off
value. The Key point is that, we do not care about the value after the decimal place, while
the integer division is performed. To reinforce this idea further, 1/3 will be 0, 2/3 will be
0 and 3/3 will be 1. Note that, the value after the decimal is simply discarded. Obviously,
this would also yield a value of zero for 99/100… However, if you insist on getting the
mathematically correct result, we should perform what is called a floating point division.
To achieve this, the variables should be declared as a float variable.
Furthermore, the above expression of division should be modified to one of the cases
below (z should be declared as float):
(a) z = 5.0 /2 ;
(b) z = 5 /2.0 ;
(C) z = 5.0/2.0 ;
and a statement z = 5/2 would only store 2.0, while all the cases above will store 2.5.
Now coming to the modulus operator, 5%2 , results in 1. We can think of 5/2 as 2 1/2 ,
where 1 is the remainder (when 5 is divided with 2). Hence, 5%2 gives the remainder,
which is 1. This / (division) and % (modulus) operators are very useful operators. One
should master the meaning of these arithmetic operations early on, to avoid any
confusion.
Multiply (*), divide (/), and modulus (%) have precedence over add (+) and subtract (-).
Thus, (1+2) * 4 yields 12, while 1+2*4 yields 9.
Quick Exercise:
1. Write the value of the variable stored in the questions below (x is declared as a float
variable, while z is declared as an int variable) ?
(a) z = 1940 % 4; (b) z = 200/3 ; (c) z = 20%4; (d) x = 19.0/4; (e) x = 19/4 ; (f) x = 19.0/4.0 ;
(g) x = 10/1.5; (h) z = 10/1.5;
2. Write a small program which would read two variables from the user and will compute the
sum and product of the two variables. Input is through the keyboard and output on the screen.
3.1.2 Relational and Equality Operators
Relational and Equality operators express the relation between two operands (or
variables). We make use of the operators to extract the relation between two variables.
They are very useful in building test conditions and to formulate expressions. The symbol
used for the operation, depends on the language. In C, we use the following symbols.
Operator
Meaning
<
Less than
<=
Less than or equality
>
Greater than
>=
Greater than or equality
==
Equal to
!=
Not equal to
Example:
Suppose that i, j and k are integer variables whose values are 1, 2, and 3, respectively.
Several logical expressions involving these variables are shown below:
Expression
i<j
(i + j) >= k
(j +k) > (I + 5)
k != 3
j = =2
Interpretation
True
True
False
False
True
Value
1
1
0
0
1
Quick exercise:
Evaluate the following Test Conditions:
int x, y, z; x = 3; y = 5; z = 8;
(a) (y > x) (b) (y >= x) (c) (y < z)
(d) (y <= z) (e) (x+y == z) (f) (y-x != z-x)
Note that all the above Test Conditions are True
3.1.3 Logical Operators
In addition to the relational operators, C has the following three logical operators.
Operator
&&
Meaning
Logical AND
||
Logical OR
!
NOT
The logical operators && and || are used when we test more than one condition and
make decision.
Given below is a truth table, which is the result of applying &&, || and ! operators on op1
and op2.
op1
True
True
False
False
op2
True
False
True
False
op1 && op2
True
False
False
False
op1 || op2
True
True
True
False
!op1
False
False
True
True
!op2
False
True
False
True
Example:
Suppose that i is an integer whose value is 7,f is a float-point variable whose value is 5.5,
and c is a character variable that represents the character ‘w’.
Expression
Interpretation
Value
(i >= 6) && (c = = ‘w’)
True
1
(i >= 6) || (c = = 119)
True
1
(f < 11) && (i > 100)
False
0
(c != ‘p’) || ((i + f) <= 10)
true
1
3.1.4 Assignment operators
Assignment operators are used to assign the result of an expression to a variable. We
have seen the usual assignment operator, ‘=’. In addition, C has a set of shorthand
assignment operators.
Example:
Statement with simple
assignment operator
a=a+b
a=a-b
a = a * (n + 1)
a = a / (n+1)
a=a%b
Statement with
shorthand operator
a += b
a -= b
a *= n + 1
a /= n + 1
a %= b
3.1.5 Increment and decrement operators
C allows two very useful operators not generally found in other languages. These are the
increment and decrement operators: ++ and - The operator ++ adds 1 to the operand, while -- subtracts 1. However, the operator ++
and - - can be used either as pre increment or post increment form.
Increment Operator ++
post increment x++;
pre increment ++x;
Decrement Operator -post decrement x--;
pre decrement --x;
A pre increment operator first adds 1 to the operand and then the result is assigned
to the variable on left. On the other hand, a post increment operator first assigns the
value to the variable on left and then increments the operand.
Example:
3.1.6 Conditional operators
Conditional/ternary operator is one which contains three operands. The only ternary
operator available in C language is conditional operator pair “?:”. It has the following
syntax:
exp1 ? exp2 : exp3;
This operator works as follows: exp1 is evaluated first. If the result is true then exp2 is
executed otherwise exp3 is executed.
Example:
a = 10;
b = 15;
x = (a > b ? a : b);
in this expression the value of b (15) will be assigned to x.
**********************************************************************************
Please bring all the errors to my notice either by sending an email to mpelmo@gmail.com or in
person. I will appreciate your kind gesture!
***********************************************************************************
Chapter 4: Decision Control Statements
Programming statements are executed in order – first statement, second statement and so
on. (in a sequential form). The control statements of a programming language allow this
execution to be altered. In fact, the ability to skip a line or a block of code is important
when we want to execute one outcome from all other outcomes, based on a Test
Condition. This mandates the need to master the statements that allow us to control the
program flow.
4.1 Test Conditions
We implement a variety of decisions in our daily lives. At every point of the decision
making process, we can think of two choices (Yes/ No; to be/ Not to be; Doing
something/ Not doing something; Presence/ Absence etc). For example, if I score more
than, 90 in Mathematics, I plan to go for Mathematics major else, never look at Math for
a life time. The real life decisions may not be that simple and straightforward (as the
above statement) but, we can formulate a compound test condition by appropriately
combining simple conditions. There are several stages in life (of a programmer), where
we are compelled to make decisions based on the situation at hand. Whenever a decision
is made, certain type of Action is chosen. For example, how to spend Sunday may have
lot of choices: (a) Go to Samdrup Jongkhar for shopping (b) Go for a hike to Yongphula
(c) Stay in the room and study. We can also have a default action of doing nothing (as
good as sitting in front of the TV and watching some junk program). All these different
actions can be implemented, based on a single or several test conditions and their
outcomes.
4.2 Simple if Statement
Programs would be very boring if they can produce only one type of outcome all the time.
Decision control statements allow us to skip or execute a block of code, based on a test
condition. Branch off is naturally applied by these decision control statements. It takes the
following form:
if (TC)
{
Action ;
}
Here, TC refers to the Test Condition, and if it is True, Action is executed only once. If it
is False, it will skip Action.
Example:
1. if(day = = “sunday”)
{
Go for shopping;
}
2. if(x < 0)
{
printf(“%f”, x);
}
3. if(average > = 40)
{
printf(“Pass”);
}
4.
if(a >= b)
{
b = c + d * x;
}
4.3 if-else Statement
The if-else statement is an extension of the simple if statement. The general form is:
if (TC)
{
Action _1;
}
else
{
Action_2;
}
If the test condition is true Action_1 is executed; otherwise Action_2 is executed. In
either case, either Action_1 or Action_2 is executed, not both.
Example:
if (score > 50)
{
printf ("Pass\n");
}
else
{
printf ("Fail\n");
}
Example:
if(n = = 50)
{
x = x + 2;
}
else
{
x= x + 4;
}
It is possible to combine logical and relational operators to formulate compound Test
Conditions, as per the context and need.
The if-else statement can be replaced by conditional operator /Ternary operator (?:).
To reflect the RHS of the above schematic, we normally write the 4 C programming lines
on the left. Since C promotes compact style of writing, we can replace the one above,
with the statement below:
max = (a>b) ? a : b;
In the above statement (a>b) is tested first. If it is true max is assigned with a otherwise
max is assigned with b.
Example program:
#include <stdio.h>
main()
{
int x=3, y=4, value;
value = (x>y) ? x*x : y*y;
printf ("value : %d\n",value);
}
Example program:
/* magic number program */
main( )
{
int magic = 223;
int guess;
printf(“Enter your guess for the number:”);
scanf(“%d”, &guess);
if(guess = = magic)
{
printf(“\n Congratulation! Right guess”);
}
else
{
printf( “\n Wrong guess”);
}
}
4.4 if else if else … sequence (else if ladder)
Here, several test conditions (TC’s) can be applied one after another. When the TC is
TRUE, corresponding Action component is executed.
A number of test conditions are executed one after another to evaluate the specific part of
the action component.
It takes the following general form:
if(TC1)
{
Action1;
}
else if(TC2)
{
Action2;
}
else if(TC3)
{
Action3;
}
else if(TC4)
{
Action4;
}
else
Action5;
The conditions are evaluated from top to down. As soon as a true condition is found, the
action associated with it is executed and the control is transferred out of the if statement
skipping the rest of the ladder. When all the n conditions become false, then the final else
containing the default action will be executed. Figure below shows the logic of execution
of else if ladder statements.
Example: Consider grading the students in an academic institution. The grading is done
according to the following rules.
Average marks
80 to 100
60 to 79
50 to 59
40 to 49
0 to 39
Grade
Honours
First Division
Second Division
Third Division
Fail
if(marks>79)
{
printf( “Honours\n”);
}
else if(marks>59)
{
printf(“First Division\n”);
}
else if(marks>49)
{
printf(“Second Division\n”);
}
else if(marks>39)
{
printf(“Third Division\n”);
}
else
printf(“Fail\n”);
(1)We notice that, a new if else can be started at the end of every previous else.
(2) All the Test Conditions are not evaluated at once but, one after another.
(3) If all the test conditions are FALSE, action part of the last else will be executed.
Example:
if (code = = 1)
{
printf(“Colour = “RED”);
}
else if(code = = 2)
{
printf(“Colour = “GREEN”);
}
else if (code = = 3)
{
printf(“Colour = “WHITE”);
}
else
printf(“Colour = “YELLOW”);
Code numbers other than 1,2 or 3 are considered to represent YELLOW colour.
Example program:
/* This program prints the cell phone status */
#include <stdio.h>
#define ON 1
#define OFF 0
main()
{
int status;
printf(“Enter cell phone status:”);
scanf(“%d”, &status);
if (status == ON)
{
printf ("Switch off your cell phone now!\n");
}
else if (status == OFF)
{
printf ("Good, the cell phone is switched off\n");
}
else
{
printf ("Incorrect cell phone status\n");
}
}
Quick exercise: Use else if ladder for the following statements. temp is declared as a
floating-point variable.
1. ICE, if the value of temp is less than 0.
2. WATER, if the value of temp lies between 0 and 100.
3. STEAM, if the value of temp exceeds 100.
4.5 Nesting of if-else statement
It is possible to nest (i.e. embed) if –else statements, one within another. There are
several different forms that nested if-else statements can take. The most general form is
as follows:
if(TC1)
{
if (TC2)
{
Action1;
}
else
{
Action2;
}
}
else
{
Action3;
}
If the TC1 is false, Action3 will be executed; otherwise it continues to perform the
second test. If the TC2 is true, Action1 will be evaluated; otherwise Action2 will be
evaluated.
Example program:
/* finding the largest of 3 numbers */
main( )
{
int a = 5, b = 2, c = 7;
if(a > b)
{
if (a >c)
{
printf (“%d is greatest”, a);
}
else
{
printf(“%d is greatest”, c);
}
}
else
{
if(b > c)
{
printf(“%d is greatest”, b);
}
else
{
printf(“%d is greatest”, c);
}
}
}
Example:
if (code = = 1)
{
printf(“Colour = RED”);
}
else if(code = = 2)
{
printf(“Colour = GREEN”);
}
else if (code = = 3)
{
printf(“Colour = WHITE”);
}
else
printf(“Colour = YELLOW”);
The above code can be written by using nested if-else statements as follows:
if(code !=1)
{
if(code !=2)
{
if(code !=3)
{
printf("colour = YELLOW");
}
else
{
printf("Colour = WHITE");
}
}
else
{
printf("Colour = GREEN");
}
}
else
{
printf("Colour=RED");
}
Quick exercise:
1.
int x;
if(x > 4)
{
printf(“Orange”);
}
else if ( x > 10)
{
printf(“Apple”);
}
else if (x > 21)
{
printf(“Mango”);
}
else
printf(“Banana”);
What will be the value of x so that “Apple” will be printed?
2. int i;
i = 2;
i++;
if(i == 4)
{
printf(“i = 4”);
}
else
{
printf(“i = 3”);
}
What is the output of the program?
3. main()
{
int age, weight;
age = 17;
weight = 75;
if (age>17 && weight >= 70 )
{
printf ("selected for wrestling.\n");
}
else
{
printf ("Rejected for wrestling.\n");
}
}
What is the output of the program? Rewrite the code using nested if-else statement.
4.6 Switch Statement
The switch statement is similar to a chain of if/else statements. The switch statement
causes a particular group of statements (actions) to be chosen from several available
groups.
The switch statement is a multi-way decision making statement, where, one of the many
action components are executed for TRUE case and value of the TC decides how the
branching takes place. Depending on the value of the TC, it branches to a specific action
parts.
The general form of a switch statement is:
switch (TC)
{
case constant1:
action1
break ;
case constant2:
action2
break;
default:
action3
}
Rules for switch statement
The switch statement evaluates the value of a TC and branches to one of
the case labels.
1. The switch TC must be an integer or character.
2. Case labels must be an integer or character constant and no floating point value.
3. Duplicate labels are not allowed, so only one case will be selected.
4. Case labels can be in any order.
5. Case labels must end with semicolon.
6. Break statement transfers the control out of the switch statement.
7. Break statement is optional. That is, two or more case labels may belong to the
same statements.
8. The default label can be put anywhere in the switch. When C sees a switch
statement, it evaluates the TC and then looks for a matching case label. If none is
found, the default label is used. If no default is found, the statement does
nothing.
The example program code below illustrates how a chain of if-else statement can be replaced by a
switch statement.
Example - if-else statement
Example – switch statement
#include<stdio.h>
void main ()
{
#include<stdio.h>
void main ()
{
char choice;
char choice;
printf("Enter
color
red):");
choice = getchar();
choice(type
if(choice=='r')
printf("RED \n");
else if(choice == 'b')
printf("BLUE\n");
else if (choice == 'g')
printf("GREEN\n");
else
{
printf("No color choice available.
Try again!\n");
}
getch();
}
r=
printf("Enter color choice(type r= red):");
choice = getchar();
switch (choice)
{
case ‘r’:
printf("RED \n");
break;
case ‘b’:
printf("BLUE\n");
break;
case ‘g’:
printf("GREEN\n");
break;
default:
printf("No color choice
available.
Try again!\n");
}
getch();
}
The example program below illustrates a simple implementation and use of switch statement.
#include <stdio.h>
main()
{
int year;
printf ("Enter your year of study\n");
scanf ("%d", &year);
switch (year)
{
case 1:
printf("You are a fresher\n");
case 2:
printf ("You are in second year\n");
case 3:
printf ("You are in third year\n");
case 4:
printf("You are in fourth year\n");
default:
printf ("Then, you are a graduate\n");
}
}
The switch statement is often used for menu selection:
Example program:
/* Simple Calculator Program */
main()
{
char character;
int result,a,b;
printf("\nSIMPLE CALCULATOR\n\n" );
printf("\n
printf("\n
printf("\n
printf("\n
printf("\n
A Addition:" );
B Sub:");
M Mul:");
X to skip:");
Eenter your choice:");
character = getchar();
switch(character)
{
case 'A':
printf("\nEnter two numbers:");
scanf("%d%d", &a,&b);
result = a +b;
printf("\nresult:%d", result);
break;
case 'B':
printf("\nEnter two numbers:");
scanf("%d%d", &a,&b);
result = a - b;
printf("\nresult:%d", result);
break;
case 'M':
printf("\nEnter two numbers:");
scanf("%d%d", &a,&b);
result = a * b;
printf("\nresult:%d", result);
break;
default:
printf("\nNo operations available!");
}
}
Quick exercise
1. Write a switch statement that will examine the value of an integer variable called flag
and print one of the following messages, depending on the value assigned to flag.
a. HOT, if flag has a value of 1,
b. LUKE WARM, if flag has a value of 2,
c. COLD, if flag has a value of 3,
d. OUT OF RANGE, if flag has any other value.
2. What is the output of the following code?
main( )
{
int i = 0;
switch(i)
{
case 0:
i++;
case 1:
++i;
}
printf(“i = %d”, i++);
printf(“i = %d”, i);
}
Practice Questions:
1. Find errors, if any, in each of the following segments:
a. if(code > 1);
a = b + c;
else
a = 0;
b. if(p < 0) || (q <0)
printf(“sign is negative”);
c. fd
2. The following is a segment of a program:
x = 1;
y = 1;
if(n > 0)
{
x = x + 1;
y = y – 1;
}
printf(“%d %d”, x, y);
What will be the values of x and y if n assumes a value of (a) 1 and (b) 0.
3. Rewrite each of the following without using compound relations:
a. if(grade <= 59 && grade >= 50)
second = second + 1;
b. if(number > 100 || number < 0)
printf(“Out of range”);
else
sum = sum +number;
c. if((m1 > 60 && m2 > 60) || t > 200)
printf(“Admited\n”);
else
printf(“Not admitted\n”);
4. What is the output from the code (or code segment) given below?
(a)
int x=8; int y=10;
if (x==8)
printf ("x=%d\n", x);
else
printf("y=%d\n",y);
(b)
#include <stdio.h>
main()
{
int z;
z = 17/5 - 8/3;
printf ("z = %d", z);
}
(c)
main( )
{
int x=10, y, z;
z
y
z
x
= y = x;
-= x--;
-= --x;
-= --x - x--;
printf("x=%d, y=%d, z=%d", x,y,z);
}
5. Rewrite the following program, correcting all errors.
include (stdio.h)
main{}
/ Program execution begins here /
(
people, legs integer;
print ("How many people are there?/n);
scanf ("%d", people);
legs = people * 2
print ("There are %f legs.");
[end main]
********************************************************************
Please bring all the errors (oversights) to my notice either by sending an
Email(mpelmo@gmail.com) or in person. I will appreciate your kind
gesture!
**************************************************************
Chapter 5: Decision Looping Statements
Suppose we want to display “hello world” on output screen five times in five different
lines, we might think of writing either five printf statement or one printf statement
consisting of constant string “hello world\n” five times. What if we want to display “hello
world” 500 times, should we write 500 printf statements? Not possible..! Therefore, we
need some programming facility to repeat certain works. Such facility is available in the
looping statements.
Looping statements allow the program to repeat a section of code any number of
times or until some condition occurs.
5.1 while statement
The while statement is used when the program needs to perform repetitive tasks.
The general form of a while statement is:
while(TC)
{
action;
}
The program will repeatedly execute the action inside the while until the condition
becomes false (0). (If the condition is initially false, the statement will not be executed.)
1
Example program: Illustrates how five printf statements to print hello five times on a
screen can be easily implemented using while statement.
main()
{
printf
printf
printf
printf
printf
("Hello
("Hello
("Hello
("Hello
("Hello
world\n");
world\n");
world\n");
world\n");
world \n");
}
main()
{
int count=0; /* Initialization */
while(count < 5) /* Testing */
{
printf ("Hello world\n");
count++; /* Incrementing */
}
}
The body of the loop is executed 5 times for count=1,2,...,5, each time printing the
message by incrementing the value of count inside the loop. The test condition may also
be written as count <= 5 with the initialization of the count = 1; the result would be the
same. The variable count is called counter or control variable.
Example program: Program to find the sum of n natural numbers
/* example 1 */
main( )
{
int sum,count;
sum = 0;
count = 1;
while(count <= 5)
{
sum +=count;
count++;
}
printf("Sum = %d", sum);
}
/* example 2 */
main()
{
int n,sum,count;
sum = 0;
count = 1;
printf(“Enter number(n):”);
scanf(“%d”, &n);
while(count <= n)
{
sum +=count;
count++;
}
printf("Sum = %d", sum);
}
In example 1, the body of the loop is executed 5 times, each time adding the value of
count to sum; count is then incremented inside the loop.
In example 2, the body of the loop is executed n times for n = 1,2,3,....n, each time adding
the value of count to sum; count is then incremented inside the loop. The value of n is
entered by the user. When the condition of the while becomes false, we come out of the
body of while loop and print the sum.
2
Example programs:
/* To find the even number up to 20 */
main()
{
int count=1;
while (count <= 20)
{
if(count%2 == 0)
printf ("%d\n",count);
count++;
}
/* To find the factorial of a number */
#include <stdio.h>
main()
{
int num;
int count = 1;
int fact = 1;
printf(“Enter number:”);
scanf(“%d”, &num);
while(count <= num)
{
fact = fact * count;
count++;
}
printf(“The factorial of %d is %d”, num, fact);
5.2 do-while statement
Same as the while loop. But, the Action part inside the while loop is guaranteed to
be executed at least once, since the test condition is performed at the bottom of the loop.
If the Test condition is True, Action component is executed again.
The general form of the do-while statement is:
do{
action;
}
while(TC);
Note the use of semi-colon after while (TC).
3
Example program:
main()
{
int count=1;
/* Initialization */
do
{
printf ("Hello world\n");
count++;
/* Incrementing */
}
while(count <= 5);
/* Testing */
}
Example program:
/* Finding the sum of n natural numbers */
main()
{
int n,sum,count;
sum = 0;
count = 1;
printf(“Enter number(n):”);
scanf(“%d”, &n);
do
{
sum +=count;
count++;
}
while(count <= n);
printf("Sum = %d", sum);
}
4
Quick exercise:
1. What is the output from the code below?
#include <stdio.h>
main()
{
int i=0, N=5, Sum=0;
while(i<=N)
{
i = i*i*i;
Sum = Sum + i;
printf("i = %d, Sum = %d\n", i, Sum);
i = i+1;
}
printf ("i = %d, Sum = %d\n", i, Sum);
}
2. int i = 2, j = 2, m = 2, n = 2;
do
{
m++;
}
while(i-- > 0 );
while(j-- > 0)
{
n++;
}
printf(“m and n = %d%d\n”,m,n);
5.3 for statement
The general form of for statement is:
for(Initialization; TC; Update )
{
action;
}
This is a fixed iterative loop. It has 3 parts inside the parentheses:
(i) Initialization,
(ii) A Test condition
(iii) an update.
5
The TC decides whether to continue Action and it controls the mechanics of loop working.
The test condition typically results in a Boolean value. Control variable does the work of the
loop. The sequence is as follows:
(i) Initialization is done only once
(ii) TC is tested. If the result is True, Action is executed.
(iii) After executing Action, it goes to Update. The update is usually a counter which is
incremented or decremented (depends on the program and what you are trying to do).
(iv) Go to Step (ii) and repeat (ii) and (iii) until TC is false.
Note: When TC is tested for the first time, and if it is false, Update is never performed.
Initialization is done only once and is never revisited. After executing Action, it goes to
update and from there to TC. Please see the arrows of the schematic starting from the start.
while statement
for statement
Initialization;
While (TC)
{
action;
Update;
}
for(Initialization; TC;
Update )
{
action;
}
6
Example:
main()
{
int count;
for(count = 1 ; count <=5; count++)
{
printf("Hello world\n");
}
}
Example: Sum of n natural numbers.
main()
{
int count,n,sum;
sum = 0;
printf("Enter number(n):");
scanf("%d", &n);
for(count = 1 ; count <=n; count++)
{
sum +=count;
}
printf("Sum = %d", sum);
}
5.4 Nested while
It is required when multiple conditions are to b tested. The syntax of nested while is:
while(TC1)
{
Action1;
while(TC2)
{
Action2;
while(TC3)
{
Action3;
}
}
}
Example:
int x;
while(x)
{
int a = 0;
7
while(a < 10)
{
a++;
}
x--;
}
5.5 Nested for
It is used when multiple set of iterations are required. The syntax for nested for is:
for(Initialization; TC1; Update)
{
action1;
for(Initialization; TC; Update)
{
action2;
}
}
Example:
for(i = 0; i < 5; i++ )
{
for(j = 0; j < 3; j++)
{
printf(“%d%d\t”, i,j);
}
printf(“\n”);
}
Output is:
i iteration
j iteration
5.6 break statement
The break statement is used to terminate loops or to exit from a switch. When a break
statement is encountered inside a loop, the control automatically passes to the first
statement after the loop. When the loops are nested, the break would only exit from the
8
loop containing it. That is the break will exit only a single loop. It can be used within a
‘while’, ‘do-while’, ‘for’ or ‘switch’ statement. The break statement is written simply as
break; without any embedded expression or statements.
Example:
/* for loop */
int x;
for(x = 1; x <= 10; x++)
{
/* break loop only if x == 5 */
if(x == 5)
{
break;
}
printf("%d", x);
}
printf("\nBroke out of loop at x == %d",x);
Output:
5.7 continue statement
Like the break statement, C supports another similar statement called the continue
statement. However, unlike the break which causes the loop to be terminated, the
continue as the name implies, causes the loop to be continued with the next iteration after
skipping any statements in between. The continue statement tells the compiler, “skip the
following statements and continue with the next iteration”. The continue statement can be
included within a while, do-while, or a for statement. It is written simply as continue;
In while and do-while loops, continue causes the control to go directly to the testcondition then to continue the iteration process. In the case of for loop, the execution
proceeds immediately to update. Then the test condition is evaluated, which determines
whether to execute action or not.
Example:
/* for loop */
int x;
for(x = 1; x <= 10; x++)
{
/* skip remaining code in loop only if x == 5 */
if(x == 5)
9
{
continue;
}
printf("%d", x);
}
printf("\nUsed continue to skip printing the value 5);
Output:
Quick exercise:
1. Find the output:
(a)
main()
{
int i = 5;
while(i)
{
i--;
if(i ==3)
{
Continue;
}
printf(“\n Smile”);
}
}
(b) main()
{
int i=0,x = 0;
for(i = 1; i < 10; i++)
{
if(i%2 ==1)
{
x += i;
}
else
{
x--;
}
printf("%d ", x);
break;
}
printf("\n x = %d",x);
}
10
(c) main()
{
int i=0,x = 0;
for(i = 1; i < 10; i++)
{
if(i%2 ==1)
{
x += i;
}
else
{
x--;
}
printf("%d ", x);
continue;
}
printf("\n x = %d",x);
}
(d) main()
{
int i, j, x = 0;
for(i = 0; i < 5; i++)
{
for(j = 0; j < i; j++)
{
x += (i + j - 1);
printf(“%d”,x);
break;
}
}
printf(“\nx = %d”, x);
}
(e)
int i;
for(i=3; i--;)
{
if(i== 1)
{
continue;
}
printf (“i= %d\n”, i);
}
Practice Questions
1) Find output:
(a) char a=’A’; int flag=1;
while(flag)
switch(a)
{
case ‘A’: printf(“%c ”,a);a=(int)a+2; break;
case ‘B’: printf(“%c ”,a);a=(int)a+2; break;
11
case ‘C’: printf(“%c ”,a);a=(int)a+2; break;
default : printf(“ Breaking..”);
flag=0;
}
b) main()
{
int i=1,j=2,k=3;
if(i==1)
if(j==2)
if(k==3)
{
printf("ok");
break;
}
else
printf("continue");
printf("bye");
}
(c)
int i, j;
for (i = 0; i <= 3; i = i + 1)
{
for (j = 0; j <= 4; j = j + 1)
{
if ( (i + 1 == j) )
{
printf ("+");
}
else
{
printf ("#");
}
}
printf ("\n");
}
********************************************************************
Please bring all the errors (oversights) to my notice either by sending an
Email(mpelmo@gmail.com/mpelmo@sherubtse.edu.bt) or in person. I will
appreciate your kind gesture!
**************************************************************
12
Chapter 6: Functions
6.1 Introduction
Let us have a fresh look at some of the following statements, which we are already
familiar with the printf("Enter values of i and j\n");
The printf() used above is indeed a library function. We have been using this
without being concerned about how it is implemented. We all know the following: If we
use some text in double quotes, it is copied on to the screen. To achieve this, someone has
written the corresponding interface. But, we do not really need to be concerned about
how that interfacing has been implemented inside.
However, we should be aware of how to make use of printf(). We have used
functions in very program that we have discussed so far namely main( ), printf(), and
scanf( ).
The above functions are already implemented through the library. We do not really know
(need not know) the implementation details. The library writers are typically software
developers, compiler writers and other IT/Scientific solution providers. They can’t
foresee all our requirements and write library functions suitable for all our requirements.
Furthermore, in a research environment, each individual may have completely different
requirements. So, we are compelled to write our own user-defined functions (Some of
you would maintain your own library of functions at a later stage).
There are basically two categories of function:
1. Library functions: available in the C standard library such as stdio.h, math.h,
string.h etc. Examples include printf( ) and scanf( ).
2. User-defined functions: developed by the user at the time of writing a
program. They are easy to define and use. Infact, this is one of the strengths of
C language.
6.2 Need for user-defined functions
As pointed out earlier, main is a specially recognized function in C. Every program must
have a main function to indicate where the program has begun its execution. While it is
possible to code any programs utilizing only main function, it leads to a number of
problems. The program may become too large and complex and as a result the task of
debugging, testing, and maintaining becomes difficult. If a program is divided into
functional parts, then each part maybe independently coded and later combined into a
single unit. These independently coded programs are called subprograms that are much
easier to understand, debug, and test. In C, such subprograms are referred to as functions.
A Function is a self contained block of statements that carries out some specific, welldefined task.
1
The notion of a function provides a convenient way to encapsulate (hide) some
computation, which can then be used without being concerned about its implementation
details.
The use of function can also avoid the need for redundant (repeated) programming of the
same instructions. For example, many programs require that a particular group of
instructions be accessed repeatedly, from several different places within the program. The
repeated instructions can be placed within a single function, which can then be accessed
whenever it is needed. This saves both time and space.
6.3 Elements of user-defined functions
We have used a variety of data types and variables in our program. We can also define
functions and use them like any other variables in C programming. Both variables and
functions share some similarities.
1. Both function names and variable names are considered identifiers and
therefore they must adhere to the rules for identifiers.
2. Like variables, functions have types (such as int) associated with them.
3. Like variables, function names and their types must be declared and defined
before they are used in a program.
There are there main elements of a function:
1. Function declaration/ function prototype: Like the declaration of a variable
before their use in the program, functions must be declared before their use.
2. Function call: that is call/invoke a function to be used in the program.
3. Function definition: is an independent program module that is specially
written to implement the requirements of the function.
We will look each of these in detail in the later part of this chapter.
The general format of a function definition:
function_type function_name(parameter list)
{
local variable declaration;
executable statement1;
executable statement1;
…………………………
return statement;
}
6.4 Development of program using get_sum() function
We start with the simplest possible program to understand the mechanics of function
development. We start with a very simple form for example, summing up two int values
by using a user defined function get_sum().
2
Example:
/* Program to sum two integer values, without using a user defined
function */
#include <stdio.h>
main()
{
int a, b;
int sum;
a = 1; b = 2;
sum = a + b;
printf("%d + %d = %d\n", a, b, sum);
}
First thing I need to know is the existence of a function. This in function terminology is
called – Function Prototype declaration (or) simply, function declaration. Second thing is,
called invoking or calling a function (function call). A function which calls a function is
called calling function and the functions which is called to perform the task is called the
called function. But, the called function would ask the calling function a simple question what is that you want me to sum up? So, the calling function needs to supply the called
function the values to sum up - these are called arguments in function terminology. C has a
protection facility for these arguments being passed to the called function, to avoid accidental
modification of the original values. So, the called function is passed with a copy of these
values and this is called function call by value. When the called function is invoked with
arguments, the control is transferred to the called function and performs the summation and
returns the value of sum back to the calling function.
The program to sum two integers using a user-defined functions get_sum()is shown
here. Different initial stages of the main()function are denoted step by step, with self
explanatory notes. The way in which get_sum()function is invoked is crucial to the
understanding of functions. res = get_sum(a, b); This statement means assign
the value returned by get_sum()function to the res variable. The function call results in
a copy by value into the arguments i,j as shown.
3
6.5 Working of Functions
¾
A C program does not execute the statements in a function until the function is called by another part
of the program.
¾ When C function is called, the program can send information to the function in the form of one or
more what is called arguments although it is not a mandatory.
¾ Argument is a program data needed by the function to perform its task.
¾ When the function finished its processing, program returns to the same location that called the
function.
¾ The following figure illustrates a function call.
¾ When a program calls a function, executions passed to the function and then back to
the calling program’s code.
¾ Function can be called as many times as needed as shown for function2() in the above
figure, and can be called in any order provided that it has been declared (as a
prototype) and defined.
Example:
/* Program to find sum and product of two numbers using userdefined functions */
4
#include<stdio.h>
/* Function declarations */
int read_input();
int get_sum(int i, int j);
int get_product(int i, int j);
void main()
{
int n1,n2,sum,product;
/* Function call */
n1 = read_input();
n2 = read_input();
sum = get_sum(n1,n2);
product = get_product(n1,n2);
/*Printing the result of sum and product */
printf("Sum = %d, Product = %d", sum,product);
}
/* Function definitions */
int read_input()
{
int num;
printf("Enter number:");
scanf("%d",&num);
return num;
}
int get_sum(int i, int j)
{
int k;
k = i + j;
return k;
}
int get_product(int i, int j)
{
int k;
k= i * j;
return k;
}
Sample output:
6.6 Function Terminology
Writing user defined functions is very similar to writing the statements of a main()
program. Mastering how to write them requires following a few basic principles and
conventions with consistency.
5
6.6.1 Prototype Declarations
Function prototype declaration is just like variable declaration. However, there are a few
simple and straightforward conventions to be followed. There are several styles (they are all
just small variations) acceptable to different compilers.
Example :
int get_sum(int i, int j);
The function get_sum() above has two parameters i and j which are of type int and it
returns an int value. This declaration should be viewed akin to the declarations for
identifiers. But, the memory allocation for the identifiers i and j is not done here. So, if a
function is declared inside main(), it becomes local to main(). If we want the function to
be accessible to all other functions, it should be declared outside main(). If the declaration
of a function B is inside a function A, then, function B becomes local to function A. This
typically means, the location of Prototype declarations decides, which functions can invoke
them.
Function prototype declaration should be made BEFORE the function is used. If the
declaration is outside any function, the declaration makes it known to all the functions after
the declaration.
If a function is declared before all other function definitions, then, it will be known to all
functions. However, if the declaration is inside a function, that function becomes local to the
function in which it is declared.
6.6.2 Function Definition
To define a function means, to define its header and the body. One can define the function
anywhere in a file. Before main() (or) after main(). If there are several functions in a
program, they can appear in any order.
Examples: typical function definitions
(a)float mul(float x, float y)
{
float result; /* local variable */
result = x * y; /* computes the product */
return(result); / * returns the result */
}
(b)void sum(int a, int b)
{
printf(“sum = %d”, a+b); /* no local variables */
return;
/*optional */
}
(c) void display(void)
{
/* no local variables */
printf(“No type, no parameters”);
/* no return statement */
}
Function definitions do not nest, unlike the other C statements.
6
Defining one function inside another is illegal :
Example:
void fun1 (int size)
{
/* some programming statements of fun1 */
int fun2 (char ch1)
{
/* Some programming statements */
}
/* Remaining programming statements of fun1 */
}
Execution of a program begins in the main()function. The main() function can call other
functions, which in turn can call other functions (including main()).
Some basic rules with function definitions:
(i) See if the function prototype declaration and header of the function definition are
consistent or not (except the semi-colon).
(ii) If your function body returns a value, is the data type of the return value correctly
reflected?
(iii) All the variables declared inside the function are local to that function. They are not
visible to other functions. This is the reason; different functions can have the same
identifier name, yet do not cause any conflict with each other.
6.6.3 Function Call
Function call refers to invoking a function (or calling someone to do some task). A function
call transfers the control to the called function. A function call should have the same return
data type as the identifier to which it is assigned.
A function may return only one value at a time, when invoked. The order in which
functions are defined and the order in which they are invoked/ called need NOT necessarily
be the same. A function can be invoked any number of times. A function can invoke any
other function. Even, main()can be called by some other function.
6.6.4 The return Statement
return statement causes a termination of the current function and execution goes back to
the calling function. Function returns a single value to the calling function.
To return without a value is simply written as : return;
To return the value exprn to the calling function : return exprn;
Unfortunately, functions CAN NOT return more than one value to the invoker.
Note:
A Function depending on whether arguments are present or not and whether a value is
returned or not, may belong to 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 one return value;
4) Functions with no arguments but return a value.
7
Quick exercise:
1. What is the output? Is the incrementing i, j in get_sum() function reflected in the
variables i,j of the main() ?
#include <stdio.h>
int get_sum(int i, int j);
main()
{
int sum;
int i=4, j=5 ;
sum = get_sum(i, j);
printf ("i = %d, j = %d, sum = %d\n", i, j, sum);
}
int get_sum(int i, int j)
{
int k;
k = i + j;
i = i + 2;
j = j + 3;
return k;
}
2. Make use of the function definition given below to compute the value of n!
int get_fact(int n)
{
int n_fact, i ;
n_fact = 1;
for (i=1;i<=n;i++){
n_fact = n_fact*i;
}
return n_fact;
}
Invoke the function get_fact()inside main() and develop a program to print the
n!
3. True/ False Exercise
The statements in (1) to (3) are based on the skeleton code given below:
#include <stdio.h>
void get_f1(float a, float b);
int main(void)
{
return 0;
}
void get_f2(int ch);
void get_f1(float a, float b)
{
void get_f3(int a, int b);
return ;
8
}
void get_f3(int a, int b)
{
return;
}
void get_f2(int ch)
{
return ;
}
(1) get_f2()can be invoked by main()function.
(2) Function get_f2()can be invoked by get_f1()but not by get_f3().
(3) Since the prototype declaration of get_f3()is inside get_f1(), get_f3()can be defined inside
get_f1()function.
(4) A function may return more than one value at a time.
(5) An invoking function must pass arguments to the invoked function
(6) The number of arguments and parameters can be different.
(7) Every function returns a value to its calling function.
(8) void is a data type that returns nothing to the calling function.
(9) Parameters are declared in the functions header.
6.7 Structured Programming
- Functions and structured programming are closely related.
- Structured programming definition: In which individual program tasks are
performed by independent sections of program code.
- Normally, the reasons for using structured programming may be:
1. Easier to write a structured program.
Complex programming problems or program are broken into a
number of smaller, simpler tasks. Every task can be assigned to a
different programmer and/or function.
2. It’s easier to debug a structured program.
If the program has a bug (something that causes it to work
improperly), a structured design makes it easier to isolate the problem
to a specific section of code.
3. Reusability.
Repeated tasks or routines can be accomplished using functions. This
can overcome the redundancy of code writing, for same tasks or
routines, it can be reused, no need to rewrite the code, or at least only
need a little modification.
- Advantages: Can save programmers’ time and a function written can be reused
(reusability).
- Structured program requires planning, before we start writing a single line of
code.
- The plan should be a list of the specific tasks that the program performs.
9
6.8 Variable Scope
The scope of a variable is the area of the program in which the variable is valid. A global
variable is valid everywhere (hence the name global), so its scope is the whole program.
A local variable has a scope that is limited to the block in which it is declared and cannot
be accessed outside that block. A block is a section of code enclosed in curly braces ({}).
The figure below shows the difference between local and global variables.
You can declare a local variable with the same name as a global variable. Normally, the
scope of the variable count (first declaration) would be the whole program. The
declaration of a second local count takes precedence over the global declaration inside
the small block in which the local count is declared. In this block, the global count is
hidden. The Figure below illustrates a hidden variable.
10
The variable count is declared as both a local variable and a global variable. Normally,
the scope of count (global) is the entire program; however, when a variable is declared
inside a block, that instance of the variable becomes the active one for the length of the
block. The global count has been hidden by the local count for the scope of this block.
The shaded block in the figure shows where the scope of count (global) is hidden.
Definitions of local and global:
Local: These variables only exist inside the specific function that creates them. They are
unknown to other functions and to the main program. As such, they are normally
implemented using a stack. Local variables cease to exist once the function that created
them is completed. They are recreated each time a function is executed or called.
Global: These variables can be accessed (i.e. known) by any function comprising the
program. They are implemented by associating memory locations with variable names.
They do not get recreated if the function is recalled.
Example: Defining global variables
/* Demonstrating Global variables
#include <stdio.h>
int add_numbers( void );
*/
/* function prototype */
/* These are global variables and can be accessed by functions from
this point on */
int value1, value2, value3;
main()
{
int result;
value1 = 10;
value2 = 20;
value3 = 30;
result = add_numbers();
printf("\n The sum of %d + %d + %d is %d\n", value1, value2,
value3,result);
}
int add_numbers( void )
{
int result;
result = value1 + value2 + value3;
return result;
}
The scope of global variables can be restricted by carefully placing the declaration. They
are visible from the declaration until the end of the current source file.
11
Example:
#include <stdio.h>
void no_access( void ); /* function prototypes */
void all_access( void );
int n2;
/* n2 is known from this point onwards */
void no_access( void )
{
n1 = 10;
/* illegal, n1 not yet known */
n2 = 5;
/* valid */
}
int n1;
/* n1 is known from this point onwards */
void all_access( void )
{
n1 = 10;
/* valid */
n2 = 3;
/* valid */
}
6.9 Recursion
Recursion is a process by which a function calls itself repeatedly, until some specified
condition has been satisfied. In order to solve a problem recursively, two conditions must
be met:
- problem must be written in recursive form
- problem statement must include a stopping condition.
An example of recursion is to calculate the factorial of a given number. The factorial of a
number n is expressed as a series of repetitive multiplication as shown below:
factorial of n = n(n-1)(n-2)……..1
for example,
factorial of 4 = 4x3x2x1 = 24
Example program:
#include <stdio.h>
int factorial(int n); //function prototype
void main()
{
int n=4;
int fact=factoral(n)
printf("The factorial of %d is: %d", n,fact);
}
12
int factorial(int n)
{
//test used to see if the factoral process is at the last stage
if (n == 1)
return 1;
//recursive step of the factoral
else
{
n *= factorial(n-1); //calls the factorial function.
//The above calls the factorial function from within the
factorial function.
return n;
}
}
Let us see how the recursion works. Assume n = 4. Since the value of n is not equal to 1,
the statement
n *= factorial(n-1);
will be executed with n =4. That is,
n = 4 * factorial(3);
will be evaluated. The expression on the right hand side includes a call to factorial with n
=3. This call will return the following value:
3 * factorial(2)
Once again, factorial is called with n = 2. This will return the following value:
2 * factorial(1)
factorial is called again with n = 1. This time, the function returns 1. The sequence of
operations can be summarized as follows:
n =
=
=
=
=
4 *
4 *
4 *
4 *
24
factorial(3)
3 * factorial(2)
3 * 2 * factorial(1)
3 * 2 * 1
Practice Questions
1. Find output
//demonstrates variables scope within a block
void myFunc();
int x = 10;
int y = 23;
// global variables declaration
void main()
{
int x = 5; //local variable declaration
printf("\nIn main x is:%d ",x);
myFunc();
printf("\n\nBack in main, x is:%d ",x);
}
13
void myFunc()
{
int x = 8; //local scope variable
printf("\n\nWithin myFunc, local x is:%d ",x);
printf("\nWithin myFunc, global y is:%d ",y);
}
2.
#include <stdio.h>
void Funny(void);
void main(void)
{
Funny();
printf("In main() – Yes it is me!\n");
Funny();
}
void Funny(void)
{
printf("In Funny() – Silly me.\n");
}
a. Number the events in order from 1 to 5.
_____ - Funny() calls printf() first time
_____ - Funny() calls printf() second time
_____ - main() calls printf()
_____ - main() calls Funny()
_____ - main() calls Funny()
b. When main() calls Funny(), which function do you think is the calling function?
c. Which function do you think is the called function?
d. When Funny() calls printf(), which function do you think is the calling function?
e. Which function do you think is the called function?
f. Which function gets called and also calls another function?
g. When main() calls Funny(), is there an argument passed to Funny()?
3.
14
a. i is a local variable in main(), which means that only main() has access to it. What
is the local variable in Funny()?
b. main() sets the value of i to 54. Then it was printed. Execution then passed to
Funny(). At the beginning of Funny() was the value of i equal to 54 or just
“garbage”?
c. Funny() set the value of i to -28. After coming back to main(), what was the value
of i?
d. Was the i in main() the same as i in Funny()?
********************************************************************
Please bring all the errors to my notice either by sending an
email(mpelmo@gmail.com/mpelmo@sherubtse.edu.bt) or in person. I will
appreciate your kind gesture!
**************************************************************
15
Chapter 7: Arrays
7.1 Introduction and definition
So far we have used only the fundamental data types, namely char, int, and float.
Although these types are very useful, they are constrained by the fact that a variable of
these types can store only one value at any given time. Therefore, they can be used only
to handle limited amounts of data. In many applications, however, we need to handle a
large volume of data in terms of reading, processing and printing. To process such large
amounts of data, we need a powerful data type that would facilitate efficient storing,
accessing and manipulation of data items. Such data type is called arrays.
An array is a collection of related data elements (items) of the same type that are
referenced by a common name. All the elements of an array occupy a set of contiguous
memory locations and by using an index or subscript we can identify each element.
The general format to declare an array is:
data_type array_name[size];
where data-type is the data type of an array, array_name is the name of an array, and
the size indicates the number of array elements.
For example, instead of declaring mark1, mark2, ..., markN to store and manipulate a set
of marks obtained by the students in certain courses, we could declare a single array
variable named mark and use an index, such as j, to refer to each element in mark. This
absolutely has simplified our declaration of the variables.
Hence, mark[j] would refer to the jth element in the array mark. Thus by changing the
value of j, we could refer to any element in the array, so it simplifies our declaration.
For example, if we have 100 list of marks of integer type, we will declare it as follows:
int mark1, mark2, mark3, … , mark100;
If we have 100 marks to be stored, you can imagine how long we have to write the
declaration part by using normal variable declaration? By using an array, we just declare
like this:
int mark[100];
This will reserve 100 contiguous/sequential memory locations for storing the integer data
type. Graphically can be depicted as follows:
1
The value of the subscript must be in the range 0 to size-1. An array subscript value
outside this range will cause a run-time-error.
7.2 One Dimensional Array: Declaration
A list of items can be given one variable name using only one subscript and such a
variable is called one-dimensional array. A single dimensional array declaration has the
following form:
array_element_data_type array_name[array_size];
Here, array_element_data_type declares the base type of the array, which is the type
of each element in the array. array_size defines how many elements the array will hold.
array_name is any valid C identifier name that obeys the same rule for the identifier
naming.
For example, to declare an array of 20 characters, named character, we could use:
char character[20];
Can be depicted as follows:
In this statement, the array character can store up to 20 characters with the first
character occupying location character[0] and the last character occupying
character[19]. Note that the index runs from 0 to 19. In C, an index always starts from
2
0 and ends with (array size-1). So, notice the difference between the array size and
subscript terms.
Examples of the one-dimensional array declarations:
int x[20], y[50];
float price[10], yield;
char letter[70];
The first example declares two arrays named x and y of type int. Array x can store up to
20 integer numbers while y can store up to 50 numbers. The second line declares the
array price of type float. It can store up to 10 floating-point values.
The third one declares the array letter of type char. It can store a string up to 69
characters. (Why 69? Remember, a string has a null character (\0) at the end, so we must
reserve for it.)
Just like ordinary variables, arrays of the same data type can be declared on the same line.
They can also be mixed with ordinary variables of the same data type like in the second
line together with yield.
7.3 Array Initialization
An array may be initialized at the time of its declaration, which means to give initial
values to an array. Initialization of an array takes the following form:
Data_type array_name[size] = {value_list};
Examples:
int id[7] = {1, 2, 3, 4, 5, 6, 7};
float x[5] = {5.6, 5.7, 5.8, 5.9, 6.1};
char vowel[6] = {‘a’, ‘e’, ‘i’, ‘o’, ‘u’, ‘\0’};
The first line declares an integer array id and it immediately assigns the values 1, 2, 3, …,
7 to id[0], id[1], id[2],…, id[6].
In the second line assigns the values 5.6 to x[0], 5.7 to x[1], and so on.
Similarly the third line assigns the characters ‘a’ to vowel[0], ‘e’ to vowel[1], and so on.
Note again, for characters we must use the single apostrophe (’) to enclose them. Also,
the last character in the array vowel is the NULL character (‘\0’).
Initialization of an array of type char for holding strings takes the following form:
char array_name[size] = "string_lateral_constant";
For example, the array vowel in the above example could have been written more
compactly as follows:
char vowel[6] = "aeiou";
3
When the value assigned to a character array is a string (which must be enclosed in
double quotes), the compiler automatically supplies the NULL character but we still have
to reserve one extra place for the NULL.
7.4 Array Manipulation: How to use an array and what array can do?
7.4.1 Accessing Array’s Element
The following program example declares and initializes the array named y of type int. It
uses a for loop with index i to access the successive elements in y. For each loop
iteration, the value accessed is displayed. Note that the loop index i run from 0 to 3, not 1
to 4. Also, note that the array size N is declared in the #define statement.
Example: Declare, initialize and print the array elements
#include<stdio.h>
#define N 4
void main()
{
int i, y[N] = {2,3,4,1};
for(i = 0; i < N; i++)
{
printf("%d ", y[i]);
}
}
Sample output:
Modify the above program to add the elements of an array y and then print the sum.
#include<stdio.h>
#define N 4
void main()
{
int i, total = 0,
for(i = 0; i < N;
{
printf(" %d ",
total += y[i];
}
printf("\n Sum of
}
y[N] = {2,3,4,1};
i++)
y[i]);
4 numbers in an arrary is : %d",total);
4
Sample output:
Example: Read array elements from the user and find the sum
#include<stdio.h>
#define N 4
void main()
{
int i, total = 0, y[N];
printf("Enter array elements:\n");
for(i = 0; i < N; i++)
{
printf("\n y[%d]:",i);
scanf("%d", &y[i]);
/ * reading from the user */
total += y[i];
}
printf("\n Printing the array elements entered:\n");
for(i = 0; i < N; i++)
{
printf("\n\n y[%d]:%d",i, y[i]);
}
printf("\n\n Sum of 4 numbers in an arrary is : %d", total);
}
Sample output:
5
Example: Generalize the above program to read array size and elements. Then, find the
sum.
#include<stdio.h>
#define N 100
void main()
{
int i, total = 0, y[N],n;
printf("\nEnter array size:");
scanf("%d", &n);
printf("Enter array elements:\n");
for(i = 0; i < n; i++)
{
printf("\n y[%d]:",i);
scanf("%d", &y[i]);
total += y[i];
}
printf("\nPrinting the array elements entered:\n");
for(i = 0; i < n; i++)
{
printf("\n y[%d]:%d",i, y[i]);
}
printf("\n\n Sum of 4 numbers in an arrary is : %d", total);
}
Sample output:
7.4.2 Searching for a value
To search an array for a value, the program looks at each element in the array and checks
if it matches the given value using if expression. The following example, finds the
character in the array named text.
#include<stdio.h>
6
void main()
{
int i;
char c, text[6]="smile";
printf("Enter character to search: ");
scanf("%c", &c);
for(i = 0; i < 6; i++)
{
if(c == text[i])
{
printf("\nCharacter %c found at location %d", c,i);
}
}
}
Sample output:
Example: To find the highest number from the given 5 numbers.[refer chapter 1 for
algorithmic steps and flowchart ]
#include<stdio.h>
void main()
{
int i, max, count, arr[4] = {4,7,12,9};
max = arr[0];
for(i=1;i<4;i++)
{
if(arr[i]>max)
{
max = arr[i];
count = i;
}
}
printf("The max number is %d found at location %d",max,count);
}
Sample output:
7.4.3 Exchanging Values of Variables
It is sometimes necessary to shuffle the order of the elements of an array. Sorting arrays
calls for the values of some elements to be exchanged. It would therefore be helpful to
7
first learn the technique of swapping variables. How would you swap the values of the
variables, let say, num1 and num2 (that is exchanging the value of num1 in num2)?
You must use a third variable as in the following example:
//assign num1 to third_var
third_var = num1;
//then assigns num2 to num1
num1 = num2;
//finally assigns third_var to num2
num2 = third_var;
7.4.4 Sorting Variables
Sorting is defined as arranging data in a certain order, is a very common activity in data
processing. Many algorithms (techniques) are available to perform sorting.
One sorting algorithm, which is quite simple to understand, but not necessarily the best,
is given in the following program example. It sorts a list of integers in ascending order of
magnitude by using an array.
#include<stdio.h>
#define N 7
void main()
{
int i,j, temp, arr[N] = {4,7,12,9,3,2,1};
printf("Unsorted list:");
for(i=0;i<N;i++)
/* Printing array elements */
{
printf("%d ", arr[i]);
}
for(i=0;i<N-1;i++)
/* Sorting */
{
for(j= i+1; j<N; j++)
{
if(arr[i]>arr[j])
{
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
printf("\nThe sorted list in ascending: ");
for(i=0; i<N;i++)
{
printf("%d ", arr[i]);
}
/* printing sorted array elements */
}
8
Sample output:
7.5 Two Dimensional Arrays
Some data fit better in a table with several rows and columns. This can be constructed by
using two-dimensional arrays. A two dimensional array has two subscripts/indexes. Its
declaration has the following form:
Data_type array_name[size1][size2];
A two dimensional array can be thought of as a table having rows and columns. The first
subscript refers to the row, and the second, to the column.
Examples:
int x[3][4];
float matrix[20][25];
The first line declares x as an integer array with 3 rows and 4 columns and the second
line declares a matrix as a floating-point array with 20 rows and 25 columns.
Descriptively, int x[3][4] can be depicted as follows:
You can see that for [3][4] two-dimension array size; the total array size (the total array
elements) is equal to 12. Hence:
For n rows and m columns, the total size equal to mn
9
The item list is read starting from the first row from left to right, and then goes to the next
row and so on.
A set of string s can be stored in a two-dimensional character array with the left index
specifying the number of strings and the right index specifying the maximum length of
each string.
For example, to store a list of 4 names with a maximum length of 10 characters in each
name, we can declare:
char name[4][10];
//can store 4 names, each is 10 characters long
Just like the one-dimensional array, a two dimensional array can also be initialized. For
example, the previous first array declaration can be rewritten along with initial
assignments in any of the following ways:
int x[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
or
The results of the initial assignments in both cases are as follows:
x[0][0]=1
x[1][0]=5
x[2][0]=9
x[0][1]=2
x[1][1]=6
x[2][1]=10
x[0][2]=3
x[1][2]=7
x[2][2]=11
x[0][3]=4
x[1][3]=8
x[2][3]=12
You can also show how the rows are filled during its initialization. For example, the array
named x can be declared as follows:
int x[3][4] = {{1,2,3,4},
{5,6,7,8},
{9,10,11,12}
};
If the number of values given is insufficient to fill in the whole array, an initial value of
zero will be assigned to all those locations, which are not given initial values explicitly.
Example:
10
So, an initial value of zero will be assigned to x[2][2] and x[2][3]. Similarly, in
declaration:
An initial value of zero will be assigned to x[0][3], x[1][3] and x[2][3].
You can fill the whole array with zeroes by using:
int x[3][4]={0}; //all array elements will be 0
In memory, despite their table-form arrangement, the elements of a two-dimensional
array are stored sequentially, that mean one after another contiguously.
An array of string can also be initialized. For example, in the following declaration:
char name[4][10] = {"Dorji", "Tshering", "Tashi", "Pema"};
The values assigned are as follows:
name[0] = "Dorji" name[1] = "Tshering"
name[2] = "Tashi" name[3] = "Pema"
Note that the second subscript here is unnecessary and therefore omitted.
7.6 Two-Dimensional Array Manipulation
Example: prints 3 x 3 array’s subscript and their element.
#include<stdio.h>
#define m 3
#define n 3
void main()
{
int i,j;
int x[m][n]={{1,2,3,}, {4,5,6}, {7,8,9}};
printf("\n3x3 array's subscripts and their respective elements\n");
printf("\n----------------------------------------------------\n");
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
{
printf("x[%d][%d]=%d\n",i,j,x[i][j]);
}
}
}
11
Sample output:
Example: prints 3 x 3 array’s elements in table
#include<stdio.h>
#define m 3
#define n 3
main()
{
int i,j;
int x[m][n]={{1,2,3,}, {4,5,6}, {7,8,9}};
printf("\n3x3 array in a form of table\n");
printf("\n----------------------------\n");
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
{
printf("%4d",x[i][j]);
}
printf("\n");
}
}
Sample output:
Example: Input 2x2 array elements from the keyboard and display
#include<stdio.h>
#define m 2
#define n 2
main()
{
12
int i,j;
int x[m][n];
printf(“Enter array elements:\n\n”);
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
{
printf("\nx[%d][%d]=",i,j);
scanf("%d", &x[i][j]);
}
}
printf("\nDisplaying the array elements entered\n\n");
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
{
printf("x[%d][%d]=%d\n",i,j,x[i][j]);
}
}
}
Sample output:
Example: Add 2 2x2 arrays and display the result.
/* add array x and y and store the result in array z */
#include<stdio.h>
#define m 2
#define n 2
main()
{
int i,j;
int x[m][n], y[m][n], z[m][n];
printf("\n First table:\n");
for(i=0; i<m; i++)
13
{
for(j=0; j<n; j++)
{
scanf("%d", &x[i][j]);
}
}
printf("\n Second table:\n");
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
{
scanf("%d", &y[i][j]);
}
}
/* Compute sum */
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
{
z[i][j] = x[i][j] + y[i][j];
}
}
printf("\nDisplaying the sum \n\n");
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
{
printf("%2d",z[i][j]);
}
printf("\n");
}
}
Sample output:
14
7.7 Multidimensional Arrays
When an array has more than one dimension, we call it a multidimensional array. We
have already looked at multidimensional arrays with two dimensions. The declaration and
manipulation of other multidimensional arrays in C are quite similar to that of the two
dimensional array. The declaration takes the following form:
Data_type name[size1][size2]…[sizeN];
Example:
int y[4][5][3];
Declares a 3-dimensional array with a depth of 4, 5 rows and 3 columns.
The are no limitation on the dimension of the arrays, but the dimension more than two
dimensional arrays are rarely used because of the complexity and code readability.
7.8 Strings
A string is defined as a character array that is terminated by a null character (\0). The null
character indicates the end of string. For example, the string "Hello" is stored in a
character array, msg[], as follows:
char msg[6];
msg[0] = 'H';
msg[1] = 'e';
msg[2] = 'l';
msg[3] = 'l';
msg[4] = 'o';
msg[5] = '\0';
When the string is retrieved, it will be retrieved starting at index 0 and succeeding
characters are obtained by incrementing the index until the first NULL character is reached
signaling the end of the string.
Although C does not have a string data type, it allows string constants. A string constant
is a list of characters enclosed in double quotes. For example
char msg[6] = “hello”;
15
You do not need to add the null character at the end of the string manually- the C
compiler does this for you automatically.
C supports a wide range of string manipulation functions. The most common are:
Name
strcpy(s1,s2)
strcat(s1,s2)
strlen(s1)
strcmp(s1,s2)
strchr(s1,ch)
strstr(s1,s2)
Function
Copies s2 into s1
Concatenates s2 onto the end of s1
Returns the length of s1
Returns 0 if s1 and s2 are the same;
less than 0 if s1<s2;
greater than 0 if s1>s2
Returns a pointer to the first occurrence of ch in s1
Returns a pointer to the first occurrence of s2 in s1
These functions use the standard header file string.h. The following program illustrated
the use of these string functions:
#include<stdio.h>
#include<string.h>
main()
{
char s1[20], s2[20];
int ls1,ls2;
puts("Enter first string (s1):");
gets(s1);
puts("Enter second string(s2):");
gets(s2);
ls1 = strlen(s1); //find the length of the strings s1 and s2
ls2 = strlen(s2);
printf("\nstrlen(s1)= %d\nstrlen(s2)= %d\n",ls1,ls2);
strcat(s1,s2); //string concatenation
printf("\nstrcat(s1,s2)= %s\n", s1);
if(!strcmp(s1,s2))
//string compare
printf("\n strcmp(s1,s2)=The strings are equal\n");
else
printf("\nstrcmp(s1,s2)=The strings are not equal\n");
strcpy(s1, s2); // string copy
printf("\nstrcpy(s1,s2)= %s\n",s1);
if(strchr(s1, 'i'))
printf("\nstrchr(s1, 'i')= character i is in s1\n", s1);
else
printf("\nstrchr(s1, 'i' )= character i is not in s2\n",s1);
if (strstr(s2, "me"))
printf("\nstrstr(s2, \"me\”)= substring me found in s2\n");
else
printf("\nstrstr(s2, \”me\”)= substring me me not found\n");
}
16
Sample output:
gets( ): gets reads a whole line of input into a string until a newline or EOF is
encountered. It is critical to ensure that the string is large enough to hold any expected
input lines.
puts( ): puts writes a string to the output, and follows it with a newline character.
Note: strcmp( ) returns false if the strings are equal. Be sure to use the logical operator! to
reverse the condition, as shown in the above program, if you are testing for equality.
7.9 Passing Arrays to Functions
7.9.1 One Dimensional Arrays
Like the values of simple variables, it is also possible to pass the values of an array to a
function. To pass one dimensional array to a called function, it is sufficient to list the
name of the array, without any subscripts, and the size of the array as arguments. For
example, the function call
largest(arr,n);
will pass the whole arrary arr to the called function. The called function expecting this
call must be appropriately defined. The largest function header might look like:
void largest (int arr[], int n)
Example program: To find the highest number from the given numbers
#define N 4
void largest(int arr[], int n);
void main()
{
int arr[N] = {4,7,12,9};
largest(arr,N);
17
getch();
}
void largest(int arr[], int n)
{
int i, max, count;
max = arr[0];
for(i=1;i<n;i++)
{
if(arr[i]>max)
{
max = arr[i];
count = i;
}
}
printf("The max number is %d found at location %d", max,count);
}
7.9.2 Two Dimensional Arrays
Like simple arrays, we can pass multi-dimensional arrays to functions. The approach is
similar to the one we did with one-dimensional arrays. The rules are simple:
1. The function must be called by passing only the array name.
2. In the function definition, we must indicate that the array has two-dimensions
by including two sets of brackets.
3. The size of the second dimension must be specified.
4. The prototype declaration should be similar to the function header.
Example program: Add 2 2x2 arrays and display the results using functions.
#define m 2
#define n 2
void readArray(int arr[][n]);
void computeSum(int arr1[][n], int arr2[][n], int arr3[][n]);
void displayArray(int arr[][n]);
void main()
{
int x[m][n], y[m][n], z[m][n];
printf("\n First table:\n");
readArray(x);
printf("\n Second table:\n");
readArray(y);
computeSum(x,y,z);
18
printf("\nDisplaying the sum \n\n");
displayArray(z);
}
void readArray(int arr[][n])
{
int i, j;
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
{
scanf("%d", &arr[i][j]);
}
}
}
void computeSum(int arr1[][n], int arr2[][n], int arr3[][n])
{
int i,j;
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
{
arr3[i][j] = arr1[i][j] + arr2[i][j];
}
}
}
void displayArray(int arr[][n])
{
int i,j;
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
{
printf("%4d",arr[i][j]);
}
printf("\n");
}
}
Quick exercise:
1. Describe the array that is defined in each of the following statements. Indicate what
values are assigned to the individual array elements.
a) float f[8] = {2., 3., 5.,7.};
b) char flag[5] = “TRUE”;
c) int p[2][4] = {1,1,2,2,3,3,4,4};
d) int p[2][4] = {
{1,3,5,7},
{2,3,4,6}
19
};
e)char colors[3][6]={“red”,”green”,”blue”};
2. Write an appropriate array definition:
a) define one-dimensional, 12-element integer array called w. Assign the values
1,3,5,7,9,11,13,15,17,19,21,23 to the array elements.
b) define one-dimensional character array called point. Assign the string
“NORTH” to the array elements.
c) define one-dimensional, 5-element character array called vowels. Assign the
characters ‘a’,’e’,’i’,’o’,’u’.
d) define two-dimensional, 3 x 4 integer array called x. Assign the following
values to the array elements:
10
0
0
12
20
32
14
43
23
0
0
0
Practice:
1. Describe the output generated by each of the following programs:
a) int i;
int array[5] = {1,2,3};
for (i=0; i<=4; i++){
printf("element number %d is %d\n", i+1, array[i]);
}
b) char str[]="abcdefghijklmn";
char vowels[]="aeiou";
int i, j;
for (j=0; vowels[j]!=’\0’; j++){
for (i=0; str[i]!=’\0’; i++){
if (str[i]==vowels[j]){
str[i]=’Y’;
break;
}
}
}
printf("string=%s\n", str);
c) #include <stdio.h>
void main(void)
{
int i, charges[5]={7,8,7,6,7};
printf("elements of charges[] are ");
for (i=0;i<5;i++){
printf("%d ", charges[i]);}
zap(charges, 5); /* function call will affect charges */
printf("\nnow elements of charges[] are ");
for (i=0;i<5;i++){
printf("%d ", charges[i]);}
20
}
void zap(int array1[], int size)
{
int i;
for (i = 0; i < size; i++) {
array1[i] = 0; /* sets all elements to 0 */
}
}
d) #include<stdio.h>
#include<string.h>
main( )
{
char str1[] = “The Pentagon”;
char str2[] = “lost world”;
printf (“%s”, strcpy(str1,str2));
}
e) int student[3][3] = {{1,4,7}, {2,5,8}, {3,6,9}};
printf(“Mark = %d\n”, student[1][2]);
printf(“Mark = %d\n”, student[2][1]);
**********************************************************************************
Please bring all the errors to my notice either by sending an email (mpelmo@gmail.com/
mpelmo@sherubtse.edu.bt) or in person. I will appreciate your kind gesture!
***********************************************************************************
21
8. Structures and Unions
8.1 Structure
A scalar variable holds a single value of a single type. An array holds several values of a
single type. It is sometimes convenient to be able to group together items of information
which are of different types. For example: an employee’s number, name, age and
position are logically related, but these pieces of data are of different types and so are not
suitable for storage in an array. A structure allows the programmer to group together
data items of different types.
Thus, a single structure can contain integer elements, floating-point elements and
character elements. The individual structure elements are referred to as members.
8.2 Defining Structures
A structure is a collection of related data items stored in one place and can be
referenced by more than one names. Usually these data items are different basic data
types. Therefore, the number of bytes required to store them may also vary.
In general terms, the composition of the structure can be defined as:
struct struct_name{
member 1;
member 2;
………..
member m;
};
The keyword struct tells the compiler that a structure is being declared; struct_name is
a name/tag that identifies structures; and member 1, member 2,and member m; are
individual member/field declarations. The individual members can be ordinary variables,
pointers, arrays or other structures. The member names within a particular structure must
be distinct from one another and individual members cannot be initialized within a
structure type declaration.
For example, to store and process a employee’s record with the elements number
1
(employee number), name, age and position, we can declare the following structure
template.
Here, struct is a keyword that tells the compiler that a structure template/composition is
being declared and Employee is a tag/structure name that identifies structure. Tag is not a
variable; it is a label for the structure’s template. Note that there is a semicolon after the
closing curly brace.
A structure tag is simply a label for the structure’s template but you name the structure
tag using the same rules for naming variables.
Compiler will not reserve memory for a structure or define a new variable. It just defines
a new datatype, called Employee. Now that we’ve defined the new datatype, we can
define variables to be of type Employee (just as we can define variables to be of type
int, char, float):
Structure variables can be declared in one of the following ways:
1. struct Employee{
int number;
char name[30];
int age;
char position[30];
}emp1,emp2;
2. struct{//no tag
int number;
char name[30];
int age;
char position[30];
}emp1,emp2;
3.
struct Employee{
int number;
char name[30];
int age;
char position[30];
};
Then in programs we can declare the structure something like this:
struct Employee emp1,emp2;
2
The above three ways are used to declares two variables, emp1 and emp2, to be of type
Employee.
Each of these structure variables has four fields:
number, name, age and position
8.3 Accessing the Structure Elements/members
A structure element can be accessed and assigned a value by using the structure
variable name, the dot operator (.) and the element’s name.
Example:
emp1.number = 4321;
emp1.age = 34;
emp1.name = Pema Tenzin
emp1.position = lecturer
strcpy(emp1.name, "Tashi Tsheden");
scanf("%s", emp1.position);
To print out the contents of this structure we could do it as follows:
printf(“Employee number: %d\n”, emp2.number);
printf(“Name: %s\n”, emp2.name);
printf(“Age: %d\n”, emp2.age);
printf(“Position: %s\n”, emp2.position);
It is often a good idea to define a function to print out structures of this type (saves you
rewriting this over and over; makes your program easier to understand, improve,
debug,…):
3
void printEmployee (struct Employee e)
{
printf("Employee number: %d\n", e.number);
printf("Name: %s\n", e.name);
printf("Age: %d\n", e.age);
printf("Position: %s\n", e.position);
}
8.4 Initializing the structure members
The members of a structure variable can be assigned initial values in much the same
manner as the elements of an array. The initial values must appear in the order in which
they will be assigned to their corresponding structure members, enclosed in braces and
separated by commas. The general form is:
struct tag variable = {value 1, value 2,…,value m};
where value 1 refers to the value of the first member, value 2 refers to the value of the
second member, and so on.
Example: illustrates the assignment of initial values to the members of a structure
variable
#include<stdio.h>
struct Employee{
int number;
char name[30];
int age;
char position[30];
};
void printEmployee(struct Employee e);
void main()
{
struct Employee emp1 = {1234, "Tashi Tsheden", 32, "lecturer"};
printfEmployee(emp1);
}
void printEmployee(struct Employee e)
{
printf("Employee number: %d\n",e.number);
printf("Name: %s\n", e.name);
printf("Age: %d\n", e.age);
printf("Position: %s\n",e.position);
}
Sample output:
4
Example: To read and print employee record.
#include<stdio.h>
struct Employee{
int number;
char name[30];
int age;
char position[30];
}emp1;
void readEmployee();
void printEmployee(struct Employee e);
void main()
{
void readEmployee();
printEmployee(emp1);
}
void readEmployee()
{
printf("Enter employee number:");
scanf("%d", &emp1.number);
printf("Enter name:");
scanf("%s", &emp1.name);
printf("Enter position:");
scanf("%s",&emp1.position);
printf("Enter age:");
scanf("%d", &emp1.age);
}
void printEmployee(struct Employee e)
{
printf("\nEmployee number: %d",e.number);
printf("\nName: %s", e.name);
printf("\nAge: %d", e.age);
printf("\nPosition: %s",e.position);
}
Sample output:
Example: Passing structure to a function and function returning a structure
/* To read and print two employee data */
#include<stdio.h>
5
struct Employee{
int number;
char name[30];
int age;
char position[30];
}emp1,emp2;
struct Employee readEmployee();
void printEmployee(struct Employee e);
void main()
{
printf("Enter information for a employee\n\n");
emp1 = readEmployee();
emp2 = readEmployee();
printf("\n\nDisplay information for a employee:\n\n");
printEmployee(emp1);
printEmployee(emp2);
}
// Function returns a structure
struct Employee readEmployee()
{
struct Employee emp;
printf("\nEnter employee number:");
scanf("%d", &emp.number);
printf("Enter name:");
scanf("%s", emp.name);
printf("Enter age:");
scanf("%d", &emp.age);
printf("Enter position:");
scanf("%s",emp.position);
return emp;
}
void printEmployee(struct Employee e)
{
printf("\nEmployee number: %d\n",e.number);
printf("Name: %s\n", e.name);
printf("Age: %d\n", e.age);
printf("Position: %s\n",e.position);
}
Sample output:
6
8.5 Nested Structures
Structures can be nested, i.e. structures within structures. For example, suppose
we defined a structure template as follows:
struct Address {
long int c_number;
char dzongkhag[20];
};
We could then incorporate this into our Employee structure template as follows:
struct Employee{
int number;
char name[30];
int age;
char position[30];
struct Address{
long int c_number;
char dzongkhag[20];
} addr;
}emp1;
OR
struct Address{
long int c_number;
char dzongkhag[20];
};
struct Employee{
int number;
char name[30];
int age;
char position[30];
struct Address addr;
}emp1;
Example: Illustrates nested structures.
#include<stdio.h>
struct Employee
{
int number;
char name[30];
int age;
char position[30];
struct Address
{
long int c_number;
char dzongkhag[20];
} addr;
}emp1;
7
void printEmployee(struct Employee e);
void main()
{
printf("Enter employee number:");
scanf("%d", &emp1.number);
printf("Enter name:");
scanf("%s", &emp1.name);
printf("Enter position:");
scanf("%s",&emp1.position);
printf("Enter age:");
scanf("%d", &emp1.age);
printf("Enter contact number:");
scanf("%ld", &emp1.addr.c_number);
printf("Enter dzongkhag:");
scanf("%s", &emp1.addr.dzongkhag);
printfEmployee(emp1);
getch();
}
void printEmployee(struct Employee e)
{
printf("\nEmployee number: %d",e.number);
printf("\nName: %s", e.name);
printf("\nAge: %d", e.age);
printf("\nPosition: %s",e.position);
printf("\nContact number: %ld", e.addr.c_number);
printf("\nDzongkhag: %s",e.addr.dzongkhag);
}
Sample output:
8.6 Arrays of Structures
Suppose you would like to store the information of 100 employees. It would be tedious
and unproductive to create 100 different Employee variables and work with them
8
individually. It would be much easier to create an array of Employee structures.
Structures of the same type can be grouped together into an array. We can declare an
array of structures just like we would declare a normal array of variables.
For example, to store and manipulate the information contained in 100 employee
records, we use the following structure template:
struct Employee{
int number;
char name[30];
int age;
char position[30];
}emp[100];
OR
struct Employee{
int number;
char name[30];
int age;
char position[30];
};
struct Employee emp[100];
These statements declare 100 variables of type Employee (a structure). As in arrays, we
can use a subscript to reference a particular Employee structure or record.
For example, to print the name of the seventh employee, we could write the following
statement:
printf(“%s”, emp[6].name);
Example: illustrates the use of arrays in structures
/* Reads in the information of two employees and display */
#include<stdio.h>
struct Employee
{
int number;
char name[30];
int age;
char position[30];
}emp1[2];
void printEmployee(struct Employee e[],int i);
void main()
{
int i;
for(i=0;i<2;i++)
{
printf("\nEnter record for employee # %d\n", i+1);
printf("Enter employee number:");
scanf("%d", &emp1[i].number);
9
printf("Enter name:");
scanf("%s", &emp1[i].name);
printf("Enter position:");
scanf("%s",&emp1[i].position);
printf("Enter age:");
scanf("%d", &emp1[i].age);
}
for(i=0;i<2;i++)
{
printf("\n\nDisplay record for Employee # %d", i+1);
printEmployee(emp1,i);
}
}
void printEmployee(struct Employee e[],int i)
{
printf("\nEmployee number: %d",e[i].number);
printf("\nName: %s", e[i].name);
printf("\nAge: %d", e[i].age);
printf("\nPosition: %s",e[i].position);
}
Sample output:
8.7 Difference between arrays and structures.
Arrays:
- same data type.
10
-
-
Memory (array size) is fixed.
Accessing an element in array takes constant time. e.g. 5th element in an array
can be accessed as array[4] i.e. searching/accessing an element in array takes
comparatively less time than in structures.
Adding/deleting an element in the array is comparatively difficult since the data
already present in the array needs to be moved.
Structures:
- different data type.
- Memory (structure size) can be changed dynamically.
- Accessing an element in a list takes more time comparatively since we need to
traverse through the list.
- Adding/deleting takes less time than in arrays.
8.8 User-defined data types (typedef)
The typedef is the user-defined new data types. Once a user-defined data type has been
established, then new variables, arrays, structures can be declared in terms of this new
data type. In general terms, a new data type is defined as:
typedef type new-type;
where type refers to an existing data type, and new-type refers to the new user-defined
data type.
Example:
typedef int age;
In this declaration age is a user-defined data type, which is equivalent to type int.
Hence, the variable declaration, age male, female; is equivalent to writing int
male, female;
Similarly, the declaration
typedef float height[50];
height male, women;
defines height as a 50-element , floating point array type. Another way to express this is
typedef float height;
height men[50], women[50];
There is one application of typedef that you may find especially useful; it can be used to
simplify the declaration of structure, union, or enumeration variables.
11
In defining structures, it eliminates the need to repeatedly write struct tag whenever a
structure is referenced. For example, consider the following declaration;
struct employee{
int number;
char name[30];
int age;
char position[30];
};
To declare a variable of type employee you must use a declaration like this:
struct employee e;
While there is certainly nothing whatsoever wrong with this declaration, it does require
the use of two identifiers: struct and employee. However, if you apply typedef to the
declaration of employee, as shown here,
typedef struct employee{
int number;
char name[30];
int age;
char position[30];
}Emp;
then you can declare variables of this structure using the following declaration:
Emp e;
Example: Modify the previous program by using typedef
#include<stdio.h>
typedef struct Employee{
int number;
char name[30];
int age;
char position[30];
}Emp;
Emp readEmployee();
void printfEmployee(Emp e);
void main()
{
Emp e1,e2;
printf("Enter information for a employee\n\n");
e1 = readEmployee();
e2 = readEmployee();
printf("\n\nDisplay information for a employee:\n\n");
printfEmployee(e1);
printfEmployee(e2);
}
12
Emp readEmployee()
{
Emp emp;
printf("Enter employee number:");
scanf("%d", &emp.number);
printf("Enter name:");
scanf("%s", emp.name);
printf("Enter age:");
scanf("%d", &emp.age);
printf("Enter position:");
scanf("%s",emp.position);
return emp;
}
void printfEmployee(Emp e)
{
printf("\nEmployee number: %d\n",e.number);
printf("Name: %s\n", e.name);
printf("Age: %d\n", e.age);
printf("Position: %s\n",e.position);
}
You can see how easy it is to declare structure variable using typedef. It is certainly
worth doing if you declare several structure variables. Using typedef can make your
code easier to read.
8.9 Enumeration (enum) data type
This is another user-defined data type consisting of a set of named constants called
enumerators. Using a keyword enum, it is a set of integer constants represented by
identifiers. The syntax is shown below:
enum identifier{value1, value 2, vauue3,…value n};
the identifier is a user-defined enumerated data type which is used to declare
variables as follows:
enum identifier v1,v2, …vn;
The compiler automatically sets integer digits beginning with 0 , unless specified
otherwise to all the enumeration constants and are incremented by 1.
Example:
enum days{Mon,Tue,Wed,Thu,Fri,Sat,Sun};
Creates a new data type, enum days, in which the identifiers are set automatically to
the integers 0 to 6. To number the days 1 to 7, use the following enumeration:
enum days {Mon = 1, Tue, Wed, Thu, Fri, Sat, Sun};
Or we can re-arrange the order:
13
enum days {Mon, Tue, Wed, Thu = 7, Fri, Sat, Sun};
Then, the integer numbers assigned are:
Mon
Tue
Wed
Thu
Fri
Sat
Sun
=
=
=
=
=
=
=
0
1
2
7
8
9
10
Example: illustrates enum
#include<stdio.h>
enum days{mon = 1,tue,wed,thu,fri,sat,sun};
main()
{
enum days count; //declaring enum data type
printf("Simple day count using enum\n\n");
for(count = mon; count<=sun; count++)
{
printf("%d\n",count);
}
}
Sample output:
8.10 Unions
Unions are a concept borrowed from structures and therefore follow the same syntax
as structures. However there is major distinction between them in terms of storage. In
structures, each member has its own storage location; where as all the members of a
union shares the same location. This implies that, although a union may contain many
members of different types, it can handle only one member at a time. The number of
bytes used to store a union must be at least enough to hold the largest member. Like
structures, a union can be declared using the keyword union as follows:
union tag{
member 1;
member 2;
-------member m;
};
14
Example:
union item
{
int p;
float q;
char n;
};
Unions may be initialized when the variable is declared. But, unlike structures, it can be
initialized only with a value of the same type as the first union member.
Example:
union item code = {12};
is valid but the declaration
union item code = {12.5};
is invalid. This is because the type of the first member is int. Other members can be
initialized by either assigning values or reading from the keyboard.
Example: to print the contents of the unions. Only one at a time!
#include<stdio.h>
union item{
int p;
float q;
char n;
}code;
void writeOutput(union item c);
main()
{
code.p = 12;
code.q = 23.45;
code.n = 'C';
printf("Display the union storage content\nONLY one at a time\n");
writeOutput(code);
printf("\n\nSee, some of the contents are rubbish!\n");
code.n = 'd';
code.p = 13;
code.q = 34.32;
writeOutput(code);
printf("\n\nSee, another inactive contents, rubbish!\n");
code.n = 'u';
code.q = 13.23;
code.p = 32;
15
writeOutput(code);
printf("\n\nSee, another inactive contents again, rubbish!”);
printf(“\nBetter use struct data type!!\n");
}
void writeOutput(union item c)
{
printf("\n p = %d", c.p);
printf("\n q = %f",c.q);
printf("\n n = %c",c.n);
}
Sample output:
8.11 Size of Structures and Unions
The sizeof() function is used to tell us the size of a structure, union, or any
variables. The size of a structure is equal to or greater than the sum of the sizes of its
members.
Example:
struct s{
char c;
int i;
float f;
}svar;
Here, sizeof(svar) = 7 (1+2+4) atleast
union u{
char c[10];
int i;
}uvar;
Here, sizeof(uvar) = 12(10+2) atleast
The size of a union is always equal to the size of its largest member.
16
Example:
union u{
char c;
int i;
float f;
}uvar;
Here,sizeof(uvar) = 4
8.12 Casting
Casting will force an expression to be a specific type by using a cast, or typecast
operation. The general form of cast is:
(type)expression;
where type is a valid C data type.
Example:
The expression
(float)x/2;
will make sure that the expression x/2 evaluates to type float.
Example:
main()
{
int i,j;
float k;
i = 5;
j = 3;
k = i/j; // this will print wrong value
k = (float)(i/j); // this will print correct value
printf(“%f”, k);
}
Quick exercise:
1. What will be the output generated by this program:
#include<stdio.h>
typedef union{
int i;
float f;
}udef;
void func(udef u);
main()
{
udef u;
u.i = 100;
17
u.f = 0.5;
func(u);
printf(“Values in main:\n”);
printf(“%d\n”,u.i);
printf(“%f\n”,u.f);
}
void func(udef u)
{
u.i = 200;
printf(“Values in function:\n”);
printf(“%d\n”,u.i);
printf(“%f\n”,u.f);
}
2. Which of the following are correct statements for declaring one-dimensional
array of structures of type struct item_bank?
a)
b)
c)
d)
e)
int item_bank items[10];
struct items[10] item_bank;
struct item_bank items(10);
struct item_bank items[10];
struct items item_bank[10];
3. What will be the output of the following program?
a)
main()
{
struct xyz
{
int xyz;
};
struct xyz xyz;
xyz.xyz = 10;
printf("%d",xyz.xyz);
}
b)
struct xxx{
int i;
char j;
};
void abc(struct xxx aaa);
main()
{
struct xxx zzz = {1,'a'};
abc(zzz);
}
void abc(struct xxx aaa)
{
printf("%d.....%c",aaa.i,aaa.j);
}
*****************************************************************************
Please bring all the errors to my notice either by sending an email (mpelmo@gmail.com/
mpelmo@sherubtse.edu.bt) or in person. I will appreciate your kind gesture!
*****************************************************************************
18
9 Pointers
9.1 What is a pointer?
Before defining pointer lets 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 PC's the size of an integer variable is 2
bytes, and that of a long integer is 4 bytes. In C the size of a variable type such as an
integer need not be the same on all types of machines. 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 2 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 2 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.
A pointer is a variable that contains the memory address (i.e. the memory location) of
another variable (k), where, the actual data (2 in above example) is stored.
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 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.
1
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.
Now 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 address of k and copies that to the contents of
our pointer ptr. Now, ptr is said to "point to" k.
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",*ptr);
to print to the screen the integer value stored at the address pointed to by ptr;.
Example: Program to print the address of a variable along with its value and shows how
to access the value stored in a variable using pointer.
#include<stdio.h>
main()
{
int a =1, b=2;
int *ptr; // declare a pointer variable ptr
ptr = &a; //assign address of a to ptr
printf("a = %d is stored at address %u\n", a, &a);
printf("b = %d is stored at address %u\n", b, &b);
printf("ptr = %u is stord at address %u\n", ptr, &ptr);
printf("ptr points to the value %d\n", *ptr);
}
Sample output:
2
Note that we have used %u format for printing address values. Memory addresses are
unsigned integers.
Example: Program to assign a value to the address of the variable using pointer
#include<stdio.h>
main()
{
int k;
//declare an integer variable k
int *ptr; //declare a pointer variable ptr
ptr = &k; //assign address of k to ptr
*ptr=7;
// copy 7 to the address pointed to by ptr
printf(" Address of k = %u\n”,&k);
printf(“Value of ptr = %u, stored at address = %u\n”,ptr, &ptr);
printf(“Value of k = %d”, *ptr);
}
The statement *ptr = 7; puts the value 7 at the memory location whose address is the
value of ptr. We know that the value of ptr is the address of k and therefore, k is
assigned a value 7. Thus, it is equivalent to k = 7;
Sample output:
9.2 Chain of pointers
It is possible to make a pointer to point to another pointer, thus creating a chain of
pointers as shown.
p2
p1
variable
address 2
address 1
value
Here, the pointer variable p2 contains the address of the pointer variable p1, which points
to the location that contains the desired value. This is known as multiple indirections.
3
A variable that is a pointer to a pointer must be declared using additional indirection
operators symbols in front of the name.
Example:
int **p2;
This declaration tells the compiler that p2 is a pointer to a pointer of int type. Remember,
the pointer p2 is not a pointer to an integer, but rather a pointer to an integer pointer.
We can access the target value indirectly pointed to by pointer by applying the indirection
operator twice.
Example: Program to illustrate the use of pointer to a pointer (**p2)
main()
{
int x, *p1, **p2;
x = 100;
p1 = &x;
/* address of x */
p2 = &p1; /* address of p1 */
printf("p1 = %d\n", *p1);
printf("p2 = %d",**p2);
}
Sample output:
9.3 Pointer Expressions
Like other variables, pointer variables can be used in expressions.
Example:
If p1 and p2 are properly declared and initialized pointers, then the following statements
are valid.
y =
sum
z =
*p2
*p1 * *p2;
same as (*p1) * (*p2)
= sum + *p1;
5* - *p2/ *p1;
same as (5*(-(*p2)))/(*p1)
= *p2 + 10;
Note that there is a blank space between / and *. The symbol /* is considered as the
beginning of a comment and therefore the statement fails.
Example:
main()
{
int a,b,sum1,sum2, *p1,*p2;
a = 15;
b = 25;
4
p1= &a;
p2= &b;
sum1 = a+b;
sum2 = *p1 + *p2;
printf("sum1 = %d, sum2 = %d", sum1,sum2);
Sample output:
Example: illustrate the use of pointers in arithmetic operations.
main()
{
int a,b,*p1,*p2,x,y,z;
a = 12;
b=4;
p1 = &a;
p2 = &b;
x = *p1 * *p2 - 6;
y = 4 * - *p2 / *p1 + 10;
z = *p1 * *p2 - 3;
printf("a = %d, b = %d\n", a,b);
printf("x = %d, y = %d, z = %d", x,y,z);
Sample output:
9.4 Pointers and arrays
A special relationship exists between pointers and arrays. An array name without
brackets is a pointer to the array’s first element. So, if a program declared an array
data[], data (array’s name) is the address of the first array element and is equivalent to
the expression &data[0] that means references the address of the array’s first element.
data equivalent to &data[0] or a pointer to the array’s first element.
The array’s name is, therefore a pointer to the array’s first element and therefore to the
string if any. Element of an array are stored in sequential memory locations with the first
element in the lowest address.
Subsequent array elements, those with an index greater than 0 are stored at higher
addresses.
Also, if an array named list[] is a declared array, the expression *list is the array’s
first
5
element, *(list + 1) is the array’s second element, and so on. Generally, the
relationship is as follows:
*(list) == list[0] //first element
*(list + 1) == list[1] //second element
*(list + 2) == list[2] //third element
…
…
*(list + n) == list[n] //the nth element
So, you can see the equivalence of array subscript notation and array pointer notation.
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 the pointer at the first integer in
an array */
And then we could print out our array either using the array notation or by dereferencing
our pointer.
Example: Accessing one dimensional array elements using array notation and the pointer
//Array
//Pointer
main()
{
int my_array[] = {1,23,17,4,-5,100};
main()
{
int my_array[] = {1,23,17,4,-5,100};
int *ptr, i;
ptr = &my_array[0]; //point the pointer to the
first element of an array
ptr = my_array;
//same as above
printf("\n Print array elements: \n");
for(i=0;i<6;i++)
{
printf(" my_array[%d] = %d\n",
i, my_array[i]);
}
}
Sample output:
printf("\n Print array elements: \n");
for(i=0;i<6;i++)
{
printf(" ptr+%d = %d\n",i,*(ptr+i));
}
}
Sample output:
6
Now, change the line printf("ptr+%d = %d\n",i,*(ptr+i)); to
printf("ptr + %d = %d\n",i, *ptr++);
Run and observe the result. Then change it to:
printf("ptr + %d = %d\n",i, *(++ptr)); Run again and observe the result.
9.5 Pointers and character strings
In C, strings are treated like character arrays. Therefore they are declared and initialized
as follows:
char str[6] = “hello”;
The compiler automatically inserts the null character ‘\0’ at the end of the string. C
supports an alternative method to create strings using pointer variables of type char.
Example:
char *str = “hello”;
This creates a string and then stores its address in the pointer variable str. The pointer
str now points to the first character of the string “hello” as:
h
e
l
L
0
\0
str
We can then print the content of the string str using either printf or puts function as
follows:
printf(“%s”,str);
puts(str);
Remember, although str is a pointer to the string, it is also the name of the string.
Therefore, we do not have to use indirection operator (*) here. Like in one-dimensional
arrays, we can use a pointer to access the individual characters in a string.
Example: To access individual characters in a string using pointer.
main()
{
char *str;
str="hello";
while(*str != '\0')
{
printf("%c is stored at address %u\n",*str,str);
*str++;
}
}
Sample output:
7
9.6 Array of Pointers
A multidimensional array can be expressed in terms of an array of pointers. The newly
defined array will have one less dimension than the original multidimensional array. Each
pointer will indicate the beginning of a separate (n-1) dimensional array.
A two dimensional array can be defined as a one-dimensional array of pointers as:
data-type *array[rows];
instead of
data-type array[rows][cols];
Example:
Suppose x is a two-dimensional integer array having 3 rows and 4 columns, we can
define x as a one-dimensional array of pointers by writing
int *x[3];
here, x[0] points to the beginning of the first row, x[1] points to the beginning of the
second row, and so on. Note that the number of elements within each row is not explicitly
specified.
An individual array element, such as x[2][3], can be accessed by writing
*(x[2] + 3);
In this expression, x[2] is a pointer to the first element in row 2, and (x[2]+3) is a
pointer to the fourth element (located at 3) within row 2. Therefore, *(x[2] + 3) refers
to x[2][3].
Example: Program to read and display 2-dimensional array having 2 rows and 2
columns using array of pointers.
#define m 2
#define n 2
main()
{
int i,j;
int *x[m];
//Read array
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
{
printf("\nx[%d]=",i);
scanf("%d", x[i]+j));
}
}
8
printf("\nDisplay array \n\n");
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
{
printf("%2d",*(x[i]+j));
}
printf("\n");
}
Sample output:
One important use of pointers is in handling of a table of strings. Consider the following
array of strings:
char name[3][25];
this says that the name is a table containing three names, each with a maximum length of
25 characters (including null character). The total storage requirements for the name table
are 75 bytes. We know that rarely the individual strings will be of equal lengths.
Therefore, instead of making each row a fixed number of characters, we can make it a
pointer to a string of varying length.
Example:
char *name[3] = {
“New Zealand”,
“Australia”,
“India”
};
In these declarations, name is an array of three pointers to characters, each pointer
pointing to a particular name as:
name[0] Æ New Zealand
name[1]Æ Australia
name[2]Æ India
This declaration allocates only 28 bytes, sufficient to hold all the characters.
To print out the names, we write as:
for(i=0;i<3;i++)
{
printf(“%s\n”, name[i])
}
9
To access the jth character in the ith name, we write as:
*(name[i]+j)
9.7 Pointers as arguments to functions
All C functions have an identical template, composed of a unique name, a return type,
argument(s), and a body. Function names are only identifiers that are treated as pointers
without explicitly being declared. The return type of a function is understood to represent
its value. A function body contains expressions, keywords, and statements that control
the actions that are to be performed. Functions may optionally be declared to accept
arguments. They can be passed as arguments by value and by reference (or by address).
When an argument is passed by value, the data item is copied to the function. Thus, any
alteration made to the data item within the function is not carried into the calling routine.
When an argument is passed by reference, however (i.e. when a pointer is passed to a
function), the address of a data item is passed to the function. Any change that is made to
the data item (i.e. to the contents of the address) will be recognized in both the function
and the calling routine.
Example: Program to illustrate call by value and call by reference
Void f(int p);
main()
{
int x = 9;
f(x); //f can't change x
printf("\nx after calling f()=%d",x);
}
void f(int p)
{
p+=10; //p changed but x unchanged
printf("p in f()= %d", p);
}
void f(int *p);
void main()
{
int x = 9;
f(&x); //call by reference
printf("\nx after calling f()=%d",x);
}
void f(int *p)
{
*p+=10; // changes the value of x
printf("p in f()= %d",*p);
}
Sample output:
Sample output:
Example: Program to illustrate a function returning more than one value at a time using
call by reference.
void sp(int num,int *s ,int *p);
void main()
{
int sum,product,num;
printf("Enter number:");
scanf("%d", &num);
sp(num,&sum,&product);
printf("\n Sum = %d, Product = %d ", sum,product);
}
10
void sp(int num,int *s ,int *p)
{
*s = num + num;
*p = num * num;
}
Since the addresses are passed, any changes made in values stored at the addresses
contained in variables would make the change effective even in main.
Thus the limitation of the return statement, which can return only one value from a
function at a time, has been overcome, and it is now possible to return two values from
the called function.
9.8 Functions returning pointers
We have seen so far that a function can return a single value by its name or return
multiple values through pointer parameters. Since pointers are data types in C, we can
also force a function to return a pointer to the calling function.
Example:
int *f(int *i);
main( )
{
int *p,j;
p=f(&j);
printf(“%d”, *p);
}
int *f(int *i)
{
*i = 20;
return(i); //address of i
}
Sample Output:
20
The function f receives the address of the variables j. Using the pointer variable i, the
value of i is assigned to 20 and then returns the address of its location. The returned value
is then assigned to the pointer variable p in the calling function. In this case, the address
of j is returned and assigned to p and therefore the output will be the value of j which is
20.
9.9 Pointers and Structures
As you may know, we can declare the form of a block of data containing different data
types by means of a structure declaration. The beginning address of a structure can be
accessed in the same manner as any other address, through the use of the address (&)
operator. Thus if variable represents a structure-type variable, then &variable
11
represents the starting address of that variable. We can declare a pointer variable for a
structure by writing
struct tag *ptvar
where, tag is the structure name and ptvar is the name of the pointer variable. We can
then assign the beginning address of a structure variable to this pointer by writing
ptvar=&variable
Example:
Consider the following structure declaration
typedef struct employee {
char fname[20]; /* last name */
char lname[20]; /* first name */
int age; /* age */
float rate; /* e.g. 12.75 per hour */
}pdata;
pdata emp, *pemp;
In this example, emp is a structure variable to type pdata, and
pemp is a pointer variable whose object is a structure variable
of type pdata. Thus the beginning address of pdata can be
assigned to pemp by writing
pemp= &emp;
An individual structure member can be accessed in terms of its corresponding pointer
variable by writing
ptvar->member
where ptvar refers to a structure-type pointer variable and the -> is comparable to the
period(.) operator. Thus the expression
ptvar->member is equivalent to writing variable.member
Example: To read and print employee record using pointer
#include<stdio.h>
typedef struct Employee{
int number;
char name[30];
int age;
char position[30];
}emp1;
void printEmployee(emp1 *e);
void main()
{
emp1 emp, *pemp;
pemp = &emp;
12
printf("Enter employee number:");
scanf("%d", &pemp->number);
printf("Enter name:");
scanf("%s", &pemp->name);
printf("Enter position:");
scanf("%s",&pemp->position);
printf("Enter age:");
scanf("%d", &pemp->age);
printEmployee(pemp);
}
void printEmployee(emp1 *e)
{
printf("\nDisplay employee information\n”);
printf("\nEmployee number: %d",e->number);
printf("\nName: %s", e->name);
printf("\nAge: %d", e->age);
printf("\nPosition: %s",e->position);
}
Sample output:
9.10 Dynamic memory allocation
In our earlier programs, we defined the array such as int arr[10]; This is a
conventional array definition. Now, as we look at pointer we can also define the array as
a pointer variable. Thus we can define int *arr; rather than int arr[10]. A
conventional array definition results in a fixed block of memory being reserved at the
beginning of program execution, whereas this does not occur if the array is represented in
terms of a pointer variable. Therefore, the use of a pointer variable to represent an array
requires some type of initial memory assignment before the array elements are processed.
This process of allocating memory at run time is known as dynamic memory allocation.
The malloc library function is used to dynamically allocate memory for the array of
pointer variable.
Example:
Suppose x is a one-dimensional, 10 element array of integers. It is possible to define x as
a pointer variable rather than an array. Thus we can write
13
int *x; rather than int x[10]; or #define SIZE 10
int x[SIZE];
x is not automatically assigned a memory block when it is defined as a pointer variable,
whereas a block of memory large enough to store 10 integer quantities will be reserved in
advance when x is defined as an array.
To assign sufficient memory for x, we can make use of the library function malloc, as
follows:
x= (int *) malloc(10*sizeof(int))
This function reserves a block of memory whose size (in bytes) is equivalent to 10
integer quantities.
Example: Program to read and print one-dimensional array elements. The size of an
array is specified at run-time.
void readinput(int n, int *arr);
void writeoutput(int n, int *arr);
main()
{
int *arr, n;
printf ("How many array elements to enter:");
scanf("%d", &n);
//allocate memory
arr = (int *) malloc(n * sizeof(int));
readinput(n, arr);
writeoutput(n,arr);
}
void readinput(int n, int *arr)
{
int i;
printf("\n Read the array elements:\n");
for(i=0;i<n;i++)
{
printf("arr[%d]= ", i);
scanf("%d", arr+i);
}
}
void writeoutput(int n, int *arr)
{
int i;
printf("\n Display the array elements:\n");
for(i=0;i<n;i++)
{
printf("arr[%d]= %d\n", i, *(arr+i));
}
}
Sample output:
14
Quick exercise:
1. What is the output of the following program?
a) void main()
{
int i=3;
int *j;
int **k;
j=&i;
k=&j;
printf(“%d”,**k);
}
b) void main()
{
int a=5,b=10,c;
int *p=&a,*q=&b;
c=p-q;
printf("%d",c);
}
c. void main()
{
int i=5,j;
int *p,*q;
p=&i;
q=&j;
j=5;
printf("value of i : %d value of j : %d",*p,*q);
}
d. #include<stdio.h>
struct field
{
int a;
15
char b;
};
main()
{
struct field *pb, bit={5, 'A'};
pb= &bit;
pb->a = 89;
pb->b = ‘R’;
printf("%c,%d", bit.b,bit.a);
}
*****************************************************************************
Please bring all the errors to my notice either by sending an email (mpelmo@gmail.com/
mpelmo@sherubtse.edu.bt) or in person. I will appreciate your kind gesture!
*****************************************************************************
16
10. Preprocessor
The C preprocessor is a collection of special statements, called directives that are
executed at the beginning of the compilation process.
The preprocessor directives are shown here:
#define
#ifndef
#endif
#pragma
#ifdef
#else
#line
#if
#elif
#include
#error
#undef
As you can see, all preprocessor directives begin with a # sign and do not end with a
semicolon. In addition, each preprocessing directive must be on its own line. For
example, this will not work:
#include<stdio.h> #include<string.h>
10.1 #define
We have already seen that the #define statement can be used to define symbolic
constants within a C program. At the beginning of the compilation process, all symbolic
constants are replaced by their equivalent text. Thus, symbolic constants provide a form
of shorthand notation that can simplify the organization of a program.
The #define statement can be used for more, however, than simply defining symbolic
constants. In particular, it can be used to define macros; i.e. single identifiers that are
equivalent to expressions, complete statements or groups of statements.
Example:
#include<stdio.h>
#define sqr x * x
void main()
{
int x=5;
printf("%d", sqr);
}
This program contains the macro sqr, which represents the expression x
* x. When the program is compiled, the expression x * x will replace
the identifier sqr within the printf statement, so the printf statement
will become printf("%d", x * x);
#include<stdio.h>
#define sqr x * x
main()
{
int x;
for(x=1; x<5; x++)
{
printf("% square = %d\n", x, sqr);
}
}
1
Sample output:
A macro definition may include arguments, which are enclosed in parenthesis. When a
macro is defined in this manner, its appearance within a program resembles a function
call.
Example: illustrates macros with arguments
#include<stdio.h>
#define sqr(x) x * x
main()
{
int x;
for(x=1; x<5; x++)
{
printf("%d square = %d\n", x, sqr(x));
}
}
There are possible side effects associated with the use of macros, particularly when
calling arguments are involved. In the program below you have to put additional
parenthesis within the macro definition as shown. Otherwise, each appearance of x will
be replaced by i+1 without the parenthesis. Therefore, the result of the macro substitution
will be i+1*i+1. Take for example i = 1, we have 1+1*1+1 =3, which is incorrect (suppose to
be 4 (2*2)).
Example: illustrate the side affects using macros when calling arguments
#include<stdio.h>
#define sqr(x) x * x
main()
{
int i;
for(i=0; i<5; i++)
{
printf("%d squared = %d\n", i+1,
sqr(i+1));
}
}
#include<stdio.h>
#define sqr(x) (x) * (x)
void main()
{
int i;
for(i=0; i<5; i++)
{
printf("%d squared = %d\n", i+1,
sqr(i+1));
}
}
Sample output:
Sample output:
2
Multiline macros can be defined by placing backward slash (\) at the end of each line
except the last. This feature permits a single macro (i.e. a single identifier) to represent a
compound statement.
Example: Program to read and print array elements using macors.
#include<stdio.h>
#define read for(i=0;i<4;i++)\
{\
printf("a[%d]= ", i);\
scanf("%d", &a[i]);\
}
#define print for(i=0;i<4;i++)\
{\
printf("a[%d]=%d",i,a[i]);\
}
main()
{
int i;
int a[4];
printf("Enter array:\n");
read
printf(“\nPrinting array:\n”);
print
}
Sample output:
10.2 #include
An external file containing functions or macro definitions can be included as a part of a
program so that we need not rewrite those functions or macro definitions. This is
achieved by the preprocessor directive
#include “filename”
where filename is the name of the file containing the required definitions or functions.
At this point, the preprocessor inserts the entire contents of filename into the source
code of the program. When the file name is included within the double quotation marks,
the search for the file is made first in the current directory and then in the standard
dirctories. Alternatively this directive is can take the form:
#include<filename>
without double quotation marks. In this case, the file is searched only in the standard
directories. If an included file is not found, an error is reported and compilation is
terminated.
3
Example:
//include.c
#include<stdio.h>
#include<conio.h>
#include "fundef.h"
main()
{
int a,b,s,p;
a = readNum();
b = readNum();
s = sum(a,b);
p = product(a,b);
printf("sum of %d and %d = %d\n", a,b,s);
printf("Product of %d and %d = %d",a,b,p);
}
//fundef.h saved in
C:\TC\INCLUDE
int readNum()
{
int n;
scanf("%d",&n);
return n;
}
int sum(int i, int j)
{
int r;
r = i+j;
return r;
}
int product(int i, int j)
{
int r;
r = i*j;
return r;
}
Sample output:
10.3 #error
The #error directive is used to produce diagnostic messages during debugging. The
general form is
#error error_message
When the #error directive is encountered, it displays the error message and terminates
processing.
Example: When the following program is compiled, the error messages should be
generated as shown.
4
Then correct the error by defining myVal to 2 as the following program and when you
rebuild, it should be OK.
10.4 Conditional Compilation Directives
There are several directives that allow you to selectively compile portions of your
program’s source code. This process is called conditional compilation. The most
commonly used conditional compilation directives are #if,#else,#elif,and
#endif. These directives allow you to conditionally include portions of code based
upon the test condition.
The general form of #if is:
#if TC
action;
#endif
If the TC is true, the action part is compiled. Otherwise, it is skipped. The #endif
directive marks the end of an #if block.
Example: simple #if
#include<stdio.h>
#define MAX 100
main()
{
#if MAX>99
printf(“compiled for array greater than 99.\n”);
#endif
}
This program displays the message on the screen because MAX is greater than 99. This
example illustrates an important point. The expression that follows that #if is evaluated
at compile time. Therefore, it must contain only previously defined identifiers and
constants - no variables may be used.
5
The #else directive works much like the else that is part of the C language. It establishes
an alternative if #if fails. The previous example can be expanded as shown here:
Example: #if/#else
#include<stdio.h>
#define MAX 10
main()
{
#if MAX>99
printf(“Compiled for array greater than 99.\n”);
#else
printf(“Compiled for small array.\n”);
#endif
}
In this case, MAX is defined to be less than 99, so the #if portion of the code is not
compiled. The #else alternative is compiled, however, and the message Compiled for
small array. is displayed.
The #elif directive means “else if” and establishes an if-else-if chain for multiple
compilation options. If the test condition is true, that block of code is compiled and no
other #elif test conditions are tested. Otherwise, the next block in the series is checked.
The general form of #elif is:
#if TC1
Action1
#elif TC2
Action2
#elif TC3
Action3
.
.
.
#elif TCN
ActionN
#endif
Example: #elif
#define
#define
#define
#define
US 0
ENGLAND 1
FRANCE 2
ACTIVE_COUNTRY US
#if ACTIVE_COUNTRY == US
char currency[] = “dollars”;
#elif ACTIVE_COUNTRY == ENGLAND
char currency[] = “pound”;
#else
char currency[] = “franc”;
#endif
6
#ifdef and #ifndef
Another method of conditional compilation uses the directives #ifdef and #ifndef,
which means “if defined” and “if not defined”, respectively. The general form of #ifdef
is:
#ifdef macro_name
Action
#endif
If the macro_name has been previously defined in a #define statement, the block of code
will be compiled.
The general form of #ifndef is:
#ifndef macro_name
Action
#endif
If macro_name is currently undefined by a #define statement, the block of code is
compiled.
Both #ifdef and #ifndef may use an #else or #elif statement.
Example: #ifdef and #ifndef
#include<stdio.h>
#define TED 10
main()
{
#ifdef TED
printf(“Hi Ted\n”);
#else
printf(“Hi anyone\n”);
#endif
#ifndef RALPH
printf( “Ralph is not defined\n”);
#endif
}
10.5 #undef
The #undef directive removes a previously defined definition of the macro name that
follows it. That is it “undefines” a macro. The general form for #undef is:
#undef macro_name
Example: #undef
#define LEN 100
#define WIDTH 100
char array[LEN][ WIDTH];
#undef LEN
#undef WIDTH
/*at this point both LEN and WIDTH are undefined*/
7
Both LEN and WIDTH are defined until the #undef statements are encountered.
Example: Sample using #define, #ifdef, #ifndef, #undef, #else and #endif
#include<stdio.h>
#define chap10 10
#define preprocessor 10.2
main()
{
#ifdef chap10
printf("Chap10 is defined.\n");
#else
printf("Chap10 is not defined.\n");
#endif
#ifndef preprocessor
printf("Preprocessor is not defined.\n");
#else
printf("Preprocessor is defined.\n");
#endif
#ifdef myRevision
printf("MyRevision is defined.\n");
#else
printf("MyRevision is not defined.\n");
#endif
#undef preprocessor
#ifndef preprocessor
printf("preprocessor is not defined.\n");
#else
printf("preprocessor is defined.\n");
#endif
}
Sample output:
10.6 Difference between macros and functions
When calling a function the compiler enters a call-sequence (which takes
time) and allocates a new stack frame for that function (which takes text
stack space) so that the function's body can be executed. After it's done
it enters a returning-sequence phase (which takes time).
A macro does not need anything of the above, because it's preprocessor's job
to expand a macro, it's only about text replacement, not about compiler
stuff or code-generating issues. So time and space is not wasted in doing what a function
would need in order to be executed. Therefore macros are generally used as part of small
8
functions to save the time of calling functions.
That makes functions and macros completely different even if the result of
using both is, in some cases, the same. One must know it's suitable to use
one or the other. For instance: you can not point a pointer to a macro, but you can use
pointers to functions.
One important thing you must understand while using Macros is that TypeChecking is
not done at any point of time.
Quick exercise:
1. Write a program to find the area of a rectangle by defining a macro area, which
represents length * breadth.
2. Write a macro called max that utilizes the conditional operator (?:) to determine the
maximum of a and b, where a and b are integer quantities.
*****************************************************************************
Please bring all the errors to my notice either by sending an email (mpelmo@gmail.com/
mpelmo@sherubtse.edu.bt) or in person. I will appreciate your kind gesture!
*****************************************************************************
9
11. File Handling in C
11.1 What is a File?
Until now, we have been using the functions such as scanf and printf to read and write
data. These are console oriented I/O functions, which always use the terminal (keyboard
and screen) as the target place. This works fine as long as the data is small. However,
many real-life problems involve large volumes of data and in such situations, the consoleoriented I/O operations pose two major problems.
1. It becomes cumbersome and time consuming to handle large volumes of data through
terminals.
2. The entire data is lost when either the program is terminated or the computer is turned
off.
It is therefore necessary to have a more flexible approach where data can be stored on the
disks and read whenever necessary, without destroying the data. This method employs
the concept of files to store data.
A file is a place on the disk where group of related data is stored.
C supports a number of functions that have the ability to perform basic file operations,
which include:
ƒ Naming a file
ƒ Opening a file
ƒ Reading data from a file
ƒ Writing data to a file
ƒ Closing a file
There are two distinct ways to perform file operations in C:
1. Low-Level I/O operation (it uses UNIX system calls)
2. High-Level I/O operation (it uses functions in C’s standard I/O library)
Table: File I/O functions
Function Name Operation
fopen()
- creates a new file for use
- opens an existing file for use
fclose()
- closes a file which has been opened for use
getc()
- reads a character from a file
putc()
- writes a character to a file
fprintf()
- writes a set of data values to a file
fscanf()
- reads a set of data values from a file
getw()
- reads an integer from a file
putw()
- writes an integer to a file
fseek()
- sets the position to a desired point in the file
ftell()
- gives the current position in a file (in terms of bytes
from the start )
rewind()
- sets the position to the beginning of the file
1
11.2 Opening a File
First things first: we have to open a file to be able to do anything else with it. For this, we
use fopen. This function takes two arguments - the first one is the path to your file,
including the filename. So if your file sits in the same directory as your C source file, you
can simply enter the filename in here. The second argument determines how the file is
opened by your program.
The general format for declaring and opening a file:
FILE *fp;
fp = fopen(“filename”, “mode”);
The first statement declares the variable fp of type FILE to point to a file located on the
computer. FILE is a structure that is defined in the I/O library (in stdio.h). The second
statement opens the file with mode specified.
Finally, fopen returns a FILE pointer if the file was opened successfully, else it returns
NULL.
Note that both the filename and modes are specified as strings. They should be enclosed
in double quotation marks.
Depending on the mode specified, one of the following actions may be performed.
1. When the mode is “writing”, a file with the specified name is created, if the file does
not exist. The contents are deleted if the file already exists.
Example:
FILE *fp;
fp = fopen(“stdRecord”, “w”);
2. When the mode is “appending”, the file is opened with the current contents safely. A
file with the specified name is created if the file does not exist.
Example:
FILE *fp;
fp = fopen(“stdRecord”, “a”);
3. When the mode is “reading”, and if it exists, then the file is opened with the current
contents safely, otherwise an error occurs.
Example:
FILE *fp;
fp = fopen(“stdRecord”, “r”);
The Table below shows the possible ways to open a file by various modes.
Table: Modes of a file
2
11.3 Closing a File
When you've finished with a file, its best if you closed it - seems logical enough!
Simply pass it a FILE pointer, but be warned, don't pass a NULL pointer (it points to
nothing), or your program might crash.
Example:
fclose(fp);
11.4 Opening Files for Reading Only
Firstly, a text file is a file that you can open and read its contents visually - for example,
C source files, .txt files, HTML etc - anything that looks "neat" in Notepad.
A binary file is a file that is written in machine code - usually seen as a mass of weird
characters in Notepad! Examples are bitmaps, executables etc.
In this chapter, we're going to be looking at standard text files. If you wanted to open a
binary file, simply put a b at the end of the second argument of fopen. To open a text file
for reading only, pass "r" as the second argument of fopen, as demonstrated in this
example:
#include <stdio.h>
void main()
{
FILE *fp; /* declare a FILE pointer */
fp = fopen("D:\hello.txt", "r"); /* open a text file for reading */
if(fp==NULL)
{
printf("Error: can't open file.\n");
}
else
{
printf("File opened. Now closing it...\n");
fclose(fp);
}
}
The file named “hello.txt” has been created earlier in Notepad and saved in a drive D:
Notice that the function call is assigned to fp. If the file was successfully opened, fp
would point to that file, else it'll point to nothing (a pointer that points to nothing is called
a NULL POINTER).
A check is performed to see if file is a NULL pointer: if(file==NULL). If so, display an
error message and quit the program.
3
If file is not a NULL pointer, display a success message and close the file.
11.5 Creating Files for Writing Only
To create a text file for writing only, pass "w" into fopen as the second argument.
Example:
#include <stdio.h>
void main()
{
FILE *fp; /* declare a FILE pointer */
fp = fopen("D:\writing.txt", "w");/* create a text file for writing */
if(fp==NULL){
printf("Error: can't create file.\n");
}
else {
printf("File created. Now closing it...\n");
fclose(fp);
}
}
Now, check the drive ‘D’ you will see a text file called "writing" created.
Warning: Creating a file that already exists wipes all the data from that file!
11.6 Input/output operations on files
Once a file is opened, reading out of or writing to it is accomplished using the standard
I/O routines that are listed in the table above.
11.6.1 Using getc and putc functions
The simplest file I/O functions are getc and putc. These are analogous to getchar and
putchar functions and handle one character at a time.
Example:
Assume that a file is opened with mode “w” and the file pointer fp. Then the statement
putc(c,fp);
writes the character contained in the character variable c to the file associated with FILE
pointer fp.
Similarly, getc is used to read a character from a file that has been opened in read mode.
Example:
The statement
c = getc(fp);
would read a character from the file whose file pointer is fp.
4
The file pointer moves by one character position for every operation of getc or putc.
The getc will return an end-of-file marker EOF, when an end of the file has been
reached. Therefore, the reading should be terminated when EOF is encountered.
Example: Program to read data from the keyboard and write it to a file called
“studentRecord”. Then read the same data from the file and display it on the screen.
#include<stdio.h>
void main()
{
FILE *fp;
char c;
//create the file for writing
fp = fopen("D:\studentRecord.txt","w");
if(fp == NULL)
{
printf("Error: Can't create file.\n");
}
else{
printf("File created. Data Input\n");
while((c =getchar()) != EOF)
putc(c,fp);
printf("\nClosing file.\n");
fclose(fp);
}
//open the file for reading
fp = fopen("D:\studentRecord.txt","r");
if(fp==NULL)
{
printf("Error: Can't open file.\n");
}
else{
printf("\nFile opened. Data output\n");
while((c = getc(fp))!=EOF)
{
printf("%c",c);
}
printf("\nClosing file.\n");
fclose(fp);
}
}
For this program, we enter the input data via the keyboard and the program writes it,
character by character, to the file studentRecord. The end of the data is indicated by
entering an EOF character, which is control+z in the reference system. The file is closed
at this signal. The end of the data can also be indicated by entering any special characters
such as $.
while((c =getchar()) != ‘$’)
5
The file studentRecord is again reopened for reading. The program then reads its content
character by character, and displays it on the screen. Reading is terminated when getc
encounters the end-of-file marker EOF.
Testing for the end-of-file condition is important. Any attempt to read past the end of file
might either cause the program to terminate with an error or result in an infinite loop
situation.
Sample output:
11.6.2 Using getw and putw functions
The getw and putw are integer-oriented functions are used to read and write integer
values. These functions are useful when we deal with only integer data. The general form
of getw and putw are:
putw(integer, fp);
getw(fp);
11.6.3 Using fprintf and fscanf functions
These functions behave exactly like printf() and scanf() functions except that they
operate with files. The first argument of these functions is a file pointer which specifies
the file to be used. The general form of fprintf is:
fprintf(fp,“control string”,list);
fscanf(fp,“control string”,list);
where fp is a file pointer associated with a file that has been opened for writing. The
control string contains output specifications for the items in the list. The list may include
variables, constants and strings.
The general form of fscanf is:
fscanf(fp,“control string”,list);
This statement would cause the reading of the items in the list from the file specified by
fp, according to the specifications contained in the control string.
6
Example: Program to read a string and an integer from the keyboard and write to a disk
file called string. The program then reads the file and displays the information on the
screen.
main()
{
FILE *fp1;
int num;
char s[30];
fp1 = fopen("D:\string.txt","w");
printf("Enter a string and a number:"); //Read from keyboard
fscanf(stdin,"%s %d",s,&num);
fprintf(fp1,"%s %d",s,num); //write to file
printf("\nClosing file.\n\n");
fclose(fp1);
fp1 = fopen("D:\string.txt","r");
if(fp1 == NULL)
{
printf("Error: can't open file.\n");
}
printf("File opened successfully. Now printing contents.\n");
fscanf(fp1,"%s %d",s,&num);
fprintf(stdout,"%s %d",s,num);
printf("\n\nClosing file.\n\n");
fclose(fp1);
}
Sample output:
11.6.4 Using feof()
The feof function is used to test for an end of file condition. It takes a FILE pointer as its
only argument and returns non zero integer value if all of the data from the specified file
has been read, and returns zero otherwise. If fp is a pointer to the file that has just been
opened for reading, then the statement
if(feof(fp))
printf(“End of data.\n”);
would display the message “End of data.” on reaching the end of file condition.
11.6.5 Random access to files
So far we have discussed file functions that are useful for reading and writing data
sequentially. There are occasions, however, when we are interested in accessing only a
7
particular part of a file and not in reading the other parts. This can be achieved with the
help of the functions fseek, ftell, and rewind available in the I/O library.
ftell()
ftell function takes a file pointer and returns a number of type long that corresponds
to the current position. It takes the following form:
n =ftell(fp);
where fp is a file pointer, and n would give the relative offset(in bytes)of the current
position. This means that n bytes have already been read (or written).
rewind()
The rewind() function resets the position to the beginning of the file. That is, it
“rewinds” the file. It takes the form:
rewind(fp);
n=ftell(fp);
would assign 0 to n because the file position has been set to the start of the file by
rewind. This function helps us in reading a file more than once, without having to close
and open the file.
fseek()
The fseek()function is used to move the file position to a desired location within the
file. It takes the following form:
fseek(fileptr, offset, position);
where fileptr is a pointer to the file concerned, offset is a number or variable of type
long, and the position is an integer number. The offset specifies the number of
positions (bytes) to be moved from the location specified by position. The position can
take one of the following three values:
Value
0
1
2
Meaning
Beginning of file
Current position
End of file
The offset may be positive, meaning move forwards, or negative, meaning move
backwards.
*****************************************************************************
Please bring all the errors to my notice either by sending an email (mpelmo@gmail.com/
mpelmo@sherubtse.edu.bt) or in person. I will appreciate your kind gesture!
*****************************************************************************
8