C Language by Example (23-2-2021)
C Language by Example (23-2-2021)
This book softcopy is available in pdfhost.io website, to download the file, search through keyword
‘cfamily1999’, along with this book, you get 500 exercise programs list on C,C++, Java programming.
This pdf file(s) designed for 2-sided print-copy (Xerox copy).
C-Family 2 Preface & Index
Functions 132
Pointers 151
operators in pointers 152
arrays & pointers, passing array to function 161,164
call-by-value vs call-by-reference 169
2D Arrays 191
Recursion 224
C by Examples
A complete reference material on C-language programming
About C
C-language is an ideal programming language and a perfect combination of power and flexibility. Though
it is a high-level language, it has low level features as well as easy interaction with hardware and OS. Even
assembly language code can be mixed in it. It is accepted as a good system programming language.
Powerful OS like UNIX was developed using C.
‘C’ is widely used in the software industry for both system and application side development. C is the
primary subject in computer science. It lays good foundation in programming and eases the learning of
any advanced courses that are to follow. So, it has been added in every branch of arts, science, and
engineering as part of curriculum. Every graduate student is going to face C, C++, DS, Java, Python and
Oracle in the first & second academic years.
I am grateful to all the students, friends, staff who helped me making this material. This book is
advisable to learn the logic and programming skills for beginners. For any suggestions contact me on
[email protected]
by Srihari Bezawada
since 1999
C-Family Computer Education,
#40-9/1-26, Vasayva Complex,
Dr. Samaram Hospital Lane,
Benz Circle, Vijayawada-10,
9440-030405, 8500-117118.
C-Family 5 Introduction to C
Introduction to C
Brief History of C
In 1960’s, there was a need for general purpose programming language and the available ones were of
specific-purpose only. For example, COBOL was meant for business applications; similarly FORTRAN was
extremely small and suitable only for scientific applications. Instead of being small, simple and specific, the
CPL was intended to support wide range of applications in all sectors; thus, the demand for a general-
purpose language led to the invention of CPL (Combined Programming Language). However, its heavy
specific features made it difficult to program. Its drawbacks were eliminated, simplified and further
developed by Martin Richards and named as BCPL (Basic CPL). Still it had some complex & difficult features
of CPL and these difficulties were simplified by ken Thompson and named it as ‘B’.
Later while developing UNIX operating system in 1969, ken Thomson faced several problems with the B
language; here B was used for programming while making UNIX software. Dennis Ritchie modified the B
language to overcome its limitations to suit all needs and renamed it as C. Of course, the development of
UNIX using C language made it uniquely portable and improvable; Finally, C was released in 1972. Dennis
Ritchie is a research scientist at Bell Telephone Laboratories in U.S.A. Brian Kernighan also participated while
making the definitive description of the language. Therefore, the C is also referred as ‘K&R-C’.
Evolution of languages
We have three types of languages 1.machine language, 2.Assembly language, 3.high level language.
Programs are written using these languages.
A) Machine Language (binary/low level language)
It is treated as first generation language, used during development of computer in 19th century. In this
language, the data and instruction of programs were written in terms of binary symbols (1&0’s), even input
and output were given in binary codes, as the computer understands the instructions only in ones and zeros.
For example, the instruction 9+13 is in binary form like 0010 1001 1101. Here, the first 4 bits represents
addition(+) code and remaining 8 bits are 9 & 13. This language is also called binary or low level language.
Actually, this language is difficult to understand, remember and writing programs in binary codes, it leads to
a lot of typing mistakes, because everything is 1&0s. This problem led to the invention of assembly language.
B) Assembly Language
this is somewhat better than binary language. Here, symbolic names were provided for every binary codes
of machine language. The names such as add, sub, mul, div, cmp, etc. So programmers can easily understand
and write instructions using these names instead of binary 1&0’s. For example adding 4 & 6 in 8088
assembly language as
mov ax,4;
mov bx,6;
add ax,bx
However, the main drawback of assembly language is, a large set of instructions are needed to be written
for simple tasks like addition of two numbers. It supports only small programs if the code is <1000 lines,
otherwise difficult to manage the code. Moreover, assembly differs from one to another machine. Some
people consider Assembly language also a machine language since the assembly codes resembles the
machine codes.
C-Family 6 Introduction to C
Operating System
The term O.S refers to a set of programs that manages the resources of a computer. The resources of
computer includes processor, main-memory, disks, and other devices such as keyboard, monitor, printer
that are connected to it. It also provides a good interface to the user. The interface provided by the O.S
enables the user to use the computer without knowing the details of the hardware. So interface hides the
underlying working of a computer. The main jobs of O.S are memory management, process management,
disk management, I/O management, security, and providing interface to the user …etc.
Currently, the widely used operating systems are MS-DOS, UNIX, and WINDOWS. DOS is a simple operating
system largely used in PCs. Unix, Linux, Mac, Windows on the other hand used variety of computers such as
mainframes, servers, graphics workstations, supercomputers, and also in PCs.
When a user runs a particular program (application) in the computer, the operating system loads the
program into main memory (RAM) from the hard-disk, and then executes the instruction by instruction with
the help of processor. The processor can take & execute only one instruction at a time. So this loading and
executing instructions is done under the control of OS. Thus OS executes our programs with the help of
hardware. OS is the main responsible for all these things and also makes the computer in working for other
tasks.
The relation between hardware, operating system, user-program, and user can simulate with a banking-
system such as bank, employee, transaction and customer. The hardware as a bank and O.S as a bank
employee, who works dedicatedly to organize all transactions of a bank, whereas the user as a customer and
user-program as a transaction, the user submit his program just by giving a command to the computer; the
responder, the O.S, takes up the program into main memory and process the instructions on the hardware
under its control. The following picture shows the layers of interaction between user and the computer.
User Customer
User program Transaction
Operating system Bank employee
Computer hardware Bank
C-Family 7 Introduction to C
Features of C-Language
A) C is a small & compact language: It has small number of keywords and symbols. Therefore, it
provides easy & compact programming. The size of software is also less compared to other language and it
has good library functions.
D) C is a portable language: The word portable means easy to carry or transfer, here the portability
refers to the ability of a program to run on different environments (hardware or operating systems).
As ‘C’ became powerful, it had provided different version of C-compilers for different operating systems.
A C-program written in one platform can be portable to any other platform with few/negligible
modifications. For example, a program written in UNIX operating system can be easily converted to run in
WINDOWS or DOS and vice versa.
E) C has flexible coding style: Unlike other languages (COBOL, FORTRAN), C provides freedom to the
programmer while coding the program. We can write the code without bothering about the alignment of
the program. The C compiler can recognize the code even when the program is not aligned or typed
properly. In other words, we can use more spaces, empty lines in between instructions (tokens), or we can
type several instructions in one line.
F) Widely Acceptable: It is suitable for both system and application side programming. It frees the
programmer from traditional programming limitations. It empowers the programmer to develop any kind of
applications. Thus, accepted by almost all users and became the most popular language in the world. In fact,
many of the software available in the market are written in C.
G) C is a case sensitive language: In C, an upper case alphabet is never treated equal to the lower
case alphabet and vice versa. All most all keywords and predefined routines of C languages use only lower
case alphabets. Therefore, it is very simple to type in only one case. Of course, some user defined symbols
(identifiers) can be typed in upper case to identify them uniquely.
Character set of C
It is a set of symbols called characters, which are supported by the C-language. C supports all most all
symbols which are provided in the keyboard
Lower case alphabets (a-z)
Upper case alphabets (A-Z)
Digits (0-9)
White space (‘ ‘)
Math symbols ( + , - , * , / , % < > = …etc )
Special symbols like {} [] () ! & , “ \ …etc )
Keywords
Like English language vocabulary, C has its own vocabulary called keywords; thus Keyword is a reserved
word, which has specific meaning in C, and it cannot be used for other purpose, using these keywords the
programs are constructed. C has the following standard set of 32 keywords.
if, else, switch, for, while, break, continue, goto, auto, register, extern, static, volatile, return, enum, void,
char, int, long, short, float, double, signed, unsigned, case, const, default, do, union, sizeof, typedef, struct;
Note: All keywords should be written in lower case. Depending on the compiler/vendor, few additional
keywords may also exist.
Tokens
Let the expression ‘x+y’. It has three tokens ‘x’, ’y’ and ‘+’. Here x, y are called operands, and ‘+’ is called an
operator. The compiler splits all the instructions into individual tokens for checking syntax errors. Splitting
expression into tokens and checking is known as parsing.
C-Family 9 Introduction to C
Now token can be defined as an elementary item in the program, which is parsed by the compiler.
Token can be a keyword, operator, identifier, constant, or any other symbol;
For example, consider the following statements.
a+b // ‘a’, ’b’ and ‘+’ are 3 individual tokens.
a<=b // ‘a’, ‘b’, and ‘<=’ are 3 tokens (not 4)
c++ // ‘c’ and ‘++’ are 2 tokens
if(a<b) // it has 6 token
Note: Here tokens ‘<=’ or ‘++’ misunderstand as two tokens, but they are single tokens.
In C, these data are classified into nine types based on the application’s requirement and hardware support;
these are known as built-in or primitive or basic types.
data
signed int or unsigned int are system dependents, for example, in 16-bit DOS, it occupies 16 bits of memory,
whereas in 32-bit Unix/Windows, it occupies 32 bits of memory. So they occupy 2/4 bytes based on system.
The keyword signed is an optional word for signed types. That means, even if we do not mention the
keyword ‘signed’, the compiler by default takes as signed types.
For example, the ‘int’ is equal to ‘signed int’ in the C-language.
int a, b, c; is equal to signed int a, b , c;
Note: This kind of value representation is called “signed magnitude representation”. Actually, 2’s
compliment representation is used for negative values. In the same way floating point numbers float,
double, long double are also represented in a special IEEE format, for further details Google it.
C-Family 11 Introduction to C
Operators
Operator is a symbol or keyword used to compute mathematical or logical calculations in a program.
C provides rich set of operators for making flexible and simple expressions. Operators are classified primarily
into four categories: arithmetic, relational, logical, and bitwise. Assignment, referencing, de-referencing are
called special operators. Each operator comes under one of the following types.
Unary Operators: These operators are associated with only one operand.
Binary Operators: These operators are associated with two operands.
Ternary Operators: These take three operands to perform an operation.
Note: just go through these operators briefly, we can learn in detailed in rest of the chapters.
A) Arithmetic operators
These operators are used to calculate arithmetical sums such as addition(+), subtraction(-), multiplication
(*), division(/) for quotient and modulus division(%) for remainder.
Let us see some of arithmetic expressions. Here a & b are operands
a + b, a - b, a * b, a / b, a%b
Integer division gives only the integer part of the result, that is, the fraction part is truncated (ignored).
For example, the result of 15/2 is 7 (not 7.5). The floating point division gives fractions also (15.0/27.5)
The modulus-division gives the remainder of a division, for example 17%32. Notice that, we cannot apply
modulus-division on floating point values as the division goes on and on, till the remainder becomes zero, so
it is meaningless applying ‘%’ on float values. For example the instruction 15.0%2.0 is an error statement.
(In some cases like 10.0%3.0 divisions goes endlessly)
C-Family 12 Introduction to C
B) Relational operators
These operators are used to find the relation between two values. If relation is found to be true then the
result is 1, otherwise it is 0. (The result of this 1 or 0 value is also said to be BOOLEAN values).
The operators such as: < > <= >= == !=
C) Logical Operators
These operators are used to combine two or more relations to form a single compound relation.
These operators also give the result either 1 or 0 (Boolean value)
&& Logical AND operator
|| Logical OR operator
! Logical NOT operator
The operator ‘&&’ works just like the word ‘AND’ in English language.
The operator ‘||’ works just like the word ‘OR’ in English language.
syntax1: relation1 && relation2 eg: if marks1>50 && marks2>50 then student passed
syntax2: relation1 || relation2 eg: if marks1<50 || marks2<50) then student failed
syntax3: ! relation ! true false
1) When we want two or more relations to be true for one action then we use AND operator(&&),
for example if A>B and A>C are true, then ‘A’ is said to be bigger than B,C.
In C-lang, it is written as: if(A>B && A>C)
here if both conditions A>B and A>C are satisfied, then the operator && gives the result 1 (true).
If anyone of them is false, the result is 0 (false).
C-Family 13 Introduction to C
2) When we want either of relations to be true for one action, then we use OR operator(||),
for example, If any marks1<35 or marks2<35 or marks3<35 are true, then student is “failed”.
in C program, it is written as if( marks1<35 || marks2<35 || marks3<35)
if anyone relation is satisfied, the operator || gives the result true. If all are false, then result is false
A B A &&B A||B !A
1 1 1 1 0
1 0 0 1 0
0 1 0 1 1
0 0 0 0 1
a
a = 10; //assigns 10 to ‘a’ (puts 10 in a’s memory)
10
e f g h
e=f=g=h=100; // assigns 100 to all e, f, g, h
100 100 100 100
2) b = ++a; this is equal to given below, first pre-increment and then assignment
++a;
b=a;
result is: a gains 6, b is gains 6
3) b = a++; this is equal to given below, first assignment and then post-increment
b=a;
a++;
result is: b gains 5, a gains 6
4) b = ++a + ++a + a++; this is equal to given below, we have two pre-increments, and one post-increment)
++a; // pre increment, so do first ( here ‘a’ becomes 6)
++a; // pre increment, so do first (here ‘a’ becomes 7)
b=a + a + a; // add all values (b=7+7+7)
a++; // post increment, so do last (here ‘a’ becomes 8)
Result of a, b are: a is 8, b is 21
note: So first do all pre increments, next process normal expressions, at last do all post increments.
5) b = a++*3 + ++a + 5*++a; this is equal to given below
++a;
++a;
b=a*3+a+5*a;
a++;
C-Family 15 Introduction to C
G) sizeof():operator gives the size of memory which is occupied by the variable or constant or data type
sizeof(int) 2
sizeof(long int) 4
sizeof(k) 2 // let k is int type variable
sizeof(10) 2 // 10 is int type value
H) Comma operator(,) : It is used to separate two or more instructions in the program. It is used in
several contexts in the programming. The actual behavior of comma operator is that, it returns the right
hand side operand value as the result of the expression.
a=2, b=3, c=10; // Here comma works as separator
c=a , b; // it is combination of two instructions “c=a and b”, but ‘b’ does nothing
a = (b, c); // it is also a combination of two instructions, “b and a=c”
Operator precedence
In general, complex expressions are formed with the combination of mathematical or logical operators.
While evaluating such expressions, initially the sub expressions are evaluated according to the precedence.
For example, the expression 5+2*4 evaluated as 5+813. Observe the following table showing the relative
precedence of operators in c. Just look once about this precedence, we can learn in detailed in next
chapters.
Priority 1 () [] -> .
Priority 2 ! ~ +(sign) -(sign) ++ -- (pre incr/decr)
Priority 3 sizeof &(reference) *(de-reference)
Priority 4 * / %
Priority 5 + -
Priority 6 << >>
Priority 7 < <= > >=
Priority 8 == !=
Priority 9 ^ | & ( ORing, ANDing)
Priority 10 && ||
Priority 11 ?: (conditional operator)
Priority 12 = *= /= %= += -= &=
Priority 13 ^= |= <<= >>=
Priority 14 Comma operator (,)
Priority 15 ++ -- (post increment/ decrement)
In the above table, Operators in the same row have the same precedence. Among same precedence
operators, the evaluation takes place from left-to-right side in the expression. Only the assignment & unary
operators are performed from right-to-left. For example a=b=c=d, here first c=d is performed later b=c ….
Consider the expression:
1+ 2*3-4+5*6 //left to right performed
1+6-4+5*6
1+6-4+30
7-4+30
3+30
33
C-Family 16 Introduction to C
Declaration of variables
The declaration specifies name, size, type and other characteristics of a variable. Before using any variable,
it must be introduced to the compiler about the name, size and type of data it is going to hold.
This introduction is called variable declaration; it involves creation of memory in the RAM and substitution
of logical address (binding) where ever it is used in the program.
Here in the syntax, the symbols “< >” represent user-defined and are compulsory, whereas square brackets
[] represent optional. [This is old style syntax, now a days nobody following this syntax]
The above syntax can be written as: dataType variable1, variable2, variable3…;
For example: int k1, k2=10; K1 k2
Garbage value 10
2 bytes 2 bytes
This declaration creates 2 bytes of memory space for k1, k2 in RAM; Here k1 has not been assigned with any
value, so by default, it contains garbage value (un-known value), whereas K2 has been initialized with 10;
Let us see more examples:
int age, experience; // holds person age and experience
char day, month; // holds day, month of a date
int year; // year of date
float salary; // salary of employee
Initialization of variables
We can set a value to the variables at the time of declaration ie, at the time of creation of memory.
This is called initialization of variable.
eg1: int k1=10; // this is called initialization, not an assignment, here k1 initialized with 10;
eg2: int k2;
----
K2=20; // this is not initialization, it is called assignment.
Note: here above 2 examples initialization & assignment affects the same result, we can follow either.
Garbage value
At the time of declaration, when a variable is not initialized with any value, then by default it holds an
unknown value called garbage value. This value may be +ve, or -ve or sometimes zero.
After completion of execution of one program, the program’s binary code or data will not be cleaned
automatically from the memory by the O.S, it exists until the next program is loaded into the same memory;
when a new program is loaded into this same memory, the old program’s code & data gets overwritten
(replaced). But when just space is allocated for new program variables, in this space, the previous program’s
binary values found or collected to these variables, which are anyway garbage to the new program.
This garbage exists until any new values scanned or assigned to this variables. For example,
int X=100, Y; // here X contains 100, but Y contains garbage value.
Note: Some times, this garbage may belong to our current running program itself. When a function is
terminated, its variable’s space is freed and reallocated for another function’s variable. So in this way the
garbage values come into picture.
C-Family 18 Introduction to C
C++ comment line: C++ supports single line comment, the syntax is
// ……………………………..comment line…………………………………….
The C++ is a superset of C, hence, we can compile C programs on C++ compiler, hence, we can use C++
comment lines in C programs (of course I myself used this comments during explanation of things).
C-Family 19 Introduction to Programming
Introduction to programming
Functions
In general speaking, in our real life, several people are required to accomplish one task with each one of
them doing one’s specialized sub task. Similar to this, a programmer cannot develop the entire code of one
application; instead many programmers contribute the code in terms of sub programs called functions.
Function is a sub-program that performs a given sub task in a program. Here each function is designed and
written for specific purpose such as calculating power, square root, logarithms …etc; thus collection of such
functions makes a C-program. For example, sqrt() is a function, it gives square root value. eg: sqrt(16)4
The functions are classified into ① library functions, ② user–defined functions
1) Library functions
These are ready-made functions, designed and written by the C manufactures to provide solutions for basic
and routine tasks in the programming. For example, the mathematical functions pow() & sqrt(), and I/O
functions scanf() & printf (),etc. The vendor of C, supply these predefined functions in compiled form with C
software.
There is huge collection of such compiled functions available in C, hence, these collections are called
functions Library. The library functions-body placed in separate files with name “xxxx.lib” in compiled
format and they are automatically linked to our program at the time of compilation, and these are hidden to
the programmer. Following library functions show how they are called from another part of program.
printf(): displays message or output values on the screen, the programs are stored permanently in
secondary storage devices like hard disk and when they get executed, loaded from hard disk to RAM and
then instruction by instruction is executed by the processor. Here nothing is displayed on the screen while
executing a program in the memory, if something need to be shown on the screen, we must add an
instruction called “printf()”, which displays data/message on the screen. For example
Syntax: printf(“format string”, list of values); here the “Format string” represents, what format we want to
display on the screen for the list of values; the format strings are
C-Family 20 Introduction to Programming
%d for printing integer value . (In this context ‘%’ is not a modulus operator)
%05d for printing integer in 5-digit format by padding with zeros.
%f for printing float value
%.2f for printing with fraction values like 123.45
%5.2f for printing float in 5.2 decimal formats
Let us have some examples, how printf() shows output on the screen
1. printf(“%d”,123); 123
2. printf(“%5d”,123); BB123 // B means blank space
3. printf(“%05d”, 123); 00123
4. printf(“%02d”, 123); 123
5. printf(“%5.2f”, 323.4); BB323.40
6. printf(“%.2f”, 1323.4256); 1323.42
7. printf(“%8s”, “Hai”); HaiBBBBB // B means blank space
8. printf(“%-8s”, “Hai”); BBBBBHai // right justification
11. printf(“hello world”); hello world // notice that, the values are not specified.
12. prinf(“10+20=30”); 10+20=30 // here + , = doesn’t work like operator, they are just to print on screen
so the printf() showoff as it is whatever message defined inside quotes(““) except %d, %f, …
program keyboard
1. scanf(“%d%d”, &x, &y); // accepts two values from keyboard and assigns into x , y;
2. scanf(“%d,%d”, &x, &y); // the input values must be separated by coma(,) 10,20⤶
3. scanf(“%d-%d-%d”, &day,&month,&year); //the date input must be separated by hypen(-) 10-2-3002⤶
2) User-defined functions
The library functions do not satisfy all the requirements of programming-needs instead they assist basic and
common programming tasks. So, one has to write one’s own functions to satisfy the needs of programming.
Thus, user defined functions are our-functions, created by ourselves to meet our requirements in the
programming. Besides our functions can be added to library files and we can use them like a library function
in our programs.
The following example explains how the function’s body are designed and written. This function body finds
big of two numbers. (Here just to create an idea about functions I have given this example. Don’t try to
understand in depth about these functions. This explained clearly in function’s chapter)
This function takes two integer values to x, y and returns biggest of it; if this function is called with
“K=big(23,4)” from another function say main() then returns 23 and assigned to k; this is as given figure
void main() int big( int x, int y)
{ int k; { int temp;
K=big(4,23); if( x>y) temp=x;
printf(“%d”,k); else temp=y;
} return(temp);
}
To solve this problem, the original proto-type of function should be added to our program to check out
syntax errors and to raise them; the functions original proto-type is provided by C-manufacturers in separate
files with name “xxxx.h”. So if any library function is used in the program, then related header file should be
included. So that, it compares our function-call statements with the original proto-type and if both are not
matched then compiler raises an error. (The word proto-type is also called function declaration/signature.)
Syntax to include file is #incldue<file name .h>
#inclue<math.h> // to check syntax errors at math functions calls
#include<stdio.h> // for all I/O function signatures
#include<graphics.h> // for graphics functions
#incldue<string.h> // for string functions
At beginning, these files name were stdio, math, string.. etc, the extension “.h” was not given then, but
overtime, when they appears as program header, gradually start calling them as header files, so added “.h”
Now, in C program, at least one function must be there, that is main(); its execution starts by operating
system when user runs the program. The other functions are executed by shifting the control temporarily
from main(); the following figure explain how the other functions are called from main() and how they are
executed by the control jumping to it.
This example explains how the control jumps over to functions for calculating 23 and √28
void main() pow(int x, int y)
{ int k; {
// body of pow()
k=pow(2,3);
-----
printf(“%d”,k); }
k=sqrt(28);
printf(“%d”,k); sqrt(int x)
{
}
// body of sqrt()
}
“K=pow(2,3)” is known as function-call instruction, when it gets executed, the control transfers to its body,
calculates xy value, later returns ‘8’ and assigned to k; similarly sqrt() is also executed;
Thus, each function is a sub program, stored separately in the memory and executed whenever it is called,
Here main () is treated as boss function and other functions are sub ordinates to main(). The main function is
called by the operating system, that is indirectly by the user [ by pressing command control+f9 in turbo C++
editor or typing .exe file name at DOS prompt, or double click on icon of .exe file in windows];
C-Family 23 Introduction to Programming
First C Program
Line 1: // A sample program to print welcome messages on the screen, written by Srihari
Line 2: #include <stdio.h>
Line 3: void main()
Line 4: {
Line 5: int a, b, c;
Line 6: a=100;
Line 7: b=200;
Line 8: c=a+b;
Line 9: printf(“output = %d”, c);
Line 10: }}
line1: generally, at first line of program, the comments are added about purpose & author of program. It is
good programming practice to add such comments (we know, these lines ignored by compiler).
line2: #include it includes library function’s header files and other code files to our program, here the
printf() syntax provided in stdio.h, hence, it included here.
line 3: void main() is the starting point of the program.
line 4: the open and close braces { } define a block. As per syntax, the executable instruction must be given
inside braces. (As C is block structured programming language)
line5: int a, b, c; here space is created to each variable with 2-bytes. (at this moment, it contains garbage)
Line6: a=100; here 100 filled to ‘a’
Line7: b=200; here 200 filled to ‘b’
Line8: c=a+b; here 300 filled to ‘c’
Line8: printf(“output = %d”,c) when this statement executes, we can see “output = 30” on the screen
Line9: ‘}’ closing braces tells the end of program execution.
Second C Program
#include<stdio.h>
void main()
{ printf(“\n welcome to C-Language programming”);
printf(“\n welcome to Vijayawada”); // ‘\n’ means print in next-line
printf(“\n welcome to C-Family Computers”);
}
we know, instructions are executed one by one from top-to-bottom in a program, so here output shown as:
welcome to C-Language programming
welcome to Vijayawada
welcome to C-Family Computers
line1: we already discussed above, now I am repeating same with more clarity.
In this line, the comments are added about program, ie, the purpose of program, input/output of
program, who & when has written, etc, are specified. Writing comments is a good programming
practice. However, this is optional.
line2: Here header files of library functions and other files are included. For example “#include<math.h> for
math functions, #include<stdio.h> for I/O functions ….etc;
line3: “void main ()” represents starting point of program, the execution starts at this point.
line4: variables are declared at the beginning of program block, and when this line is executed, space
is allocated for variables in the RAM.
line5: the input statements are used to accept values from the keyboard and other terminals.
line6: Here process statements specify the processing of input data
line7: here the output statements are used to show output on the screen or other terminals;
Note: the opening and subsequent closing braces {} defines a block; as per C syntax rules, the instruction
must be given inside block; all instructions must be terminated by “;”
note: we can use notepad editor to type the program code, but it does not provide to compile/run the
programs. It is just editor to type and save the code. So IDE is the ultimate tool for programming.
The following figure shows the turbo C++ IDE editor on DOS.
C-Family 25 Introduction to Programming
File menu: this menu-driven facility used to handle file operations such as opening a new file, or opening an
existing file, saving a file, etc.
Edit menu: this is used to copy, cut, and paste a group of selected lines.
Compile menu: to create object files, making executable files, linking a program….
B) Compiling & Running: Irrespective of number of languages in the market, the computer
processor understands only one language called machine language, this language designed with basic set of
operations like addition, subtraction, multiplication, comparison, etc. These operations are designed in
circuitry level in the form of 1’ and 0’s to execute directly by the processor, therefore this language is also
called low level or binary language.
The compiler is translation software, which translates high level program into machine code; the compiler
generates machine code of each line and stores into another file called “exe” (executable) file; this file can
be executed directly on the machine; once the exe file is generated then compiler and source file are not
required. These are required when modification are needed in the source code;
Thus, every high level language program must be translated to machine code; for this reason, every
language must have its own compiler to translate it into machine code; for example, the C compiler for C
programs, C++ compiler for C++ programs. if two same programs are written, one in C, and another in C++
then two compilers generates equivalent machine code;
C program file.
let file name is “sample.c”
Compiler software
Library functions
Linker Software
are attached here
Executable file
“sample.exe”
D) Compiler vs Interpreter
Interpreter is a translator, which translates our ‘C’ program into machine code, here it translates one line
at a time and then executes immediately on the machine. That is, it translates line by line and then executes
instantly on the machine. So it also called instant compiler. Whenever we run the program, the interpreter
translate and executes, if we run more times, more translations it takes. It seems to be unnecessary
translating same program again & again in every use. This redundant translation leads to wastage of CPU
time and other resources.
Actually, interpreter is used for single-use applications like queries, commands, to check spellings in word
processing, language translators, internet browsing, etc. The web-sites are coded in the form of html, css,
etc and these files are downloaded and interpreted by the browsers, web browsers are nothing but
interpreters. So for single use applications interpreter is the choice.
C-Family 27 Introduction to Programming
Compiler translates line by line and stores into “.exe” file to execute later time, thus instead of executing
each line instantly on the processor, it stores into .exe file. Now this file contains all machine code
instructions of our C-program’s source file. This file can be executed directly on the machine whenever we
want, while running this .exe file, the compiler is not required. So here, no translation takes place again &
again in every use. The interpreter doesn’t create “.exe” file, so in every use translation is required.
Some kind of applications needed to execute regularly like calculator, business accounting, games, etc.
Here compiler is used to generate machine code file, so that, such file can be executed at any time without
translating again and again.
Conclusion: compiler is the choice for regular use applications, whereas interpreter is the choice for single
use application. For single use applications, it is un-necessary creating machine code file.
Process Program
input: radius(r) void main()
output: area ( ) { float radius, area, circum;
circumference (2 printf(“\n Enter radius of circle :”);
scanf(“%f”, &radius);
Input & output area=22/7.0 * radius * radius;
ip: Enter radius of a circle: 5 circum= 2*22/7.0*radius;
op: Area = 78.57143 printf(“the Area is %f\n”, area);
Circumference = 31.40 printf(“\nthe Circumference is %f”, circum);
}
void main()
{ float basic, hra, da, ta, netSalary;
printf(“enter basic salary :”);
scanf(“%f”, &basic);
hra=24*basic/100; // calculating 24% for house rent allowance
ta=7*basic/100; // calculating 7% for travelling allowance
netSalary=basic+ta+hra;
printf(“Net salary = %f”, netSalary);
}
Type casting
Process of converting a value from one type to another type is called type casting. In C, the type casting is
done in two ways. ①Implicit type casting (automatic casting) ②Explicit type casting (manual casting)
①Implicit Typecasting
For example, the expression 10+20.54(int+float), here the operand 10 automatically converts into float-type
as 10.00, because, we must hand over same size and type of data to the CPU before computing. So compiler
automatically is done this conversion. So implicit type casting automatically is done by the complier when
two operands are not same type with in the expression. Let us see some examples,
②Explicit typecasting
Sometimes, we need to convert explicitly to get desired result from the expression.
syntax: (conversion-type) expression
eg: (float) 15 15.00
(int) 2.6 2
In the above expression, 15 is int. But, upon prefixing (float)15, its type will be changed to float (as 15.00).
eg: void main()
{ int a=10, b=3;
float k;
k=a/b;
printf(“\n Before type casting K=%f”,k);
k=(float) a/b; // here ‘a’ converted by me, ‘b’ is converted by compiler.
printf(“\n After type casting K= %f”,k);
}
Before type casting K=3.000000
after type casting K= 3.333333
Representation of Constants in C
In programming, Data is represented in two ways in terms of constants and variable data. Constants are
represented in special manner by adding format string or other symbols to the value. For example, ‘10L’ is
long int type.
Automatically, compiler understands some types of constants in the program. For example, the constant ‘10’
is considered as int-type, 34.55 as double-type, ‘A’ as char-type. These are default types and automatically
understand by the compiler. But some constant types are needed to specify explicitly along with format
string. The following list explains about all constant types. Do not use other symbols like comma, spaces,
quote, etc while specifying constants.
C-Family 33 Type Casting
integer Constants
A collection of one or more digits with or without a sign referred to as singed int constants. This is the
default type for integral values.
eg. 5, 256, 9113, 6284, +25, -62, etc are valid signed integers.
Similarly to represent unsigned int, the format string ‘u’ or ‘U’ is suffixed to the value.
eg. 67U, 43U, 4399u, 45u are valid unsigned integers.
Note that, -3428u is also a valid number. Here this -3428 is converted into equivalent unsigned integer
62108. Because, here the sign bit is also considered as data bit. (But this style is not recommended)
Some invalid declaration of integer constants are:
15,467 $25,566 4546Rs
long integer constants
for the long integer constants, the format string ‘l’ or ‘L’ is suffixed to the value.
eg: 2486384L –123456L 5434545l –34545l are valid long int constants
893434lu -3Lu … etc are valid unsigned long integers.
Octal int/long integer constants
for the octal integers, zero is prefixed before the value. (0 is like octal).
eg: 0123, 0574, 01, 046342L etc are valid octal integers.
0181, 09, 12, etc are in-valid octal integers. (In octal system 0-7 digits are used)
Hexadecimal int/long integer constants
in the hexadecimal number system, the symbols 0, 1, 2, 3 … 9, A, B, C, D, E, F are used.
(Total 16 symbols are used; because, the number system’s base is 16)
The symbol “0x or 0X” is prefixed before the hexadecimal number.
For example: 0x1, 0x123, 0xa5, 0xfldb, 0x0, 0xABC, 0xflc etc are valid hexadecimals.
character constants
To specify a character constant, we must enclose the character within the pair of single quotes.
eg. ‘A’ ‘z’ ‘s’ ‘8’ ‘+’ ‘;’ etc
string constants
It is a collection of characters enclosed within double quotes, used to represent names, codes, abels, etc.
eg: “Hello! Good morning!” “Magic mania” “A” “123” “A1” “#40-5-8A” “C-Family”
float constants (Real numbers)
We can specify the real numbers in two different notations, namely general and scientific notation.
Here the format string ‘f’ is attached at the end of value.
In normal representation: 3.1412f -25.62f 98.12f -045632.0f 1.f 9.13f
In scientific exponential representation: the syntax is [-]d.dddde[+/-]ddd where d is any digit.
2.32e5f (means 2.32 x 10^5 i.e. 232000.0)
12.102e-3f (means 12.102 x 10^-3 i.e., 0.012102)
-2. 165e6f (means -2.165 x 10^6 i.e., -2165000.0)
3.68e3f (means 3.68 x 10^3 i.e., 3680.0)
double constants: This is the default type for real numbers (floating point values).
eg: 1.2 45.3 4.39393 349.34899034
45.4e15 44.54e4 (‘l’ or ‘L’ is option for double)
long double: for the long double, the format string ‘l’ or ‘L’ is used.
eg: 3.14L
314.41 (Equivalent to 314. 0L)
3.68e3L (Means 3.68 x 103 i.e., 3680.0L)
C-Family 34 flow charts
Flow chart
It is a pictorial representation of flow of a program, which illustrates the sequence of operations to be
performed to get the solution of a problem. It is often used as a visual planning tool, how the control to be
moved from one point to another point to get a solution. It is like drawing a building plan before
constructing a building.
Flowcharts are generally drawn in the early stages of formulating computer solutions. It facilitates
communication between programmers and business people. It plays a vital role to understand the logic of
complicated and lengthy problems. Once the flowchart is drawn, it becomes easy to write the program in
any high level language. The following mathematical symbols are used to represent specifications with
directions to indicate the flow of control.
Start/stop a program
Predefined actions
File
Looping
C-Family 35 flow charts
Algorithm
In mathematics and computer science, an algorithm is a finite set of computational instructions that carry
out a particular task, which takes input and produces desired output. In simple words, it is step-by-step oral
explanation of logic how to construct instructions in a program; here English & math symbols are used to
explain logic in words
Flowchart depicts how the control to be moved in the program from one point to another point to get a
solution, whereas algorithm tells step-by-step explanation how to construct instructions in a program.
This is an independent method to explain the logic regardless of programming language used by the
programmer. Here English and math symbols are used to explain the logic. People write algorithm for
complex and complicated tasks to explain the logic in words, for example, sorting algorithms, searching
algorithms, shortest path in network …etc. Any algorithm follows,
1. Describes the input and output
2. Describes the data entities with purpose (variables)
3. Explains process in step by step using English and math symbols
4. Add comments at every step what it does, use square brackets [ ] for comments
5. Each instruction is clear and unambiguous (definiteness)
6. The algorithm terminates after finite number of steps
Note: there are no standard rules and regulation to implement algorithm/flowchart, so one can implement
one’s convenience but ensure that other must be understood it.
Flow chart to find big of two numbers Algorithm to find big of two numbers
Start
step1: let us take a,b as type integer variables
step2: let us take ‘big’ to store big value
read(a,b) step3: [ scanning input from keyboard ]
read(a,b)
step4: [ finding big of 2 numbers ]
if a>b if(a>b) big=a
else big=b;
true false
step5: [ printing output ]
big=a big=b
print(big)
step6: [ closing the program]
stop
Print(big)
stop
C-Family 36 flow charts
Start
read(a,b,c)
true false
if(a>c) if(a>b) if(b>c)
stop
start
print(“enter n:”);
read(n)
sum=0;
i=1;
false
if(i<=n)
true
sum=sum+’i’;
i++;
print(sum)
stop
C-Family 37 flow charts
Pseudo code
Pseudo code is a short hand way of describing a program or algorithm in general language syntax rather
than in specific language syntax. Algorithm uses English and math symbols to explain logic in stepwise,
whereas pseudo code uses programming language syntax to explain logic in term of instructions. So pseudo
code resembles the program with general language syntax. Most of the people adopt C or Pascal language’s
syntax and their control structures to describe the pseudo code.
Algorithm is understandable by any nonprogrammer but pseudo code understandable by a person who
knows at least one programming language. So it is a method used to explain the logic between two
programmers. It is easier for programmers to understand the general workings of one program which is
written by other programmer.
Flow chart shows only execution flow (directions), algorithm explains, what are the steps be taken to get a
solution, but it does not give clear explanation of how to write instructions, for example, to swap 2 values in
the algorithm, we write as: swap(a,b). In pseudo code we write as: t=a, a=b, b=t. So in pseudo code every
step is written in detailed, which is near to programming. So, one can say loosely, pseudo code is nothing
but a program without accurate syntax (syntax is ignored).
[FlowchartAlgorithm Pseudo codeProgram]
Example for Pseudo code: Calculating sum of 1 to n numbers (1+2+3+4…+n)
Control Statements
Generally, instructions in a program are executed sequentially one after the other, in an order in which they
appear in the program. However, in practice, we need to bypass the control over some set of instructions, or
repeatedly process some instructions or to alter some other sequence depending upon the requirement.
For this purpose, special statements are necessary in programming to handle the control accordingly.
C possesses such a handy control statements like if, if-else, switch, while, etc. These statements alter the
normal execution sequence of a program according to our requirement. Therefore these statements are
called as control statements. These control-handling statements are of two types.
① Conditional control statements ② Unconditional control statements
Control statements
Conditional Un-conditional
Decision Looping
1) if 1) while 1) goto
2) if-else 2) for 2) break
3) conditional operator 3) do-while 3) continue
4) switch case selection 4) return
Decision control statements: These statements change the flow of execution depending on given logical
condition. Used to execute or skip some set of instructions based on given condition.
Loop statements: These are also called iterative statements, used to execute some set of instructions re-
peatedly until a given condition is failed.
Unconditional control statements: These statements unconditionally transfer the control from one location
to another specified location within a program.
if – statement
It is a decision control statement, executes or skips a given set of instructions depending upon the given test
condition. The syntax is
if(test-condition) false
test condition
{ instruction 1;
true
instruction 2;
Instruction 1;
------- Instruction 2
instruction N; …
Instruction n
}
instruction N+1; // after “if” statement
Instruction N+1
instruction N+2; Instruction N+2
------
------
C-Family 40 if-else
In the above if-statement, if the test-condition is success (true) then instruction-1, instruction-2, … instruc-
tion-N will be executed, later, the control comes out of if-body and proceeds with instruction N+1, instruc-
tion N+2 …etc. This is shown in the flow chart.
If the result of test-condition is false then control jumps out of if-body and proceeds with instruction N+1,
instruction N+2 …etc. In this case, the instruction-1 to instruction-N will not be executed.
if( 10 < 5 )
{ printf(“hai ”)
}
printf(“bye”);
}
op: hello bye
In the above, the first condition (10>5) is true, so printf(“hello”) will be executed, but the second condition
(10<5) is false, so printf(“hai”) will not be executed. The final printf(“bye”) executes irrespective of
if-statements.
This program accepts +ve or –ve integer from keyboard and displays result in +ve.
If user entered –ve value, converts it into +ve by multiplying it with -1.
start
ip: -14 ip: 15
op: 14 op: 15
read(n)
void main()
{ int n;
false
printf(“Enter a +ve/-ve value ”); if n>0
scanf(“%d”,&n); true
true
if(n<0) // if n<0 means, it is -ve
n=n*-1
{ n=n*-1; // if –ve, then converting to +VE
}
printf(“\n Result = %d”, n); print(n)
}
In this program, the instruction n=n*-1 executes when the input is -ve. stop
As per C-Syntax, the above two constructions are same, so it is better to avoid braces when we have single
instruction in if-body, but this single instruction must be followed indentation otherwise leads to confusion.
Indentation means writing instruction inside with tab-space, following code shows indentation
if-else statement
This is two-way decision control statement, executes either if-block or else-block based on given condition.
If the condition is true then if-block executes, otherwise else-block executes. Let us see the syntax,
if (test-condition )
{
instruction 1; false
Test
instruction 2; // if-block
condition
true
----
instruction K; true
} Instruction 1; Instruction k+1;
else Instruction 2; Instruction k+2;
… …
{ Instruction k; Instruction n;
instructionK+1;
instructionK+2; // else-block
----
instruction N;
}
instruction N+1:
instruction N+2:
----
In the above if-else statement, always only one block will be executed, either if-block or else-block.
The test-condition is true, if-block is executed, and otherwise, the else-block is executed.
If the test-condition is true, the instruction-1, instruction-2, … instruction-k will be executed, later control
jumps out of ‘if’ construct and proceeds with instruction N+1, instruction N+2 …
If the condition is false, the else-block is executed i.e., instruction K+1, instruction K+2, … instruction N are
executed and then control proceeds with instruction N+1, instruction N+2 … statements.
Nested-If Construct
Construction of one if-statement within another if-statement is called as nested-if. The inner and outer ‘if’
may have ‘else’ part of it. Look at the following different syntaxes of nested-if construct.
The simple form of nested-if statement is
if(condition) // outer if
{
if(condition) // inner if
{
instruction 1;
instruction 2;
---------
instruction n:
}
}
Let us see some more examples of nested-if with different styles
Example 1 Example 2 Example 3
* As inner if-else statement is a single statement, braces are not required to make into single for outer-if.
Based on this feature, we can remove braces of outer-if statement. The above code after removing braces is
if(x>y)
if(x>y)
big=x; single statement
else
big=z;
else single statement
if(y>z)
big=y; single statement
else
big=z;
printf(“\n biggest=%d”, big );
In this way, in C, any control statement can be taken as single statement including nested-if, thus above en-
tire if-statement can be taken as single compound statement. But sometimes, some people used to give
braces for clarity purpose even though they are not required.
Using logical operators (&&), above code can be simplified as
if( x > y && x > z )
big=x;
else // if control came to else part means, the ‘x’ is not the biggest
if(y>z) // so biggest is either ‘y’or ‘z’, compare and find it.
big=y;
else
big=z;
C-Family 51 if-else
Points to note
*As inner-if is single statement, the braces are not needed to make into single for outer-if. In this way outer-if
also becomes as single compound statement. This sense is to avoid overhead of braces in the program.
* In some cases, the braces make more clarity, so some coders use even though they are not required.
* When nesting is occurred, care should be taken between outer-if and inner-if. The else always belongs to
nearest above if-Statement. Let us see following example
up to 100 as above said, for remaining units 5.50/- per unit and category is ‘B’
if units >300 then // tariff-3
up to 300 as above said, for remaining units 8.00/- and category is ‘C’
input: no.of units consmed: 70⤶ input: no.of units consmed: 170⤶
output: bill amount is: 245.00 output: bill amount is: 7355.00
category is: ‘A’ category is: ‘B’
void main()
{ float billAmount;
int units;
char category;
printf(“Enter no.of units consumed: ”);
scanf(“%d”, &units);
C-Family 53 if-else
if (units<101)
{ // this braces can’t be removed, because two instructions exist in this body
billAmount=units*3.50;
category=’A’;
}
else
{ // this pair of braces can be removed, as the inner if-else is single statement.
if(units<301)
{ // this braces can’t be removed, because two instructions exist in this body
billAmount=100*3.50 + (units-100)*5.50;
category=’B’;
}
else
{ // this braces can’t be removed, because two instructions exist in this body
billAmount= 100*3.50 + 200*5.50 + (units-300)*8.00;
category=’C’;
}
}
printf(“The bill is : %.2f”, billAmount);
printf(“\n Category is : %c”, category);
}
C-Family 54 if-else
Here conditions are evaluated from top to down, as soon as a true condition is found, the instruction
associated with it is executed and the rest of the ladder is bypassed. If none of the conditions are true, the
final ‘else-part’ will be executed. That is, if all other condition tests fail, the final ‘else’ instruction-n will be
performed. If the final ‘else’ is not present, no action takes place.
Although, the above ‘if-else-if’ ladder is technically correct, it can lead to bit confusion to the programmer.
For this reason, the ‘if-else-if’ ladder is usually written as
if(condition 1)
instruction 1;
else
if(condition 2)
instruction 2;
else
if(condition 3)
instruction 3;
-----------
-----------
else
instruction n;
Observe here, the nested statements are started in a new
line unlike same line as above said.
C-Family 55 if-else
if(m1<35||m2<35||m3<35) if(m1<35||m2<35||m3<35)
printf(“\n F grade”); printf(“\n F grade”);
else else if(avg>=60)
{ if(avg>=60) printf(“A grade”);
printf(“A grade”); else if(avg>=50)
else printf(“B grade”);
{ if(avg>=50) else
printf(“B grade”); printf(“C grade”);
else }
printf(“C grade”);
}
}
}
The above left side given nested-if cross aligned, however it is readable(because few decisions exist). If the
programmer did not take care while aligning the code properly, it makes un-readable and difficult to debug.
Hence, if-else-if ladder style is always best. If more than 10 alternative decisions exist, the normal nested-if
seems to be awkward and confusion, so the ladder-style is the alternative under any case.
C-Family 56 if-else
These two statements are same with little difference, you can follow whichever you
like
void main() void main()
{ int daysLate, fine; { int daysLate, fine;
printf(“the number days late :”); printf(“the number days late :”);
scanf(“%d”, &daysLate); scanf(“%d”, &daysLate);
if( daysLate <=10 ) if(daysLate <=10)
fine=5; fine=5;
else else if(daysLate<=20)
if( daysLate<=20) fine=10;
fine=10; else if(daysLate<=30)
else fine=20;
if( daysLate<=30) else
fine=20; fine=daysLate;
else
fine=daysLate; printf(“fine amount = %f”, fine);
printf(“fine amount = %d”, fine); }
}
up to 100 as above said, for remaining units 5.50/- per unit and category is ‘B’
if units >300 then // tariff-3
up to 300 as above said, for remaining units 8.00/- and category is ‘C’
input: no.of units consmed: 70⤶ input: no.of units consmed: 170 ⤶
output: bill amount is: 245.00 output: bill amount is: 7355.00
category is: ‘A’ category is: ‘B’
void main()
{ float billAmount;
int units;
char category;
printf(“Enter no.of units consumed: ”);
scanf(“%d”, &units);
C-Family 57 if-else
if(units<101)
{ billAmount=units*3.50;
category=’A’;
}
else if(units<301)
{ billAmount=100*3.50 + (units-100)*5.50;
category=’B’;
}
else
{ billAmount= 100*3.50 + 200*5.50 + (units-300)*8.00;
category=’C’;
}
printf(“The bill is : %.2f”, billAmount);
printf(“\n Category is : %c”, category);
}
else if(m==2 && y%4!=0 && d>28) // for February and non-leap year checking
bool=0;
else if((m==4 || m==6 || m==9 || m==11) && d>30) // for 30-days month checking
bool=0;
if(bool==1) printf(“date is valid”); //finally check the bool and print the output
else printf(“date is in-valid”);
}
Incrementing given date by 1 day (let the input date is valid-date)
ip: 29 2 2012 ip: 31 12 2010 ip: 21 1 2010
op: 1 3 2012 op: 1 1 2011 op: 22 1 2010
void main()
{ int d, m, y;
printf(“enter a valid date :”);
scanf(“%d%d%d”, &d, &m, &y);
// incrementing day by 1-day
d++;
// after incrementing, if ‘day’ crosses the end of month limits, then shift to next month
if(m==2)
{ if(y%4==0 && d>29)
{ d=1;
m++;
}
else if(y%4!=0 && d>28)
{ d=1;
m++;
}
}
else if((m==4 || m==6 || m==9 || m==11) && d>30)
{ d=1;
m++;
}
else if(d>31)
{ d=1;
m++;
if(m==13)
{ d=1;
y++;
}
}
printf(“date after incrementing is %d-%d-%d”, d, m, y);
}
Conclusion: The choice of usage of if, if-else, nested-if, if-else-if ladder is left to the programmer. There are
no specific situational suggestions which statement is to be used when and where. However, ensure that,
the written code should be correct, clear, and easy to understand. While writing code, the programmer
should remember that, the C possesses, there is always a good structured alternative control statement
exist whenever complexity rises with one control statement.
C-Family 60 if-else
if - else linking
eg1) In C, if & else are 1:1 type, one else-statement always linked to only one if-statement in the program,
we cannot write one else-statement for two or more if-statements, following example explains it.
if( marks1>50)
if(marks2>50)
if(marks3>50)
printf(“passed”);
else
printf(“failed”);
in above , the else-part joins only to the last if-statement(marks3>50), so we can’t write one else-part to
many if-statements. The solution is, we need to write else-part to every if-statement, this is as
if(m1>=35)
if(m2>=35)
if(m3>=35)
printf(“passed”);
else
printf(“failed”);
else
printf(“failed”);
else
printf(“failed”);
------------------------------------------------------------------------------------------------------------------------------------------------
eg2) In some situations, where the ‘else’ is available to the outer-if and not to the inner-if , in that case, the
inner-if should be enclosed within braces { }, otherwise compiler links outer-else body to the inner-if.
Observe the following example
if(x==1)
if(y==2)
printf(“ x is 1, y is 2 ”);
else
printf(“x is not 1”);
Here, the programmer wrote else-part to the outer-if, but compiler links to the inner-if, to avoid this logical
error, enclose inner-if within braces { }. This is as follows
if(x==1)
{ if(y==2) // now this ‘if’ has no else part of it
printf(“x is 1, y is 2”);
}
else
printf(“x is not 1”);
That means any non-zero value (not necessarily 1) is considered to be true, whereas zero is false.
Observe the following program output
void main()
{ int x=0, y=1, z=10;
if( 0 ) // false
printf(“ Black ”);
if(x&&y)
printf(“Black”); // if( x&&y ) if( 0 && 1 ) if(false && true) if( false)
if(x||y)
printf(“Grey”); // if( x||y ) if( 0 || 1 ) if(false || true) if( true)
}
Switch Statement
Switch is another conditional control statement used to select one option from several options based on
given expression value. This is an alternative to the if-else-if ladder when comparisons happened against
with constants. The if-else-if seems to be lengthy and awkward when more comparisons exist. Switch is a
good alternative as its construction is simple and looking comfortable even if more cases found or nested.
However it does not support in all situations in which if-else-if support. ie, it compares only against with
integral constants.
In switch construct, the instructions are divided into case blocks based on logical condition and any number
of case blocks can be defined within it. Observe the following syntax and flow chart.
switch(expression) // switch header
{
case constant-1: instruciton-1;
instruciton-2;
..…
break;
case constant-2: instruciton-1;
instruciton-2;
……
break;
………
.…….
default: instruciton-1;
instruciton-2;
……
}
* The expression in switch() header should be an integral type value such as char, int, long int.
* The expression value compares with constant-1, constant-2,… etc, if anyone matches then the control
jumps into associated case block and executes all the instructions within it, later comes out by break.
The break throws the control out of switch statement. In other words, keyword break used to come out of
switch after execution of selected case block. However break is an optional statement. If it is not present at
end of case-block, the control enters into next case block even though its constant value differs.
*The case constants may not be in ascending or descending order. The two or more case constants may be
associated with single block.
*The default block executes when no case is matched. The default is optional block and generally it is used
to handle input errors.
*In case block of switch, we can write any other control statement, sometimes it can be switch(nested)
C-Family 66 switch statement
If no case matches with the given value, then the default block executes and we get “Invalid input”.
Generally, default block used to handle errors like “invalid-input” and other things.
Suppose the input is 4, then the “case 4:” matches and printf(“four”) executes. Later control comes out
when break gets executed.
The above program can be written using if-else-if ladder form as shown below.
void main()
{ int k ;
printf(“Enter a digit:”);
scanf(“%d”,&k);
if(k==0) printf(“zero”);
else if(k==1) printf(“one”);
……
else if(k==9) printf(“nine”);
else printf(“Invalid input”); // like default block
}
The above two programs generate exactly same result. However, as you might notice that the first program
is easier to write, understand and modify. Structure of switch statement is more readable even if it is nested
2 or 3 times.
switch(N)
{ case 1: printf(“red”); // observe “break” not given
case 2: printf(“green”);
break;
case 3: printf(“blue”);
default: printf(“black”);
}
}
if input: 1 red green
if input: 2 green
if input: 3 blue black
if input:4 black
if input:5 black
if input:0 black
switch(ch)
{ case ‘a’:
case ‘e’:
case ‘i’:
case ‘o’:
case ‘u’: printf(“It is a vowel “);
break;
default: printf(“It is a consonant”);
}
}
Here all case blocks associated with only one instruction, which is printf(“it is a vowel”); Thus, for any input
vowel, the same message “It is vowel” is displayed. Otherwise, we’ll get the “It is a consonant”.
goto Statement
It is used to jump the control from one location to another location within a function. This unconditional
control statement diverts the control to a specified location where the label is mentioned. Using this, the
control can be moved to forward or backward or in any order in the function.
The early high level languages such as ALGOL, FORTRAN were influenced by a combination of if & goto
statements. The goto was considered to be a powerful statement as any problem (program) can be solved
using this. But program becomes complex, if the code is big and many goto statements are used.
As a result this statement fell out of favor some years ago, hence several alternative rich set of control
statements are provided in modern languages such as switch, while, for, do-while, break, continue, and
return. However, for some kind of situations like getting out of nested loops, to solve recursive like programs
using loops, …etc. We cannot get a solution using these rich set, so, goto occasionally has its uses.
Syntax: goto label; // Here, the label is a valid identifier followed by a colon, indicates a location to where
the control has to be jumped using goto. Label name follows the rules of a variable name.
void main()
{ printf(“India\n”);
goto end; //observe here, the control will be transferred to “end”
printf(“American\n”);
printf(“Australia\n”);
end: // here ‘end’ is a label
printf(“Russia\n”);
printf(“Japan\n”);
}
Output: India
Russia
Japan
When “goto end” is executed, the control simply jumps over to label “end” and follows next instructions.
These loop control statements are used to execute some set of instructions repeatedly until a given test
condition is attained. Each loop structure has its own style and provides a convenience to the user. The user
can select any loop control statement in the program according to the requirement and convenience and
there are no specific situational suggestions, which loop to use when and where.
All loop control statements are attached with a test-condition and a body. This body contains one or more
instructions, which are to be executed repeatedly until the test condition becomes false. We can write any
type of instructions or even another control statement with in this body.
If the test-condition becomes false then the control jumps out of loop-body and follows the bottom
instructions “instruction n+1, instruction n+2 ….”
If loop body has only one instruction, the pair of braces {} are optional. This is as said in if-statement.
If loop-body has more instructions exist, they must enclose by pair of braces{}.
The test-condition must fail after certain number of times. Otherwise, it goes to infinite loop.
Don’t terminate loop header with semi-colon, otherwise, the head & body gets separated.
while(test-condition) // only the first instruction is repeated here. (Observe no braces is given)
instruction 1;
instruction 2;
instruction 3;
instruction 4;
--
In the above loop, only the instruction1 repeats until the test-condition becomes false. When the test-
condition fails then loop will be terminated and follows instruction-2, instruction-3… onwards.
(if braces not provided then compiler takes only first instruction into loop body)
Observe semicolon at the end of loop-header Let us imagine this semicolon in the next line
and how it formed as null-body (null instruction)
void main()
{ int i=1; // initialization of loop variable with 1
while(i<=10) // loop begins here
{ printf(“%d ”, i ); // printing ‘i’ value on the screen
i++; // incrementing ‘i’ by 1
}
printf(“\n this is end of loop ”);
}
Generally, programmers always take loop variable name as ‘i’ , because loop cycles are called iterations and
first letter of it taken as loop variable. Generally loop variable begins with value ‘1’ and increments up to ‘N’.
i=10;
while(i>=1) // loop begins here
, printf(“%d ”, i); // printing ‘i’ value on the screen
i--; // decrementing ‘i’ by 1
}
}
Printing 1, 10, 100, 1000, 10000, 1000000 for 6 times [ do not use pow() fn ]
1. take ‘i’ as loop variable with starting value 1, here ‘i’ works as loop counter as well as to print output(s)
2. print ‘i’ value as output
3. multiply 10 to ‘i’, to generate next value of output
4. repeat step2 and step3 until i<=100000
5. stop.
void main()
{ int i=1;
while(i<=1000000)
, printf(“%d “, i );
i=i*10;
}
}
while(i<2*N)
, printf(“\t %d “, i );
i=i+2;
}
}
void main()
{ int i,n;
printf(“enter n value :”);
scanf(“%d”, &n);
i=n/2; // checking for factors starting from n/2
while(i>0) // we are expected to check up to 1.
{ if(n%i==0) // verifying ‘n’ with each number.
break; // break stops the loop.
i--;
}
printf(“%d\t “, i); // printing big factor
}
Here N verified repeatedly for big factor from N/2 to 1, meanwhile, if it is divided with any of ‘i’ then loop
stops by break and prints it as big factor. The break statement stops the loop and moves the control out of
loop-body, which is as above shown arrow.
Above program can be written in simple form as
i=n/2;
while(n%i!=0)
i--;
printf(“big factor is %d”, i);
void main()
{ int n, i, bool ;
scanf(“%d”, &N);
i=2, bool=1; // assume ‘N’ is prime, so take bool as 1 (true).
while(i<=N/2)
{ if(N%i==0)
{ bool=0; // here N divided, therefore N is not prime, so set bool to 0 (false) and stop
break;
}
i++; // if N is not divided then check with next ‘i’ value until i<=n/2
}
if( bool==1) printf(“prime”); // printing output, after completion of loop
else printf(“not prime”);
}
Logic2: Count all factors of N, that is, divide N with all numbers from 1 to N and count them, if factors
count==2 then say it is “prime” or else “not prime”. This is simple logic but execution is slow, because it is
unnecessary check with all numbers if once N is divided. (here we are not stopping by break)
count=0; i=1;
while(i<=N) // loop to count all factors between 1 to N
{ if(N%i==0)
count++; // increments ‘count’ when N is divided with ‘i’
i++;
}
if( count==2) printf(“not prime”);
else printf(“prime”);
void main()
{ int i, n, sum, x, p;
printf(“enter x , n value :”);
scanf(“%d%d”, &x, &n);
sum=0; i=1;
1
p=x; // first value of p is x
while(i<=n) // loop to add up to ‘n’ terms
1 2 3
{ sum=sum + p; // adding x , x , x … to sum
i
p=p*x; // to generate next x value
i++;
}
printf(“\n sum=%d”, sum);
}
i=s=1;
while( i<=n)
{ printf(“%d “, s*i );
s = -1*s;
i++;
}
}
Finding sine series value: sin(x) x1/1! - x3/3! + x5/5! – x7/7! … up to 10 terms
ip: x=3, N=5
op: sum=0.1453 [ (3.0) + (-4.5) + (2.025) + (-0.4339) + (0.05424) ]
void main()
{ long int i, fact, sign;
float x, sum, p;
printf(“enter sign(x) value :”);
scanf(“%f”, &x);
i=fact=1; p=x; sign=1; sum=0;
while(i<20) // adding 10 terms ( not 20, because ‘i’ is incrementing by 2)
{ sum=sum+ sign* p/fact;
sign=-1*sign; // changing ‘sign’ for next term
i
p=p*x*x; // getting next x value
i=i+2; // getting next odd number
fact=fact*(i-1)*(i); // getting next factorial value
}
printf(“\n sum =%f”, sum);
}
Printing each digit separately in a given number (N) [ printing right to left ]
ip: 2345 ip: 724
op: 5,4,3,2 op: 4, 2, 7
Logic: extract digit by digit from N, and print on the screen, given below logic extracts the digits from right-
to-left in N, and prints on the screen
step1: divide N with 10 and collect the remainder(s), the remainder is always the last digit of N, when it is
divided with 10 (lastDigit=N%10)
step2: now print the last digit
step3: to get next digit of N, now remove current last digit from N by doing N=N/10
step4: repeat step-1, step-2, step-3 until N>0
Let the input is 2345 and program prints as given below table
Iteration-4 10 ) 2 (0
N is 2 0
----------
2 printf(“2”)
N is 0
( stop ) 0 (stop)
while(N>0)
{ d = N%10;
if(d==5)
{ bool=1; // now the digit ‘5’ is found
break;
}
N=N/10;
}
if(bool==1) printf(“the digit 5 is exist”);
else printf(“the digit 5 is not exist”);
}
void main()
{ int N, digitCount=0;
printf(“enter N value :”);
scanf(“%d”, &N);
while(N>0)
{ N=N/10; // removing last digit from N.
digitCount++; // counting the digits
}
printf(“no of digits = %d”, digitCount);
}
while(N>0)
{ digit=N%10;
rev=rev*10+digit; // adding digit at end of ‘rev’
N=N/10;
}
printf(“reverse = %d”, rev);
}
Let input is 2345, then the instruction “rev=rev*10+digit” in every iteration is as follows
Let N=2345 d=n%10 rev = rev*10+digit N=N/10
st
After 1 cycle 2345%10 5 0*10+5 5 234
nd
After 2 cycle 234%10 4 5*10+4 54 23
rd
After 3 cycle 23%10 3 54*10+3 543 2
th
After 4 cycle 2%10 2 543*10+2 5432 0
Let the input is 2345 and program prints as given below table
N=2345, P=1000 Program code is
p) N (q void main()
Iteration1 1000)2345(2 printf(“two”) { int N, q, P=1;
N2345 2000 printf(“enter N value:”);
P1000 ----------- scanf(“%d”, &N);
345
count-1
Iteration2 while(N/P>9) // generating ‘p’ to 10
N345 100) 345 (3 printf(“three”) { P=P*10;
P100 300 }
-----------
45 while(P>0) // printing each digit in English words
{ q=N/P; // gives first digit of N as quotient
switch(q)
Iteration3 10) 45 (4 printf(“four”)
{ case 0: printf(“zero”); break;
N45 40
case 1: printf(“one”); break;
P10 -----------
case 2: printf(“two”); break;
5
…
case 9: printf(“nine”);
Iteration4 1 ) 5 (5 printf(“five”) }
N5 5 N=N%P;
P1 ---------- P=P/10;
0 }
N0 Stop }
3 2 1 0
1 1 0 1 1*2 + 1*2 + 0*2 + 1*2 13
3 2 1 0
2 2 2 2 8 + 4 + 0 + 1
2 13
2 6- 1
2 3- 0
3 2 1 0
2 1- 1 10 * 1 + 10 * 1 + 10 * 0 + 10 * 1
0- 1 L R
The remainders, we get one by one must be inserted in first position of ‘sum’ value. (‘sum’ holds output)
For example, the remainders of 13 are: 1, 0, 1, 1 (from top to bottom). These remainder should be inserted
in ‘sum’ as 1 01 101 1101
step1: multiply each reminder with 10i and sum up
step2: the binary number formed as 1000*1+100*1+10*0+1*1 1101
void main()
{ int N, i, rem;
long int sum;
printf(“enter any decimal number :”);
scanf(“%d”, &N);
sum=0; i=0;
while( N>0 )
{ rem=N%2;
sum=sum + rem*pow(10,i); // include math.h file for pow() fn.
N=N/2; i++;
}
printf(“\n binary number = %d”, sum);
}
16 370359
16 23147 7 0*100+7 7
16 1446 11 (B) 7*100+11 711
16 90 6 711*100+6 71106
16 5 10(A) 71106*100+10 7110610
5 7110610*100+5 07 11 06 10 05
C-Family 101 Loops
Iteration-1 0 1 1 2 3 5 8…
X Y new=X+Y
Iteration-2 0 1 1 2 3 5 8…
X Y new=X+Y
Iteration-3 0 1 1 2 3 5 8…
X Y new=X+Y
C-Family 102 Loops
void main()
{ int X, Y, new, i;
X=0; Y=1; i=1
while(i<=10)
{ printf(“%d\t”, X);
new=X+Y; // generating next fibo number
X=Y; // advancing X to Y and Y to new
Y=new;
i++;
}
}
void main()
{ int x , y , rem;
printf(“enter x, y values :”);
x y x y stop scanf(“%d%d”, &x, &y);
12 ) 18 ( 1 6 ) 12 ( 2 while(1)
12 12 { rem=y%x;
6 if(rem==0)
0 break;
y=x; // take x as y
x=rem; // take rem as x
}
printf(“\n GCD = %d”, x);
}
C-Family 103 Loops
2 20 15 35
2 10 15 35
2, 3 5 15 35
3,4,5 5 5 35
5,6,7 1 1 7
1 1 1
void main()
{ int x,y,z, lcm=1, i=2, bool;
printf(“enter 3 numbers :”);
scanf(“%d%d%d”, &x, &y, &z);
while( x>1 || y>1 || z>1) // repeat until all become 1.
{ bool=0;
if( x%i==0 )
{ bool=1;
x=x/i;
}
if( y%i==0 )
{ bool=1;
y=y/i;
}
if( z%i==0 )
{ bool=1;
z=z/i;
}
if(bool==1) lcm=lcm*i; // then take ‘i’ as factor
else i++; // if no number divisible then try with next number(s)
}
printf(“\n lcm = %d”, lcm);
}
C-Family 104 Loops
intialization
Syntax for for-loop is
for(initialization; test-condition; increment)
{ instruction 1; condition
false
instruction 2; increment ntion
true
----
---- Instruction 1
instruction N; Instruction 2
} ---
instructionN
instruction N+1;
instruction N+2;
----
----
Instruction N+1
Instruction N+2
---
This loop repeats as long as the condition is true, first it enters into loop-body through initialization-part.
From 2nd cycle, the control enters through increment/decrement part. This is as given below
Note: for-loop header must have only two semicolons, if not, it is an error.
Let us have some examples,
C-Family 106 for- loop
loop to print odd numbers from 1 to 100 loop to print odds from n to 1.
for(i=1; i<100; i=i+2) for(i=n; i>0; i--)
{ { if( i%2==0)
printf(“%d “, i ); printf(“%d “, i );
} }
eg) all the three parts of loop header may not present, we can avoid any part just by leaving it blank.
However, the two semicolons must present as they indicates the separation of three parts.
do-while loop
The do-while loop is quite opposite to while-loop, in case of while-loop, the condition part appears at the
top of loop-body, whereas for do-while loop, the condition part appears at bottom of loop-body.
Thus while-loop is top-test construct, and do-while is bottom-test construct.
As a result, the do-while body executes at least once irrespective of condition is true/false.
The while-loop may or may not be executed; it may fail at the beginning, at least without executing once.
But do-while loop executes at least once irrespective of condition is true/false.
This is rarely used in the programing, who wants to execute loop body at least once.
Syntax is
do
Instruction 1
{ instruction 1; Instruction 2
instruction 2; ---
instruction N
-----
----
instruction N; true
condition
} while( condition ); // bottom test-condition
instruction N+1; false
instruction N+2;
Instruction N+1
InstructionN+2
---
Some programmers dislike do-while loop because of its structure, so they always avoid with the help of
while-loop using break statement, which is as given below
while(1)
{ ----
----
----
----
if(condition) break; // bottom test-condition, now it is like do-while loop
}
“Continue” is also a condition less control statement, skips some instruction in the loop when it gets
executed. When continue gets executed then the control immediately transfers back to beginning of loop
and follows next cycle, so that bottom instructions are bypassed. This is as shown below
while ( condition )
{
instruction 1;
instruction 2;
if( condition )
continue;
instruction 3;
instruction 4;
instruction 5; // instructions-3 to instruction-N are bypassed by continue
----
instruction N;
}
while(condition )
while(condition 1) {
{ instruction 1; instruction 1;
instruction 2; instruction 2;
….. …..
instruction k; instruction k;
for( initialization; condition; increment )
while(condition 2) {
{ instruction k+1; instruction k+1;
instruction k+2; instruction k+2;
…… ……
instruction m; instruction m;
} }
instruction m+1; instruction m+1;
instruction m+2; instruction m+2;
…... …...
instruction n; instruction n;
} }
C-Family 113 Nested-Loop
Observe the inner loop ‘j’ in each & every iteration at outer loop is
1st iteration, when i=1 for(j=1; j<=1; j++)
printf(”%d “, j); // 1
4th
iteration, when i=4
for(j=1; j<=4; j++)
printf(”%d “, j); // 1 2 3 4
=======================================================================================
123456 for( i=6; i>=1; i--) The ‘j’ loop repeats as follows
12345 {
1234 for(j=1; j<=i; j++) for(j=1; j<=6; j++) // 1 2 3 4 5 6
123 printf(“%d “, j); printf(“%d “, j);
12 printf(“\n”);
1 } for(j=1; j<=5; j++) // 1 2 3 4 5
printf(“%d “, j);
654321 for( i=6; i>=1; i--) The ‘j’ loop repeats as follows
54321 {
4321 for(j=i; j>=1; j-- ) for(j=6; j>=1; j--) // 6 5 4 3 2 1
321 printf(“%d “, j); printf(“%d “, j);
21 printf(“\n”);
1 } for(j=5; j>=1; j--) // 5 4 3 2 1
printf(“%d “, j);
The first ‘j’ loop prints the 12345, whereas second ‘j’ loop prints the 54321
5 blanks
for(x=5,i=1; i<=6; j++)
1
{ for(j=1; j<=x; j++) // loop to print blanks
4 blanks 2 2
printf(“⨿“);
3 blanks 3 3 3 for(j=1; j<=i ; j++)
2 blanks 4 4 4 4 printf(“*⨿“);
1 blanks 5 5 5 5 5 printf(“\n”);
0 blanks 6 6 6 6 6 6 x--;
…6 rows
}
The 1st inner j-loop prints the spaces before
printing numbers
the second inner loop prints the stars.
Try without using ‘x’.
C-Family 116 Nested-Loop
11 to get this pattern, some spaces need to be added before each row,
1221 which is below shown
123321 7 blanks 1 1
12344321 6 blanks 1 2 2 1
1234554321 5 blanks 1 2 3 3 2 1
123456654321 4 blanks 1 2 3 4 4 3 2 1
12345677654321 3 blanks 1 2 3 4 5 5 4 3 2 1
1234567887654321 2 blanks 1 2 3 4 5 6 6 5 4 3 2 1
1 blacks 1 2 3 4 5 6 7 7 6 5 4 3 2 1
0 blanks 1 2 3 4 5 6 7 8 8 7 6 5 4 3 2 1
5 blanks
for(x=5,i=1; i<=6; j++)
*
{ for(j=1; j<=x; j++) // loop to print blanks
4 blanks * * *
printf(“⨿“);
3 blanks * * * * * for(j=1; j<2*i; j++)
2 blanks * * * * * * * printf(“*“);
1 blanks * * * * * * * * * printf(“\n”);
0 blanks * * * * * * * * * * * x--;
…6 rows
}
The 1st inner j-loop prints the spaces before
printing numbers
the second inner loop prints the stars.
Try without using ‘x’.
0 blanks * * * * * * * * * * *
N=6;
1 blanks * * * * * * * * * for(x=0,i=1; i<=N; j++)
2 blanks * * * * * * * { for(j=1; j<=x; j++) // loop to print blanks
3 blanks * * * * * printf(“ “);
4 blanks * * * for(j=1; j<2*N-2*i; j++)
5 blanks * printf(“*“);
printf(“\n”);
x++;
}
C-Family 117 Nested-Loop
Space for all items of array is allocated in contiguous memory locations in the RAM and each item is
accessed with their index value in the program. For example, in the above array values, the index of 13 is 0,
26 is 1, and 7 are 2 and so on.
Arrays can be extended to any number of dimensions, but most of the time, we use single or double
dimension arrays in the programming, the arrays are represented as,
int x[5]; single dimensional array int y[5][6]; two dimensional array
Y[2][0] … … … … Y[2][5]
Y[3][0] … … … … Y[3][5]
Y[4][0] … … … … Y[4][5]
Here, the ‘X’ is an array name, which holds 7 integer items. The declaration of array is same as any other
normal variable except the arrSize. The size should be mentioned with constant value and which represents
count of elements that are collectively created as array.
Accessing array elements
Each value in the array is accessed independently using its index value with the array name. Especially in C,
the index ranges from 0 to arrSize-1.
The syntax to access array element is: array-name[index]
the expression x[0] accesses the 1st element in array. x[0] 13
the expression x[1] accesses the 2nd element of array. x[1] 26
the expression x[i] accesses the i+1th element of array.
Printing first ‘5’ elements of an array is
for(i=0; i<5; i++)
printf(“%d “, x*i+); // 13 26 7 15 10
C-Family 122 1D-Arrays
Initialization of array
Assigning values at the time of declaration of array is called “array initialization”
So we can assign (initialize) values to array just like normal variable’s initialization.
Syntax: data-type array-name[arrSize]={ list of values };
int a[5]={10,20,30,40,50}; 10 20 30 40 50
void main()
{ int m[4], total, avg, i;
printf(“enter marks of 4 students :”);
for( i=0; i<4; i++)
scanf(“%d”, &m*i+);
for(i =0; i<4; i++)
total = total + m[i];
avg = total/4;
printf(“\n total = %d, average = %d”, total, avg);
}
The size of program will remain same even if the number of students increases. Also it leaves the code
simple & readable.
eg3) int a[ ]; // error, size must be given at coding time ( empty array not allowed)
Note: These arrays are called static-size-arrays(fixed size arrays), these are used when we know the size of
array at coding time. For examples phone[12], name[30], pincode[6], address[50].
Sometimes, we can’t expect the array-size(data-size) at coding time, then dynamic arrays are the alternative.
We will see at end of chapters [ malloc(), calloc(), realloc(), free() ]
C-Family 125 1D-Arrays
If all inputs are –ve like -12, -45, -6, then the condition if(Bigx<a[i]) always fails, because initial value of big is
zero, and no array value is > zero, so output zero is printed as big value. So to solve this problem, initialize
Bigx & Smallx with any one element in the array before comparison. It is better to initialize with a[0].
scanf(“%d”, &n);
for( i=0; i<n; i++)
{ printf(“enter value of a*%d+ :”, i );
scanf(“%d”, &a*i+);
}
for( i=0; i<n; i++)
{ if( a[i]%3 ==0 )
count++;
}
printf(“no.of 3 divisible are: %d”, count);
}
void main()
{ int a[20], i, bool, n;
printf(“enter how many input values :”);
scanf(“%d”, &n);
for( i=0; i<n; i++)
{ printf(“enter value of a*%d+ :”, i );
scanf(“%d”, &a*i+);
}
bool=1;
for( i=0; i<n-1; i++)
{ if( a[i] > a[i+1] ) // if any one value is bigger than next value, not in ascending order
{ bool=0;
break;
}
}
if(bool==1) printf(“yes, in ascending order”);
else printf(“no, not in ascending order”);
}
void main()
{ int a[20],i,j, n, temp;
printf(“enter no. of input values ‘n’:”);
scanf(“%d”, &n);
printf (“enter %d values to array :“, n);
for( i=0; i<n; i++)
scanf(“%d”, &a*i+);
for(i=0, j=n-1; i<j; i++, j--)
{ temp=a[i];
a[i] = a[j];
a[j] = temp;
}
printf(“\n after reversing, the array elements are \n”);
for(i=0; i<n; i++)
printf(“%d “, a*i+);
}
C-Family 129 1D-Arrays
99 87 43 34 17
45 56 77 60 22
87 43 34 44 22
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8] A[9] A[10] A[11] A[12]
Now write a program, where accept N values from keyboard and delete kth element in the array(k<N)
later print all elements after deleting kth element.
45 56 77 60 99 87 43 34 44 22
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8] A[9] A[10] A[11] A[12]
void main()
{ int a[20],i, k, new;
printf(“enter no.of input values n :”);
scanf(“%d”, &n);
printf(“enter %d values to array : “, n);
for( i=0; i<n; i++)
scanf(“%d”, &a*i+);
printf(“enter new element and position to insert :”);
scanf(“%d%d”, &new, &k);
for(i=n; i>=k; i--) // shifting elements to right-side
a[i] = a[i-1];
a[k-1]=new; // inserting new element
n++; // now array contains n+1 elements
printf(“\n after inserting elements, the array is :”);
for( i=0; i<n; i++)
printf(“%d “, a*i+ );
}
C-Family 130 1D-Arrays
Let the average(mean) of all values are M, the formula as given below
sd = sqrt ( (A0-M)2 + (A1-M)2 + (A2-M)2 + (A3-M)2 + … + (An-M)2 / N )
void main()
{ int a[20], i, N, mean;
float sum, sd;
printf("enter the no.of input values N :");
scanf("%d", &N);
printf("enter %d values to array :", N);
for( i=0; i<N; i++)
scanf("%d", &a[i]);
for(i=sum=0; i<N; i++) // calculating sum of all values
{ sum=sum+a[i];
}
C-Family 131 1D-Arrays
21 44 55 62 56 23
B[0] Bb[1] B[2] B[3] B[4] B[5]
C-Family 132 Functions
Functions
Function is a subprogram that performs a specific independent sub-task in a program. It is a self-contained
block of instructions with an associated name to perform a specific, well-defined task. Functions mainly
provide reusability and modularity. It breaks down a big program into several sub programs and each is
designed and developed to perform a specific task. Thus collection of functions makes a C-program.
In computer science, the function is also called as routine, subroutine, subprogram, procedure, or method or
module.
While developing a big application, it should be designed in such a way that, it is divided into several
meaningful modules and each module again divided into several sub-modules called functions. For example,
let us consider Bank automation project, it can be divided into several modules say account, transaction,
customer, loan, etc. Each of these modules is made up of several functions which accomplish individual
tasks. Generally, every module is developed in separate files like “accounts.c”, “customers.c”, “loans.c”, etc;
finally, all such files which are developed by several people are integrated to build the whole project.
Types of functions
Functions are classified into two types: 1. Library functions 2. User-defined functions
Library functions: These are ready-made functions, which are designed and written by the C
manufactures to provide solutions for basic and routine tasks in the programming. For example I/O
functions printf() & scanf(), mathematical functions pow() & sqrt(), etc. The vendor of C, supply these
predefined functions in compiled form(object code format) with C software. There is huge collection of
functions available to meet all requirements in the programming, thus collection of such compiled functions
are called as function Library.
User-defined functions: We can write our own functions as per our requirement just like any library
function. There is no conceptual difference between user-defined and library functions, all works in similar
way, besides, our functions can be added to existing library and we can use like a library function. If more
collections found, then we can create our own library.
In C, the main() is also a user defined function, the word main is reserved by the complier but the body is
implemented by the programmer. The main() function works as start & end point of program. The remaining
functions execute by transferring the control temporarily from main().There is no syntax difference between
main() and other functions, all works in similar way.
Let us see the following example, which illustrates how the functions are executed in the program. The
instruction k=findBig(4,23) is a function-call statement in main(), when it gets executed, the control jumps to
the findBig() fn body along with values (23,4), and these values are assigned to (x, y) variables , after
calculating big value(z), it returns and assign back to k, this is as shown below.
void main()
{ int findBig ( int x, int y)
int k; { int z;
if( x>y)
k=findBig(23,4); z=x;
else
printf(“%d”,k); z=y;
} return(z);
}
C-Family 133 Functions
*While jumping the control from main() to findBig(), the values(23,4) are passed and assigned to (x, y),
after finding the big value to ‘z’, it returns and assign back to ‘k’. In this way functions are executed.
*the passing input values to function are said to be arguments, whereas the receiving variables of such
arguments are said to be parameters. In this example, the values(23,4) are arguments and (x, y) are
parameters. The arguments and parameters count must be matched, and type should be compatible.
*In this program, we have two functions main() and findBig(). Here the main() is invoking(calling) the
findBig(), so in this context main() is said to be calling-function, whereas findBig() is said to be called-
function.
*Here the word “findBig” is said to be the name of function and it follows the rules of variables name. We
can give any name to the function just like a variable name in the program.
*The type int before the function name is said to be return-value-type. In this example, the function is
returning integer value of ‘z’, therefore return-value-type declared as int. The return-type explicitly tells
what type of value the function is returning. It is useful for compiler to check syntax errors as well as to the
programmer for documentation.
*Thus, every function does something and returns calculated result to the calling-function. Every function
including main() fn follows same syntax rules with one or two optional statements. The following figure
shows the each & every entity of function
Return-value-type
Return-value-type
Here this ‘return’ statement is not required, because, the last closing
braces ‘}’ of function works as “return” statement.
This is said to be “return-value-type” of a function, this type must be matched with the return-value
of a function. In this example x+y is returning as int, therefore return-value-type declared as int.
C-Family 134 Functions
The function findTax() is taking employee salary as input(argument), and after calculating tax amount, it
returns and assigns back to ‘tax’. This is as shown in the above figure, here the variable ‘salary’ is said to be
argument, whereas ‘sal’ is said to be parameter. In the above findBig() example, the arguments (23,4) are
constants, but in this example, argument salary is a variable. Here value of salary is passed as argument to
the function. Sometimes argument and parameter names can be same, but they are different copies, let us
see following example
Here argument and parameter variable’s name are same, but they are different copies, so in this total
program two ‘salary’ variables and two ‘tax’ variables exist. One set belongs to main() fn and second set
belongs findTax() fn (A separate memory space is created for each set like above shown picture).
So, argument variables are always different from parameter variables, parameters work like a copy of
arguments. It can be imagined as parameters are place-holder of arguments. Generally, beginners get
confusion when argument & parameters names are same.
C-Family 135 Functions
* The fact() function takes argument ‘N’(5) as input and stores into parameter ‘X’.
* After calculating factorial value, it returns and assigns back to ‘k’.
* In this way, function can be called as many times as we want. Let us see in next examples, how functions
can be called more than once.
void main()
{ int N=5, result; int findSum( int N)
result=findSum(N); // function call { int i , sum=0;
if(result==N*(N+1)/2) for(i=1; i<=N; i++)
printf(“program is correct”); sum=sum+i;
else return sum;
printf(“program has some logical errors”); }
}
C-Family 136 Functions
Syntax of function
Function has 3 syntaxes
1. Function definition/body ( defines the code of function )
2. Function calling/invoking ( activating the function )
3. Function declaration ( also called proto-type )
① Syntax of function-body
return-value-type function-name( parameters-list )
{ variable-declaration;
instruction1;
instruction2;
……..
return(result);
}
The function body defines the task of function, ie, what it does. This body executes when this is called
explicitly from other part of program. Every function follows this syntax with one or two optional
statements.
* Calling a function means invoking the function task, ie, asking the function to do his respective job. When
the above function-call statement gets executed, the control transfers to its body along with arguments and
after executing all instruction within the body, the control returns to same point of call-statement.
* To understand the mechanism of function-call, let us consider a simple example. Suppose a bank manager
wants to verify cash in the bank, he calls his assistant and gives argument to him, later assistant returns the
details of cash. In the first example, the manager is main() and assistant is findBig(). Here main() wants to
find the big of two, so it called the findBig() and gave arguments (23,4) to him. In this way functions work.
* Function name: The body of function associate with a name and this name should be relevant to
function’s task, it should express the purpose of function. For example, if a function is written to find the
square root of a value, then it is better to name it as ‘sqrt()’. The body of function invokes by calling with this
name in the program.
* Calling vs Called: Here the main() is calling the findBig() function, so in this context, main() is said to be
calling-function whereas findBig() is said to be called-function.
* Arguments vs Parameters: Arguments are nothing but input values of function. When a function is called,
they are passed from calling-function to called-function along with the control. Whereas parameters are
variables, which receives (hold) the argument values at called-function. (Arguments are values whereas
parameters are variables)
* The following figure illustrates the relation between argument and parameters.
C-Family 137 Functions
As per old compilers, function proto-type must be given at the beginning of program followed by #include
statements. This declaration is nothing but introducing the function to the compiler about function-name,
parameters-type and return-type. This is similar to variable declaration in the program. It has no special
syntax like control statements. This syntax is simply a header line of function-body with the semicolon
termination. For example, int big(int,int); this syntax is telling, the function name is “big” and taking two
int-arguments and returning int-value. In this way, we define proto-types as given below example.
#include<stdio.h>
int big(int,int); // big() function proto-type
void main() // main() function body
{ ………
}
int big(int x, int y) // big() function body
{ …….
}
Note: if called-function body is provided before calling-function, then this body itself works as proto-type.
In this case, no special proto-type required in the program, for example,
#include<stdio.h>
int big(int x, int y) // this body also works as proto-type
{ …….
}
void main()
{ ………
}
Note: we have a freedom to write function in any order, even main() fn can be written at bottom of program
like above shown. But as main() fn is starting point of program, the compiler automatically moves to
beginning in .exe file. In this way programmer has a freedom to write functions in any order.
C-Family 138 Functions
void main()
{ float pie()
float area, radius=8; {
return 3.14;
area = pie() * radius *radius; }
void main()
{ int n;
printf(“enter n value :”);
scanf(“%d”, &n);
if( isArmstrong(n)==1)
printf(“yes, it is Armstrong“);
else
printf(“no, not Armstrong”);
}
Printing list of Armstrong numbers between 1 to 1000 (using above fn)
Output: 1, 153, 370, 371, 407.
void main()
{ int n;
for( n=1; n<=1000; n++)
if( isArmstrong(n)==1 )
printf(“%d “, n);
}
Finding prime-ness of a given number using function
This function takes integer N as argument and returns the prime or not. If prime returns 1, otherwise, 0;
int isPrime(int n)
{ int i;
for(i=2; i<=n/2; i++) //checking ‘n’ by dividing from 2 to n/2
{ if(n%i==0)
return(0); // here N divided, so returning ‘0’ as not-prime
}
return(1); // not at all divided, so returning ‘1’ as prime
}
void main()
{ int n;
printf(“enter n value :”);
scanf(“%d”, &n);
if( isPrime(n) ==1)
printf(“prime number “);
else
printf(“not prime number”);
}
Printing prime numbers from 50 to 100 using above “isPrime()“ fn.
void main()
{ int n;
for(n=50; n<=100; n++)
{ if( isPrime(n)) if(1) true or if(0) false
printf(“%d “, n);
}
}
Here isPrime() will be called 50 times with arguments 50, 51, 52, 53, 54, 55, 56, ….,100;
C-Family 142 Functions
The above “welcome()” function is just displaying a message on the screen, it is taking no argument and
returning no-value. Therefore, the return-value-type ‘void’ has given in this example. The last closing braces
of a function works as “return” statement, therefore “return” an optional statement at the end of function.
As we know, the main() function generally returns no-value, that is why we always write main() function
body as “void main(){…}”
void x()
{ printf(“\n before y() function”);
y();
printf(“\n after y() function”);
}
void y()
{ printf(“\n On behalf of C-Family Computers”);
}
before x() function
before y() function
On behalf of C-Family Computers
after y() function
after x() function
C-Family 144 Functions
* Scope of variables
If any variable declared within a block then it becomes private and cannot be used or accessed outside of
that block, same way, we cannot use/access one function’s variable in other function. In this way, every
function is independent as per their data & code. Only the data is exchanged between functions by passing
and returning.
void main()
{
{
int k=10;
}
{
printf(“%d ”, k); // error, undefined symbol ‘k’
}
}
Here compiler shows an error message “undefined symbol k”, because the variable ‘k’ declared in 1st inner
block and we are trying to access in 2nd inner block. Thus ‘k’ cannot be used other than 1st block as it is
private to that block. In this way, variables are block-scope types. Let us see one more example
void main()
{ int k=100;
test();
printf(“the k value =%d”, k);
}
void test()
{ k++; // error, undefined symbol ‘k’
}
Here compiler again shows same error message “undefined symbol k”. The variable ‘k’ declared in main()
function body and it cannot be accessed in test() function body.
example3
void test()
{ int k=100;
return(k);
}
void main()
{ test();
printf(“%d “, k ); // error, undefined symbol ‘k’
}
The variable ‘k’ declared in test() fn, cannot be accessed in main() fn, so it is an error.
C-Family 145 Functions
Example 1 Example 2
n n
void main() 10 void main() 10
{ int n=10; { int n=10;
printf(“\n before calling =d”,); printf(“\n before calling = %d”, n);
test(n); test(n);
printf(“\n after calling = %d “, n); printf(“\n after calling = %d “, n);
} }
return(0) defines the normal termination of program and it closes all files, i/o streams and other resources
before termination of program.
return(1),return(2), etc defines the abnormal termination of program, here OS records the error-code or
error-type in log files for future reference. (Like history in web-browsers)
C-Family 148 Functions
2. function with arguments and no return value: some functions take arguments but returns nothing,
eg printing multiplication table.
3. function with no arguments but returns a value: this task is less common in programming , takes no
arguments but returns a value, like calling: rand() fn, getTime() fn, getDate() fn, getGPS() fn.
4. function with no arguments and no return value: this is used for fixed jobs, the tasks like clearing
screen, printing common messages.
5) Function proto-type
This concept is very good for senior programmers when they want to create abstract data-type, but for
beginners who learning C/C++, it seems to be worst concept. It creates much confusion over function-call vs
function-proto type. Good news is, in modern compilers this concept eliminated/removed.
The English word proto-type means a model to an actual implementation, in C, it is used to introduce the
function to the compiler to give an idea about the return-type, function-name, argument-type and count.
Let us see, why it is required
C-Family 149 Functions
void main()
{ ---
k=test(20,30); // function-call
---
}
float test(float a, float b) // function body
{
return(a+b);
}
In C, functions are compiled in an order in which they are written in the program. Here first main() fn, later
test() fn will be compiled. While compiling main() function, at that time, compiler doesn’t know about test()
function( because it appeared at bottom). When compiler faces the call statement “k=test(20,30)”, it
notices and assumes, the ‘test()’ is a function with arguments 20,30. Based on this call statement, compiler
understands it as, the function is taking two int-type arguments by seeing (20,30) and returning int-type
value. (because default return type is int)
But later when compiling test() function-body, it will notices as, it is taking ‘float-type’ arguments with
return value float, therefore, this leads to data-type mismatch error between call and body.
To solve this problem, we have two options,
1. Declare the function before first call (or)
2. Define the function body before first call. (called-function before calling-function )
float test(float , float); // function proto-type Float test(float a, float b) // this body also works as proto-type
void main() {
{ --- return a+b;
k=test(); }
---
} void main()
float test(float a, float b) { ---
{ k=test();
return(a+b); ---
} }
7) Advantages of functions
Reduces repetition of code: the repeated code can be converted into a function and called as many
times as we want in the programing.
Code reusability: Once, if function is made ready for use, it can be used several times in several programs
where ever it is necessary. Thus, reuse of function makes the programming easier and speed. Generally,
programmers develop applications from already existing code not from zero level. As we know pow(), sqrt(),
printf(), scanf(),…etc are preexisting functions and they are using many times almost in every program.
Reduces complexity: when a big program is divided into several functions, it reduces complexity,
improves readability, easy to modify and also debugging made easy.
Ease of debugging: debugging means finding syntax and logical errors. If any error occurs in a particular
function then it doesn’t require checking in other functions. Therefore, it is easy to find errors.
Increases readability: By observing function call statements (function-name), one can understand what
the function does, functions written by several people for several purposes. Generally, one doesn’t involve
or try to know how other’s functions made it. For example, we are calling “sqrt()” without knowing how it
works. So it is easier to understand the logic when program is made up with collection of functions. By
observing only function call statements in the program one can easily understand the entire logic.
Easy to modify: if one function is modified, that does not affect the other functions as they are
independent.
Portability: in computer science, C became a vital language, its usage extended in almost all fields in the
real world. Therefore, today, the C software is available in most of the computer environments. If a function
is developed on a particular operating system then it can be easily adapted to other operating systems
without/negligible modifications. Such written functions are portable and generic.
C-Family 151 pointers
Pointers
Pointers play an important role in C language, the excellent features of pointers have made ‘C’ a vital
language in computers world. In some other languages like Pascal, Basic, etc pointers are not programmers-
friendly as they are in C. In C, pointers are simple to use and programs can be made efficiently and
compactly. They give tremendous power to the programmer. A veteran programmer feels that, in the
absence of pointers no application could be made as efficiently as he expected. However pointers are
dangerous too, for example a pointer variable containing an invalid address can cause the program to crash.
In C program, in all situations, we cannot access the data directly using variable name. The alternative is,
accessing the data indirectly through its address; this is achieved through pointers. Pointer is a special type
of variable, which is used to store address of memory location, so that, such memory location can be
accessed using pointer from any point in the program. In this way, pointers provide indirect memory
accessing. Pointers are preferred mostly in manipulation of arrays, lists, tables, files, etc. Pointers and arrays
are closely related. Pointers provide quick and dynamic access of arrays. They have well support of
implementing linked lists, stacks, queues, trees, graphs and other dynamic data structures.
As we know, one function’s local variable visible/access within that function and cannot be accessed in other
function. This feature makes security, comfort and hidden away from other part of program. But some
variables (but not all) need to be accessed in other part of the program. In such case, pointers are the
alternatives. Using pointers, we can access calling-function’s data at called-functions. In case of large
collection of data like arrays, we cannot provide name for every data item to refer individually. For such kind
of data, pointers are the alternatives. Using pointers, we can access all items under one name using their
addresses, since the data items are stored sequentially one after the other in the memory. If we know the
address of one item, we can access adjacent items using pointer. Actually, the items of an array are accessed
internally through this technique only. Here array name acts as a pointer. Thus, arrays and pointers are
conceptually same. In case of dynamic collection of data, the size of input data cannot be estimated until the
execution time unlike static arrays. To provide space & access for such random size input data, pointers are
the alternative.
Definition of pointer
Pointer is a special kind of variable used to store address of memory location through which indirect
memory accessing can be performed. In other words, pointer is a variable used to access the data in the
memory through its address, i.e., pointers provide indirect memory accessing.
We know that, memory is a collection of bits, in which each eight-bits constitute one byte. Every byte has its
own unique location number called address. This location number (address) is just a serial number of the
byte sequence. For example, first byte address is 1, second byte address is 2, and so forth. To store this
address we need a special kind of variable called ‘pointer variable’.
Address of memory location is just a serial number in the byte sequence, so, to store such address, a normal
integer variable is enough. However, indirect accessing of memory is difficult, because the compiler cannot
determine whether the variable is holding an address or value. To work with pointers, we have two unary
operators
Reference operator (&)
De-reference operator (*)
The ‘&’ and ‘*’ operators work together for referencing and de-referencing.
C-Family 152 pointers
k variable name
For example: int k=10; 10 value
2020 2021 assumed addresses
The address of a variable may not be always a fixed location like 2020 as shown in above, and it is
randomly given by the computer. Here we assumed k’s address as 2020.
Here the expression ‘&k’ is pronounced as “address of k”. The space for ‘k’ at run time may allocate
anywhere in the RAM, and to get such address, the reference operator(&) is used.
The format string %u or %p is used to print the address. [%pprints the address in hexadecimal format]
We know that, the variable ‘k’ occupies two bytes in memory. Suppose if it has occupied memory
locations 2020 & 2021, only the first byte address (2020) is considered to be the address of ‘k’ by the
compiler. As compiler aware that ’k’ occupies two bytes in memory, if the first byte address is 2020 then
obviously the second byte address would be 2021. So we always take first byte address as the address
of a variable irrespective of variable size.
Remember that, address is an unsigned-int type value.
X Y Z
10 int 20.45 float ‘A’ char
2000 int* 3000 float* 4000 char*
Address types are derived types, by adding a symbol star (*) to the any existing data-type, it becomes as
address-type.
The data type “int*” derived from “int”
“float*” derived from “float”
“char*” derived from “char”
“int**” derived from “int*”
“int***” derived from “int**”
In this way address types are defined in the program, these are infinite types.
C-Family 153 pointers
Syntax to get ‘value’ at given address is: *addressable_expression // prefix the symbol ‘*’ before the address
The reference operator (&) gives the address of ‘k’, whereas de-reference operator (*) gives the value in that
address, so finally it is ‘k’ value.
For example: int *p; // integer pointer, it holds a integer variable address
float *q; // float pointer, it holds a float variable address
Here p and q are pointer variables and they are capable of holding address of int & float variables
respectively. Here p is also called a pointer to int and q is called a pointer to float. The integer pointer is
used to access the integer data indirectly and a float pointer is used to access the float data indirectly.
int k=10; P k
int *p; 2020 10
4040 2020
p=&k; //p=2020
printf(“\n the value of k = %d”, *p); // output is 10
printf(“\n the value of k = %d”, **&p);
Note: Address is an integer type value, to store such address pointers take 2-bytes memory.
Therefore, in C, all pointers occupy 2-bytes memory. Here p & q pointers occupy 2-bytes each.
Let us see some demo programs to get command over pointers and their applications and to know how the
pointers can be applied in programs efficiently.
Demo1
void main()
{ int k=10;
int *p; // here ‘*’ used to declare ‘p’ as a pointer
p=&k;
printf(“\n output1 = %d”, *p); //here ‘*’ used to get value of k
*p=20; // here ‘*’ used to assign value 20 to k
printf(“\n output2 = %d”, *p); // here ‘*’ used to get value of k
printf(“\n output3 = %d”, k);
}
Demo2
This demo program tells how two pointers can points to same location.
void main()
2020
{ int k=10, *x, *y; X 4040
x=y=&k; // both pointers x, y is assigned with &k K
printf(“\n output1 = %d %d”, *x, *y); 10
*x=20; Y 2020 2020
*y=30; 5050
k=40;
printf(“\n output2 = %d %d %d”, *x, *y, k);
}
Output1: 10 10
Output2: 40 40 40
*Any number of pointers can points to one variable (one location), if the value is changed through one
pointer then the other pointers also gains changed value.
*Here both pointers x,y pointing to the same location ‘k’. Hence k’s memory can be accessed in three ways
using direct access k, using indirect access *x, and *y; here *x, *y, k accessing same location(k).
C-Family 155 pointers
Demo 3
This demo program swaps two values using pointers.
void main()
{ int k1=10, k2=20, *x, *y, t; X K1 (*x)
x=&k1; 2000 10
y=&k2; 4000 2000
t=*x; // t=k1; Y K2 (*y)
*x=*y; // k1=k2; 3000 20
6000 3000
*y=t; // k2=t;
printf(“\n output1 = %d %d”, *x, *y);
printf(“ \n output2= %d %d”, k1, k2);
}
Output:
output1 = 20 10
output2 = 20 10
Demo 4
Demo program for swapping two pointers and it is just like swapping two integer values.
} X K1
Output: &k2 10
output1 = 20 10 2000 4000
output2 = 10 20
Y K2
&k1 20
3000 5000
Initially x,y holding address of k1,k2; after swapping x & y, ‘x’ redirected to k2, ‘y’ to k1.
In this way we can change the pointing address while running a program. Let us have one more example
Demo 5
Expect the output of following program.
void main() X K1 K2
{ int k1=10, k2=20, *x; &K1 10 20
x=&k1;
*x=30;
x=&k2; X K1 K2
*x=40;
&K2 10 20
printf(“\n %d %d %d %d”, *x, k1, k2);
}
Here the pointer ‘x’ initially pointing to ‘k1’, later it is changed to point ‘k2’;
so the expression “*x” accesses the memory which is currently pointing to.
C-Family 156 pointers
Demo 6
Expect the output of following program.
void main() x K1
{ int k1=10, k2=20, *x, *y, t; &k1 10
x=&k1;
Y K2
y=&k2;
&k2 20
*x=*x+*y;
*y=*x+*y;
printf(“ \n output2= %d %d”, k1, k2);
}
Demo 7
Expect the output of following program X Y K
void main() &k &k 10
{ int k=10, *x, *y;
x=&k;
y=x;
*y=55;
*x=66;
printf(“\n %d %d %d %d”, *x, *y, k);
}
Demo 8
Expect the output of following program
void main()
{ int k1=10, k2=20;
int *x,*y;
x=&k1;
y=&k2;
printf(“\n enter any two values “);
scanf(“%d%d”, x, y); // passing x, y values to scanf(), which are nothing but &k1 , &k2
printf(“\n %d + %d = %d”, k1, k2, *x+*y);
}
C-Family 157 pointers
Here ‘p’ and ‘q’ are pointers of type ‘int*’ and ‘float*’ types respectively.
If there is any data type like ‘XYZ’ then ‘XYZ*’ will become pointer type.
Memory is a large collection of bytes, in which it is divided into several logical blocks called segments, and
each segment contains 65,535 bytes (64K) called offsets. The size of segment may vary from one to another
operating system. This is as given below
Segment 1 Segment 2 Segment 3 …
For example: int k=10; // Let us say, the variable ‘k’ allocated in 2020th offset of 3rd segment, then k address
would be 3:2020, but our programs print this address as a single number like 32020.
K variable name
10 value
th rd
3 : 2020 allocated in 2020 offset of 3 segment
Conclusion: based on compiler and operating system, the pointer takes 2/4 byte.
p
2000
3000 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6...
2000 2001 2002 2003 2004 2005
*p
q
2000 *q
4000
Here the expression *p accesses the first 2-bytes of pointing memory like above picture.
Here the expression *q accesses the first 4-bytes of pointing memory like above picture.
As p is int* pointer, it access only first 2-byte memory as ‘int’ type.
As q is float* pointer, it access only first 4-byte memory as ‘float’ type.
in this way, pointer access pointing memory.
printf(“sizeof(p) = %d”, sizeof(p)); // sizeof(p) = 2
printf(“sizeof(*p) = %d”, sizeof(*p)); // sizeof(*p) = 2
printf(“sizeof(q) = %d”, sizeof(q)); // sizeof(q) = 2
printf(“sizeof(*q) = %d”, sizeof(*q)); // sizeof(*q) = 4
printf(“\n before incrementing, the address is =%u %u”, p , q); // say output 2000, 4000
p++; q++; // p increments by 2, q increments by 4
printf(“\n after incrementing, the address is =%u %u”, p , q); // output will be 2002, 4004
}
sizeof() is an operator, which gives number of bytes occupied by a variable or expression.
While accessing array elements using pointer, the incrementing/decrementing is required, where ‘int*’
increments by 2, ‘float*’ increments by 4 to access next value in the array. We will see later topics.
C-Family 159 pointers
output 1 = garbage
output 2 = 100
As we know, the expression *p access only first 2 bytes of k memory as p is int* pointer. For accessing total
value of k then p should be type-casted to long int*. This is shown in second printf() statement.
---
}
q=NULL;
---
}
C-Family 161 pointers
{ int k=10; K
10 20
printf("\n before call = %d" , k);
2020
test(&k);
printf("\n after call = %d ", k);
}
void test( int *p) // int *p=&k; test() funciton
{ p
2020
*p=20;
4040
}
before call = 10
after call = 20
When the test() function calls in main(), the ‘&k’ passes and assigns to parameter p,
thereby using p, we can read/write/modify the value of k from the test() function.
The expression *p=20 assigns 20 to k.
this calling mechanism is known as call-by-reference
C-Family 162 pointers
Arrays VS pointers
Pointers and arrays are closely related, the array expressions can be taken as pointer expressions, for
example X[i] can be written as *(X+i). The C developers provided these excellent facilities to handle arrays
using pointers. The compiler itself manages arrays as pointers.
In arrays, the array name itself without any index works as constant pointer variable, which gives the
address of first element. If X*+ is an array, then the expression ‘X’ gives address of first element ( &X[0] ).
Here X , Y acts as int* and float* pointers, when the index value is added to it, they increments depends
upon its base type. The int* increments by 2, float* increments by 4 ….etc, because to get next element in
the array, pointer has to be incremented in such way.
C-Family 163 pointers
So the expressions *(p+0) p[0] *p accesses the x[0] // since *(p+0) p[0]
*(p+0) *(2000+0) *2000 10
Example2: if the pointer ‘p’ is pointing to a[2] then the expressions are as follows
int x[5] = {12,13,14,15,16};
p = &x[2]; P[-2] P[-1] P[0] P[1] P[2]
*(p-2) *(p-1) *(p) *(p+1) *(p+2)
P X[0] X[1] X[2] X[3] X[4]
2004 12 13 14 15 15
4000 2000 2002 2004 2006 2008
P After p++
2000 2002
4000 4000
}
void display(int *p / int p[] )
{ int i;
for( i=0; i<5; i++)
printf(“%d “, p*i+ OR *(p+i) ); p
OR &x[0]
The first declaration ‘int *p’ makes some confusion whether the pointer ‘p’ is pointing to single-integer or
array-of-integers, so one cannot be determined immediately. Therefore, C providers gave 2 nd declaration.
But by seeing 2nd declaration int p[], one might think that ‘p’ is an empty-array, but actually it is also same as
int *p. This declaration gives a clear idea that, ‘p’ is receiving an array-address instead single integer address.
While developing big size applications, there exist many functions and all are messed up in the program.
The called-function may not be found at bottom of calling-function, it may exist in some other file, that is
why they recommend this array-like-pointer declaration “int p*+”. It gives clear idea that, p is pointer to an
array instead of single-value.
return(big);
}
void main()
{ int a[20], n, i, k;
printf(“enter number of input values to array :”);
scanf(“%d”, &n);
printf(“enter %d values to array:”,n);
for( i=0; i<n; i++)
scanf(“%d”, &a*i+);
k = findBig(a, n);
printf(“\n the biggest element = %d”, k );
}
input: enter number of input values to array: 5
enter 5 values: 45 17 88 44 3
output: 88
The ability to access calling-function’s array elements at the called-function using its base-address
provides convenience for moving multiple data items back and forth between functions shows the
excellence of pointers in C.
The expression ‘*r’ accesses the ‘q’, the ‘**r’ accesses ‘p’, the ‘***r’ accesses the ‘k’ value.
Array of pointers
In computer science, array of pointers are used vastly in the programming. I recommend practice more on
this kind of applications. Arrays, which can hold the collection of addresses is known as array of pointers.
For example, we can declare array of pointers as int *p[3] instead of int *p1,*p2,*p3.
Using this feature, we often handle 2D array data such as matrices, tables, with flexible and compact code.
“float *p*3]. Here p[0], p[1], p[2] are pointers of type ‘float*’ each. (array of float pointers)
output: 1 2 3 4 5 6 7 8 9 10
6 7 8 9 10 4000
11 12 13 14 15
11 12 13 14 15 16
6000
C-Family 168 pointers
In call by reference method, the address of arguments are passed and stored into corresponding pointer-
parameters. Now, using these parameters, we can read/write/modify the argument values.
For example, calling swap(), getDate() function, …etc. Let us see an example
As we know, using ‘return’ statement, we can return only one value from a function, because most of the
time we return only one value, therefore syntax provided in that way. So to return more values, pointers are
alternative. We can return indirectly through pointers. The above swap() function indirectly returns the
swapped values to main() function through pointers.
Let us see one example
Following function takes radius as argument and returns area & perimeter of a circle.
void find( float radius, float *p, float *q)
{ *p= 3.14 * radius *radius; // assigning indirectly to ‘area’ in main() fn.
*q=2*3.14*radius; // assigning indirectly to ‘circum’ in main() fn.
}
void main()
{ float radius, area, circum;
printf(“enter radius of circle :”);
scanf(“%f”, &radius);
find( radius, &area, &circum);
printf(“ area = %f”, area);
printf(“\ncircumference = %f”, circum);
}
C-Family 169 pointers
Here find() function is taking radius as input and calculating area & circum. These two values indirectly
assigning to main() function’s area & circum variables through p&q variables.
P q
&area &circum
area circum
34.56 10.45
Advantages of pointers
1. Call by reference
We can return more values from a function
Passing array to function is possible only through call-by-reference
If data is big like strings, structure, file then call by reference saves the time and space.
2. Dynamic memory allocation is possible only with the help of pointers.
3. Direct interaction with hardware and O/S is possible.
4. Pointers are the alternative to implement dynamic data structures.
5. Pointers make the program flexible, compact and fast execution
6. Through pointers it is easy to handle the data.
3. The type difference between one to another pointer helps to determine the data type of target location
which the pointer pointing to
int* pointer points to int memory
float* pointer points to float memory
Similarly all pointers occupy in that way.
Pointer to a function
Pointer not only points to a data, but also can points to a code. That is, a pointer can be made to points to a
function. So that using pointer, we can make function calls also. In C, every function is loaded in separate
memory location as it appears in C program. This location address is the entry point of a function, ie, it is the
first instruction address of a function. Using this address, we can shift the control from caller-function to the
called-function.
This approach seems to be unnecessary in general programming. Because in C, all functions are global, any
function can be called from anywhere in the program. However, it is possible to pass addresses of different
functions in different times to a function thereby making function-calls more flexible and abstract.
Syntax to declare a pointer to function
return-value-type (*pointer-variable-name) ( list-of-parameters-type);
To get the address of a function, use the function name without parenthesis and arguments that gives
starting address of a function. The following program gives a demo.
void test(); // function-declaration
void main()
{ void (*p)(); // pointer to function, which takes no arguments and returns no value.
p=test; // assigning tes() function address to ‘p’
p(); // calling test() function through ‘p’
(*p)(); // this is another style of calling the test() fn, old style.
}
void test()
{ printf(“\n Hello World”);
}
void (*p)(): this declaration is a pointer to function, this tells that ‘p’ is a pointer, which pointing to a
function, and that function takes no arguments and returns no value.
switch(ch)
{ case 1: p=add; break;
case 2: p=multiply; break;
case 3: p=divide; break;
case 0: exit(0);
}
result = p(v1,v2); // calling the function on user selected choice
printf("output = %d", result);
}
Bubble sort
In bubble sort, the adjacent pair of elements is compared one with next element, and placed into sorted
order by swapping disorder elements. ie, it compares a[i] with a[i+1], if a[i]>a[i+1] then swapping takes
place. In this way bubble sort works. Each pair we feel like bubble while comparing elements, therefore it
was called as bubble sort. The process will be as follows
Step1: In every iteration of loop, it compares a[i] with a[i+1], if any a[i]>a[i+1] then swapping takes place. It
compares and swaps from first element to last element. After this process, the biggest element will be
moved to last position and it is said to be sorted.
Step2: In second iteration of loop, compares and swaps for first N-1 elements as said in step1,
because, the last element already sorted in previous step. In this step, the second big will be moved to N-1th
position and it is said to be sorted. In this way, the bubble sort works.
Selection sort
In selection sort, first it finds the smallest element in the array, and exchanges it with the first position
element. Next it finds the second smallest element and exchanges it with the second position element.
In this way selection sort works. Let us take 5 elements: 90, 30, 70, 10, 20
After every pass of outer loop, the elements is as follows
st
Before 1 iteration 90 30 70 10 20
nd
Before 2 iteration 10 30 70 90 20
rd
Before 3 iteration 10 20 70 90 30
th
Before 4 iteration 10 20 30 90 70
Consider all the time the condition a[pos] > a[j] may not be true ,then if we take average assignments
then it is n2/4.
swapping elements in every outer-loop takes ‘n’ operations.
But swapping takes three operations, so it takes 3*n.
Now total no. of operations =total comparisons + total assignments + total swapping
= n2/2 + n2/4 + 3 * n this is proportional to n2
Insertion sort
Insertion sort inserts elements in proper places among those already in sorted order (these are sorted by
previous iterations of loop). It shifts all previous bigger elements to right band side, so that we get a gap to
insert new element in its proper position.
How insertion sort works?
Let us take first ‘k-1’ elements in the array (sub array) and assume these are already in sorted order (sorted
by previous iterations of loop). Now take kth element, compare it with previous position elements and shift
all bigger elements one by one to right hand side so that we get a gap, where insert kth element. These
inserted positions may not be final positions, as they have to be moved again to make a room for further
smaller elements, which may be encountered later.
Let us observe following elements:
10 12 16 18 19 34 14 30 35 38 55 58 40 60
For easy understating, let us take two elements 14 & 40 have to be sorted. Now take 14 and compare with
previous elements one by one and move all bigger elements (34, 19, 19, 18, 16) to right side, so that we get
a gap at 16 element place, where insert 14. In this way, insertion sort works. But this process starts from
2nd element.
Note: While comparing and moving preceding elements to right side, if any element is found to be smaller,
stop the process. Because, all the remaining preceding elements are also smaller as they already sorted by
previous cycles, now insert the picked element in the vacant room.
C-Family 177 Sortings
In Other Cases: When the records are large size in file, then amount of time to move the data one place to
another place takes a lot of time, in this case selection sort is better than insertion sort, because selection
sort takes only N swaps.
Suppose in case of keys are strings then comparison of strings takes a lot of time than moving data one place
to another place. In selection sort no. of comparison greater than insertion sort, so in this case, insertion
sort is the best even though records are large size. (Courtesy book: algorithms by Robert Sedgwick)
C-Family 178 Sortings
Searching techniques
Searching is the process of finding required key element in the group of elements.
We haves several techniques in computer science, the two basic techniques are
1. Sequential or linear search
2. Binary or two-way search
void main()
{ int a[200], n, i;
printf(“enter number of input values to array :”);
scanf(“%d”, &n);
printf(“enter %d values to array:”,n);
for( i=0; i<n; i++)
scanf(“%d”, &a*i+);
printf(“\n enter element to search :”);
scanf(“%d”, &key);
k=linearSearch(a, n, key);
if(k ==-1) printf(“\n not found”);
else printf(“\n element found at %d position”, k+1);
}
Binary search
The linear search is used when input file is small or elements are not in sorted order, it takes 0(n) time.
If elements are in sorted order, the binary search is the best choice, it takes <log2(n) time.
Step1: In binary search, the array is divided into three parts at middle position, the left sub-array, middle
element, right sub-array.
Step2: If middle-element==searchKey, it returns index of middle-element and stops the process.
Step3: If middle-element < key, it continues search in left-sub-array as said in step-1.
Step4: If middle-element > key, it continues search in right-sub-array as said in step-1.
step5: Repeat step1 to step4 until left/right sub-array partition becomes<1 element.
C-Family 179 Sortings
key
57
Low high
12 16 28 33 38 43 48 50 57 79
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8] A[9]
key
57
Low high
43 48 50 57 79
A[5] A[6] A[7] A[8] A[9]
key
57
Low high
A[8] A[9]
57 79
Local scope: In C program, we can declare variables anywhere in the program, but they must be defined
just immediate of block-open. This block may belong to if-else, while-loop, for-loop, or function. Such
variables scope belongs to that block and cannot be accessed outside. These are often called local/private
variables. See the following program.
Example1: void main()
{
{
int k=100;
}
{
printf(“\n the value of k = %d”, k); // error
}
}
At compile time, we get an error called un-defined symbol ‘k’ at printf(), because the ‘k’ belongs to first
inner block and cannot be accessed in 2nd inner block.
Example2: void main()
{ // say it is outer block
int x;
{ // it is inner block
int y;
x=100;
y=200;
}
printf(“\n the value of x = %d, y=%d”, x, y); // error at ‘y’.
}
At compile time, we get error “undefined symbol y” at printf(), because the inner-block variable can’t be
accessed in outer block ( out of scope)
Overriding of variables
If any two variables are declared in inner and outer blocks with the same name, then two copies will be
created in the program, the outer-block variable is overridden by the inner-block variable when the control
presents in the inner-block. That is, if the control is in inner-block, then the preference is given to inner-block
variable.
void main()
{ int k=10;
{ int k=20;
{ int k=30;
printf(“ k = %d “, k);
}
printf(“ k = %d “, k);
}
printf(“ k = %d “, k);
}
Output: k=30 k=20 k=10
Storage classes
For big applications, the code is certainly split into several functions and these functions may be distributed
into several files. During the execution, the control jumps from one function to another function. In such
case, some variables are required to access across different places in the application. According to presence
of control in one part, some variables are needed to be visible and some are invisible, this can be achieved
by storage classes.
A variable that defined in the program possesses some characteristics such as data type and storage class.
Data type tells the size and type of the value, whereas storage class tells the behavior of a variable, such as
initial-value, scope, life-span and storage-place. Scope means region in which the variable can access. We‘ve
already discussed it. The initial value is zero/garbage. The life span specifies when the variable comes into
existence and when it goes off (when it is created & when it is destroyed).
We have 4 storage classes 1.auto(automatic), 2.register, 3.static, 4.global.
For example: auto int x,y,z; // now the storage class of x, y, z is auto
register long int a,b,c; // the storage class of a, b, c is register
static float p,q,; // the storage class of p, q is static
The auto & register are temporary variables, whereas static & global are permanent variables.
The program’s memory divides into code & data area, the code area contains instructions whereas data area
contains variables, string-constants, etc. The data area is again classified into stack & heap area. The stack is
the place where temporary variables are stored & managed, and in the heap area, the permanent variables
are managed. (The stack & heap are predefined Data Structures in OS level).
the program’s data area is again divides and loads into memory as
Global Static String Auto /*Register Function
variables variables constants… variables variables */ return-address
Heap Area (permanent variable’s area ) Stack Area (temporary variable’s area)
The temporary variables create in stack area, whereas permanent create in heap area.
By default, stack variables contain garbage values, whereas heap variables contain zeros.
C-Family 182 storage classes
Auto (automatic)
example: auto int x, y, z; //this is equal to int x, y, z;
If any variable is declared inside a block, by default, it is auto storage class. So the keyword ‘auto’ is optional
for all local variables. Of course, from the beginning of this book, we have been using ‘auto’ variables.
Initial value: garbage is the initial value. (If not initialized with any value)
Scope: this variable can access only within the block in which it is declared, ie, we cannot access outside
(but using pointers, we can access indirectly from outside of block)
Life: it is also belongs to a block as long as the control presence in that block. ie, when control enters into
a block, all auto variables gets created (life starts) and when control leaves the block, all such variables
gets destroyed (life ends).
void main()
{ test(); // calling 3 times
test();
test();
}
void test()
{ auto int k=10; // memory space of k is created here, when the function starts
printf(“ %d “, k);
k++; // no use of incrementing before dying ( just for demo this is given)
} // memory space of k will be destroyed here, before returning from function
output: 10 10 10
The variable ‘k’ will be created & destroyed 3 times upon calling test() function 3 times. When the control
enters into the test() function body, the ‘k’ will be created & initialized with 10 and when the control leaves
the function, the ‘k’ will be destroyed. Hence the output is 10 10 10.
Of course, it is meaningless to survive the ‘k’ in the memory after finishing of function task. Therefore, all
auto variables will be destroyed before closing the function. But rarely some variables are needed to be
survived, where the static class is the choice.
Static
The static is created just before start of program (before main() fn starts) and survived till end of program,
used to access/share previous call of function values for next subsequent calls. Unlike auto, the static is
used to preserve the values even after closing the function. The static persist the values among several calls
of function. It will not be recreated & reinitialized in every call of function. Only once the variable is created
and exists until the total program is terminated. Scope belongs to local as auto, but initial value is zero.
Example2
void main()
{ int i;
for(i=0; i<10; i++)
{ auto int k1=10;
static int k2=10;
printf(“\n %d %d”, k1, k2);
k1++;
k2++;
}
}
output: 10 10
10 11
10 12 …
Note: variables can be declared anywhere in the program but they must be immediate of block open(first
line of block open). These blocks may belong to any control structures such as while-loop, for-loop, etc.
Register
Register is a small memory unit available in the processor (ALU) itself, before doing any arithmetic operation,
the values are copied from RAM to registers and then given operation takes place, because RAM does not
support bit by bit operations to do respective sum and also technically not possible. We know that, only 3 to
5 registers available in processor and always 1 or 2 are busy. So other unused registers can be used for our
variables, so that, they can have faster access. It saves the time to load & unload variables between RAM &
register. This is very much suitable for frequently used variables like loop variables.
Only temporary integral types (char, int, long) are allowed as registers. The floating point types, arrays,
pointers, static types are not allowed. Anyway, the keyword register is not a command, is just a request to
the compiler, because, if registers are not available then space allocates in the RAM. The other behavior
like scope, life, initial value is same as auto type.
Example: register int a, b ,c , d, e;
register float x, y, z; // error, float are not allowed
In above declaration, all (a, b, c, d, e) may not be allocated in the registers, because, we have limited number
of registers. The x, y, z cannot be taken as register as they are float type.
Registers in Circuits of
RAM Processor Processor ALU
Byte1 Byte2 Byte3 …. AX Addition circuit
BX Subtraction circuit
CX Multiplication circuit
DX ……
C-Family 184 storage classes
Global
As we know, one function’s local variable can’t be accessed in another function, but sometimes, some
variables need to be accessed throughout the program (in several functions) then it should be declared
global scope(outside of all blocks). Global scope is the region that doesn’t belongs to any specific function or
block, it belongs to entire program. Global variable preferably declared at the beginning of program or in a
separate file. These variables life span is until the total program exit(same as static). The word global is not a
keyword and hence it is not required while declaration of variable.
int k; //now the ‘k’ is global and default value is zero
void main()
{ printf(“ k = %d”, k);
test();
printf(“, k = %d”, k);
}
void test()
{ k++;
}
Output: k=0, k=1
the variable ‘k’ is now global and can be accessed (shared) in both functions.
The static & global variables life-scan is same but scope is different.
Extern (proto-type)
If program is very big, obviously its code may distribute into several files and each file may contain several
functions. Here, each file can be compiled independently and produced object file, later all produced object
files can be linked together. In this compilation process, we get some problems. If one file uses global
variable but it is declared in another file then we get undefined-symbol errors. To avoid this type of errors,
we need to specify the proto-type of global variable using keyword extern.
After compiling the 1st and 2nd program files separately, the object code for those files will be created with
the file names “dis.obj” and “main.obj”. Suppose, if we are using Turbo C, then the command line usage of
the compiler will be as follows
tcc –IC:\tc\include –c dis.c
tcc –IC:\tc\include –c main.c
Here “–I” specifies the include path of library functions, and “-c” is for only compilation.
Suppose if we are using C on UNIX system, then the method for using the compiler ‘cc’ is
cc –c dis.c //-c is for only compilation and not creating machine code file
cc –c main.c
the above two commands will create the object files “dis.obj” and “main.obj” respectively. (in Unix it is dis.o
and main.o) Now link these object files using the linker command. (Generally, the compiler itself can handle
the linking job). The command line usage of the TCC will be as shown in the below example:
TCC –Lc:\tc\lib main.obj dis.obj
C-Family 185 storage classes
here –L specifies the library files path. To do the same with UNIX’s CC
CC main.o dis.o final.exe
The above command will create the executable binary file with name “final.exe”
This extern keyword can also be used with function proto-types. This is especially when we want to access a
function that is defined in other files or external pre-compiled modules. For example
Program file1: “dis.c” Program file2: “main.c”
void display()
void main()
{
{
printf(“ experience =%d”, exp);
display();
}
}
If we compile these two files separately, we don’t get any error, but at linking time, we get an error called
“undefined symbol exp” in display() function. Because the variable “exp” is local to “main.c” file, since it is
declared as static, therefore it is not accessible other than this file.
C-Family 186 pre-processor directives
Preprocessor Directives
The preprocessor, as its name implies, is a program, which performs some kind of text manipulations just
before compilation begins. It provides some facilities like automating repeated constants, simplifies complex
math equations by giving shortcuts, providing conditional compilation, combining two or more files…etc.
Actually, the compiler does not have these features in built; this is an additional tool kit, which helps the
programmer.
In real life programming, it is mandatory to symbolize the repeating constants, so that they can be easily
remember and modify. For example: #define PIE 3.14; Wherever the pie value 3.14 is required, we can
use PIE symbol, so it is easy to remember and modify, similarly we can simplify repeated expressions in a
short form, for example: #define sum(x) (3*x*x+4*x+5)
Generally, we break down a big application into several functions and we write in several files, later these
files are combined using #include directive. This directive combines two or more files into a single file.
All preprocessor directives start with #(hash) symbol, and we can use these statements anywhere in the
program. the following statements are used #define , #include , #error , #line , #if , #else , #endif , #elif ,
#ifdef , #ifndef , #undef
Remember, the pre-processor directive manipulates the source code file before compilation begins; it
replaces every directive with its replacement string and such file is given to the compiler. So, the compiler
does not know about #define, #include statements. The following gives idea how the pre-processor and
compiler works.
This macro directive defines a macro-name for a given replacement-expression. The replacement-expression
is substituted in every occurrence of macro-name in the source file. The replacement-expression can be
anything like constant, expression, string, etc. Let us observe the following examples.
Example1: Following program calculates the area & perimeter of circle for a given radius.
#define PIE 3.14 // do not give semicolon at end
void main()
{ float area, perimeter, radius;
printf (“enter the radius:”);
C-Family 187 pre-processor directives
Note: if any word found to be capital letters in the C/C++ programming, it definitely a macro-name, it is the
convention for the C/C++ programmers, so that, one can easily identify macros easily. So, I strongly
recommend follow this rule who ever use macros. It is usually best to put all #define declarations at the
start of the program or in a separate header file rather than placing all over the program.
No need of specifying data types for the parameters, hence, we can use same macro with different data
items. For example, the above macro sum(x, y) works with all data types like sum(4.5, 5.4) of float type.
C-Family 188 pre-processor directives
#include directive
It is used to join the contents of one file into another file, we have 3 syntaxes
syntax1: #include “file name”
syntax2: #include ”path + filename”
syntax3: #include <file name>
The first syntax is used, when the include file is in current working directory.
The second syntax is used, when the include file is in some other directory.
The third one, when the include file is in C-software directory.
For example:
here the file “main.c” contained main-program, “sub.c” file contained sub-program and the sub-file should
be included as
Conditional Compilation
It is possible to compile selected portions of your program’s source code. This process is called conditional
compilation and it is used widely by commercial software houses that provide and maintain many
customized versions of one program.
As we know, these days, all commercial software designed keeping in mind all the aspects of related
organizations in nature. For example, one bank’s software can be utilized in another bank with a few
modifications. We cannot determine and finalize all the details of an application at the time of program
development, for example, regarding of OS, hardware, services,…etc. Therefore, while developing software,
the programmer must predict all possibilities that occurs later stages, thereby, it is needed to write the code
for all possibilities so that we can add, remove, or modify the code according to the organizations required
by the customer(client) before installation of software. In this way, the generic program can be changed
according before delivering software with help of preprocessor. Let us see one example
#if COUNTRY==1
char curr*+=”Rupees”;
#elif CUNTRY==2
char curr*+=”Dollor”;
#else
char curr*+=”No currency defined”;
#endif
void main()
{ printf(“our currency = %s”, curr);
}
By changing country code in first line, the corresponding currency name is applied to the ‘curr[]’
example1 example2
#define SIZE 100
#ifndef SIZE
#ifndef SIZE #define SIZE 200
#define SIZE 200 #endif
#endif
void main()
void main() {
{ printf(“\n the size = %d”, SIZE);
printf(“\n the size = %d”, SIZE); }
}
Output: the size = 100 Output: the size = 200
Example 3: Let us see one more practical example
C-Family 190 pre-processor directives
In the above program, unfortunately the “factorial.c” file is included two times. At compile time, the
preprocessor includes two copies of “factorial.c” file code in the program. As a result, we get an error at
compile time. To avoid this type of errors, it is better to attach the macro check condition. This is as …
Sub file “factorial.c”
#ifndef FACT
#define FACT 1
long int fact( int n)
{
long int f=1;
while( n>1)
f=f*n--;
return(f);
}
#endif
In the above code, at 1st time of inclusion of file, the symbol FACT is not yet defined, therefore the file
“factorial.c” includes to the “main.c” file, and same time the FACT defines to 1.
In 2nd time inclusion, the FACT has already been defined; therefore it will be skipped by the #ifndef directive.
#undef
This directive removes a previously defined definition of the macro-name, for example
void main()
{ after void main()
#define X 20 preprocessing {
printf(“%d “, X); printf(“%d “, 20);
#undef X printf(“%d “, X);
}
printf(“%d “, X);
} Error :undefined symbol “X”
#error
Suppose programmer wants to show an error message if specific macro was not defined previously in the
program. In those cases, we may use this #error to produce an error and to stop the compilation. This #error
stops the compilation based on given condition. For example
#ifdef PIE
#define Area(r) (PIE*r*r)
#define Perimeter(r) ( 2*PIE*r)
#else
#error “the symbol PIE was not defined”
#endif
If we compile the above program, we get an error message, because the symbol “PIE” has not been defined
in the program.
C-Family 191 2D-Arrays
2D arrays: int x[3][5]; Here the value 3 represents row-size, 5 represents column-size.
Then the 2D array is as follows
Columns
R x[0][0] x[0][1] x[0][2] x[0][3] x[0][4]
o
w x[1][0] x[1][1] x[1][2] x[1][3] x[1][4]
s
x[2][0] x[2][1] x[2][2] x[2][3] x[2][4]
In the last two declarations, the row size automatically calculates by the compiler. Here, the row-size equal
to (number-of-elements)/(column-size). The column size is mandatory while declaration of array.
inta[2][]={ {1,2,3}, {4,5,6} } // error, the column size must be required
void main()
{ int a[2][3]={ {1,2,3}, {4,5,6}, {7,8,9} };
int b[2][3]={ {9,8,7}, {6,5,4}, {3,2,1} };
int i, j;
for( i=0; i<3; i++)
1 2 3 9 8 7
{ for( j=0; j<3; j++)
4 5 6 6 5 4
c[i][j]=a[i][j]+b[i][j]; 7 8 9 3 2 1
} A[ ][ ] B[ ][ ]
// displaying result of the matrix
for( i=0; i<3; i++) output matrix c[][] is:
{ for( j=0; j<3; j++) 10 10 10
printf(“ %d “, c*i+*j+); 10 10 10
10 10 10
printf(“\n”);
}
}
Finding biggest of each row & column of 2D array data (R X C size matrix)
Input: Output:
23 55 66 7 row1 big = 66
31 12 61 17 row2 big = 61
5 14 98 47 row3 big = 98
2 24 8 97 row4 big = 97
void main()
{ int a[10][20], r, c, i, j;
printf(“enter row and column size of input matrix :”);
scanf(“%d%d”, &r, &c);
for(i=0; i<r; i++)
{ for(j=0; j<c; j++)
{ printf(“ enter element of *%d+*%d+ :”, i, j);
scanf(“%d”, &a*i+*j+);
}
}
printf(“\n each row output \n”);
C-Family 194 2D-Arrays
#define M 3 ip:
1 2 3 4
#define N 4
5 6 7 8
void main() 9 10 11 12
{ int A[M][N] = { {1, 2, 3, 4},
{5, 6, 7, 8}, op: 1 5 9
2 6 10
{9, 10, 11, 12},
3 7 11
}; 4 8 12
int B[M][N], i, j;
// transposing elements from A[][] to B[][]
for(i=0; i<M; i++)
for(j=0; j<N; j++)
B[i][j] = A[j][i];
printf("Result matrix is \n");
for(i = 0; i < N; i++)
{ for(j=0; j< M; j++)
printf("%d ", B[i][j] );
printf("\n");
}
}
void main()
{ int a[10][10], b[10][10], c[10][10];
int r1, r2, c1, c2, i, j, sum;
printf(“\n enter size of input matrix :”);
scanf(“%d%d”, &r1, &c1);
printf(“\n enter size of second matrix :”);
scanf(“%d%d”, &r2, &c2);
if( c1 != r2)
{ printf(“sizes not equal, cannot be multiplied”);
exit(0);
}
printf(“\n enter elements of first matrix :”);
st
for(i=0; i<r1; i++) // loop to multiply 1 matrix of each row
nd
{ for(j=0; j<c2; j++) // loop to multiply 2 matrix of each column
{ sum=0;
for(k=0;k<c1;k++) // loop to multiply to get element of output matrix
sum = sum + a[i][k] * b[k][j];
c[i][j]=sum;
}
}
printf(“\n output matrix is \n:”);
for(i=0; i<r1; i++)
{ for(j=0;j<c2;j++)
printf(“ %d ”,c*i+*j+ );
printf(“\n”);
}
}
Observe the multiplication stages carefully, it contained 3 loops, 1st loop is for maintaining the row index of
1st matrix, and 2nd loop is for column index of 2nd matrix. The 3rd loop is to keep the track of sum of products
of row wise of 1st matrix with the columns wise of 2nd matrix. Finally this sum is assigned to the target
matrix of relevant position.
void main()
{ int a[100][4]; // let the maximum number of student are 100, and subjects are 4.
int i, j, total[100], avg[100], n;
char result[100][20];
printf(“enter number of students :”);
scanf(“%d”, &n);
for(i=0; i<n; i++)
{ printf(“enter student %d marks of sub1, sub2, sub3, sub4 :”);
scanf(“%d%d%d%d”, &a*i+*0+, &a[i][1], &a[i][2], &a[i][3]);
}
for(i=0; i<n; i++) // calculating total, avg and the result.
{ for(j=0; j<4; j++)
total[i]=a[i][j]+a[i][j]+a[i][j]+a[i][j]);
avg[i]=total[i]/4;
if( a[i][0]<40 || a[i][1]<40 || a[i][2]<40 || a[i][3]<40 )
strcpy( result*i+, “Failed”);
else if ( avg[i] >= 80 )
strcpy( result*i+, “A-Grade”);
else if ( avg[i] >= 60 )
strcpy( result*i+, “B-Grade”);
else
strcpy( result*i+, “C-Grade”);
}
// printing result
printf(“ student idno marks1 marks2 marks3 marks4 total avg result “);
printf(“\n===================================================”);
for(i=0; i<n; i++)
printf(“\n %d %d %d %d %d %d %s“, a*i+*0+,a*i+*1+,a*i+*2+,a*i+*3+ );
}
C-Family 197 2D-Arrays
X[0][0] X[0][1] X[0][2] X[0][3] X[0][4] X[1][0] X[1][1] X[1][2] X[1][3] X[1][4] X[2][0] X[2][1] X[2][2] X[2][3] X[2][4]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
2000 2002 2004 2006 2008 2010 2012 2014 2016 2018 2020 2022 2024 2026 2028
In one dimensional arrays, the expression x[i] can be written in pointer form as *(x+i)
lly, In two dimensional arrays, the x[i][j] can be written in pointer form as *(x[i]+j) or *(*(x+i)+j)
But implicitly the expression x[i][j] is converted as *(x+i*column-size+j). This equation is called row-major
order formula. This method used by compiler implicitly to access elements in the 2D-array, because, the row
elements are expanded in column-wise. (Some other languages use column-major order formula)
Let us see how elements are accessed in 2D array
x[i][j] *(x+i*column-size+j).
x[0][0] *(x+0*5+0) *(2000+0) *2000 1
x[0][1] *(x+0*5+1) *(2000+1) *2002 2 // integer address increments by 2
x[1][0] *(x+1*5+0) *(2000+5) *20010 6
x[1][1] *(x+1*5+1) *(2000+6) *2012 7
x[2][0] *(x+2*5+0) *(2000+10) *2020 11
x[2][1] *(x+2*5+1) *(2000+11) *2022 12
Here special types of pointers are used to access the 2D array elements. For example
int (*p)[3]; pointer to 2d-array where the column size is 3. The row size can be anything.
int (*p)[3][4]; pointer to 3d-array where the row-column sizes are 3-4, table size can be anything.
void main()
{ int a[2][3]={{1,2,3}, {4,5,6},{7,8,9} };
int (*p)[3]; // pointer ‘p’ to 2d-array with the columns size 3.
p=a; // p=&a[0][0]; making pointer to 2D array
for(i=0; i<2; i++)
{ for(j=0; j<3; j++)
printf(“%d”, p*i+*j+); // p[i][j] expands to *(p+i*3+j)
printf(“\n”);”
}
}
Passing 2D array to function
it is just like passing 1D array to functIon, here array base address is passed and accessed through pointer.
void main()
{ int a[3][4]={ {1,2,3,4}, {5,6,7,8}, {9,10,11,12} };
display(a); // display( &a[0][0]);
}
void display( int (*p)[4] or int p[][4] )
{ inti,j;
for(i=0; i<3; i++)
{ for(j=0; j<4; j++)
printf(“%d ”, p*i+*j+ ); // p[i][j] *(p+i*4+j)
printf(“\n”);”
}
}
The second declaration for the parameter p[][4] is also a valid and this type of declaration is allowed only for
the parameters while receiving 2D array. This is also implicitly a pointer of type “int (*p)*4+”.
Character Handling
In programming, it is often need to handle single character data items such as employee sex, account type in
the bank, marks grade of a student, color of an object, etc. These characters may be an alphabet, digit, or
any other symbol, which is to be handled as a single character item in the program.
Character variable: The characters are stored in the form of ASCII values in the computer, and all
character’s ascii values lie in between 1 to 255, so to store such ascii codes, the suitable type is ‘char’. If we
take int or long int, the memory gets unused(wasted). The char occupies 1 byte and it is suitable for values in
the range of 0 to 255. ASCII American standard code for information interchange.
Syntax to declare character variables is: char variable1, variable2,…variableN;
example: char sex, accountType, colorType;
Character constant: If any single character enclosed within a pair of single quotes is known as char
constant. Unlike integer or float constants, the char constants must be enclosed within a pair of single
quotes.(not double quotes)
for example ‘a’, ‘A’, ‘9’, ‘+’ …etc are valid character constants.
‘abc’, ‘123’, ‘+12’, “A”, “5” … are not valid character constants.
(19, 34, 10, -10, 45 are integer constants.)
The value of character constant is nothing but their ASCII code, at compile time, the compiler replaces these
single quoted characters with their ASCII codes, For example, ASCII value of ‘A’ is 65, ‘B’ is 66. Remember,
the data type of these constant is ‘char’. The following table shows ASCII codes of all characters set
Characters ASCII values
A to Z 65 to 90
a to z 97 to 122
0 to 9 48 to 57
‘ ‘ (blank space) 32
‘\n’ ( enter key) 13
In computer’s memory, the characters are stored in terms of their ASCII values but not in its picture form as
visible on the screen. Remember that, these ASCII values stores in its binary form as computer understand it.
ASCII values are standard serial numbers given to each alphabet, digit, and all symbols in the keyboard. This
standard is called American Standard Code for Information Interchange proposed by international
computer associations. Here the word “information interchange” means, exchanging data from one device
to another or one computer to another in terms of ASCII values.
Hence every symbol internally represents in binary format and when it is to be displayed on the screen, it
converts into symbolic picture form (picture in pixel form). Internally, special software continuously
performs this graphical conversion job while displaying contents on the monitor. The hardware
manufacturers provide this kind of software.
C-Family 201 Characters & Strings
getchar(): this is similar to scanf() function, it accepts a single character from standard input stream (
program’s stream) not directly from keyboard stream. Stream or buffer is a small capacity memory, works as
mediator between device & app, used to store data temporarily for a while before reading/writing in it.
Whatever you entered in the keyboard, that input values are inserted into keyboard buffer, later our
program(scanf) reads the input values from the buffer. Thus stream works as mediator between device &
application(our program).
getchar()
scanf()
our progoram’s keyboard stream
Keyboard
stream memory memory(buffer)
getch()
getche()
getch(): Accepts a single character directly from keyboard stream, without echoing(displaying) on the
screen. Unlike getchar(), it doesn’t wait for enter-key for input confirmation. That is, all io functions waits for
enter-key at the end of input. When user press the enter-key, then io functions starts scanning input and
stores into variables. But getch(), getche() does not wait for enter-key for confirmation of input.
Note: The getch(), putch(), getche() are non-standard function, so it may not be available in all versions of C.
It works only on DOS based C-Software like Turbo-C.
C-Family 202 Characters & Strings
getche(): it is just as getch(), but it shows the input character on the screen.
putchar(): this is similar to printf() function for showing single character on the screen.
putch():it sends the input character directly to the monitor stream.
Strings
String is a collection of characters arranged sequentially one after the other in the memory, used to
represent names of persons, items, countries, cities and sometimes to represent messages. Generally, any
non-computable data manipulates as strings. That is, on strings data, we don’t do any arithmetical operation
such as addition, subtraction, multiplication, division. To handle strings, there is no direct data type in C,
instead we have to access them as normal array of characters. However, C provides some basic facilities to
handle strings easily, such as representation of string constants, initialization of string, implicit generation of
references to the string and also provided several standard library functions to manipulate strings.
The strings such as “India”, “China”, “C-Family”, “123”, “A123”, etc.
Note: The ascii values of chars lie in between 1-255, so the value 0 is taken as null character value as a string
terminator. But in the program, it is better to write ‘\0’ instead of 0(zero) to represent in symbolic way.
String constants
A set of zero or more characters represented within a pair of double quotes is known as string constant.
All characters in a string are stored sequentially in contiguous memory locations in the form of their ASCII
values. These can be accessed just as any normal array of elements. Therefore, whatever operations can be
applied on arrays, they can also be applied on strings. For example, passing string to function, accessing
string through pointer, etc.
Example for string constants: “India”, “C-family”, “ ”, “9440-030405”, “A123”, “123”, etc.
The string “INDIA” occupies 6 bytes in the memory (5bytes for INDIA+1byte for null-char).
The compiler automatically appends a null character at the end of string constants.
For example, the string “INDIA” in the memory as ‘I’ ‘N’ ‘D’ ‘I’ ‘A’ ‘\0’
The integer constant 1234 stored in two bytes of memory in its binary format as: 00000100-11010010
Do not confuse string constant with integer constant.
123 is said to be integer constant, whereas “123” is string constant.
C-Family 205 Strings
String constants
Heap
Data Global variables
Area
Area Static variables
Stack Local variables
Area Function return address
The data area is again divided into two parts, heap area & stack area. In heap area, a permanent data items
like string constants, global and static variables are managed. Whereas, in stack area, the temporary local
variables and function return addresses are manipulated. (Refer the chapter storage-classes)
All string constants in a program are moved to data-area, whereas in the code-area their starting addresses
are substituted. Let us see following example
String variable
we know that, variable is a space, used to store and access a value. Similarly, to store and access characters
of a string, one is required “char [+” array.
For example: char arr[20]; // It can hold a string with the maximum length 19 chars and 1 byte for null.
Initialization of strings: like normal arrays, we can initialize character arrays with the strings in
different ways. This is as given below example.
char a*9+=”C-Family”; // here null character automatically appends at end by the compiler
char a*+=”C-Family”; // the size of array calculates by the compiler, which is equal to length of “c-family”+1
char a[9+=, ‘C’, ’-‘, ’F’, ’a’, ’m’, ’i’, ’l’, ’y’, ‘\0’-; // we can initialize with char by char
char a*+=, ‘C’, ’-‘, ’F’, ’a’, ’m’, ’i’, ’l’, ’y’, ‘\0’-; // size not given, automatically calculated by compiler, it is 9
char a[]={67,45,70,97,109,105,108,121,0}; // we can also initialize with ASCCII values of “c-family”
The last declaration with ASCII values is somewhat confusion and not suggestible, it is just given for fun.
The First two declarations are more convenient & easy to understand.
C-Family 206 Strings
char a*5+=”C-Family”; // compiler raises an error, because, the array size is not enough for the string;
char a*20+=”hello”; // remaining 14 locations gets unused(empty)
Accessing individual characters in a string is same as accessing elements in the array. The index of the
character should be specified as array subscript.
For example: char a*+=”C-Family”;
The expression ‘a*0+’ accesses the first character ‘c’,
‘a*1+’ accesses the second character ‘-’
‘a*2+’ accesses the second character ‘F’, …
in this way, we can access any element in the array
① scanf(“%s”, ..) : this reads a string char by char until a new-line or a blank-space is found,
whichever comes earlier. If input is “jack and jill”, then scanf() accepts only “jack”.
② scanf(“%*^\n+”, ..) : this reads a string char by char until new-line is found, that is, it accepts total string
with spaces like “jack and jill”. The gets() and this scanf(“%*^\n+”, ..) works in similar way. These input
functions automatically append null character at the end of string. For example
The puts() and printf() works in similar way, all i/o functions take first byte address (base address of array) as
argument and prints the given string using pointer.
The i/o function gets() accepts “Sri Hari” char by char from keyboard and stores into given array in &a[0],
&a[1], &a[2],etc. The “%c” prints the character in symbolic form, whereas %d prints its ASCII code.
Here the for-loop repeats until null character is found.
Input: A L L A P P L E S A R E R E D \0
void main()
{ char a[100]; int i, count;
printf(“\n enter a multi word string :”);
gets(a);
for(i=0; a*i+!=’\0’; i++)
{ if( a*i+==’ ‘) // if space is found then count as one word
{ count++;
while( a*i+1+==’ ‘) // if next char is also space, then skip by incrementing loop.
i++;
C-Family 208 Strings
}
}
printf(“\n number of words = %d”, count);
}
Let us observe the input string, contains more than one space between words. The inner while loop used to
skip extra spaces between words. When the index pointer ‘i’ moves to first space then count increments and
all succeeding space if any are skipped by the inner while loop.
void main()
{ char a[100]; int i;
printf(“\n enter string :”);
gets(a);
for(i=0; a*i+!=’\0’; i++)
{ if( a*i+ >= ’a’ && a*i+ <= ’z’ ) // if( islower( a[i] ) a[i]=toupper(a[i]) ;
a[i]=a[i]-32;
else if( a*i+ >= ’A’ && a*i+ <= ’Z’ ) // if( isupper( a[i] ) a[i]=tolower(a[i]) ;
a[i]=a[i]+32;
}
printf(“ output string is %s:”, a);
}
Converting every first letter of word to upper case and remaining to lower case.
Ip: all apples are good, some are in white colors and some are in read color.
op: All Apples Are Good, Some Are In White Colors And Some Are In Read Color.
(Let the words in a string are separated with single space)
void main()
{ char a[100]; int i ;
printf(“enter string :”);
gets( a );
a[0]=toupper( a[0] ); // converting first character to upper case.
for(i=1; a*i+!=’\0’; i++)
{ if( a[i-1+==’ ‘ ) a[i]=toupper( a[i] ); // if previous char is space then word started
else a[i]=tolower( a[i] ); // if a[i] is not first letter of word then convert to lower
}
printf(“output string is %s ”, a);
}
C-Family 210 Strings
Pointer to string
As we know, string can be in the form of variable or constant. In both cases, the strings are handled in
similar way. For example
char a[20+=”Hello”;
char *p=”World”;
a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] a[10] … a[19]
‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘\0’ - - - - - - -
As per first declaration, we can say that, the string is in the form of variable. In later part of the program, we
can replace this string “Hello” by some other string, but new string length must be <20 chars (array-size).
As per second declaration, we can say that, the string is in the form of constant. The space allocation for
string is exactly length+1(6 bytes), here first character address (&h) assigns to the pointer ‘p’. Now using ‘p’,
we can read the string “World”. In later part of the program we can replace this string “World” by some
other string, but the new string must be the same length or less. If more size then, it crosses memory limits
and causes program crash. Pointer initialization widely used when no changes happen in the strings like
company names, country name, codes, labels…etc.
Pointer to a string is just like a pointer to an array, either the string may be a variable or constant. In both
cases, the characters are accessed in similar way. If pointer ‘p’ is pointing to first character in a string, the
expression ‘*p’ accesses the first character, *(p+1) accesses the second character, etc. As we know, the
expressions *p, *(p+1), *(p+2)... can be written in array fashion as p[0], p[1], p[2],etc. For example
C-Family 211 Strings
char a*10+=”C-Family”;
char *p;
p=&a[0]; // p=a;
Now we can imagine pointer to a string as
p *p *(p+1) *(p+2) …
&a[0] ‘C’ ‘-‘ ‘F’ ‘a’ ‘m’ ‘i’ ‘l’ ‘y’ ‘\0’
a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8]
void main()
{ char a[ +=”C-Family”, *p;
p=a; // p=&a[0];
for(i=0; p*i+!=’\0’; i++)
printf(“%c”, *(p+i) );
for(i=0; p*i+!=’\0’; i++)
printf(“%c”, p*i+ );
for(i=0; *p=’\0’; i++)
{ printf(“%c”, *p );
p++; // increments to next char
}
}
The three loops print same output, the first two loops are same as they are accessing characters in a string
using pointer ‘p’ and ‘i’. Here the pointer will not be moved to end of string after completion of loop. But in
third loop, the pointer advances to next char after reading every single character. After completion of this
loop, the ‘p’ moves to end of string.
The pointer parameter ‘p’ points to the string(s) in every call as given below
&a[0] ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘W’ ‘o’ ‘r’ ‘l’ ‘d’ ‘\0’
P a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8]
&a[0] ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘W’ ‘o’ ‘r’ ‘l’ ‘d’ ‘\0’
P a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8]
&C ‘C’ ‘-’ ‘F’ ‘a’ ‘m’ ‘i’ ‘l’ ‘y’ ‘\0’
P
&F ‘C’ ‘-’ ‘F’ ‘a’ ‘m’ ‘i’ ‘l’ ‘y’ ‘\0’
P
As we know, the parameter declaration “char *p” in pointer style is informal and sometimes confusion.
Most of the programmers prefer array-like-pointer declaration as “char p*+”. This is formal and it tells that ‘p’
is receiving string array address rather than single char address. The parameter declaration “char p*+” seems
to be an empty-array, actually, implicitly it is also a pointer of type “char *p”. This declaration provided for
easy understanding and nothing more
While manipulating strings, we often need to perform some common operations like copying a string,
concatenation of string, changing the case, comparing, reversing, finding sub-string, converting text
format to numeric, etc. As these operations are common in programming and we prefer to abstract (hide)
these tasks by writing separate functions for each operation. The string library functions named strlen(),
strcpy(), strcmp(), strrev(),etc are already exist to cooperate the programmer instead of writing from low
level. The following programs show, how string library functions are developed and used. Here some
sample user-defined functions are implemented to know how library function works internally.
if(“Hello”==“Hello”) printf(“equal”);
else printf(“not equal”);
}
Output: not equal
not equal
C-Family 214 Strings
Even though two array contents are same, the output will be ‘not equal’, because, unknowingly, we are
trying to compare base addresses of two arrays, the if(x==y) is nothing but if(x[0] == &y[0] ). As we know,
two arrays will not be located in the same location of RAM.
In second if-statement also, the base address of strings if(&H==&H) are compared and we get again “not
equal”. Because two string constants will not be located in the same location.
The solution is, compare char by char in two strings using loop, which is as given below
void myStrcmp( char x[], char y[] )
{ int i, j;
for( i=0; x*i+ != ’\0’; i++)
{ if( x[i] != y[i] )
break;
}
return x[i]-y[i]; // returning ascii difference
}
If both strings are equal then returns 0, otherwise returns +ve/–ve of first un-matched characters ASCII
difference of two strings. If return value is +ve, then string1>string2 in dictionary order(Alphabetical order)
or else string1<string2. For example, if two strings are:
“Hello” and “Hello” then returns (0);
“World” and “Words” then returns (‘l’-‘d’); // ascii difference is +ve
“Words” and “World” then returns (‘d’-‘l’); // ascii difference is -ve
The main() function to check the above function is
void main()
{ char x[50], y[50];
int k;
printf(“\n enter string 1:”);
gets(x);
printf(“\n enter string 2:”);
gets(y);
k=myStrcmp(x,y);
if( k==0) printf(“string1 == string2”);
else if( k<0) printf(“string1<string2”);
else printf(“string1 > string2”);
}
Reversing a string
void myStrrev( char *a )
{ int i;
for(i=0; a*i+!=’\0’; i++)
{ // empty loop to calculate length, loop ends when ‘i’ reached to null char.
}
for( j=i-1, i=0; i<j; i++, j--) // ‘i’ points to first element, ‘j’ points to last element in the string.
{ t=a[i]; // swapping
i j
a[i]=a[j]; ‘A’ ‘B’ ‘C’ ‘D’ ‘E’ ‘F’ ‘G’ ‘H’ ‘I’ ‘J’
A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8] A[9]
a[j]=t;
}
}
C-Family 216 Strings
void main()
{ char a[100];
myStrrev( a );
printf(“\n string after reversing %s”, a );
}
ip: ABCDEFGHIJ
op: JIHGFEDCBA
strcat()
here ‘cat’ means concatenation, it attaches one string at the end of another string. That is, it concatenates
two strings like addition.
syntax: strcat( string1, string2 ); // string1=string1+string2;
proto-type: char* strcat( char*, char*);
void main()
{ char a*20+=”Hello”, b*20+=”World”;
strcat(a,b);
printf(“output1 = %s”, a);
strcat(a,”India”);
printf(“output2 = %s”, a);
}
Output: output1=HelloWorld
output2=HelloWorldIndia
strrev()
it reverses the given string
syntax: strrev(string);
proto type: char* strrev(char*);
void main()
{ char a*20+=”Hello”
strrev(a);
printf(“output1 = %s”, a);
strrev(a);
printf(“output2 = %s”, a);
}
output1: olleH
output2: Hello
strcmp()
compares two string whether they are equal or not? If both strings are equal then returns (0), otherwise
returns “first un-matched characters ASCII difference in +ve or –ve”.
If returned value is +ve, then string1>string2 in dictionary order (alphabetical order), or else string1<string2.
void main()
{ char a*30+=”Hello World”;
char b*30+=”Hello World”;
K=strcmp(a,b); // copies char by char including null.
if( k==0) printf(“both string are equal”);
else if(k<0) printf(“first string < second string”);
else printf(“first string > second string”);
k=strcmp(“xyz”, “abcdef”);
if( k==0) printf(“both string are equal”);
else if(k<0) printf(“first string < second string”);
else printf(“first string > second string”);
}
op: both string are equal
first string > second string
C-Family 218 Strings
strcmpi() or stricmp()
It compares two strings, which is same as strcmp(), but it ignores the upper/lower case of alphabets.
Syntax: int strcmpi(string1, string2);
void main()
{ if(strcmpi(“DELHI", "delhi")==0)
printf("Both are equal");
else printf("Not equal");
}
Outputs: Both are equal
strncmpi() or strnicmp()
It compares two strings up to some specified number of characters, and also ignores the case difference.
Syntax: int strncmpi( string1, string2, no-of-chars-to-compare);
void main()
{ if( strncmpi(“Garden", "gardening",3) == 0 )
printf("Both are equal");
else printf(“Not equal");
}
Output: Both are equal
strupr()
It converts all lower case alphabets into upper case in a given string.
Syntax: strupr( string);
void main()
{ char a[]="Pens and Pads";
strupr(a);
printf("%s", a);
}
Output: PENS AND PADS
strlwr()
It converts all upper case alphabets into lower case in a given string.
Syntax: strlwr( string);
void main()
{ char a[]="Jack n JILL";
strtwr( a);
printf("%s", a);
}
Output: jack n jill
strchr()
It searches for a given character in a string, it searches one by one from first position towards end of string.
It returns first occurrence of a specified character address if it is found. Otherwise it returns NULL value.
Syntax: char* strchr(string, char to search);
void main()
{ char *p;
p=strchr("Hello world", ‘w’); // returns “&w” in “hello world” string.
printf("%s", p);
}
C-Family 219 Strings
This printf() will prints the message "world" , because ‘p’ pointing rest of the string “world”
&a[6] ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘W’ ‘o’ ‘r’ ‘l’ ‘d’ ‘\0’
P a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] a[10] a[11]
strstr()
it searches for a sub-string in a given main-string. It returns the first occurrence of sub-string address if it is
found. Otherwise, it returns NULL, if not found.
void main()
{ char *p;
p=strchr("I like you very much", “you”);
printf("%s", p);
}
This printf() will print the message "you very much"
&a[6] ‘I’ ‘ ’ ‘l’ ‘i’ ‘k’ ‘e’ ‘ ’ ‘y’ ‘o’ ‘u’ ‘ ’ ‘v’ ‘e’ ‘r’ ‘y’…
P a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] a[10] a[11] a[12]
atoi()
It converts a numeric-string value into equivalent integer-value.
Syntax: int atoi(string);
Example: int k;
k= atoi("123")+atoi("234");
printf(" output = %d", k);
output will be: 357
atol()
Converts long int string value to equivalent long integer value
Syntax: long int atol(string);
Example: long int k;
k= atol("486384")-atol("112233");
printf(“output = %ld”, k);
output will be = 374151
atof()
Converts floating point text format value to double value.
Example: float f;
f=atof("3.1412")*5*5;
printf(“%f “, f);
output will be: 78.530000
itoa(),itoa(),ultoa()
These functions converts a given number (int/long int/unsigned long int)equivalent to string format based
on the given numbering system radix value.
These functions take three arguments, the numeric value, target string address in which the value to be
stored and radix value. Finally returns the target string address, so that function-call can be used as
argument/expression.
C-Family 220 Strings
To store a group of strings, we need a data structure like 2-dimensional array with N*M size, where N is
number of strings and M is maximum size of string length.
Recursion
Calling a function within the same function is called as recursion. It is the process of defining something in
terms of itself, and is sometimes also called as circular definition.
The syntax, the usage, and the execution of recursive function is just like any normal function. There is no
technical difference between recursive and normal function. However, for beginners, the logic of recursion
is somewhat difficult to understand and writing programs in it. The major confusion is, understanding the
logic regarding self-calling, self-returning, and how the arguments & local variables are managed in
recursive-calls. If you are familiar with functions, here by observing some simple examples we can follow the
logic easily. Here some examples explained with pictures to understand the basic concept of recursion.
Let us see the following simple examples, how recursive calls are made, before that, let us see some
mathematical analysis recursion.
1) f(n)=n+n/2+n/4+n/8+….+1
the recurrence relation is:
f(n)=n+f(n/2) if n>1
f(n)=1, if n==1
2) fact(n) = n*n-1*n-2*….3*2*1
the recurrence relation is:
fact(n)=n*fact(n-1), if n>1
fact(n)=1, if n==1
void main()
{ printf(“hello ”);
main(); // self-calling (recursive-call )
}
output: hello hello hello hello … until stack overflow (memory full)
Here the main() fn called recursively inside its body, therefore control re-enter into same body again and
again as it repeatedly called again and again(), it prints “hello” message many times, but in every recursive
call some memory is consumed by operating system to store function-return-address, after some calls, the
memory gets full and program gets crashed.
void main()
{ int k=1;
if( k==5)
return;
printf(“%d ”, k );
k++;
main(); // self-calling (recursive-call)
}
Here we expect the output 1, 2, 3, 4, it is wrong. It shows 1, 1, 1, 1, 1, … until memory is full. For every
recursive call, one extra new variable ‘k’ is created and initialized with 1. So for every call of function, a
separate fresh copy of ‘k’ is created and initialized with 1. So output is 1, 1, 1, 1…..
Here the k value never reaches to 5, the incremented ‘k++’ at one call, will not be affected to next call of ‘k’,
so always prints 1,1,1,1….. until memory full.
Note: For our program variables, the operating system reserves some amount of space in RAM (stack
segment), when this memory gets full then OS shows stack-overflow error. Here for every recursive call, one
copy of ‘k’ is created, after some calls many k’s are created and makes the memory full.
For every recursive call, one set of local variables (in this example ‘k’) are created and available up to
that call is terminated. That is, when such call is terminated, all local variables are freed (deleted). The
recursive function executes just as any normal function in the system. Therefore, to share(use) local
variables over several calls, we have to pass them as an arguments between function calls.
Recursive function executes like a loop statement, as we know, every loop has a terminating condition,
in the same way, to stop the recursive calls, there must be termination condition and often called it as
base condition. Generally, it appears at the beginning of function (we will see in the examples).
This figure explains how recursive calls are made for above example code
*Here in every recursive call, one fresh copy of ‘k’ is created initialized with 1, the incremented k++ will not
be affected to next call. So output is 1 1 1 1….
Taking ‘k’ as parameter instead of local variable, let us see following example
C-Family 226 Recursion
void main()
{ display(1); // passing argument 1
}
void display(int k)
{ if(k==5) // termination of recursion
return;
printf("%d ", k);
display(k+1); // recursive call
}
Output: 1 2 3 4
For every next call, we are passing k+1 value as argument, therefore at first-call k=1, at second-call k=2,…
At 5th call k=5, here terminates the recursion and returns the control. So output is 1,2,3,4.
When above ‘return’ statement gets executed in recursion, people think that, the control immediately
transfer back to main(), this is the big misunderstanding many people think like that, actually here the
control returns to previous-call in the series of calls. Here is the following example explains clearly.
*Printing 1 2 3 3 2 1 recursively
void main()
{ display(1); // passing argument 1
}
void display(int k)
{ if(k==4) return;
printf("%d ",k); // printing output before going to next-call
display(k+1);
printf("%d ",k); // printing output after coming back from next-call
}
Here the output '1 2 3' prints by first printf(“%d “, k), whereas second output '3 2 1' prints by second
printf(“%d “, k) statement. The first printf() executes just before next call is made. Whereas second printf()
executes just after returning from next-call.
This figure shows how the output 1 2 3 3 2 1 prints on the screen.
void main()
{ display(1);
}
1st call, here k=1 2nd call, here k=2 3rd call, here k=3 4th call, here k=4
void display( int k) void display( int k) void display( int k) void display( int k)
{ { { {
if(k==4) if(k==4) if(k==4) if(k==4)
return; return; return; return;
printf(“%d “, k); printf(“%d “, k); printf(“%d “, k); printf(“%d “, k);
display(k+1); display(k+1); display(k+1); display(k+1);
printf(“%d “, k); printf(“%d “, k); printf(“%d “, k); printf(“%d “, k);
} } } }
C-Family 227 Recursion
The last closing braces works as ‘return‘ statement in the function, like above shown picture.
Recursive function executes like a loop statement. As we know, every loop has a terminating condition,
in the same way, to stop the recursive calls, there must be termination condition and often called as
base condition. Generally, it appears at the beginning of function. Here in this example if(k==4) return;
Printing output 1, ….. N/4, N/2, N using recursion (reverse output of above program)
This function takes N as argument and prints output from 1 to N.
ip: N=100
op: 1, 3, 6, 12, 25, 50, 100
void main()
{ int N;
scanf(“%d”, &N);
show(N);
}
void show(int N)
{ if( N==0) return;
show(N/2); // sending half value to next call
printf(“%d “, N); // printing while going back to previous-call
}
C-Family 228 Recursion
First call (n=4) Second call (n=3) Third call (n=2) Fourth call (n=1)
Finding factorial in iterative process (using loop) is the simple & easy compared to recursion. This is just
a demo program to explain the logic of how recursion executes.
The last call returns ‘1’ and is substituted in its previous-call, the previous-call again returns ‘2*1’ and is
substituted in its previous call. In this way, the final result 24 is returned to main() fn.
The logic is, continuously divide the y with x until remainder is zero. Here take y as dividend and x as
devisor. If y%x is zero then x will be the GCD and stop the process. If y%x is not zero then take x value to y
and y%x value to x for next cycle. Do this process until y%x==0.
For example, the input values are 12 and 18 then the function and their calls are as
x y x y stop
12 ) 18 ( 1 6 ) 12 ( 2
12 12
6 0
void main() int GCD( int x, int y ) int GCD( int x, int y )
{ { {
int k; if(y%x==0) if(y%x==0)
k=GCD(12 , 18); return x; return x;
printf(“\n gcd=%d”, k); return GCD(y%x , x); return GCD(y%x , x);
} } 6 }
Find best code of following recursive functions, which finds sum of 1+2+3+…+N
In this program, one can think that, only one copy of x, y is enough for all recursive calls
rather than creating fresh copy in every call. So to avoid these additional copies, we can
declare x, y as static/global. But there is a problem! Once static/global variable is created, it
will not be killed even after function ends; moreover they cannot be reinitialized for
int k=1;
upcoming calls. Let us have one more example with global variable
C-Family 233 Recursion
int k;
void main()
{ show(); // at this call, output is 1 2 3 4
show(); // at this call, no output
}
void show()
{ if(k==5) return;
printf(“%d “, k);
k++;
show();
}
op: 1 2 3 4
we expect output as 1 2 3 4 1 2 3 4 [as two times show() fn called from main()], as ‘k’ is global variable,
only one copy is created and shared to all calls. After printing 1 2 3 4 at first call in main(), the k attains 5 and
will not be re-initialized to 1. So for 2nd call at main(), no output is displayed.
Fibo(5) fibo(4)+fibo(3)
fibo(4-1)+fibo(4-2)+fibo(3-1)+fibo(3-2)
fibo(3-1)+fibo(3-2) +fibo(2)+fibo(2)+fibo(1)
fibo(2)+fibo(1)+fibo(2)+fibo(2)+fibo(1)
1+0+1+1+0 3
void main()
{ int n=5;
x=find(n);
printf(“ the Nth term = %d”, x);
}
int fibo( int n)
{ if(n<=2)
return(n-1);
return fib(n-1)+fibo(n-2);
}
Observe the following figure and try to understand how recursive calls are made.
C-Family 234 Recursion
int fibo( int n : 3) int fibo( int n : 2 ) int fibo( int n : 1 ) int fibo( int n : 1)
{ if(n<=2) { if(n<=2) { if(n<=2) { if(n<=2)
return(n-1); return(n-1); return(n-1); return(n-1);
return fibo(n-1)+fibo(n-2); return fibo(n-1)+fibo(n-2); return fibo(n-1)+fibo(n-2); return fibo(n-1)+fibo(n-2);
} } } }
While terminating function calls, the following statements are gets executed
return (2+1)
{ puts(a);
return;
}
for(j=i; j<=len; j++)
{ k=a[i]; a[i]=a[j]; a[j]=k; // swapping a[i], a[j]
permute(a, i+1, len);
k=a[i]; a[i]=a[j]; a[j]=k; // swapping a[i], a[j]
}
}
If an application is very complex, having rare usage, and taking less space for local variables, then it is better
to implement recursive rather than non-recursive. Recursive is simple and easy to code
It is the programmer’s choice, which method is to be used when and where. If execution time and space are
not constraints, then it is better to implement recursive application.
Implementation of recursion nature problem in non-recursive using loop and stack is an advanced concept.
That topic is beyond the scope of this book.
C-Family 237 Dynamic Memory Allocation
Here compiler creates 206 bytes of memory for int a, b, c[100], d. It adds instructions for allocation & de-
allocation of memory in our program [It creates memory in stack as stack.push(206) and stack.pop(206) ]
The static allocation system is much suitable when we know the size of data like employee-name(25 chars),
address(50 chars), pin-code(6), phone-number(12),…
Dynamic Memory Allocation system
in many real time systems, the count/size of data items are not known or cannot be expected until runtime.
Here dynamic system is the alternative to the programmer. Dynamic allocation refers to the allocation of
such memory during execution of program. Here programmer needs to allocate & de-allocate the memory
with the help of pointers.
This DMA system provides us to create, expand, reduce, or even destroy the memory at runtime. This
feature is very much useful for efficient memory management especially while handling huge collection of
data using ‘data structures’ for example arrays, lists, stacks, queues, trees, graphs, etc. To work with this
feature, C provides the following built-in functions
1. malloc() // include alloc.h or malloc.h file to use these functions
2. calloc()
3. realloc()
4. free()
malloc()
It allocates required size of memory and returns the starting byte address (called base address). This
allocated memory is said to be raw-memory and where we can store any type of data such as int, float, char,
etc. For this reason, malloc() returns an address which has no type. That is, it returns address as “void*”
type and it is often called generic address. Unfortunately, if memory is not available then malloc() or other
functions returns NULL value.
prototype: void* malloc(unsigned int);
syntax: pointer= malloc( no of bytes to be allocated);
example: p=malloc(10); // creates 10 bytes of memory and gives starting address to ‘p’
In the above example, the function malloc() allocates 10 bytes of memory in the RAM and returns the
starting byte address, which is then assigned to 'p'. Here one question arises! What type of pointer ‘p’
C-Family 238 Dynamic Memory Allocation
should be? This is fairly depends upon what type of data we are going to keep in this memory. Suppose if we
are going to store array of float values then pointer should be “float*” type. Remember that malloc() returns
just address which has no type, that is, it returns “void*” type address. So it should be type casted as per
our pointer type. (All malloc(), calloc() and realloc() function’s return-type is void* type)
In the above, the array creates with the input size ‘n’, later access through the pointer ‘p’. Here the input
size(n no.of input values) can be anything, thus it makes efficient usage of memory.
calloc()
It is also like malloc(), but after allocation of memory, it clears the garbage values by filling with zeros in all
bytes of memory.
pointer = calloc (no.of items, size of item );
It takes two arguments, first one is number of items to be allocated and second one is size of the item. For
example, allocating memory for 5 floats
float *p;
p = (float *) calloc(5, sizeof(float));
realloc()
It is used to resize (reduce or expand) the memory which is already allocated using malloc() or calloc() or
realloc(). It takes previously allocated memory address and adjusts to new size.
While expanding the size of old memory, if required amount of memory is not available at the adjacent
locations, then it allocates in new location and copies the old memory contents to newly allocated area and
then releases the old memory. If the memory is not available, then it returns null.
syntax: pointer = realloc( oldAddress, newSize);
For example
int *p,
p=(int*)malloc(10*sizeof(int));
----
p=(int*)realloc(p , 20*sizeof(int)); // expanding 10 integers to 20 integers
----
p=(int*)realloc(p , 5*sizeof(int)); // reducing 20 integers to 5 integers
----
Note: p=(int*)realloc(NULL, 10*sizeof(int)) // here oldAddress is null, so it creates fresh memory like malloc() function.
free()
It is used to release the memory which is no longer required by the program. This memory should not
belongs to static allocated system like “int a[10]”. This must be a dynamic memory which is allocated by
malloc() or other functions. It takes the base address of memory as an argument and frees it.
Prototype: void free(void *);
Syntax: free(address);
Example: int *p;
p=(int *)malloc(50*sizeof(int));
---
---
free(p);
Prone and cons of systems
Program’s data area divides into stack & heap area. In stack area, the temporary local variables and function
call-return addresses are stored, whereas in heap area, permanent variables are stored. For DMA system a
special block of memory is created in the RAM and managed as heap.
In static system, at coding time (before compilation), the size of array must be defined with constant value
and it cannot be changed at run time.
C-Family 240 Dynamic Memory Allocation
Allocation of static memory is faster than dynamic, because allocation of memory in the stack is faster than
heap. In static system, at compile time, the relative memory address is fixed for all variables, so it will be
faster. Whereas in DMA system, at run time, the memory is allocated by searching a suitable location and
also maintains a separate table for registering address which location is allocated and which is not, this
makes the program slow.
“Pakistan”
“Srilanka”
C-Family 241 Command Line Arguments
When a program is run, the operating system loads .exe file into memory and invokes the startup function
main(). Here, we can assume the OS is the caller of main() function. Therefore, the arguments can be passed
to the main() by specifying a list of values at the command line as shown below.
C:\tc\bin\>sum 10 20 30
Unlike other functions, the arguments to main() passes in a different manner. They pass as array of string
constants. That means, even if you give an integer values, they pass as strings. In the above case also, the
arguments passed as "sum”, "10", "20", "30". (passes as array of addresses shown in below picture).
But main() receives them as two arguments, the first argument is integer, which specifies the count of
arguments which we passed including file-name. The second argument is, an array of addresses containing
strings. Thus main() function should be defined as
Example1 : this program adds all such integers which we passed through command line as above shown
Input: c:\tc\bin\>sum 10 20 30 40
Output: sum of numbers = 100
void main( int count, char *a[ ] )
{ int sum=0,i=0;
for(i=1; i<count; i++)
sum = sum+atoi(a[i]); //atoi() function converts numeric string to integer value
printf("\n sum of numbers = %d", sum);
}
Example2: The following program takes string as input from command line and displays length.
It also shows an error, if user enters less number of strings.
Input: C:\tc\bin\>sample C-Family
Output: length of C-Family = 8
Primitive Data types: these are also called built-in or basic types, for example int, char, float, int*, etc;
these primitive types and their functionalities are already designed and developed in compiler level during
development of C software. Therefore, we can directly use them in programs.
User defined Data types: ‘C’ gives a freedom to the user (programmer) to define his own data types
according to requirement in the program. Therefore, these are called user-defined types. We have 3 types,
①structure ②union ③enumerator.
Generally, it is difficult to handle large collection of data using basic types. Using arrays, we can handle only
collection of homogeneous items of known size. However, to handle collection of heterogeneous items then
user-types are required. For example, consider an employee data containing id, name, address, salary, etc.
Handling such heterogeneous items individually is difficult and leads to complex task. If we group all these
items into single (as one record) then they can be handled easily. For this, fortunately, C is providing a
structures concept.
1) Structures
Structure is a collection-type user-defined data-type, used to pack several different items together as single
item. So we often state that, array is collection of homogenous items, whereas structure is a collection of
heterogeneous data items. Sometimes, the items in a structure can be same type.
The items in a structure are called data-members and we can have as many members as we want.
Syntax to declare a structure
struct tag-name
{ data_memberl;
data_member2;
…
data_memberN;
};
For example:
struct student
{ int idno;
char name[30];
int marks1, marks2,marks3;
};
This structure declaration defines a new data-type called “struct student”, using this, we can create
variables and its data can be managed.
This structure declaration works as a blue-print or template of our type and it does not occupy any space in
executable file. Just it gives layout idea to the compiler i.e, about tag-name, data type of members and space
required for each member. Now using this structure template, we can create variables and its data can be
managed. Here tag-name is the name given to the structure and it follow rules of variable naming.
The structure can be declared in local or global scope, depends upon requirement of program.
C-Family 243 structures, unions , enums
Note: the definition of a structure works as building-plan, whereas, its variables works as building.
a b
100 Lokesh 45 78 47 101 Srihari 44 55 67
A
100 Lokesh 45 78 47
a.idno a.name a.mark1 a.marks2 a.marks3
now the expression ‘*p’ accesses the total memory of ’a’ [ so *p==a ]
the expression (*p).idno accesses the ‘idno’ in ‘a’
(*p).idno is equal to a.idno
(*p).idno is equal to p->idno // this ‘p->idno’ is a short form, this is called: p arrow idno )
(*p).name or p->name is equal to ‘a.name’
C-Family 244 structures, unions , enums
Note: the expression (*p).name cannot be written as *p.name, because, the dot operator (.) has high
priority than pointer operator (*), so first, the compiler try to evaluate p.name and it shows an error.
Because ‘p’ does not have the data members of a structure, it contains address, whereas, the expression
(*p) is pointing to the memory of ‘a’ and it contained member’s data.
Accepting two dates and find whether they are equal or not?
* trying with & without using functions
ip: 12 9 2010 ip: 12 9 2010
12 9 2010 13 9 2011
op: equal op: not equal
struct Date
{ int d, m, y;
};
void main()
{ struct Date a , b;
int k;
read( &a ); // scan date1 (day, month, year) using read() function.
read( &b ); // scan date2 (day, month, year)
k=compare( a , b ); // compares two dates and returns 1/0
if( k==1) printf(“equal”);
else printf(“not equal”);
}
void read( struct Date *p )
{ printf(“enter day month year:”);
scanf(“%d%d%d”, &p->d, &p->m, &p->y);
}
int compare( struct Date p , struct Date q )
{ if( p.d==q.d && p.m==q.m && p.y==q.y)
return 1;
else return 0;
}
the read() fn followed call-by-reference, because, the scanned values at read() fn need to be returned to
main() fn, therefore we have to store indirectly through pointers, whereas compare() fn follows call-by-
value, it is just comparing given two dates.
Accepting two times from keyboard and printing addition of two times
Let the two times are employee working time in two shifts, later add & print total time worked in two shifts.
ip: 12 50 58 (shift-1 worked duration : Hours=12, Min=50, Seconds=58 )
2 53 55 (shift-2 worked duration : H= 2, M=53, S=55 )
op: 15hr 44min 53sec (total duration worked in two shifts)
struct Time
{ int h, m, s ;
};
void main()
{ struct Time a, b, c;
a=read(); // this read() fn returns the scanned time ( it is opposite to above read() fn)
b=read()
c=add(a,b); // add two times like c=a+b
write(c); // print output time on the screen
}
C-Family 247 structures, unions , enums
Array of structures
Array of structures is useful when several instances of details are to be handled in the program.
We can create array of structures just like any normal data types.
Syntax: struct tagName arrayName[size];
Here every element “s*i+” is a structure item and accessing of each structure is just as accessing each item in
the array. Each individual structure member can be accessed as
Syntax: arrayName[index].memberName
The expression s[0].name accesses the name in s[0]
The expression s[0].age accesses the age in s[0]
(or)
for( i=0; i<3; i++)
{ printf(“\n %s %d “, p->name, p->age);
p++; // increments by 22, to points to next structure
}
}
above two loops do same job in accept() & display() function, but second loop little faster than first loop.
#define maxSize 20
struct POLY
{ int exp;
int coeff;
};
void readPoly(struct POLY p[])
{ int prev=maxSize+1, i=0;
while(1)
{ printf("\nEnter coefficient (use 0 to exit) :");
scanf("%d",&p[i].coeff);
if(p[i].coeff==0) break;
printf("\nEnter exponent: ");
scanf("%d",&p[i].exp);
// the input exponents must be in sorted order like shown in above equation, otherwise shows input error
if( p[i].exp > prev)
{ printf("input error");
continue; // go back and read again
}
prev=p[i].exp;
i++;
}
}
void printPoly(struct POLY p[])
{ int i;
for(i=0; p[i].coeff!=0; i++)
printf("%d^%d + ", p[i].coeff, p[i].exp);
printf("\n ");
}
void addPoly( struct POLY p3[], struct POLY p1[], struct POLY p2[])
{ int i=0, j=0, k=0;
while (p1[i].coeff!=0 && p2[j].coeff !=0 )
{ if( p1[i].exp > p2[j].exp)
p3[k++] = p1[i++];
else if( p1[i].exp < p2[j].exp)
p3[k++] = p2[j++];
else
{ p3[k].exp = p1[i].exp;
p3[k++].coeff = p1[i++].coeff + p2[j++].coeff;
}
}
while(p1[i].coeff!=0 ) p3[k++] = p1[i++];
while(p2[j].coeff!=0) p3[k++] = p2[j++];
p3[k].coeff = 0;
}
void main()
{ struct POLY p1[maxSize], p2[maxSize], p3[maxSize];
printf("enter polynomial 1:");
readPoly(p1); // accepting first polynomial
printf("enter polynomial 2:");
readPoly(p2); // accepting second polynomial
addPoly(p3,p1,p2);
printf("\n The resultant poly after addition is\n");
printPoly(p3);
}
C-Family 252 structures, unions , enums
Nested structures
Structure in structure is said to be nested structure, we can nested as many times as we want, complexity
will not be increased even though nested many times. for example,
struct Student
{ int idno;
struct Date
{ int d,m,y;
} joinDate;
};
void main()
{ struct Student p;
p.idno=10; P
p.joinDate.d=10; idno joinDate
p.joinDate.m=12; d m y
p.joinDate.y=2020;
-----
}
C-Family 253 structures, unions , enums
typedef
“typdef” is a keyword,used to define new convenient names for existing types.
It works as alias name for existing types, but we don’t lose old name.
Syntax: typedef existing-name new-name;
For example
typedef float RS;
typedef float DOLLOR;
typedef int* INTP;
Let us see, how variables can be declared
RS amount1;
DOLLOR amount2;
Here amount1, and amount2 are nothing but float type variables and this is equal to
float amount1, amount2;
Advantages of a structure
It is rather easy to handle all items in structure as a single item than individual, which gives the following
advantages.
1. Assignment between structures is possible
the compiler supports for copying one structure to another structure just like any integer value.
Here all members in the structure are copied bit by bit.
struct empleoyee e1=,100, “Srihari”, 50000.00};
structu employee e2;
e2=e1; // all members of e1 is copied to e2
Unions
Union defines the generic data-type instead of specific type, where we can store any type of value such as
int/float/char/etc. Union is also similar to structure but all the members in the union share the common
memory area. Here space is created for only one member and remaining members share the same space,
therefore we can store & access only one member at a time. The size of union is equivalent to biggest data
member in it. The main purpose of union is to save the memory space, and also gives flexibility in coding.
item
union myType
{ char c; Byte1 Byte2 Byte3 Byte4
int i;
long int l; c
float f; i
f/l
};
union myType item;
The above union variable ‘item’ occupies 4bytes of memory. Among 4 members, the first member ‘c’ uses
only first byte. The second member ‘i’ uses first two-bytes. Similarly remaining f & l uses total 4bytes.
Demo program for how data is handled in union variables
union myType
{ int i, j, k;
};
void main()
{ union myType var;
var.i=10;
printf(“\n i=%d j=%d k=%d", var.i, var.j, var.k);
}
Output: i=10 j=10 k=10
In the above program, when ‘var.i’ is assigned a value 10, the other union members ‘var.j’ and ‘var.k’ also
gain the same value as they are sharing the common memory space.
void main()
{ union myType var;
var.i=10;
var.j=20;
var.k=30;
printf(“\n i=%d j=%d k=%d", var.i, var.j, var.k);
}
op: 30 30 30. Here var.j=20 overwrites the var.i=10, var.k=30 overwrites var.j=20;
Let us see one more example
union myType
{ long l;
float f;
};
void main()
{ union myType var;
var.f=200;
printf("\n l=%ld f=%f\n", var.l, var.f);
var.l=100; // overwrites var.f=200 value
printf("\n l=%ld f=%f\n", var.l, var.f);
}
Output: l=garbage f=200.000000
l=100 f=garbage
C-Family 255 structures, unions , enums
Let us see practical example, the print() function can print all types of data.
typedef struct
{ union
{ char cc;
int ii;
float ff;
}value;
char valueType;
}MyType;
void main()
{ MyType var;
var.value.cc='A';
var.valueType='c';
print(var);
var.value.ii=100;
var.valueType='i';
print(var);
var.value.ff=300.45;
var.valueType='f';
print(var);
}
Enumeration
Enumerator data type is used to symbolize a list of constants with names, so that, it makes the program easy
to read and modify. Enumerator maps the values to names there by we can handle the values with names.
enum tagName { name1, name2, name3, ... nameN } ;
For example
enum Colors{ red, green, blue }; // here red=0, green=1, blue=2
enum Boolean{ false, true }; // false=0, true=1
In this way, we can specify enumerated set with valid unique names.
At compile time, all these names are automatically assigned with integer values 0, 1, 2, 3 etc.
Ambiguity error
There is one problem with enumeration, if any variable exist with same name in enumerator set in same
scope then we get error at compile time.
For example,
enum color { red, green, blue, white, yellow};
int red=0; /* ambiguity error with red, so either one must be removed */
void main()
{ int white=100; // preference is given to local white variable, instead of white in enumeration
printf("%d %d %d %d", green, blue, white, yellow};
}
output: 0 1 100 4
Enumeration variables
Using enumerator tag name, we can specify variables of its type. This makes the convenient and increases
the readability of the program. The enumerator variables are nothing but int-types. For example
enum tagname variable-1 ,variable-2, variable-3, ... ;
enum Color { Red=15, Green=26, Blue=13, White=5, Yellow=4, Grey=17 };
void main()
{ enum Color wallColor, floorColor;
wallColor=White;
floorColor=Grey;
…
…
}
C-Family 258 Data Files
File handling in C
In real life applications, some kind of input/output data need to be accessed frequently by many persons in
many times whenever it is required. Therefore, such data need to be placed permanently in the computer,
so that it can be accessed many times later.
For this purpose, secondary storage devices are used to store the data permanently in the form of files.
These files often called data files. Thus, data file can be defined as collection of data, stored permanently in
secondary storage device. Each file is identified by a valid name called file-name. The interaction with files is
treated as interaction with io devices in the computers. Therefore, all secondary memory devices treated as
io devices.
Let us consider a menu driven program to automate student marks in a college. Generally, we provide all
options that are required by the college management. Let the marks data scanned from keyboard and
stored permanently in a data file called "marks.dat", later, such marks are processed and stored the results
in a separate file called "result.dat" or displayed on the screen. This is depending upon the requirement of
problem. The interaction of application with io devices is as follows
Here in first figure, the application is interacting with keyboard as input device and file as output device.
In second figure, the both input and output devices are files.
1. Text Files (Text format files here data is stored in the form of ascii values (string format))
2. Binary Files (Binary format files data is stored as it is in program variables (raw format))
C-Family 259 Data Files
Text Files
In text files, everything is stored in the form of ascii values, even numeric data is converted into string
format with its ascii values of each digit and stored in file. For example, 'k' contained a value 2891, this
number is stored in text file as
Here 50, 56, 57,49 are ascii values of 2, 8, 9,1 respectively. Internally each digit ascii again stored in binary
form as above shown(as computer understands only binary values), in this way text data is stored and
retrieved from file. These files are only suitable for presentation of data, i.e, for displaying or printing
purposes only. For example, document files, help files, message files, public related files, source program
files, small data files, configuration files, etc are handled in text format. In general, these files are handled in
two ways, by writing a specific program to manage them, or by using ready-made text editors. Using text
editor, we can create, modify the text data. We have several text editors like notepad, word pad, ms-word,
etc.
At end of text files, the value 26 is inserted to indicate end-of-file mark and also the new-line character is
stored as "\r\n"(unix format). The library functions does this job while writing ‘\n’ to file, whereas while
reading back, it is considered as only one character (\n). (We don’t worry about this ‘\n’)
Binary files
In this kind of file organization, all the contents are stored as it is in program variables. Here no conversion is
made while storing and reading back unlike text files. Generally, binary files are extensively used for
maintaining similar type of data like employee records or bank accounts, insurance accounts, etc.
In binary i/o, as it is of storing & reading back takes place between the RAM & secondary memory, therefore
binary files is faster than text files. At end of text files, the value 26 is inserted to as end-of-file-mark,
whereas in binary files no such value is inserted, where end-of-file mark is known by the file-size.
In case of binary files, we cannot manipulate the data using text editors. For example, take student structure
idno|name|marksint|char[30]|int. if this data is dumped into file as it is, then it has to be read back as it
is.(2byte at a time for idno, 30byte at a time for name,..) So, text editors are unaware of this user-defined
structure, hence we cannot handle binary files using text-editors. (text editors read/write data only in the
form of ascii)
There should be separate software needed to handle binary tiles. For example ‘pdf’ file is a binary format file
and cannot be opened in text editor, special software like Adobe-Reader is used. Similarly, jpg files, image
files, sound files, movie files are managed using special software.
in C, files can be handled in two ways, 1. High level file handling, 2. Low level file handling.
C-Family 260 Data Files
High-level file IO
For high-level file handling, C provides more facilities like file streaming (buffering) with related library
functions. The library functions like reading/writing data from file, converting numeric into text format, and
text to numeric and redirection of output into other destinations like screen, printer, etc is also possible.
File stream: As we know, stream is a data structure, works as mediator between device and our
application. It is like a pipeline structure between motorwater tanktap at your home. Any stream has
built-in i/o functions with array of bytes of space in the RAM called buffer. (stream=buffer memory + io
functions).
Write() Array of bytes Read()
In other words, it is a temporary storage service to store & retrieve the data for a while in the program.
Loosely saying, it acts as a go-down between manufacturer and retail-shopper for stock maintenance, here
we keep items temporarily for a while. In computers, the well-known example is Youtube streaming, etc.
In computer, every device has own streaming like keyboard-stream, mouse-stream, monitor-stream, printer-
stream, etc. When you type something on the keyboard, the input characters are inserted in keyboard
stream-buffer, later our scanf()/gets() read from the stream-buffer. Thus stream works as mediator between
device & app. This file stream is available in C languages with the name FILE.
The total hard disk space logically divided into several blocks and each block size is around 1024bytes.
This is custom size, we can change this size to 2048/4092/…) The hard disk header-pin can read/write at a
time one block of data (not in bytes). As we know, the files are stored permanently in hard disk in the form
of blocks. Let each block size is 1024bytes on your disk and your file size is 3000bytes, then your file takes
3blocks to store on disk. Storing and reading files from hard disk is managed by the operating system.
Thus, before doing any operation on your file, first its contents (not total file) are placed in stream’buffer
and then operations takes place. That is, when we open a file, the first block of file contents is loaded into
the stream’buffer, and then io operations performed on it. Whenever another block is required, then
current block is replaced with next block. This process is called streaming and is done with the help of OS.
For this, the C providing a FILE structure variable to store the meta-data of file. The meta-data such as file-
name, file-type, open-mode, pointer to file-data(block), pointer to current read/write record, error-code,
block-number, and other O.S related details.
This predefined FILE structure provided in 'stdio.h' file as
typedef struct
{ int level; // fill empty level of buffer
unsigned flags; // file status flags
char fd; // file descriptor
unsigned char hold; // ungetc char if no buffer
int bsize; // buffer size
unsigned char *buffer; // data transfer buffer
unsigned char *curp; // current active pointer
unsigned istemp; // temporary file indicator
short token; // used for validity checking
} FILE;
This FILE structure details are related to operating system, this FILE details are used by the library functions
implicitly while taking i/o operations on file data, so we don’t need not learn & apply in the program. The
following figure explains how FILE structure filled with file data(meta-data) when it opened/loaded in RAM.
C-Family 261 Data Files
Pointer
to file
File stream ( file structure detailsmeta data)
File Pointer to Pointer to current Open mode File type Block Error
name file data read/write record (read/write) (text/binary) reference code
b/t (Binary file/Text file):To specify that a given file be a text or binary file.
Closing a file: The function 'fclose()' closes an already opened file. After completion of read/write/modify
jobs on a file, it must be closed. This operation involves in updating file contents on disk (saving back to disk)
and also releases buffer & FILE structure’s space in the RAM. The syntax is
int fclose(FILE *filePointer); // It returns zero, if successfully closed a file, otherwise returns -1.
fread(), fwrite(): These functions are specialized to handle binary files. Of course, we can also use for text
files, but formatted input/output does not support.
fputc(): It is used to write single character to a file. It takes two arguments, a character which is to be
written, and a pointer of FILE structure. Syntax: int fputc(character, FILE pointer);
fgetc(): It is used to read single character from a file and returns ASCII value of it.
syantax: ch=fgetc( file pointer );
fputs(): Writes a string to file
fgets(): Reads a string from file
fprintf(): It works like a printf(), but writes data to file
fscanf(): It also works like a scanf(), but reads data from file
fread(): This is used for binary files, but also works for text files
fwrite(): It is opposite to fread()
ftell(): returns current read/write position of the file pointer.
fseek(filePointer, 0, SEEK_END): moves the file pointer to end of file.
fseek(filePointer, -100, SEEK_END): moves the file pointer 100 bytes back from end position.
fseek(fp, 0, SEEK_SET): moves file pointer to beginning of file.
fseek(fp, 100, SEEK_SET): moves file pointer to 100bytes forward from beginning.
fseek(fp, 10, SEEK_ CUR): moves file pointer 10bytes forward from current position.
fseek(fp, -10, SEEK_ CUR): moves file pointer 10bytes backward from current position.
SEEK_END is a macro defines the end-of-file. Value is equal to 2.
SEEK_SET is a macro defines the begging-of-file. Value is equal to 0.
SEEK_CUR is a macro defines the current-position of file. Value is equal to 1.
EOF: it is a macro, represents end of file mark for the text files. (EOF value is equal to 26)
feof(): It is used to check whether a given file has reached the End Of File mark or not.
rename():changes the name of an existing file. syntax: rename(“oldName”, “newName”);
remove():deletes a file from disk. syntax: remove(“fileName”);
filelength(): it gives length of file (the number of bytes occupied by the file)
Output
file name: sample.txt
10 20 30 40 50
C-Family 263 Data Files
}
upperCount=lowerCount=digitCount=lineCount=wordCount=0;
while(1)
{ ch=fgetc(fp); // reading single char from file
if(ch==EOF) break; // EOF end of file indicator
if( isupper(ch) ) upperCount++;
else if( islower(ch) ) lowerCount++;
else if( isdigit(ch) ) digitCount++;
else if(ch==' ') wordCount++;
else if(ch=='\n')
{ wordCount++;
lineCount++;
}
}
fclose(fp);
printf("lower count = %d", lowerCount);
printf("upper count = %d", upperCount);
printf("digits count = %d", digitCount);
printf("words count = %d", wordCount);
printf(" lines count = %d", lineCount);
}
#include<stdio.h>
void main()
{ acceptMarks();
processAndShow();
}
void acceptMarks()
{ FILE *fp;
struct Student st;
fp=fopen("marks.dat","wb");
while(1)
{ printf("\n enter idno (0 to stop):");
scanf("%d",&st.idno);
if( st.idno==0) break; // 0 is end of input
printf("enter name:");
fflush(stdin);
gets(st.name);
printf("enter marks1:");
scanf("%d",&st.m1);
printf("enter marks2:");
C-Family 267 Data Files
scanf("%d",&st.m2);
fwrite( &st, sizeof(st), 1, fp); // for total, average garbage will be stored
}
fclose(fp);
}
void processAndShow()
{ FILE *fp;
struct Student st;
int k, total, avg;
char *result;
fp=fopen("marks.dat","rb");
printf("\n%6s %-20s %5s %5s %-20s", "idno", "name", "mark1", "mark2", "result");
printf("\n---------------------------------------------------------------------------");
while(1)
{ k=fread( &st, sizeof(st), 1,fp);
if(k<=0) break; // end of file reached then stop it.
total=(st.m1+st.m2);
avg=total/40;
if( st.m1<35 || st.m2<35 )
result="Failed";
else if(avg>=60)
result="First class";
else if(avg>=50)
result="Second class";
else result="Third class";
printf("\n %-6d %-20s %5d %5d %-20s", st.idno, st.name, st.m1, st.m2, result);
}
fclose(fp);
}
void main()
{ int choice;
while(1) // loop to display menu continuously
{ printf("\n\n=============================================================");
printf("\n 1.append \n 2.delete \n 3.modify\n 4 print \n 0.exit");
printf("\n Enter choice [1,2,3,4,0]:");
scanf("%d", &choice);
switch(choice)
{ case 1: append(); break;
case 2: delete(); break;
case 3: modify(); break;
case 4: print(); break;
case 0: exit(0);
}
}
}
// ------------------------------------------------------------------------------------------------------------------------
// this append function appends a record in the file
void append()
{ FILE *fp; EMP e;
fp=fopen("emp.dat", "ab");
if(fp==NULL)
{ printf("\nUnable to open emp.dat file");
return;
}
printf("\n enter employee no:");
scanf("%d",&e.empNo);
printf("Enter employee name:");
fflush(stdin);
gets(e.name);
printf("enter salary :");
scanf("%f",&e.salary);
fwrite(&e,sizeof(e),1,fp);
fclose(fp);
printf("\n successfully record added");
}
// --------------------------------------------------------------------------------------------------------------------------
// deleting record, generally, it is not possible to delete a record in a file. Alternative is, copying all records
// into another temporary file except deleting record; later temporary file will be renamed with the original
// file name.
void delete()
{ FILE *fp,*ft; EMP e;
int eno, found=0, k;
fp=fopen("emp.dat", "rb");
ft=fopen("temp.dat", "wb");
if(fp==NULL || ft==NULL )
{ printf("\nunable to open file");
fclose(fp); fclose(ft); return;
}
printf("\nenter employee number to delete record :");
scanf("%d",&eno);
while(1)
{ k=fread(&e,sizeof(e),1,fp);
C-Family 269 Data Files
if(k==0)break;
if(eno==e.empNo)
found=1; // record is found
else
fwrite(&e,sizeof(e), 1 ,ft);
}
if(found==1) printf("\nRecord deleted success fully");
else printf("\nRecord Not found");
fclose(fp); fclose(ft);
remove("emp.dat");
rename("temp.dat","emp.dat");
}
// --------------------------------------------------------------------------------------------------------------------------------------
// Modifying data in a record. First, it searches for modifying record in a file, if record is not found then
// displays error message & returns. If found, then old-salary overwrites by new-salary of a record
void modify()
{ EMP e;
int found=0 , eno, k;
long int pos;
FILE *fp;
fp=fopen("emp.dat","rb+");
if(fp==NULL)
{ printf("\nfile not found ");
exit(0);
}
printf("\n enter employee number:");
scanf("%d",&eno);
while(1)
{ k=fread(&e,sizeof(e),1,fp);
if(k==0) break;
if(eno==e.empNo)
{ found=1; // record is found
break;
}
}
if(found==0)
{ printf("\n Record not found");
return;
}
pos=ftell(fp);
pos=pos-sizeof(e);
fseek(fp, pos, SEEK_SET); // move the file pointer one position back
printf("old salary : %.2f", e.salary);
printf("enter new salary:");
scanf("%f", &e.salary);
fwrite(&e,sizeof(e), 1 ,fp); // overwriting old record
fclose(fp);
printf("\n address suceessfully modified");
}
// --------------------------------------------------------------------------------------------------------------------------------------
C-Family 270 Data Files
This book softcopy is available in pdfhost.io website, to download the file, search through keyword ‘cfamily’.
This pdf file(s) designed for 2-sided print-copy (Xerox hard copy).