Programing in C - A Study Material
Programing in C - A Study Material
Compiled By:
TABLE OF CONTENTS
MODULE I:
Chapter 01: Data Types, Variables & Constants .. 02
MODULE II:
Chapter 05: Functions. 35
Chapter 06: Storage Classes 41
Chapter 07: Arrays 44
Chapter 08: Pointers 55
Chapter 09: Dynamic Memory Allocation. 62
Chapter 10: Command Line Argument 64
MODULE III:
Chapter 11: Structures, Unions & Enumerations 65
Chapter 12: File Handling. 71
Chapter 13: Preprocessors.. 84
MODULE I
Char
int
Float
Double
1. char:
1 byte
2 bytes (16 bit compiler)
4 bytes (32 bit compiler)
4 bytes
8 bytes
Range
-128 to 127
-32678 to 32767
-2147483648 to 2147483647
3.4e - 38 to 3.4e + 38
1.7e - 308 to 1.7e + 308
char is a Integral type stored in computer as coded set of binary digits having positive decimal equivalent
and able to hold 8 bits of data. For signed char 1 sign bit and 7 data bits for unsigned char all 8 data bits.
Modifiers
: signed, unsigned
Size : 1 bytes
Range: signed char : -128 to 127
unsigned char : 0 to 255
Format specifier: %c
If data value exceeds max limit or min limit, it loops back to the min limit and max limit respectivily.
For negative numbers sign bit will be 1 and data bits will be stored in 2s complement. For positive
numbers sign bit will be 0 and data bits will be stored directly.
2. int:
Variables of int data type hold an integer value. For signed int, 1 sign bit and rest data bits. For unsigned
int, all are data bits.
Modifiers:
signed, unsigned, short, long
Size:
short : 2 bytes
int
: 2 bytes (16 bit machine) and 4 bytes (32 bit machine)
Long : 4 bytes
Range: signed short int
: -32768 to 32767
unsigned short int
: 0 to 65355
signed int
: -2n-1 to 2n-1-1 (n is the number of bits)
unsigned int
: 0 to 2X2n-1-1 (n is the number of bits)
signed long int : -2147483648 to 2147483647
unsigned long int
: 0 to 4294967295
Types: decimal integer, octal integer, hexadecimal integer.
Format specifier:
int: %d, %i
unsigned int: %u (unsigned)
long int: %ld, %li
short int: %h, %hi, %hd
octal: %o
hexadecimal: %x
If data value exceeds max limit it loops back from the min limit and similarly for min limit.
For negative numbers sign bit will be 1 and data bits will be stored in 2s complement. For positive
numbers sign bit will be 0 and data bits will be stored directly.
Endianness is the system attribute that indicates whether the integers represented from right or
left.
Big-endian is an order in which the big end (Most significant value in the sequence) is stored first
(at lowest storage address) and in little-endian little end (least significant value in the sequence)
is stored first (at lowest storage address).
3. float :
4. void:
Its and empty data type associated with function and pointer. Its used:
To explicitly declare a function returning no value. E.g. void show ( );
To declare a function having no argument. E.g. void show (void );
To create a generic pointer. e.g.
void main ( ){
void *p;
printf (enter a number);
scanf(%d, (int) &p);
printf(%d, (int) p); }
5. enum:
int a = -11;
unsigned int b=2579;
if (a>b)
printf (Hello);
else
printf (Hi); }
Output: Hello
Explanation: When the -11(signed) is compared with 2579(unsigned), then the signed -11
converted to the unsigned, i.e. 65536-11=65525(since the max range of unsigned int is 65536)
which is greater than 2579.
9. When the conversion is from integer to float using the format specifiers such as %d and %f, the
same variable and the next variable(s) will suffer i.e. loss of data. e.g.
void main ( )
{
int a=5, b=7;
float c=9.9;
printf ( %d %d %d , c, a, b);
}
Output: garbage or wrong value.
Explanation: memory representation of integer is different from that of float.
10. Cycle is present in integer and character data type but is not present in float or double types. If a
value of a variable exceeds its range of its types, it immediately wraps round to positive or negative.
Finding the output:
If the given value of an integer is more then 65535 then ans = given value % 65536
If the given value of an integer is in between 32767 and 65536 then ans = given value - 65536
e.g.
void main ( )
{
int s = 90000, c = 50000;
printf (%d\t%d,s,c);
}
Output: 24464
-15536
11. The recurring 32 bits real number is less than 64 bits recurring real number. E.g.
void main()
{
float x=4.2;
if (x == 4.2)
printf (hello);
else
printf (hi);
}
Output: hi
Explanation: 4.2 consumes 8 bytes i.e. 64 bits. When its stored in x which is a float variable, it
consumes 4 bytes i.e. 32 bits. Binary number 4.2 (8 bytes ) > binary number x (4 bytes).
12. % (modulus) operator is not applicable to any floating number. Itll show a error (illegal use of
floating point).
13. Character variables always consume 1 byte but character constants always consume 2 bytes.
(Character constants are always stored in memory in their ASCII value which is a integer.)
e.g.:
void main ( )
{
char p = A;
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
void main ( )
{
short int a=20000, b=20000;
short int c=a+b;
if(c>0)
printf("hello");
else
printf("Hi");
}
Output: Hi
(Value of an integer variable wraps
to the negative value due to overflow.)
Variables:
Its a named object that resides in the memory (RAM) and is capable of being examined and modified.
Variable name is a name given to a location in memory of a computer where different constants are
stored.
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
Variable Declaration:
A variable must be declared before using it to make the compiler know the name and type of variable so
that itll decide what type of values it can take and what will be the size itll take in memory.
E.g.
static int a;
char a;
Variable Initialization:
Giving an initial value to a variable is called initialization of a variable. A variable should be initialized to a
value to be used in different operations.
E.g.
Properties of Variables:
The properties of variables are decided or affected by the following aspects and factors.
Scope of the variables (local and global)
Life span of the variable
Default initial value of a variable
Storage of the variable (in memory or in register)
L value and R value of the variable
Qualifier of the variable
Use of Variables:
Fixed value: value of a variable is fixed after initialization if its value does not change in the run time.
Stepper/Counter: Used in loops.
Most-recent holder: Repeatedly asks the user to input until the given value is valid in as per the pre
defined criteria and the variable holds the last valid input.
Gatherer: The value of a gatherer accumulates all the values gone through so far in a cumulative
effect.
Transformation: In this case the variable always gets its new value from the value(s) of other
variable(s) through the same calculation.
One-way flag: Its a Boolean variable which once changed cant get its original value anymore.
Follower: it always gets the old value of another known variable as its new value.
Temporary: If the value of a variable is needed only for a short period.
Organizer: Its an array which is used for recognizing its elements after organization.
Naming Conventions:
ANSI has formulated a set of rules for naming the variables in an efficient manner.
The variable name must be within 32 characters.
The first character must be an alphabet or an underscore (_) and the rest can be alphabets, digits or
underscores.
No space or special characters are allowed.
No keyword can be a variable name.
Declaration is used to specify the name and type of an object to the compiler. It asserts that the object
exists but does not actually allocate memory space for it. (Reuse of the variable from somewhere out of
scope).
While definition is used to provide a value to a variable so that itll reserve memory space for itself.
E.g.
void main ( )
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
}
int x = 5; // variable definition
Qualifiers:
Qualifiers improve the quality, efficiency and accessibility of the data objects or function objects.
Volatile qualifier:
E.g. int volatile x; or volatile int x;
Volatile is used to explicitly tell the compiler that a variables value may be changed at any time by
some external source (from outside the program, may be a kernel code or device drivers).
When the variable is declared as volatile, the compiler will examine the value of the variable each
time its encountered to see whether any external alteration has changed the value or not.
The volatile qualifier tells the compiler that a variable may be referenced in such a way that the
values hidden from the compiler but known to the programmer.
Value of the volatile qualifier gets refreshed every time its accessed and hence should be used to
qualify variables which are very frequently accessed, like loop counters.
In case of hardware mapping the variable must be declared to be volatile.
Const qualifier:
const qualifier tells the compiler, the variable value cannot be changed in the current file, but can be
modified in another file.
E.g. int const x=5; or const int x=5;
A const variable can be initialized only at the time of declaration.
In case of a constant pointer (const *p) the address, the pointer refers to can never be changed as
well the pointer cant be initialized in future. But the value at the address the pointer contains can be
changed.
Const in function parameter provides security to data while passing data as a parameter in a function.
Global Identifiers:
Turbo c uses many global variables for different purposes. All global variables are pre fixed with an
underscore (_) character. E.g. _ _TIME_ _ (no space) will show the current time.
Constants:
A constant is an entity that does not change or alter. In C constants can be created using const, enum, or by
using Macro expansion (#define c=11). There are different types of constants as follows.
Integer Constant:
If the number is preceded with a 0 or 0x, its an octal or hexa-decimal integer constant respectively. If the
number is succeeded with a L or u, its an long or unsigned integer constants respectively. (5L, 9u)
Its normally a character out of 256 characters enclosed with in a single quote ( ). Octal character
constants usually preceded by a backslash (\a). Hexa-decimal character constants are preceded by a \x.
e.g. char p=34;
All escape character constants start with \ and implicitly represented in the form of octal numbers.
If the escape character range is more than 255, itll cause an error Numeric constant too large.
\377 is a valid character constant as its by default an octal number with decimal value 255. But
\378 is a not valid octal number hence not a character constant.
\457 is a valid octal number but range is beyond 255 and hence invalid character constant.
If the 1st character followed by a \, is a valid octal digit (0 to 7), itll be considered as an octal number
or else as any character constant.
Some valid Escape Characters:
Escape Character
ASCII value
Purpose
\a
7
Bell character
\b
8
Back space
\t
9
Horizontal tab
\n
10
New line
\v
11
Vertical tab
\f
12
Form feed
\r
13
Carriage return
Real Constant:
Its the floating point constants. It could be written in two forms: Fractional form and exponential form.
e.g.
float x = 4.5;
//4.5 is double constant.
float x = 4.5f;
//4.5f is float constant.
float x = 4.5e+2;
//4.5e+2 is exponential constant.
float x = 4.5L;
//4.5L is long double constant.
1. 2 types of variables: value type (int a;) and reference type (int a[5];).
value type variables are created in the stack area while reference type variables are created in the
heap area.
2. Microprocessor generates the address for the variables and the storage class decides where it will
be created and how many bytes itll occupy.
3. When the sizeof ( ) operator is used with an object, parenthesis is not compulsory, but when used
with any data type, its compulsory. E.g. sizeof x; sizeof 5; sizeof (int);
4. Variables cant be initialized in the sizeof ( ) operator.
5. An ordinary pointer may be used to point a pointer to volatile object, but for that an explicit type
cast must be used to assign a pointer to a volatile object to an ordinary pointer.
e.g.
volatile int volatile_int;
int *ordinary_ptr;
volatile int *ptr_to_volatile;
int *volatile volatile_ptr;
ptr_to_volatile = ordinary_ptr;
//valid
ordinary_ptr = ptr_to_volatile;
//invalid
ordinary_ptr = (int *) ptr_to_volatile;
//valid
6. 5 is a character constant while 5 is a string constant. 5L is a long integer constant while 5.0L is a
long double constant.
7. const and volatile can be used together. E.g. const volatile int x=5; or volatile const int x=5;
8. Function name can be used as a variable name inside that function only.
main is a special type of function, not a keyword.
9. The minimum octal character constant is \000 and maximum octal character constant is \377.
10. All constants in C are R value category of objects.
11. The number of constants and variables in C are equal.
12. Constant variables, array name and function name; enum constants are R value category of objects
and they should always be placed in the right side of an equal-to operators.
13. All escape sequence characters are octal character constants.
14. The size of the null string constant is 1 byte.
15. \0 is null character constant whose ASCII value is 0.
16. Every variable and function allocates memory in load time and run time, but how much memory will
be allocated and where will be allocated that is decided during compile and linking time.
CHAPTER 2 (OPERATORS)
Operators specify the basic operations that are to be performed with the basic data objects (variables and
constants). C consists of 45 operators. Expressions formulated with the help of them and are evaluated to
get desired result.
Operators are classified depending upon the number of operands, where an operand is the data item upon
which the operators act. E.g. X+Y (X and Y: operands, +: an operator)
Classifications:
1. Unary (1 operand)
2. Binary (2 operands)
3. Ternary (3 operands)
Precedence Table:
Precedence Operator
1
( ) [ ] -> .
- ++ _
2
~ ! &
* (Type) sizeof ( )
3
* / %
4
+ 5
<< >>
6
< <= > >=
7
== !=
8
&
9
^
10
|
11
&&
12
||
13
?:
= *= /= %=
14
+= -= &= ^= |=
<<= >>=
15
,
Associative
Left to Right
Right to Left
Left to Right
Left to Right
Left to Right
Left to Right
Left to Right
Left to Right
Left to Right
Left to Right
Left to Right
Left to Right
Right to Left
Right to Left
Left to Right
10
<
- is less than operator
>
- is greater than operator
==
- is equals to operator
>=
- greater than equals to operator
>=
- less than equals to operator
!=
- not equals to operator
Relational expressions:
Relational expressions always result either 0 (false) or 1(true non-zero).
&&
- logical and operator (if the values of both the objects are non-zero (true), it results 1 else
0.)
||
- logical or operator (if the values of both the objects are zero (false), it results 0 else 1.)
!
- logical not operator (if the value of an object is 0, it results 1 else 0.)
Logical expressions:
Logical expressions also return either 0 or 1.
=
- assignment operator (its used to assign the value of an expression to a variable.)
Short-hand arithmetic assignment operator: (op=)
C has a set of short-hand assignment operators of the form
v op= exp;
Where v is a variable, exp is an expression and op is c binary arithmetic operator. op= is known as
shorthand assignment operator.
The assignment statement v op= exp;
is same as
v = v op (exp);
with v evaluated only once.
e.g.
x += y+1; is same as x = x + (y+1);
The short-hand operator += means add y+1 to x or increment x by y+1.
Advantages of using short-hand assignment operator are:
1. The left hand side is not repeated in the right hand side and hence easier to write.
2. The statement is more concise and easier to read.
3. The statement is more efficient.
6. Conditional Operators: ( ? : )
11
~
>>
- bitwise ones complement operator. E.g. int x= ~5; here x= -6. (~a = -(a+1))
- bitwise Right shift operator. E.g. int x= 5>>1; here x= 2. (binary of 5 is shifted to right by
1bit )
<<
- bitwise Left shift operator. E.g. int x= 5<<1; here x= 10. (binary of 5 is shifted to left by 1bit
)
&
- bitwise AND operator. E.g. int x= 5&9; here x= 1.
|
- bitwise OR operator. E.g. int x= 5|9; here x= 13.
^
- bitwise XOR operator. E.g. int x=5^9; here x=12.
C supports bitwise operators (except ~) combined with assignment operator to create short hand
bitwise assignment operators. E.g. >>=
8. Special Operators:
a. Data Access Operator:
()
[]
.
->
&
*
1. Precedence decides the priority of the operators while associativity determines the order of
evaluation.
2. Precedence and associativity of an operator is only implemented if expression is represented in INFIX
notation.
3. The operator which requires three operands is called ternary operator. ?: is a conditional ternary
operator.
4. sizeof ( ) is a operator which is also a keyword but looks like a function. It does not evaluate any
expression passed as an argument. Its applicable only to the variables, constants, data types but not
to the functions.
5. Modulus (%) works only with the integral operands and cant be applied to float or double (Error:
Illegal use of floating point).
6. C does not allow ** like ++ as ** is not an operator.
7. Increment/ decrement operators can only be applied to the variables. Cant be applied to the
constants (5++; Error: Lvalue required.)
8. Return keyword cant be used with conditional operator.
e.g. p > 65540 ? return 1: return 0;
//Error: expression syntax.
9. Bitwise operators work with only integer and characters.
e.g. float x=2.0&5; //Error: Illegal use of floating point.
10. Continuous triple plus (+++) are allowed but not more. e.g. a+++5; //a++ + 5
If more than three plus are used, then they must be separated by spaces.
E.g.
a++ + ++b;
//valid
a+++++b;
//Error: L value required.
11. If the left hand operand yields false value, the right operand is not evaluated in a logical expression
using &&. E.g.
int x, y = 2, a = 5;
x = y-2 && a++;
12
13
Header file
: stdio.h
Prototype
: int getc(FILE *stream);
Description
: Gets character from stream. getc returns the next character on the given input stream and
increments the stream's file pointer to point to the next character.
Note: For Win32s or Win32 GUI applications, stdin must be redirected.
Return Value : On success, getc returns the character read, after converting it to an int without sign extension. On
end-of-file or error, it returns EOF.
Example:
#include <stdio.h>
int main(void)
{
char ch;
printf("Input a character:");
ch = getc(stdin); //reads a character from the standard input stream
printf("The character input was: '%c'\n", ch);
return 0;
}
getch()
Header file
: conio.h
Prototype
: int getch(void);
Description
: Gets character from keyboard, does not echo to screen. getch reads a single character directly from
the keyboard, without echoing to the screen.
Note: Do not use this function for Win32s or Win32 GUI applications.
Return Value : getch returns the character read from the keyboard.
Example:
#include <conio.h>
#include <stdio.h>
int main(void)
{
int c;
int extended = 0;
c = getch();
14
getchar()
Header file
: stdio.h
Prototype
: int getchar(void);
Description
: Gets character from stdin. getchar is a macro that returns the next character on the named input
stream stdin. It is defined to be getc(stdin).
Note: Do not use this function for Win32s or Win32 GUI applications.
Return Value : On success, getchar returns the character read, after converting it to an int without sign extension.
On end-of-file or error, it returns EOF.
Example:
#include <stdio.h>
int main(void)
{
int c;
/* Note that getchar reads from stdin and is line buffered; this means it will not
return until you press ENTER.*/
while ((c = getchar()) != '\n')
printf("%c", c);
return 0; }
getche()
Header file
: conio.h
Prototype
: int getche(void);
Description
: Gets character from the keyboard, echoes to screen. getche reads a single character from the
keyboard and echoes it to the current text window using direct video or BIOS.
Note: Do not use this function for Win32s or Win32 GUI applications.
Return Value : getche returns the character read from the keyboard.
Example:
#include <stdio.h>
#include <conio.h>
int main(void)
{
char ch;
printf("Input a character:");
ch = getche();
printf("\nYou input a '%c'\n", ch);
return 0;
}
gets()
Header file
: stdio.h
Prototype
: char *gets(char *s);
Description
: Gets a string from stdin. gets collects a string of characters terminated by a new line from the
standard input stream stdin and puts it into s. The new line is replaced by a null character (\0) in s. gets allows input
strings to contain certain whitespace characters (spaces, tabs). gets returns when it encounters a new line; everything
up to the new line is copied into s.
Note: For Win32s or Win32 GUI applications, stdin must be redirected.
Return Value : On success, gets returns the string argument s. On end-of-file or error, it returns NULL
Example:
#include <stdio.h>
int main(void)
15
: stdio.h
: int putc(int c, FILE *stream);
: Outputs a character to a stream. putc is a macro that outputs the character c to the stream given by
: On success, putc returns the character printed, c. On error, putc returns EOF.
putch()
Hederfile
: conio.h
Prototype
: int putch(int c);
Description
: Outputs character to screen. putch outputs the character c to the current text window. It is a text
mode function performing direct video output to the console. putch does not translate linefeed characters (\n) into
carriage-return/linefeed pairs. The string is written either directly to screen memory or by way of a BIOS call,
depending on the value of the global variable _directvideo.
Note: This function should not be used in Win32s or Win32 GUI applications.
Return Value : On success, putch returns the character printed, c. On error, it returns EOF.
Example:
#include <stdio.h>
#include <conio.h>
int main(void)
{
char ch = 0;
printf("Input a string:");
while ((ch != '\r'))
{
ch = getch();
putch(ch);
}
return 0;
}
putchar()
Header file
: stdio.h
Prototype
: int putchar(int c);
Description
: putchar(c) is a macro defined to be putc(c, stdout).
Note: For Win32s or Win32 GUI applications, stdout must be redirected.
Return Value : On success, putchar returns the character c. On error, putchar returns EOF.
Example:
#include <stdio.h>
/* define some box-drawing characters */
#define LEFT_TOP 0xDA
#define RIGHT_TOP 0xBF
#define HORIZ
0xC4
#define VERT
0xB3
#define LEFT_BOT 0xC0
#define RIGHT_BOT 0xD9
int main(void)
{
char i, j;
/* draw the top of the box */
16
puts()
Header file
: stdio.h
Prototype
: int puts(const char *s);
Description
: Outputs a string to stdout. puts copies the null-terminated string s to the standard output stream
stdout and appends a newline character.
Note: For Win32s or Win32 GUI applications, stdout must be redirected.
Return Value : On successful completion, puts returns a nonnegative value. Otherwise, it returns a value of EOF.
Example:
#include <stdio.h>
int main(void)
{
char string[] = "This is an example output string\n";
puts(string);
return 0;
}
17
scanf()
Header file
: stdio.h
Prototype
: int scanf(const char *format[, address, ...]);
Description
: Scans and formats input from the stdin stream.
Note
: For Win32s or Win32 GUI applications, stdin must be redirected.
The scanf function:
scans a series of input fields one character at a time
formats each field according to a corresponding format specifier passed in the format string *format.
vsscanf scans and formats input from a string, using an argument list.
There must be one format specifier and address for each input field. scanf might stop scanning a particular field before
it reaches the normal end-of-field (whitespace) character, or it might terminate entirely.
Warning
: scanf often leads to unexpected results if you diverge from an expected pattern. You must provide
information that tells scanf how to synchronize at the end of a line. The combination of gets or fgets followed by sscanf
is safe and easy, and therefore recommended over scanf.
Return Value : On success, scanf returns the number of input fields successfully scanned, converted, and stored.
The return value does not include scanned fields that were not stored. On error: if no fields were stored, scanf returns
0. if scanf attempts to read at end-of-file or at end-of-string, it returns EOF.
cscanf()
Header file
: conio.h
Prototype
: int cscanf(char *format[, address, ...]);
Description
: Scans and formats input from the console. cscanf scans a series of input fields one character at a
time, reading directly from the console. Then each field is formatted according to a format specifier passed to cscanf in
the format string pointed to by format. Finally, cscanf stores the formatted input at an address passed to it as an
argument following format, and echoes the input directly to the screen. There must be the same number of format
specifiers and addresses as there are input fields.
Note
: cscanf might stop scanning a particular field before it reaches the normal end-of-field (whitespace)
character, or it might terminate entirely for a number of reasons. See scanf for a discussion of possible causes.
Note
: Do not use this function for Win32s or Win32 GUI applications.
Return Value : cscanf returns the number of input fields successfully scanned, converted, and stored; the return
value does not include scanned fields that were not stored. If no fields were stored, the return value is 0. If cscanf
attempts to read at end-of-file, the return value is EOF.
Example:
#include <conio.h>
int main(void)
{
char string[80];
/* clear the screen */
clrscr();
/* Prompt the user for input */
cprintf("Enter a string with no spaces:");
/* read the input */
cscanf("%s", string);
/* display what was read */
18
sscanf()
Header file
: stdio.h
Prototype
: int sscanf(const char *buffer, const char *format[, address, ...]);
Description
: Scans and formats input from a string.
Note
: sscanf scans a series of input fields, one character at a time, reading from a string. Then each field
is formatted according to a format specifier passed to sscanf in the format string pointed to by format. Finally, sscanf
stores the formatted input at an address passed to it as an argument following format. There must be the same
number of format specifiers and addresses as there are input fields. sscanf might stop scanning a particular field
before it reaches the normal end-of-field (whitespace) character, or it might terminate entirely, for a number of
reasons.
Return Value : On success, sscanf returns the number of input fields successfully scanned, converted, and stored;
the return value does not include scanned fields that were not stored. If sscanf attempts to read at end-of-string, it
returns EOF. On error (If no fields were stored), it returns 0.
Example:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
char *names[4] = {"Peter", "Mike", "Shea", "Jerry"};
#define NUMITEMS 4
int main(void)
{
int
loop;
char temp[4][80];
char name[20];
int
age;
long salary;
clrscr();
// clear the screen
/* create name, age and salary data */
for (loop=0; loop < NUMITEMS; ++loop)
sprintf(temp[loop], "%s %d %ld", names[loop], random(10) + 20, random(5000) +
27500L);
/* print title bar */
printf("%4s | %-20s | %5s | %15s\n", "#", "Name", "Age", "Salary");
printf("
--------------------------------------------------\n");
/* input a name, age and salary data */
for (loop=0; loop < NUMITEMS; ++loop)
{
sscanf(temp[loop],"%s %d %ld", &name, &age, &salary);
printf("%4d | %-20s | %5d | %15ld\n", loop + 1, name, age, salary);
}
return 0;
}
19
printf ( %c , ch ) ;
// ch is a variable of character .
printf ( %f , f ) ; // f is a variable of float
printf ( %d %f %c , i , f , c ) ;
NOTE:
1. The order of the format specifiers matches with that of the variables (arguments ).This is a
must when we are displaying values of more then one variable.
2. Many times, the printf ( ) is used to display just some messages.
Format specifiers for other data types available in C are:
Format Specifiers
Meaning
%c
Character
%d
Decimal integer
%ld
Long integer
%f
Floating point value in decimal point notation
%e
Floating point value in exponential form
%h
Short integer
%lf
Long float
%s
String
%u
Unsigned integer
%p
Pointer
%o
Octal number without the prefix 0
%x
Hexadecimal number without the prefix 0x
Escape Sequence Characters
Escape
Meaning
sequence
\n
New line
\t
Horizontal tab
\v
Vertical tab
\f
\b
Form feed
Back space
\a
\\
\?
\
\
Escape
sequence
Meaning
Alert character
Backslash
Question mark
Single quote
Double quote
printf()
Header file
: stdio.h
Prototype
: int printf(const char *format[, argument, ...]);
Description
: Writes formatted output to stdout.
printf function:
Accepts a series of arguments.
Appllies to each argument a format specifier contained in the format string *format.
Outputs the formatted data (to the screen, a stream, stdout, or a string).
There must be enough arguments for the format. If there are not, the results will be unpredictable and likely
disastrous. Excess arguments (more than required by the format) are merely ignored.
Note
: For Win32s or Win32 GUI applications, stdout must be redirected.
Return Value : On success, printf returns the number of bytes output. On error, printf returns EOF.
cprintf()
Header file
: conio.h
Prototype
: int cprintf(const char *format[, argument, ...]);
Description
: Writes formatted output to the screen. cprintf accepts a series of arguments, applies to each a
format specifier contained in the format string pointed to by format, and outputs the formatted data directly to the
current text window on the screen. There must be the same number of format specifiers as arguments. The string is
written either directly to screen memory or by way of a BIOS call, depending on the value of the global variable
20
sprintf()
Header file
: stdio.h
Prototype
: int sprintf(char *buffer, const char *format[, argument, ...]);
Description
: Writes formatted output to a string.
Note
: sprintf accepts a series of arguments, applies to each a format specifier contained in the format
string pointed to by format, and outputs the formatted data to a string. sprintf applies the first format specifier to the
first argument, the second to the second, and so on. There must be the same number of format specifiers as
arguments.
Return Value : On success, sprintf returns the number of bytes output. The return value does not include the
terminating null byte in the count. On error, sprintf returns EOF.
Example:
#include <stdio.h>
#include <math.h>
int main(void)
{
char buffer[80];
sprintf(buffer, "An approximation of Pi is %f\n", M_PI);
puts(buffer);
return 0;
}
Formatting of Outputs
Formatting of outputs refers to displaying the outputs in more readable and comprehensible manner. The
main objective of formatting is to increase the degree of readability of outputs.
Formatting of Integers
Formatting of float point values
Formatting of Integers
Suppose i is a variable of type int and its value is 3456. The value of i can be formatted by modifying the
above control string. The modified control string would be %wd, where w is an interger specifying the
width which the value of i has to be displayed.
Different cases of representation of formatted output:
1. printf ( %6d , i ) ;
3
4
5
6
Since, the width specified is six, six columns are allocated and the value of i is right justified in the specified
width.
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
21
2. printf ( %3d , i ) ;
3
4
since , the width specified is less than the actual number of digit of the value in i ,the width is ignored and
full value is displayed.
Suppose f is a variable of type float and its value is 3456.56. To display the value of f, we use the following
printf( ) statements:
printf(%f, f );
As a result, the value of f will be displayed on the screen starting from the first column of the screen as
follows:
3456.560000
The value of f can be formatted by modifying the above control string. The modified control string would
be %w.pf, where w is an integer specifying the width within which the value of f has to be displayed and p
denotes the number of digits to be displayed after the decimal point.
1. printf( %7.2f, f );
3
Since the width specified is seven, seven columns are allocated and the value of f is displayed as shown
earlier. Note that the decimal point also occupies one location and only two digits are displayed after
the decimal point.
2. printf( %3.2f, f );
3
Since the width specified is less than the actual number of digits of the value in f width is ignored
and the full value is displayed.
3. printf( %9.2f, f );
3
4
5
6
.
5
6
Since the width specified is nine which is greater than the number of digits in the given number, nine
columns are allocated and the value of f is right justified in the specified width.
4. printf( % - 9.2f, f );
3
4
5
6
.
5
6
Since the width specified is nine which is greater than the number of digits in the given number, nine
columns are allocated and the value of f is left justified in the specified width because of the presence
of symbol before the width specifier.
5. printf( % 09.2f, f );
0
0
3
4
5
6
.
5
6
Since the symbol 0 is used before the width specifier, the leading blanks are filled with zeros. The
number is said to have been padded with zeros.
6. printf( % 7.1f, f );
3
4
5
6
.
6
Since the number of digits to be displayed, which is one, is less than the actual number of digits (two)
after the point in the given number, the value is rounded off to the first digit.
7. printf( % e, f );
3
.
4
5
6
5
6
0
e
+
0
3
Display the floating point number in exponentiation form with six digits after the point in the mantissa.
8. printf( %10.2 e, f );
3
.
4
6
e
+
0
3
Display the floating point number in exponentiation form with three after the point in the mantissa
within the specified width. The display is right justified.
9. printf( % - 10.2 e, f );
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
22
3
.
4
6
e
+
0
3
Display the floating point number in exponentiation form with three after the point in the mantissa
within the specified width. The display is left justified because of the presence of minus symbol before
the width.
Formatting Of Characters:
Suppose c is a variable of type char. To display the character stored in the variable C, we use the following printf ( )
statement:
printf ( %c , c ) ;
As a result of the execution of the statement, the character stored in will be displayed on the screen in the current
position of the cursor. Similar to formatting of integer s, characters also can be formatted. The modified control
string to display a character is
%wc, where w is the width specifier.
The character will be displayed right-justified in the field of w columns. We can make the display left-justified by
placing a minus sign before the integer w. The default value for w is 1.
Example:
1. printf ( %4c , c ) ;
Since, the width specified is four, four columns are allocated and the character stored in c is displayed right justified
in the width as follows:
a
2. printf ( % -4c , c ) ;
Since the width is four, four columns are allocated and the character stored in c is displayed left justified in the
specified width because of the presence of symbol before the width specifier as follows:
a
Formatting of Strings:
The format specification for outputting strings is similar to that of real numbers. It is of the form
%w.ps
Where w specifies the field width for display and p instruct that only the first p characters of the string are to be
displayed. The displayed is right-justified.
The following example shows the effect of variety of specifications in printing a string NEW DELHI 110001,
containing 16 characters (including blanks).
Specification
%s
Output
1
%20s
10
%20.10s
%.5s
%-20.10s
%5s
11
12
13
14
15
16
17
18
19
20
1. scanf returns the number of input fields successfully scanned, converted, and stored. The return value does not
include scanned fields that were not stored. On error: if no fields were stored, scanf returns 0. if scanf attempts
to read at end-of-file or at end-of-string, it returns EOF.
On success, printf returns the number of bytes output. On error, printf returns EOF.
2.
3. The conversion specifier p displays an address in an implementation-defined manner (on many systems,
hexadecimal notation is used rather than decimal notation).
4. To print a literal percent character (%), use %% in the format control string in the printf.
5. If the field width is larger than the object being printed, the object is right justified in the field by default.
6. The - flag left justifies its argument in a field.
23
Output:
Enter a date in the form mm-dd-yyyy: 10-18-2011
month=10
day=18
year=2011
Enter a date in the form mm/dd/yyyy: 10/18/2011
month=10
day=18
year=2011
12. A sequence of characters can be input using a scan set. A scan set is a set of characters enclosed
in square brackets, [ ], and preceded by a percent sign in the format control string.
13. A scan set in a scanf scans the characters in the input, looking only for those characters that
match characters contained in the scan set. When a character is matched, it is stored in a
character array. The scan set stops inputting characters when a character not contained in the
scan set is encountered.
14. To create an inverted scan set, place a caret (^) in the square brackets before the scan characters.
This causes characters input with scanf and not appearing in the scan set to be stored until a
character contained in the inverted scan set is encountered.
15. Address values are input with scanf with the conversion specifier p.
16. Conversion specifier n stores the number of characters input previously in the current scanf. The
corresponding argument is a pointer to int.
17. The conversion specifier %% with scanf matches a single % character in the input.
18. A field width is used in scanf to read a specific number of characters from the input stream.
19. Precision used with integer conversion specifiers indicates the minimum number of digits printed. If the value
contains fewer digits than the precision specified, zeros are prefixed to the printed value until the number of
digits is equivalent to the precision.
20. Precision used with floating-point conversion specifiers e, E and f indicates the number of digits that appear
after the decimal point. Precision used with floating-point conversion specifiers g and G indicates the number
of significant digits to appear.
21. Precision used with conversion specifier s indicates the number of characters to be printed.
22. The field width and the precision can be combined by placing the field width, followed by a decimal point,
followed by the precision between the percent sign and the conversion specifier.
23. Its possible to specify the field width and the precision through integer expression in the argument list
following the format control string. To use this feature, insert and asterisk (*) in place of the field width of
precision. The matching argument in the argument list is evaluated and used in place of asterisk. The value of
argument can be negative for the field width but must be positive for the precision.
24
if else statement:
The ifelse statement provides a way to execute one block of code if a condition is true and another block
of code if its false.
Syntax:
if (<expressions>)
{
Statements 1;
}
else
{
Statements 2;
}
E.g.:
if(salary < 5000)
{
bonus=0;
}
else
{
bonus= (10*salary/100);
}
25
The scope delimiter ({ }) of an if statement can be removed if the number of statements in the if part is
one. If more than one statements written in the if part without scope delimiter, the very first statement
will be part of the if statement, but others will not belong to the if statement and are called as hanging
statement which is not allowed in c and causes
Error: misplaced else.
E.g.:
1. if(a>b)
a=0;
else
a=100;
program is valid.
2. if(a>b)
a=0;
b=1;
else
a=100;
Error: misplaced else.
Nested if statement:
When one conditional statement will be executed under another conditional statement, in other words
one if construct within another if construct, then we need a nested if statement.
Syntax:
if (<expressions>)
{
if (<expressions>)
{
if (<expressions>)
{
Statements;
}
}
}
E.g.:
if(a==1)
{
if(b==2)
{
printf(hello);
}
}
When therell be more than two statements and only one has to be executed in accordance with a
condition, else-if ladder is used.
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
26
Syntax:
if (<expression 1>)
{
Statement 1;
}
else if (expression 2)
{
Statement 2;
}
else if (expression 2)
{
Statement 2;
}
:
:
else if (expression n)
{
Statement n;
}
else
{
Statements;
}
E.g.:
If (a==1)
printf(hello);
else if (a==2)
printf(hi);
else if (a==3)
printf(how r u);
else
printf(welcome);
27
If (c==3)
printf (great);
this can also be written as
if (a==1 && b==2 && c==3)
printf (great);
4. Hanging if is not allowed in C.
- This is the option to be selected or matched with the switch expression value.
default- The default case is executed when none of the cases match with the value in switch.
break - Its optional in switch case statement, but prevents unnecessary flowing of control to the
statements subsequent to the case where a match has been found.
Syntax:
switch ( expression )
{
case <constant expression>:
program statement;
program statement;
......
Break;
case <constant expression>:
program statement;
program statement;
......
Break;
......
Default:
program statement;
program statement;
}
28
printf(default);
case 25:
printf(case 25);
case 10:
printf(case 10);
}
5. The continue keyword cant be used in place of break in switch statement. Itll generate an error.
6. Case labels can never be identical. A duplicate case is not allowed.
7. default case is optional. If eliminated, therell be no error.
8. The case expression can be integral constant or character constant etc. but can never be a variable.
9. If 0 is given as an argument, switch evaluates it as an expression instead of false.
10. switch statement does not need braces if it has only one case to execute.
11. There must be a space between the case keyword and the option value. If the space is omitted, itll
not show any error but will be considered as a goto label.
12. Switch statements can be nested.
13. No braces are required for the case block. But if given, itll not show any error.
14. If theres no case then therell be no error at all. E.g.
switch (4)
{
}
Looping Construct:
Iteration (repeating a process) is achieved by loop control instructions in C. Looping means repeating an
instruction set till a condition satisfies. There are 3 types of loop in C: for, while, do while.
Every loop contains 3S:
for loop:
Its used to loop a portion of program for finite number of times. All parts of it are optional and hence
cause an infinite loop.
Syntax:
for (Expression opt ; Expression opt; Expression opt)
{
<statement>;
}
29
while loop:
Its used to loop a portion of program for unknown number of times as long as the user wants.
Syntax:
while (Expression)
{
<statement>;
}
30
printf (hello:);
i++;
do - while loop:
Its used to loop a portion of program at least once as the condition checking is being done at the end of
the loop.
Syntax:
do
{
<statement>;
} while (Expression);
31
Jumping Statements:
To transfer the control from one portion of a program to another portion, jumping statements are allowed.
Three types of jumping keywords are used: break, continue and goto.
break:
Its used in loops and switch case to transfer the control to outside the block. In loops its usually
associated with if statement. E.g.
int i = 100;
while ( 1 )
{
printf (hello);
if (i>=5)
break;
i++;
}
continue:
Its used in loops to transfer the control to the beginning of the loop by skipping the subsequent sequences
in the loop allowing the control to jump to the next iteration skipping the present. E.g.
int i;
for (i=1; i<=10; i++)
{
if (i>=5)
{
printf (hi);
continue;
}
printf (hello);
i++;
}
goto:
Its an unconditional branching statement. It causes the control to be transferred from one part to another
part of the function.
Syntax:
goto label;
//where label is a valid c identifier and marks a place where
//the control has to be transferred in a function.
The statement to which the control has to be transferred is preceded by a label and a colon.
E.g.
Forward jumping:
goto abc;
s1;
s2;
abc: s3;
s4;
Forward jumping:
abc: s1;
s2;
goto abc;
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
32
Its mostly avoided in C programming as it makes the program difficult to understand. Its
generally used in nested loops to transfer the control to the end of all loops from the innermost loop.
int i=0;
while(i<=10);
printf (%d,i++);
int i=0;
do printf (%d,i++);
while (i<=10);
output: 10
output: 10
5. Curly braces are necessary only when we work with multiple statements inside the loop. They can be
dropped if theres a single statement.
6. The for and while are pre-tested while the dowhile is a post-tested.
7. If step value is dropped, the loop is infinite.
8. If loop counter is beyond its range, that loop will become an infinite loop. E.g.
char ch;
for (ch=5; ch<=256; ch++)
printf (%d,ch);
//infinite as range of char is -128 to 127.
9. Continue can only be used in a looping construct.
10. In for, while, etc, the order is from left to right.
int x=5, y=7;
while ( x, y)
{
printf (%d%d ,x,y);
x--; y--;
}
output: 57 46 35 24 13 02 -11
Explanation: since left to right order, the while didnt terminated when x=0; but when y becomes 0, it
evaluates as FALSE and hence terminated.
11. Loop is also used for software delay. E.g.
int i;
printf (hello);
for ( i=1; i<=10000; i++)
printf (hi);
12. Loop counter can be int, char, and float.
13. If loop counter is not initialized in a loop, that is called odd loop.
14. Loop is an alternate of function recursion and function recursion is an alternate of loop.
15. for loop is suitable for finite loop, while loop is suitable for unknown loop and do while loop is
suitable for looping at least once.
16. Loop counter has its own block scoping.
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
33
34
MODULE II
CHAPTER 5 (FUNCTIONS)
Functions are the small and self-contained components of a program, which have some unique identifiable purpose.
Every C function composed of same things: name, return type, arguments and a body. These are used to break down
large programs into smaller modules. These modularize the program and this is called as the modular property of
function which makes debugging easier i.e. improves the programs readability, enhances the programming
structure and helps the programmer to detect the errors faster and more easily.
Use of Functions:
Code Reusability: saves repetition of common routines. Functions once written can be reused in different
programs without having to rewrite them again.
Program portability: This is a benefit arising from re-usability of code. Because programs will become smaller
in size and subsequent packaging or programs will become easier and faster.
Maintaining large programs become easier because of the following reasons:
Different modules work independently of each other.
We just need to understand and monitor what the large pieces or modules or functions as a whole
will do, individual statements or the program are not important.
Unnecessary details are hidden.
Changing one modules or functions code should have limited effects on other parts.
Modularizing the program: easier to debug the program.
Allows function recursion or recursive execution of a module or functionality.
TYPES OF FUNCTIONS:
1. Standard Library Functions : These are technically not a part of the C language. But theres a wide prepackaged
functions available in the standard library to reduce program development time and make programs more
portable. To use a standard library function we have to include its header file, which contains the header
information such as prototype, macros, typedef names, global variables. E.g. scanf ( ), printf ( ), strlen ( ), etc.
2. User Defined Functions
: These are defined by the programmer to perform specific tasks. E.g.
main ( )
{
int a, b;
printf (sum = %d,add(a,b));
/*function call*/
}
int add (int x, int y)
/*function definition*/
{
return x+y;
}
Here add ( ) is a user defined function, which is used to add two numbers.
PARTS OF FUNCTIONS:
Return
Type
Function
Name
Function
Argument
35
36
37
38
39
RECURSION
Nesting of the function calls can be to any level depending on the requirement. The phenomena of a function calling
itself directly or indirectly is called recursion (direct recursion or indirect recursion). The function involved in the
process is referred to as a recursive function.
Example: WAP to find factorial of a number using recursive function.
#include<stdio.h>
int fact ( int );
void main( )
{
int number,f;
printf ( enter a number \n) ;
scanf ( %d,&number) ;
f = fact ( number ) ;
printf ( fact = %d \n,f) ;
}
int fact ( int number)
{
int f;
if ( number == 0)
return 1;
else
f = number * fact (number -1);
// fact ( ) call itself
return f;
}
OUTPUT:
Enter a number
4
factorial of 4 = 24.
Properties of function recursion:
i. Alternative to looping constructs.
ii. Nature of function recursion is always an infinite loop or stack overflow.
iii. Expensive in both processor time and memory space as compare to loop.
iv. Helps in writing cryptic codes.
v. Used for some specific purpose, like in-order, pre-order and post-order traversal of a tree, tower of Hanoi,
Quick sort, etc.
40
Depending on where a variable is allocated required storage (CPU register or RAM), the area of existence in a
program (scope) and its longevity (lifetime), variables are classified into what are called storage classes. They help to
determine four properties, namely lifetime, storage, visibility (scope) and default initial value. Following are four
storage classes:
1. automatic
2.static
3.register
4.extern
Automatic Storage Class:
The variable declares with in a function are by default of an automatic storage class. The keyword auto can also be
used to explicitly specify it.
void fun()
{
int i;
// storage class of variable i would be auto
auto int j;
// storage class of variable j explicitly auto
}
Automatic variables are characterized by the following properties:
i) Automatic variables are stored in memory.
ii) The default initial value of automatic variable is garbage.
iii) They are visible within the block in which they are defined.
iv) Their lifetime is the duration of the function or block only.
v) Every local variable is by default auto variables.
vi) They can not be declared outside of functions.
Static storage class:
Variable can be made to belong to static storage class by explicitly using the keyword static while declaring them.
The variable of static storage class may be declared either within or outside the functions.
void fun()
{
static int a ;
}
Static variables are characterized by the following properties:
i. static variables are stored in memory.
ii. The default initial value of static object is 0(zero).
iii. They are local to the block in which they are defined.
iv. Their lifetime is the duration of the entire programs duration.
v. Static variables are initialized at compile time and therefore they are initialized only once. They can not be
reinitialized on the re-entry into the function. The previous values persist.
vi. Static variables can be used to retain values between function calls. Count the number of calls made to a
function can be done by the static variable.
Example:
OUTPUT:
x=1
x=2
x=3
vii. static variables can be initialized with constant expression, address of other static or extern variables.
viii. It is used to overcome dangling pointer problems.
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
41
42
43
CHAPTER 7 (ARRAYS)
To process large amounts of data (a group of data items), we need a powerful data type that would
facilitate efficient storing, accessing and manipulation of data items. To overcome the problem stated
above, C supports a derived data type known as array that can be used for such applications.
Definition:
An array is defined to be a group of logically related data items of similar type, stored in contiguous
memory locations, sharing a common name but distinguished by subscript(s) values. So, an array is a finite
ordered set of homogeneous elements.
Example:
List of employees in an organization.
List of products and their cost sold by a store.
Test scores of a class of students.
List of customers and their telephone numbers.
CLASSIFICATION OF ARRAY:
Depending on the number of subscripts used, arrays are classified into the following types:
One-dimensional arrays
Two-dimensional arrays
Multidimensional arrays
ONE-DIMENSIONAL ARRAYS
An array with only one subscript is termed as one-dimensional array or single-subscripted variable. It is
used to store a linear list of values.
DECLARATION OF ONE-DIMENSIONAL ARRAYS:
108
A[0]
A[1]
A[2]
A[3]
A[4]
Here LB = 0, UB = 4 and the size of each element ESIZE = 2 bytes
Then address of the element present at subscript 3 can be calculated as
LOC (A[I]) = Base (A) + ESIZE * (I-LB)
LOC (A[3]) = 100 + 2 * (3 0) = 106
INITIALIZATION OF ONE-DIMENSIONAL ARRAYS:
44
We can initialize the elements of arrays at the time of declaration. The general form of initialization of
arrays is
data-type array-name[size] = {value0, value1,value2, };
{value0, value1, , valuesize-1} are constant values.
Example: int A[5] ={10,20,30,40,50};
100
102
104
106
108
10
20
30
40
50
A[0]
A[1]
A[2]
A[3]
A[4]]
Points to remember:
1. Number of values should not exceed the size of the array.
2. If the number of values is less than the size of an array, then the remaining elements are initialized
to zero, if the array type is numeric and NULL if the type is char.
Example:
int A[5] = {10, 20, 30};
100
102
104
106
108
10
A[0]
20
A[1]
30
A[2]
A[3]
A[4]
3. If size is omitted in a 1-d array declaration, which is initialized, the compiler will supply the size by examining
the number of values in the initialize-list.
Example:
int A[ ] = {10, 20, 30, 40, 50}; Here the size of a is automatically supplied as five.
4. There is no array bound checking mechanism built into C-compiler. It is the responsibility of the programmer
to see to it that the subscript value does not go beyond size-1. If it does, the system may crash.
Example:
int A[5];
A[6] = 10;
it may lead to unpredictable results or even to system crash.
Run Time Initialization:
An array can be explicitly initialized at run time. This approach is usually applied for initializing large arrays.
For example, consider the following segment of a C program.
int num[50] , i ;
for(i = 0; i<50; i++)
{
num[i] = 1 ; // assignment statement
}
All the 50 elements are initialized to 1.
We can also use a read function such as scanf ( ) to initialize array elements with the values entered through the
keyboard.
Example:
int num[10], I ;
for(i=0 ; i<10; i++)
{
scanf(%d, &num[i]) ; }
Renaming an Array
An array can also be renamed by using of typedef.
Example:
typedef int Array[10];
Here Array becomes a data type for an array of 10 integers. i.e. if we wire:
Array my_arr;
It declares my_arr as an array of 10 integers and if we write:
Array arr2d[5];
It declares arr2d as an array of 5 arrays of 10 integers each.
Also note that:
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
45
TWO-DIMENSIONAL ARRAYS
An array with two subscripts is termed as two-dimensional array. It enables us to store multiple rows of elements,
that is, a table of values or a Matrix. For this reason, the two dimensional arrays are the perfect data structures for
storing matrices. Hence two-dimensional arrays are sometimes called matrix arrays.
Declaration of two-dimensional arrays:
The syntax of declaring a two-dimensional array is as follows:
Data-type array-name[rowsize][colsize];
Example:
int mat[3][4];
float marks[10][6];
char names[10][30];
The element of A with first subscript (row subscript) I and second subscript (column subscript) J will be
denoted by A[I][J]. The length of a dimension is the number of integers in its index set. The pair of lengths
m x n (read m by n) is called the size of the array.
The length of a given dimension can be obtained from the formula
Length = upper bound lower bound + 1
A two-dimensional 3 X 4 array A is shown bellow:
COLUMNS
0
1
2
3
A[0][0]
A[0][1]
A[0][2]
A[0][3]
0th ROW
A[1][0]
A[1][1]
A[1][2]
A[1][3]
A[2][0]
A[2][1]
A[2][2]
A[2][3]
1st Row
2nd ROW
ROW 1
ROW 2
ROW-MAJOR ORDER
Column 0
Column 1
Column 2
COLUMN -MAJOR ORDER
Computes the address LOC (A[I][J]) of A[I][J] using the formula
Row major order:
LOC(A[I][J]) = Base(A) + ESIZE [ n ( I RLB ) + ( J CLB) ]
Or the formula for Column major order:
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
ROW 3
Column 3
46
We can initialize the elements of a 2-d array at the time of declaration. There are two forms of initializing a
2-d array.
First form of initializing 2-d arrays is as follows:
data-type array-name [rowsize] [colsize] = { initializer-list };
Example:
int A[3][4] = { 2,5,11,6, 8,20,15,10,4,7, 13,18};
The second form of initializing a 2-d array has the following general syntax:
data-type array-name [rowsize] [colsize] = { {initializer-list1},{initializer-list2}, };
Example: int A[3][4] = { {2,5,11,6},{ 8,20,15,10},{4,7, 13,18}};
Point to Note:
If the number of values in the initializer-list is less than product of row size and column size, only the first
few matching locations of the array would get values from the initializer-list row wise. The trailing
unmatched locations would get zeros.
If the number of values specified in any initializer-list is less than colsize, only those many first locations in
the corresponding row would get these values. The remaining locations in that row would get zeros.
Example: int A[2][3] = { { 3, 4 } , { 4 , 5 , 6 } };
Run Time Initialization:
A 2-d array can be explicitly initialized at run time. For example, consider the following segment of a C
program.
int mat[3][4] , i , j ;
for(i = 0; i<3; i++)
{
for(j = 0; j<4; j++)
{ mat[i][j] = 1; // assignment statement
}
}
All the elements are initialized to 1. We can also use a read function such as scanf to initialize array
elements with the values entered through the keyboard.
Example:
int mat[3][4], i, j;
for(i=0 ; i<3; i++)
{
for(j=0; j<4; j++)
{ scanf(%d, &mat[i][j]); }
}
Multidimensional Arrays
C allows arrays of more than two dimensions (multidimensional arrays). The exact limit is determined by
the compiler. ANSI C does not specify any limit for array dimension. However, most compilers permit seven
to ten dimensions. Some allow even more.
Multidimensional Array Declaration:
The general form of a multidimensional array declaration is
data-type array-name[size1][size2][size3] . . . [sizeN];
Example:
int survey[3][5][12]; // three-dimensional array of 180 integers
float table[5][4][5][3]; // four-dimensional array of 300 floats
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
47
48
2. In the function definition, we must indicate that the array has two dimensions by including two sets
of brackets.
3. The size of the second dimension must be specified. It is to help the function select appropriate
elements when it moves to different rows. However, specification of size within the first pair of
square brackets is optional.
4. The prototype declaration should be similar to the function header.
STRINGS
A string in C is defined to be a sequence of characters terminated by the null character ( \0 ). The null
character indicates the end of a string.
Declaration of a String Variable:
C does not support strings as a data type. However, it allows us to represent strings as character arrays. In
C, therefore, a string variable is any valid C variable name and is always declared as an array of characters.
The general form of declaration of a string variable is:
char string-name[size];
Example:
char name[30];
char city[20]; char address[50];
Note: When the compiler assigns a character string to a character array, it automatically supplies a null
character (\0) at the end of the string. Therefore, the size should be equal to the maximum number of
characters in the string plus one.
Initializing String Variables (character arrays):
Character arrays may be initialized when they are declared. C permits a character array to be initialized in
either of the following two forms:
First form of initialization:
char string-name[size] = string;
Example:
char name[5] = John;
char city[10] = Berhampur;
Second form of initialization:
char string-name[size] = { chr1, chr2,,\0};
Example:
char name[5] = {J, o, h, n, \0};
char city[10] = {B, e, r, h, a, m, p, u, r};
Note that when we initialize a character array by listing its elements, we must supply explicitly the null
terminator.
STRING I/O:
Using scanf() and printf():
Syntax of using scanf() to accept a string into a string variable is as follows:
scanf(%s, string-name);
%s is the format specification for strings.
Note that string-name is not preceded by symbol & (address of operator). This is because, the
string variable name itself gives the address of the string.
The above statement accepts a string up to a white space character(Blanks, tabs, carriage returns,
form feeds, and new lines). The null character \0 will be automatically appended to the string. The
size of string-name is thus expected to be large enough to collect even the null character.
Example:
char str[10];
scanf(%s, str);
If the input is:
abcd xyz
Only abcd would be taken by str. Any subsequent scanf() to accept a string would read the string xyz.
Example:
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
49
50
gets () is used to read a string up to a newline character into a string variable. It automatically appends the
null character \0 to the end of the string. The syntax of its usage is
gets(string-name);
Example:
char text[80];
gets (text);
The purpose of puts() is to display a string contained in a string
variable. It also adds the new-line
character \n to the string automatically, as a result of which the cursor is moved down by one line after
the string is displayed. The syntax of its usage is
puts (string-name);
Example:
char text[80]= Ram is a good boy.;
puts (text);
Arithmetic and Relational Operations on Characters
Whenever a character constant or character variable is used in an expression, it is automatically converted
into an integer value by the system. The integer value depends on the local character set of the system. If
the machine uses the ASCII representation, then,
int x = a;
printf(%d, x);
will display the number 97 on the screen.
The expression ch>= A && ch<=Z would test whether the character contained in ch is an upper-case
letter.
We can convert a character digit to its equivalent integer value using the relationship x=ch 0
Where x is an integer variable and ch is a character variable and contains the character digit.
String Manipulation using Standard Library Functions:
Header file : <string.h>
Function
Prototype
Purpose/ Task
strlen(s)
strcmp(s1,s2)
strcpy(s1,s2)
strncpy(s1,s2,n)
strstr(str,substr)
strcat(s1,s2)
51
strrev(s)
52
//function body
}
Example:
void display(char names[][30], int n)
{
int i;
for (i=0;i<n;i++)
printf(%s\n ,names[i]);
}
While calling the function, the calling program needs to pass just the array-name (with no square brackets),
number of rows(strings) as:
function-name(array-name, no_of_strings);
Example:
char names[3][30]={John, Jimy, jack};
display (names,3);
Limitations of Array:
It is static in nature.
Array size cant expand or cant be squeezed at run time
Holds only similar type of data.
Unused memory cant be used at the time of requirement
TIPS AND TRICKS:
1. Size of an array must always be mentioned as a positive, non-zero integer constant.
2. A single dimensional arrays elements can be represented in four different ways.
Example:
int a[5] = { 1,2,3,4,5};
printf(%d %d %d %d, 0[a], a[0], *(0+a), *(a+0));
3. Array size cant be variable at the time of declaration.
4. Array name is a constant pointer and gives the address of the 0th element of the array.
5. Limitation of an array is:
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
53
}
show (int p[4],int x)
{
printf(%d,sizeof(p));
}
Output: 2 or 4
Here p[4] is used as the receiver in the function show() which acts as an array equivalent pointer.
22. The maximum number of bytes that can be allocated through an array must be less than 65536
because of the segmented architecture used with C for DOS.
54
CHAPTER 8 (POINTERS)
A pointer is a derived data type, built from one of the fundamental data types available in C.
Pointers contain memory addresses as their values. Since these memory addresses are the
locations in the memory where program instructions and data are stored, pointers can be used to
access and manipulate data stored in the memory.
Advantages of Using Pointers:
1. Pointers are more efficient in handling arrays and data tables
2. Pointers can be used to return multiple values from a function via function arguments.
3. Pointers permit references to functions and thereby facilitating passing of functions as arguments
to other functions.
4. The use of pointer arrays to character strings results in saving of data storage space in memory.
5. Pointers allow C to support dynamic memory management.
Pointers used to manipulate dynamic data structures such as structures, linked lists, queues, stacks and
trees.
7. Pointers reduce length and complexity of programs.
8. They increase the execution speed and thus reduce the program execution time.
Memory Organization
Memory is organized as a sequential collection of storage cells.
Each cell commonly known as a byte.
Each byte is identifiable by a unique number called address associated with it.
Typically, the addresses are numbered consecutively, starting from zero. The last address depends on the
memory size. A computer system having 1KB memory will have its last address as 1023.
Memory cell
Address
.
.
.
1022
1023
55
2. Establishes a mapping between the address of the location and the name of the variable. Note that
the address is of the first byte of the location of the variable.
The actual location of a variable in the memory is system dependent. We can determine the address of a
variable with the help of the operator &. The operator & immediately preceding a variable returns the
address of the variable associated with it.
Example:
the statement p=&x;
would assign the address of the variable x (i.e. 5000) to the variable p.
The & operator can be used only with a simple variable or an array element. The following are illegal use of
address of operator:
1. &125 (pointing at constants).
2. &(x+y) (pointing at expressions).
3. The & operator must never appear on the left hand side of an assignment statement.
Pointer Variables:
The address of a variable can be retrieved and stored in another variable. A variable which can store the
address of another variable is called as a pointer variable (i.e. pointer).
Declaring Pointer Variables:
The syntax to declare a pointer variable is
data-type *pt-name;
This tells the compiler three things about the variable pt-name.
1. The asterisk (*) tells that the variable pt-name is pointer variable.
2. pt-name needs a memory location.
3. pt-name points to a variable of type data-type.
Example:
int *pi;
float *pf;
All un-initialized pointers will have some unknown values that will be interpreted as memory addresses.
Thus they are called wild pointers.
Initializing a Pointer Variable:
The process of assigning the address of a variable to a pointer variable is known as initialization. The syntax
to initialize a pointer variable is
data-type *pt-name = &var-name;
Or
data-type *pt-name;
pt-name = &var-name;
Example:
int x=120, *px;
px=&x;
Notes:
We could also define a pointer variable with an initial value of NULL or 0 (zero). That is the
following statements are valid.
int *p = NULL;
int *p = 0;
With the exception of NULL and 0, no other constant value can be assigned to a pointer variable. For
example, the following is wrong:
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
56
int *p = 6300;
/* absolute address */
Pointers are flexible. We can make the same pointer to point to different data variables in different
statements. Example:
int x, y, z, *p;
p = &x;
..
p = &y;
..
p = &z;
..
We can also use different pointers to point to the same data variable.
Example:
int x;
int *p1 = &x;
int *p2 = &x;
int *p3 = &x;
57
x[0]
10
500
x[1]
20
502
x[2]
x[3]
x[4]
30
40
50
504
506
508
If we declare a pointer to integer, then we can make the pointer p to point to the array x by the following
assignment:
p = x;
This is equivalent to
p = &x[0];
Now, we can access every element of x using p++ to move from one element to another. The relation
between p and x is shown as:
p = &x[0] (= 500)
p+1 = &x[1] (=502)
p+2 = &x[2] (=504)
p+3 = &x[3] (=506)
p+4 = &x[4] (=508)
The address of an element can be calculated using its index and the scale factor of the data type. For
instance
address of x[3] = base address + (3 X scale factor of int)
= 500 + (3 X 2) = 506
To access elements of the array we can use pointers instead of using array indexing. The pointer accessing
method is much faster than array indexing.
The relationship between pointer accessing method and array indexing method:
*x = *p = *(x + 0) = x[0]
*(p+1) = *(x + 1) = x[1]
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
58
<- ptr
<- ptr+1
2,0
*(ptr 2)
2,3
<-ptr+2
An element A[i][j] in a two-dimensional array can be represented by the pointer expression as follows:
*(*(A+i)+j) or *(*(ptr+i)+j)
ptr pointer to first row
ptr+i pointer to ith row
*(ptr+i) pointer to first element in the ith row
*(ptr+i)+j pointer to the jth element int the ith row
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
59
*(*(ptr+i)+j) value stored in the cell (i,j) (ith row and jth column)
(A+0) is the address of first 1-d array *(A+0) is the first 1-d array
(A+1 ) is the address of second 1-d array
*(A+1) is the second 1-darray
(A+2) is the address of third 1-d array
*(A+2)is the third 1-d array
st
*(A+0)+0 is the address of first element in the 1 1-d array
*(A+0)+1 is the address of 2nd element in the 1st 1-d array
Similarly.
*(*(A+0)+0) gives the 1st element in the 1st 1-d array
*(*(A+1)+0) gives the 1st element in the 2nd 1-d array
*(*(A+2)+1) gives the 2nd element in the 3rd 1-d array
*(*(A+0)+1) gives the 2nd element in the 1st 1-d array
Pointers And Character Strings
C supports an alternative method to create strings using pointer variables of type char.
Example:
char *str = good;
This create a string for the literal and then stores its address in the pointer variable str. The pointer str
now points to the first character of the string good as follows:
g
\0
str
Point to Note:
The string name itself is pointer to the string. So, we do need to use indirection operator.
Pointer As Function Arguments
We can pass addresses to a function; the parameters receiving the addresses should be pointers. The
process of calling a function using pointers to pass the addresses of the variable is knows as call by
reference.
Example:
main ( )
{
int x;
x = 20 ;
change ( &x );
printf ( %d \n , x);
}
change ( int *p)
{
*p = *p + 10;
}
Thus, call by reference provides a mechanism by which the function can change the stored values in the
calling function. This mechanism is also knows as call by address or pass by pointers.
FUNCTION RETURNING POINTERS:
A function can return a single value by its name or return multiple values through pointer parameters.
Since, pointers are a data type in C, we can also force a function to return a pointer to the calling function.
int *large ( int * , int * ) ;
main ( )
{
int *p;
p = large ( &a, &b );
}
int * large ( int *x, int *y)
{
}
60
Note: The address returned must be the address of a variable in the calling function. It is an error to return
a pointer to a local variable in the called function.
POINTERS TO FUNCTION:
In C it is possible to declare a pointer to a function, which can then be used as an argument in another
function. A pointer to a function is declared as follows:
type (*fptr ) ( ) ;
This tells the compiler that fptr is a pointer to a function, which returns type value. The parentheses
around *fptr are necessary.
We can make a function pointer to point to a specific function by simply assigning the name of the function
to the pointer. For example:
double mul ( int ,int ) ;
double ( * p1 ) ( ) ;
p1 = mul ;
declare p1 as a pointer to function and mul as a function and then make p1 to point to the function mul. To
call the function mul, we may now the pointer p1 with the list of parameters. That is,
(* p1) (x, y) / * function call */
Is equivalent to mul ( x ,y ).
Note:
type *gptr ( ); this statement declare as a function returning a pointer to type.
TIPS & TRICKS:
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
61
62
63
64
MODULE III
Structures sometimes referred to as aggregates are collections of related variables under one name. Structures
may contain variables of many different data types in contrast to arrays that contain only elements of the same
data type.
Structures are commonly used to define records to be stored in files.
Structures and pointers facilitate the formation of more complex data structures such as linked lists, queues,
stacks and trees.
Structure Definitions:
Structures are derived data types they are constructed using objects (variables) other types.
Syntax:
struct tag_name
{
datatype member1;
datatype member2;
.
.
datatype membern;
};
where struct is a keyword. tag_name is a user defined name (it is the name of the structure).
Example:
struct employee
{
int empno;
char name[30];
float salary;
};
Structure members are not variables by themselves. So, Structure definitions do not reserve any space in
memory; rather, each definition creates a new data type that is used to define variables. Memory locations get
allocated only when variables of the structure are declared.
A structure cannot contain an instance of itself. For example, a variable of type struct employee cannot be
declared in the definition for struct employee. However, a pointer to struct employee may be included. A
structure containing a member that is a pointer to the same structure type is referred to as a self-referential
structure. Self-referential structures are used to build linked data structures. For example:
struct linkedlist
{
int info;
struct linkedlist *link;
};
Declaration of Structure Variables:
Syntax:
struct tag_name variable_name;
As a result of this , n memory locations get allocated for n members of the structure.
Example:
struct employee e;
This results in allocation of three locations which are contiguous in nature as follows:
e.empno
e.name
e.salary
All the data items share the common name e and are distinguishable by members empno, name and salary.
65
e.name
e.salary
john
20000.00
If there are fewer initializers in the list than members in the structure, the remaining members are
automatically initialized to 0 (or NULL if the member is a pointer).
Structure variables may also be initialized in assignment statements by assigning a structure variable of the
same type, or by assigning values to the individual members of the structure.
Accessing Members of Structures:
Two operators are used to access members of structures: the structure member operator (.) also called the dot
operator and the structure pointer operator (->) also called the arrow operator.
The structure member operator accesses a structure member via the structure variable name.
Syntax:
structure-variable-name.member-name
Example: to print member empno of structure variable e use the statement
printf(%d,e.empno);
The structure pointer operator accesses a structure member via a pointer to the structure.
Syntax:
structure-pointer-name->member-name
Example:
struct employee *eptr = &e;
To print member empno of structure variable e with pointer eptr, use the statement
printf(%d,eptr->empno);
The expression eptr->empno is equivalent to (*eptr).empno, which dereferences the pointer and
accesses the member empno using the structure member operator. The parentheses are needed
here because the structure member operator (.) has a higher precedence than the pointer
dereferencing operator (*).
66
01100001
00000000
01100001
(Possible storage alignment for a variable of type struct example showing an undefined area in memory)
If the members are stored beginning at word boundaries, there is a 1-byte hole (byte 1 in the figure) in the
storage for variables of type struct example. The value in the 1-byte hole is undefined. Even if the member
values of sample1 and sample2 are in fact equal, the structures are not necessarily equal, because the
undefined 1-byte holes are not likely to contain identical values.
Note: because the size of data items of particular type is machine dependent and because storage alignment
considerations are machine dependent ,so too is the representation of a structure.
Using Structures With Functions:
Structures may be passed to functions by passing individual structure members, by passing an entire
structure or by passing a pointer to a structure.
When structures or individual structure members are passed to a function, they are passed by value.
To pass a structure by reference, pass the address of the structure variable. Array of structures like all
other arrays are automatically passed by reference.
An array could be passed by value by using a structure. To pass an array by value, create a structure with the
array as a member. Structures are passed by value, so the array is passed by value.
Passing structures by reference is more efficient than passing structures by value (which requires the entire
structure to be copied).
typedef:
The keyword typedef provides a mechanism for creating synonyms (or aliases) for previously defined
data types. Names for structure types are often defined with typedef to create shorter type names. For
example, the statement
typedef struct employee Emp;
defines the new type name Emp as a synonym for type struct employee.
C programmers often use typedef to define a structure type, so a structure tag is not required. For
example, the following definition
typedef struct
{
int empno;
char name[30];
float salary;
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
67
UNIONS
A union is a derived data type like a structure with members that share the same storage space. The number of
bytes used to store a union must be at least enough to hold the largest member.
A union is defined with keyword union in the same format as a structure. The union definition
Syntax:
union tag_name
{
data-type member1;
data-type member2;
.
.
data-type member;
};
Example:
union number
{
int x;
double y;
};
In a declaration, a union may be initialized with a value of the same type as the first union member. For example
union number value = { 10 };
is valid initialization of union variable value.
The operations that can be performed on a union are the following: assigning a union to another union
of the same type, taking the address of a union variable, and accessing union members using the
structure member operator and structure pointer operator.
unions may not be compared using operators == and != for the same reasons that structures cannot be
compared.
68
BIT FIELDS
A bit-field is basically a set of adjacent bits in a word of memory. Members of structure can include bit-fields. Bit
fields enable better memory utilization by storing data in the minimum number of bits required. Bit field members
must
be
declared
as
int
or
unsigned
int.
The syntax of defining structure template using bit-fields is given as:
struct tag_name
{
data-type m1 : size;
data-type m2 : size;
.
.
data-type mn: size;
};
Example:
struct bitfieldexample
{
int a : 3;
int b : 3;
unsigned int c : 3;
};
Bit fields can not be arrayed
We can not retrieve the address of a bit field. Consequently, the concept of pointer to a bit fields does not
arise.
If a bit field does not fit into a word, the bit field is placed into the next word.
Some members in the structure can be of normal data type also.
It is possible to specify an unnamed bit field to be used as padding in the structure. For example, the
structure definition
struct example
{
unsigned a: 13;
unsigned : 19;
unsigned b: 4;
};
uses an unnamed 19-bit field as padding nothing can be stored in those 19 bits. Member b (on our 4-byteword computer) is stored in another storage unit.
An unnamed bit field with a zero width is used to align the next bit field on a new storage unit boundary. For
example, the structure definition
struct example
{
unsigned a : 13;
unsigned : 0;
unsigned b : 4;
};
uses an unnamed 0-bit field to skip the remaining bits (as many as there are) of the storage unit in which a is
stored and to align b on the next storage-unit boundary.
Bit field manipulations are machine dependent. For example, some computers allow bit fields to cross word
boundaries, whereas others do not.
Although bit fields save space, using them can cause the compiler to generate slower-executing machinelanguage code. This occurs because it taked extra machine language operations to access only portions of an
addressable storage unit. This is one of many examples of the kinds of space-time trade-offs that occur in
computer science.
Enumerated data type offers us a way of inventing our own data type. The invented new data type enables us to
assign symbolic names to integer constants, thereby increasing the degree of readability and maintainability. An
enumeration, introduced by the keyword enum, is a set of integer enumeration constants represented by identifiers.
Values in enum start with 0, unless specified otherwise, and are incremented by 1. However, the default integer
69
70
OPENING A FILE:
: stdio.h
: FILE *fopen(const char *filename, const char *mode);
: Opens a stream. fopen opens the file named by filename and associates a stream with it. fopen
returns a pointer to be used to identify the stream in subsequent operations. The mode string used
in calls to fopen is one of the following values:
71
Return Value
: On successful completion fopen returns a pointer to the newly opened stream. In the event of
Closing a File:
fclose()
Header file
Prototype
Description
: stdio.h
: int fclose(FILE *stream);
: Closes a stream. fclose closes the named stream. All buffers associated with the stream are flushed
72
#include <string.h>
#include <stdio.h>
int main(void)
{
FILE *fp;
char buf[11] = "0123456789";
/* create a file containing 10 bytes */
fp = fopen("DUMMY.FIL", "w");
fwrite(&buf, strlen(buf), 1, fp);
/* close the file */
fclose(fp);
return 0;
}
fcloseall()
Streams Manipulations
Reading and Writing a character into a stream:
fgetc()
Header file
Prototype
Description
Return Value
: stdio.h
: int fgetc(FILE *stream);
: Gets character from stream. fgetc returns the next character on the named input stream.
: On success fgetc returns the character read after converting it to an int without sign extension. On
#include <string.h>
#include <stdio.h>
#include <conio.h>
int main(void)
{
FILE *stream;
char string[] = "This is a test";
char ch;
/* open a file for update */
stream = fopen("DUMMY.FIL", "w+");
/* write a string into the file */
fwrite(string, strlen(string), 1, stream);
/* seek to the beginning of the file */
fseek(stream, 0, SEEK_SET);
do
{
/* read a char from the file */
ch = fgetc(stream);
/* display the character */
putch(ch);
} while (ch != EOF);
fclose(stream);
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
73
fputc()
Header file
Prototype
Description
Note
Return Value
Example:
: stdio.h
: int fputc(int c, FILE *stream);
: Puts a character on a stream. fputc outputs character c to the named stream.
: For Win32s or Win32 GUI applications, stdin must be redirected.
: On success, fputc returns the character c. On error, it returns EOF.
#include <stdio.h>
int main(void)
{
char msg[] = "Hello world";
int i = 0;
while (msg[i])
{
fputc(msg[i], stdout);
i++;
}
return 0;
: stdio.h
: char *fgets(char *s, int n, FILE *stream);
: Gets a string from a stream. fgets reads characters from stream into the string s. The function stops
reading when it reads either n - 1 characters or a newline character whichever comes first. fgets retains the newline
character at the end of s. A null byte is appended to s to mark the end of the string.
Return Value : On success fgets returns the string pointed to by s; it returns NULL on end-of-file or error.
Example:
#include <string.h>
#include <stdio.h>
int main(void)
{
FILE *stream;
char string[] = "This is a test";
char msg[20];
/* open a file for update */
stream = fopen("DUMMY.FIL", "w+");
/* write a string into the file */
fwrite(string, strlen(string), 1, stream);
/* seek to the start of the file */
fseek(stream, 0, SEEK_SET);
/* read a string from the file */
fgets(msg, strlen(string)+1, stream);
/* display the string */
printf("%s", msg);
Header file
Prototype
Description
74
fputs()
: stdio.h
: int fputs(const char *s, FILE *stream)
: Outputs a string on a stream. fputs copies the null-terminated string s to the given output stream; it
does not append a newline character and the terminating null character is not copied.
Return Value : On success fputs returns a non-negative value. On error it returns a value of EOF.
Header file
Prototype
Description
Example:
#include <stdio.h>
int main(void)
{
/* write a string to standard output */
fputs("Hello world\n", stdout);
return 0;
}
: stdio.h
: int putw(int w, FILE *stream);
: Puts an integer on a stream. putw outputs the integer w to the given stream. putw neither expects
nor causes special alignment in the file.
Return Value : On success, putw returns the integer w. On error, putw returns EOF. Because EOF is a legitimate
integer, use ferror to detect errors with putw.
Headerfile
Prototype
Description
Example:
#include <stdio.h>
#include <stdlib.h>
#define FNAME "test.$$$"
int main(void)
{
FILE *fp;
int word;
/* place the word in a file */
fp = fopen(FNAME, "wb");
if (fp == NULL)
{
printf("Error opening file %s\n", FNAME);
exit(1);
}
word = 94;
putw(word,fp);
if (ferror(fp))
printf("Error writing to file\n");
else
printf("Successful write\n");
fclose(fp);
/* reopen the file */
fp = fopen(FNAME, "rb");
if (fp == NULL)
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
75
getw()
: stdio.h
: int getw(FILE *stream);
: Gets integer from stream. getw returns the next integer in the named input stream. It assumes no
special alignment in the file. getw should not be used when the stream is opened in text mode.
Return Value : getw returns the next integer on the input stream. On end-of-file or error, getw returns EOF.
Note
: Because EOF is a legitimate value for getw to return, feof or ferror should be used to detect end-offile or error.
Headerfile
Prototype
Description
Example:
#include <stdio.h>
#include <stdlib.h>
#define FNAME "test.$$$"
int main(void)
{
FILE *fp;
int word;
/* place the word in a file */
fp = fopen(FNAME, "wb");
if (fp == NULL)
{
printf("Error opening file %s\n", FNAME);
exit(1);
}
word = 94;
putw(word,fp);
if (ferror(fp))
printf("Error writing to file\n");
else
printf("Successful write\n");
fclose(fp);
/* reopen the file */
fp = fopen(FNAME, "rb");
if (fp == NULL)
{
printf("Error opening file %s\n", FNAME);
exit(1);
}
/* extract the word */
word = getw(fp);
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
76
: stdio.h
: int fprintf(FILE *stream, const char *format[, argument, ...]);
: Writes formatted output to a stream. fprintf accepts a series of arguments applies to each a format
specifier contained in the format string pointed to by format and outputs the formatted data to a
stream. There must be the same number of format specifiers as arguments.
Return Value : fprintf returns the number of bytes output. In the event of error it returns EOF.
Header file
Prototype
Description
Example:
#include <stdio.h>
int main(void)
{
FILE *stream;
int i = 100;
char c = 'C';
float f = 1.234;
/* open a file for update */
stream = fopen("DUMMY.FIL", "w+");
/* write some data to the file */
fprintf(stream, "%d %c %f", i, c, f);
/* close the file */
fclose(stream);
return 0;
}
fscanf()
: stdio.h
: int fscanf(FILE *stream, const char *format[, address, ...]);
: Scans and formats input from a stream. fscanf scans a series of input fields one character at a time
reading from a stream. Then each field is formatted according to a format specifier passed to fscanf
in the format string pointed to by format. Finally fscanf stores the formatted input at an address
passed to it as an argument following format. The number of format specifiers and addresses must
be the same as the number of input fields.
Note
: fscanf can stop scanning a particular field before it reaches the normal end-of-field character
(whitespace) or it can terminate entirely for a number of reasons.
Return Value : fscanf returns the number of input fields successfully scanned, converted and stored. The return
value does not include scanned fields that were not stored. If fscanf attempts to read at end-of-file,
the return value is EOF. If no fields were stored, the return value is 0.
Header file
Prototype
Description
Example:
#include <stdlib.h>
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
77
: stdio.h
: size_t fread(void *ptr, size_t size, size_t n, FILE *stream);
: Reads data from a stream. fread reads n items of data each of length size bytes from the given
input stream into a block pointed to by ptr. The total number of bytes read is (n * size).
Return Value : On success fread returns the number of items (not bytes) actually read. On end-of-file or error it
returns a short count (possibly 0).
Header file
Prototype
Description
Example:
#include <string.h>
#include <stdio.h>
int main(void)
{
FILE *stream;
char msg[] = "this is a test";
char buf[20];
if ((stream = fopen("DUMMY.FIL", "w+"))
== NULL)
{
fprintf(stderr, "Cannot open output file.\n");
return 1;
}
/* write some data to the file */
fwrite(msg, strlen(msg)+1, 1, stream);
/* seek to the beginning of the file */
fseek(stream, SEEK_SET, 0);
/* read the data and display it */
fread(buf, strlen(msg)+1, 1, stream);
printf("%s\n", buf);
fclose(stream);
return 0;
}
78
fwrite()
: stdio.h
: size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream);
: Writes to a stream. fwrite appends n items of data each of length size bytes to the given output file.
The data written begins at ptr. The total number of bytes written is (n x size). ptr in the declarations
is a pointer to any object.
Return Value : On successful completion fwrite returns the number of items (not bytes) actually written. On error
it returns a short count.
Header file
Prototype
Description
Example:
#include <stdio.h>
struct mystruct
{
int i;
char ch;
};
int main(void)
{
FILE *stream;
struct mystruct s;
if ((stream = fopen("TEST.$$$", "wb")) == NULL) /* open file TEST.$$$ */
{
fprintf(stderr, "Cannot open output file.\n");
return 1;
}
s.i = 0;
s.ch = 'A';
fwrite(&s, sizeof(s), 1, stream); /* write struct s to file */
fclose(stream); /* close file */
return 0;
}
freopen()
: stdio.h
: FILE *freopen(const char *filename, const char *mode, FILE *stream);
: Associates a new file with an open stream. freopen substitutes the named file in place of the open
stream. It closes stream regardless of whether the open succeeds. freopen is useful for changing the file attached to
stdin, stdout, or stderr. The mode string used in calls to fopen is one of the following values:
Header file
Prototype
Description
Value
Description
r
w
a
r+
w+
a+
To specify that a given file is being opened or created in text mode append a t to the mode string (rt w+t and so on);
similarly to specify binary mode append a b to the mode string (wb a+b and so on). If a t or b is not given in the mode
string the mode is governed by the global variable _fmode. If _fmode is set to O_BINARY files are opened in binary
mode. If _fmode is set to O_TEXT they are opened in text mode. These O_... constants are defined in fcntl.h. When a
file is opened for update, both input and output can be done on the resulting stream; however, output cannot be
directly followed by input without an intervening fseekor rewind input cannot be directly followed by output without
an intervening fseek, rewind, or an input that encounters end-of-file
Return Value : On successful completion freopen returns the argument stream. On error it returns NULL.
Example:
#include <stdio.h>
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
79
: stdio.h
: int fseek(FILE *stream, long offset, int whence);
: Repositions a file pointer on a stream. fseek sets the file pointer associated with stream to a new
position that is offset bytes from the file location given by whence. For text mode streams offset
should be 0 or a value returned by ftell. whence must be one of the values 0. 1, or 2 which represent
three symbolic constants (defined in stdio.h) as follows:
Constant
whence
SEEK_SET
SEEK_CUR
SEEK_END
0
1
2
File location
File beginning
Current file pointer position
End-of-file
fseek discards any character pushed back using ungetc. fseek is used with stream I/O; for file handle I/O use lseek.
After fseek the next operation on an update file can be either input or output.
Return Value : fseek returns 0 if the pointer is successfully moved and nonzero on failure. fseek might return a 0
indicating that the pointer has been moved successfully when in fact it has not been. This is because
DOS, which actually resets the pointer, does not verify the setting. fseek returns an error code only
on an unopened file or device.
In the event of an error return the global variable errno is set to one of the following values:
EBADF
Bad file pointer
EINVAL
Invalid argument
ESPIPE
Illegal seek on device
Example:
#include <stdio.h>
long filesize(FILE *stream);
int main(void)
{
FILE *stream;
stream = fopen("MYFILE.TXT", "w+");
fprintf(stream, "This is a test");
printf("Filesize of MYFILE.TXT is %ld bytes\n", filesize(stream));
fclose(stream);
return 0;
}
long filesize(FILE *stream)
{
long curpos, length;
curpos = ftell(stream);
fseek(stream, 0L, SEEK_END);
length = ftell(stream);
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
80
ftell()
: stdio.h
: long int ftell(FILE *stream);
: Returns the current file pointer. ftell returns the current file pointer for stream. The offset is
measured in bytes from the beginning of the file (if the file is binary). The value returned by ftell can
be used in a subsequent call to fseek.
Return Value : ftell returns the current file pointer position on success. It returns -1L on error and sets the global
variable errno to a positive value. In the event of an error return the global variable errno is set to
one of the following values:
EBADF
Bad file pointer
ESPIPE
Illegal seek on device
Header file
Prototype
Description
Example:
#include <stdio.h>
int main(void)
{
FILE *stream;
stream = fopen("MYFILE.TXT", "w+");
fprintf(stream, "This is a test");
printf("The file pointer is at byte %ld\n", ftell(stream));
fclose(stream);
return 0;
}
rewind()
: stdio.h
: void rewind(FILE *stream);
: Repositions a file pointer to the beginning of a stream. rewind(stream) is equivalent to
fseek(stream, 0L, SEEK_SET), except that rewind clears the end-of-file and error indicators, while
fseek clears the end-of-file indicator only. After rewind, the next operation on an update file can be
either input or output.
Return Value : None.
Header file
Prototype
Description
Example:
#include <stdio.h>
#include <dir.h>
int main(void)
{
FILE *fp;
char *fname = "TXXXXXX", *newname, first;
newname = mktemp(fname);
fp = fopen(newname,"w+");
fprintf(fp,"abcdefghijklmnopqrstuvwxyz");
rewind(fp);
fscanf(fp,"%c",&first);
printf("The first character is: %c\n",first);
fclose(fp);
remove(newname);
return 0;
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
81
fgetpos()
: stdio.h
: int fgetpos(FILE *stream, fpos_t *pos);
: Gets the current file pointer. fgetpos stores the position of the file pointer associated with the
given stream in the location pointed to by pos. The exact value is unimportant; its value is opaque
except as a parameter to subsequent fsetpos calls.
Return Value : On success fgetpos returns 0. On failure it returns a nonzero value and sets the global variable
errno to
EBADF
Bad file number
EINVAL
Invalid number
Header file
Prototype
Description
Example:
#include <stdlib.h>
#include <stdio.h>
void showpos(FILE *stream);
int main(void)
{
FILE *stream;
fpos_t filepos;
/* open a file for update */
stream = fopen("DUMMY.FIL", "w+");
/* save the file pointer position */
fgetpos(stream, &filepos);
/* write some data to the file */
fprintf(stream, "This is a test");
/* show the current file position */
showpos(stream);
/* set a new file position, display it */
if (fsetpos(stream, &filepos) == 0)
showpos(stream);
else
{
fprintf(stderr, "Error setting file pointer.\n");
exit(1);
}
/* close the file */
fclose(stream);
return 0;
}
void showpos(FILE *stream)
{
fpos_t pos;
/* display the current file pointer
position of a stream */
fgetpos(stream, &pos);
printf("File position: %ld\n", pos);
}
82
83
CHAPTER 13 (PREPROCESSORS)
In C, the source program is first passed to the program called as PREPROCESSOR , the preprocessor acts on the
source program according to the instructions specified to it in the source program and the output produced by the
preprocessor is then submitted to the C compiler.
The instructions specified in the source program to the preprocessor are called the PREPROCESSOR DIRECTIVES.
Compilation of C program:
Source Program
Preprocessor
Expanded source
program
C compiler
In the first step, the process of preprocessor directive substitution is carried out by the preprocessor. The end result
is a modified C program.
In the second step, the modified source code is compiled into machine language code.
General Rules of Preprocessor Directives:
All preprocessor directives should start with the symbol #. ANSI allows the symbol to be preceded by space
or tabs.
Only one directive can appear in a line.
The directives are not terminated by semicolons.
The preprocessor directives can be placed anywhere in a source program. The directives apply to the source
code, which follows them.
Classification of Preprocessor Directive
The preprocessor directives are broadly classified into three types based on the purpose for which they are used.
1. Files Inclusion Directives
2. Macros Definition Directives
3. Conditional Compilation Directives.
FILE INCLUSION DIRECTIVES:
The #include preprocessor directive is used to include a file as part of the source program file. In response to the
directive #include <stdio.h> , the preprocessor expands the source file by embedding the contents of the header file
stdio.h, before the source program is submitted to the C compiler.
As a matter of fact, contents of any text file can be included as part of a source program with the help of the
directive. If the file name is enclosed within double quotes then the file is expected to be available in the current
working directory.
Example: suppose a file by name function.c in the current working directory, contains the definitions for the
functions used by a program, the file function.c can be included as part of the source program with the
directive #include function.c.
#include <stdio.h>
#include function.c
void main ( )
{
}
Here, the preprocessor embeds the contents of the header file stdio.h and the contents of the file function.c into the
source program before the program is passed onto the compiler.
MACROS DEFINITION DIRECTIVES-[#DEFINE, #UNDEF]:
A MACRO is defined to be a symbolic name assigned to a segment of text. The preprocessor directive #define is used
for defining macros. The syntax of its usage is as follows:
#define MACRO_NAME segment_of_text
Here macro_name is the name of a macro; which is used to construct valid identifiers and normally it is written using
upper case letters just to distinguish it from the identifiers. Segment_of_text is actually the string referred to bt the
MACRO_NAME.
Once a symbolic name (macro_name) is assigned to segment of text throughout the program, the symbolic name
can be used in place of the segment of text. The preprocessor then replaces all the occurrences of the macro_name
by the segment of text.
Example:
#define COUNT 10
// segment of text is numeric value
#define NO_OF_STUDENT 100
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
84
Example 1:
Wap to illustrate macro definition.
#define PI 3.14
#include<stdio.h>
main ( )
{
int area ,r ;
printf ( Enter the redius :) ;
scanf (%d , &r ) ;
area = PI * r * r ;
printf ( arer = %d , area );
}
Explanation: The macro PI has been replaced by the value 3.14 by the preprocessor. The process of replacement
of macros by their corresponding segments of texts is termed as macros substitution.
Example 2:
#define ACCEPT printf (enter two number :)
#include<stdio.h>
main ( )
{
ACCEPT;
}
MACROS WITH ARGUMENTS:
The preprocessor permits us to pass arguments to macros in such the same way as we pass arguments to functions.
Examples:
#define INCRE(x) if (x > 0) x = x +1
#define SQUARE ( x ) x * x
#define SQUARE(x) (x) * (x)
Then INCRE (a ) would be expanded to the statement if ( a > 0 ) a= a + 1
INCRE (b) would be expanded to the statement if (b > 0) b= b + 1
Example:
#include <stdio.h>
#define INCRE( x ) if ( x>0 ) x = x + 1
main ( )
{
int a , b ;
printf ( enter value of a: ) ;
INCRE ( a ) ;
printf ( %d , a ) ;
}
Q. T find the square of a number using macro with argument
#include <stdio.h>
#define SQUARE( x ) ( ( x ) * ( x ) )
main ( )
{
int a =5 ,sqr ;
sqr = SQUARE ( 4 ) ;
printf ( %d , sqr ) ;
}
Points to Note:
Consider two cases of macro as below
#define SQUARE(x) x * x
#define SQUARE(x) ((x) * (x))
Let us take the 1st case; SQUARE (3) expands to 3*3. We would get the square of 3, which is 9. To find square of the
expression a+2, we would use the macro SQUARE (a+2) expands to
a+2 * a+2
VIGNAN INSTITUTE OF TECHNOLOGY AND MANAGEMENT
85
86
87
88
89