Professional Documents
Culture Documents
C Notes Full
C Notes Full
C Notes Full
C Programming
Prepared by
Dr. M Naresh Babu
Contents
C Programming Introduction ......................................................................................................................... 1
Algorithm ................................................................................................................................................... 1
Why to use C ? ........................................................................................................................................... 2
History of C ................................................................................................................................................ 3
Characteristics of C .................................................................................................................................... 3
C Program Structure .................................................................................................................................. 3
Identifiers and Keywords ........................................................................................................................... 4
Variables .................................................................................................................................................... 5
Defining Global Variables ...................................................................................................................... 5
Operators........................................................................................................................................................ 6
Arithmetic Operations ............................................................................................................................... 6
Relational Operators .................................................................................................................................. 8
Logical Operators ....................................................................................................................................... 9
Bitwise Operators ...................................................................................................................................... 9
Assignment Operators .............................................................................................................................10
Misc Operators ↦ sizeof & ternary .........................................................................................................11
Operators Precedence in C...........................................................................................................................11
Implicit Type Conversion ............................................................................................................................13
Explicit Type Conversion ............................................................................................................................13
Conditionals .................................................................................................................................................14
The ‘if’ statement.....................................................................................................................................14
The ? : operator .......................................................................................................................................15
The switch statement ..............................................................................................................................16
LOOPs .........................................................................................................................................................17
The for loop..............................................................................................................................................23
The while loop .........................................................................................................................................24
The do while loop ....................................................................................................................................25
Break and continue ..................................................................................................................................26
Arrays and Strings .......................................................................................................................................27
Single and Multi-dimensional Arrays .......................................................................................................27
Strings ......................................................................................................................................................28
Pointers ........................................................................................................................................................30
C Pointer Syntax .......................................................................................................................................31
Pointing to Something: Retrieving an Address .......................................................................................32
Functions......................................................................................................................................................35
Parameters in C functions........................................................................................................................36
Pass by Value .......................................................................................................................................36
Pass by Reference ................................................................................................................................36
Structures .....................................................................................................................................................39
Defining New Data Types.........................................................................................................................40
Unions ......................................................................................................................................................41
Enumerated Types ...................................................................................................................................42
Coercion or Type-Casting............................................................................................................................43
Static Variables ............................................................................................................................................44
Files..............................................................................................................................................................45
Reading and writing files .........................................................................................................................46
sprintf and sscanf .....................................................................................................................................47
Stream Status Enquiries ...........................................................................................................................48
Low Level I/O ...........................................................................................................................................48
Closing Files..............................................................................................................................................51
Direct input function: the fread function ................................................................................................54
Exercises.......................................................................................................................................................55
References ...................................................................................................................................................58
C Programming Introduction
Computer is an electronic device that stores, processes, inputs, and outputs data to produce a
result. Computer contains electronic components. Every operation will be done in terms
voltages. Computer/ Machine can understand only 0s and 1s (may be 0v to represent 0 and +5v
to represent 1).
A computer is a general purpose device that can be programmed to carry out a set of arithmetic
or logical operations automatically.
Can we say calculator is computer? yes, in calculator we can give input, we can
perform arithmetic operations like +,-, * etc., we can also store using M+. But calculator has its
own limitation. Like that mobile is also a computer.
Now days modern computer comes with 4 GB RAM, 500GB Harddisk to store and Intel Core i7
processor, for input keyboard with 108 keys etc.,
As machine can understand 0s and 1s, as a human it is difficult to write complex programs in 0s
and 1s. There is something needed to convert human understandable program to machine
understandable called complier.
Algorithm
Algorithms are essential to the way computers process data. Many computer programs contain
algorithms that detail the specific instructions a computer should perform (in a specific order) to
carry out a specified task.
• The method prescribes starting in the central column of the first row with the number 1.
• After that, the fundamental movement for filling the squares is diagonally up and right,
one step at a time.
• If a filled square is encountered, one moves vertically down one square instead, then
continues as before.
• When an "up and to the right" move would leave the square, it is wrapped around to the
last row or first column, respectively.
Flowchart
The flowchart is a means of visually presenting the flow of data through an information
processing systems, the operations performed within the system and the sequence in which they
are performed.
Page 1 of 58
A flowchart is a diagrammatic representation that illustrates the sequence of operations to be
performed to get the solution of a problem.
Off page connector is used to show that the flow is on a different page.
Why to use C ?
C was initially used for system development work, in particular the programs that make-up the
operating system. C was adoped as a system development language because it produces code that
runs nearly as fast as code written in assembly language. Some examples of the use of C might
be:
• Operating Systems
• Language Compilers
• Assemblers
• Text Editors
• Print Spoolers
• Network Drivers
• Modern Programs
Page 2 of 58
• Data Bases
• Language Interpreters
• Utilities
History of C
The milestones in C's development as a language are listed below:
• UNIX developed c. 1969 -- DEC PDP-7 Assembly Language
• BCPL -- a user friendly OS providing powerful development tools developed from
BCPL. Assembler tedious long and error prone.
• A new language ``B'' a second attempt. c. 1970.
• A totally new language ``C'' a successor to ``B''. c. 1971
• By 1973 UNIX OS almost totally written in ``C''.
Characteristics of C
We briefly list some of C's characteristics that define the language and also have lead to its
popularity as a programming language. Naturally we will be studying many of these aspects
throughout the course.
• Small size
• Extensive use of function calls
• Loose typing -- unlike PASCAL
• Structured language
• Low level (BitWise) programming readily available
• Pointer implementation - extensive use of pointers for memory, array, structures and
functions.
C has now become a widely used professional language for various reasons.
• It has high-level constructs.
• It can handle low-level activities.
• It produces efficient programs.
• It can be compiled on a variety of computers.
Its main drawback is that it has poor error detection which can make it off putting to the
beginner.
C Program Structure
A C program basically has the following form:
• Preprocessor Commands
• Type definitions
• Function prototypes -- declare function types and variables passed to function.
Page 3 of 58
• Variables
• Functions
We must have a main() function.
C Statements
}
C keeps a small set of keywords for its own use. These keywords cannot be used as identifiers in
the program — a common restriction with modern languages.
Page 4 of 58
Variables
C has the following simple data types:
short number,sum;
int bignumber,bigsum;
char letter;
main()
{
It is also possible to pre-initialise global variables using the = operator for assignment.
a=b=c=d=3;
a=3;
b=3;
c=3;
d=3;
This kind of assignment is only possible if all the variable types in the statement are the same.
You can define your own types use typedef. This will have greater relevance later in the course
when we learn how to create more complex data structures.
Page 5 of 58
As an example of a simple use let us consider how we may define two new types real and letter.
These new types can then be used in the same way as the pre-defined C types:
Variables declared:
real sum=0.0;
letter nextletter;
C uses formatted output. The printf function has a special formatting character (%) -- a character
following this defines a certain format for a variable:
%c -- characters
%d -- integers
%f – floats
%s -- string
Operators
An operator is a symbol that tells the compiler to perform specific mathematical or logical
manipulations. C language is rich in built-in operators and provides the following types of
operators:
• Arithmetic Operators
• Relational Operators
• Logical Operators
• Bitwise Operators
• Assignment Operators
• Misc Operators
Arithmetic Operations
As well as the standard arithmetic operators (+ - * /) found in most languages, C provides some
more operators. There are some notable differences with other languages, such as Pascal.
Page 6 of 58
Increment ++, Decrement -- which are more efficient than their long hand equivalents, for
example:-- x++ is faster than x=x+1.
The ++ and -- operators can be either in post-fixed or pre-fixed. With pre-fixed the value is
computed before the expression is evaluated whereas with post-fixed the value is computed after
the expression is evaluated.
int x,y,w;
main()
{
x=((++z)-(w--)) % 100;
int x,y,w;
main()
{
z++;
x=(z-w) % 100;
w--;
So make sure you do this. The correct (for division) answer to the above is x = 3.0 / 2 or x= 3 /
2.0 or (better) x = 3.0 / 2.0.
Page 7 of 58
It is very common to have expressions like: i = i + 3 or x = x*(y + 2)
So we can rewrite i = i + 3 as i += 3
and x = x*(y + 2) as x *= y + 2.
Following table shows all the arithmetic operators supported by C language. Assume variable A
holds 10 and variable B holds 20 then:
Relational Operators
Following table shows all the relational operators supported by C language. Assume variable A
holds 10 and variable B holds 20, then:
Page 8 of 58
not, if yes then condition becomes true.
!= Checks if the values of two operands are equal or (A != B) is true.
not, if values are not equal then condition becomes
true.
> Checks if the value of left operand is greater than (A > B) is not true.
the value of right operand, if yes then condition
becomes true.
< Checks if the value of left operand is less than the (A < B) is true.
value of right operand, if yes then condition
becomes true.
>= Checks if the value of left operand is greater than (A >= B) is not true.
or equal to the value of right operand, if yes then
condition becomes true.
<= Checks if the value of left operand is less than or (A <= B) is true.
equal to the value of right operand, if yes then
condition becomes true.
Logical Operators
Following table shows all the logical operators supported by C language. Assume variable A
holds 1 and variable B holds 0, then:
Bitwise Operators
Bitwise operator works on bits and perform bit-by-bit operation. The truth tables for &, |, and ^
are as follows:
Assume if A = 60; and B = 13; now in binary format they will be as follows:
Page 9 of 58
A = 0011 1100
B = 0000 1101
-----------------
~A = 1100 0011
The Bitwise operators supported by C language are listed in the following table. Assume variable
A holds 60 and variable B holds 13, then:
Assignment Operators
There are following assignment operators supported by C language:
Page 10 of 58
operand to the left operand and assign the result to +A
left operand
-= Subtract AND assignment operator, It subtracts C -= A is equivalent to C = C -
right operand from the left operand and assign the A
result to left operand
*= Multiply AND assignment operator, It multiplies C *= A is equivalent to C = C
right operand with the left operand and assign the *A
result to left operand
/= Divide AND assignment operator, It divides left C /= A is equivalent to C = C /
operand with the right operand and assign the A
result to left operand
%= Modulus AND assignment operator, It takes C %= A is equivalent to C = C
modulus using two operands and assign the result %A
to left operand
<<= Left shift AND assignment operator C <<= 2 is same as C = C << 2
>>= Right shift AND assignment operator C >>= 2 is same as C = C >> 2
&= Bitwise AND assignment operator C &= 2 is same as C = C & 2
^= bitwise exclusive OR and assignment operator C ^= 2 is same as C = C ^ 2
|= bitwise inclusive OR and assignment operator C |= 2 is same as C = C | 2
Operators Precedence in C
Operator precedence determines the grouping of terms in an expression. This affects how an
expression is evaluated. Certain operators have higher precedence than others; for example, the
multiplication operator has higher precedence than the addition operator.
For example x = 7 + 3 * 2; here, x is assigned 13, not 20 because operator * has higher
precedence than +, so it first gets multiplied with 3*2 and then adds into 7.
Page 11 of 58
Here, operators with the highest precedence appear at the top of the table, those with the lowest
appear at the bottom. Within an expression, higher precedence operators will be evaluated first.
Operators higher in the chart have a higher precedence, meaning that the C compiler evaluates
them first. Operators on the same line in the chart have the same precedence, and the
"Associativity" column on the right gives their evaluation order.
Page 12 of 58
When variables and constants of different types are combined in an expression then they are
converted to same data type. The process of converting one predefined type into another is called
type conversion.
The compiler converts all operands into the data type of the largest operand.
The sequence of rules that are applied while evaluating expressions are given below:
1. If either of the operand is of type long double, then others will be converted to long
double and result will be long double.
2. Else, if either of the operand is double, then others are converted to double.
3. Else, if either of the operand is float, then others are converted to float.
4. Else, if either of the operand is unsigned long int, then others will be converted to
unsigned long int.
5. Else, if one of the operand is long int, and the other is unsigned int, then
1. if a long int can represent all values of an unsigned int, the unsigned int is
converted to long int.
2. otherwise, both operands are converted to unsigned long int.
6. Else, if either operand is long int then other will be converted to long int.
7. Else, if either operand is unsigned int then others will be converted to unsigned int.
It should be noted that the final result of expression is converted to type of variable on left side
of assignment operator before assigning value to it.
Also, conversion of float to int causes truncation of fractional part, conversion of double to float
causes rounding of digits and the conversion of long int to int causes dropping of excess higher
order bits.
Page 13 of 58
(data_type)expression;
where, data_type is any valid c data type, and expression may be constant, variable or
expression.
For example,
1x=(int)a+b*d;
The following rules have to be followed while converting the expression from one type to
another to avoid the loss of information:
Conditionals
Various methods that C can control the flow of logic in a program. Apart from slight
syntactic variation they are similar to other languages.
One other operator is the unitary - it takes only one argument - not !.
if (expression)
statement
...or:
Page 14 of 58
if (expression)
statement1
else
statement2
...or:
if (expression)
statement1
else if (expression)
statement2
else
statement3
For example:-
int x,y,w;
main()
{
if (x>0)
{
z=w;
........
}
else
{
z=y;
........
}
The ? : operator
The ? (ternary condition) operator is a more efficient form for expressing simple if statements. It
has the following form:
Page 15 of 58
It simply states:
z = (a>b) ? a : b;
if (a>b)
z = a;
else
z=b;
switch (expression) {
case item1:
statement1;
break;
case item2:
statement2;
break;
statementn;
break;
default:
statement;
break;
}
In each case the value of itemi must be a constant, variables are not allowed.
The break is needed if you want to terminate the switch after execution of one choice. Otherwise
the next case would get evaluated. Note: This is unlike most other languages.
We can also have null statements by just including a ; or let the switch statement fall through by
omitting any statements (see e.g. below).
Page 16 of 58
The default case is optional and catches any other cases.
For example:-
switch (letter)
{
case `A':
case `E':
case `I':
case `O':
case `U':
numberofvowels++;
break;
case ` ':
numberofspaces++;
break;
default:
numberofconstants++;
break;
}
In the above example if the value of letter is `A', `E', `I', `O' or `U' then numberofvowels is
incremented.
If none of these is true then the default condition is executed, that is numberofconstants is
incremented.
LOOPs
FOR - for loops are the most useful type. The syntax for a for loop is
Page 17 of 58
The variable initialization allows you to either declare a variable and give it a value or give a
value to an already existing variable. Second, the condition tells the program that while the
conditional expression is true the loop should continue to repeat itself. The variable update
section is the easiest way for a for loop to handle changing of the variable. It is possible to do
things like x++, x = x + 10, or even x = random ( 5 ), and if you really wanted to, you could call
other functions that do nothing to the variable but still have a useful effect on the code. Notice
that a semicolon separates each of these sections, that is important. Also note that every single
one of the sections may be empty, though the semicolons still have to be there. If the condition is
empty, it is evaluated as true and the loop will repeat until something else stops it.
Example:
#include <stdio.h>
int main()
int x;
/* The loop goes while x < 10, and x increases by one every loop*/
printf( "%d\n", x );
getchar();
Page 18 of 58
This program is a very simple example of a for loop. x is set to zero, while x is less than 10 it
calls printf to display the value of the variable x, and it adds 1 to x until the condition is met.
Keep in mind also that the variable is incremented after the code in the loop is run for the first
time.
while ( condition ) { Code to execute while the condition is true } The true represents a boolean
expression which could be x == 1 or while ( x != 7 ) (x does not equal 7). It can be any
combination of boolean statements that are legal. Even, (while x ==5 || v == 7) which says
execute the code while x equals five or while v equals 7. Notice that a while loop is like a
stripped-down version of a for loop-- it has no initialization or update section. However, an
empty condition is not legal for a while loop as it is with a for loop.
Example:
#include <stdio.h>
int main()
printf( "%d\n", x );
getchar();
Page 19 of 58
This was another simple example, but it is longer than the above FOR loop. The easiest way to
think of the loop is that when it reaches the brace at the end it jumps back up to the beginning of
the loop, which checks the condition again and decides whether to repeat the block another time,
or stop and move to the next statement after the block.
DO..WHILE - DO..WHILE loops are useful for things that want to loop at least once. The
structure is
do {
} while ( condition );
Notice that the condition is tested at the end of the block instead of the beginning, so the block
will be executed at least once. If the condition is true, we jump back to the beginning of the
block and execute it again. A do..while loop is almost the same as a while loop except that the
loop body is guaranteed to execute at least once. A while loop says "Loop while the condition is
true, and execute this block of code", a do..while loop says "Execute this block of code, and then
continue to loop while the condition is true".
Example:
#include <stdio.h>
int main()
int x;
x = 0;
Page 20 of 58
do {
} while ( x != 0 );
getchar();
Keep in mind that you must include a trailing semi-colon after the while in the above example. A
common error is to forget that a do..while loop must be terminated with a semicolon (the other
loops should not be terminated with a semicolon, adding to the confusion). Notice that this loop
will execute once, because it automatically executes before checking the condition.
Two keywords that are very important to looping are break and continue. The break command
will exit the most immediately surrounding loop regardless of what the conditions of the loop
are. Break is useful if we want to exit a loop under special circumstances. For example, let's say
the program we're working on is a two-person checkers game. The basic structure of the program
might look like this:
while (true)
take_turn(player1);
take_turn(player2);
Page 21 of 58
This will make the game alternate between having player 1 and player 2 take turns. The only
problem with this logic is that there's no way to exit the game; the loop will run forever! Let's try
something like this instead:
while(true)
{break;}
take_turn(player1);
{break;}
take_turn(player2);
This code accomplishes what we want--the primary loop of the game will continue under normal
circumstances, but under a special condition (winning or exiting) the flow will stop and our
program will do something else.
Continue is another keyword that controls the flow of loops. If you are executing a loop and hit a
continue statement, the loop will stop its current iteration, update itself (in the case of for loops)
and begin to execute again from the top. Essentially, the continue statement is saying "this
iteration of the loop is done, let's continue with the loop without executing whatever code comes
after me." Let's say we're implementing a game of Monopoly. Like above, we want to use a loop
to control whose turn it is, but controlling turns is a bit more complicated in Monopoly than in
checkers. The basic structure of our code might then look something like this:
{player = 1;}
Page 22 of 58
if (is_bankrupt(player))
{continue;}
take_turn(player);
This way, if one player can't take her turn, the game doesn't stop for everybody; we just skip her
and keep going with the next player's turn.
#include<stdio.h>
int main()
{
int i;
for (i = 0; i < 10; i++)
{
printf ("Hello\n");
printf ("World\n");
}
return 0;
}
Note: A single instruction can be placed behind the “for loop” without the curly brackets.
Let’s look at the “for loop” from the example: We first start by setting the variable i to 0. This
is where we start to count. Then we say that the for loop must run if the counter i is smaller then
ten. Last we say that every cycle i must be increased by one (i++).
Page 23 of 58
In the example we used i++ which is the same as using i = i + 1. This is called incrementing. The
instruction i++ adds 1 to i. If you want to subtract 1 from i you can use i--. It is also possible to
use ++i or --i. The difference is is that with ++i (prefix incrementing) the one is added before the
“for loop” tests if i < 10. With i++ (postfix incrementing) the one is added after the test i < 10. In
case of a for loop this make no difference, but in while loop test it makes a difference. But before
we look at a postfix and prefix increment while loop example, we first look at the while loop.
#include<stdio.h>
int main()
{
int counter, howmuch;
scanf("%d", &howmuch);
counter = 0;
while ( counter < howmuch)
{
counter++;
printf("%d\n", counter);
}
return 0;
}
Let’s take a look at the example: First you must always initialize the counter before the while
loop starts ( counter = 1). Then the while loop will run if the variable counter is smaller then the
variable “howmuch”. If the input is ten, then 1 through 10 will be printed on the screen. A last
thing you have to remember is to increment the counter inside the loop (counter++). If you forget
this the loop becomes infinitive.
As said before (after the for loop example) it makes a difference if prefix incrementing (++i) or
postfix incrementing (i++) is used with while loop. Take a look at the following postfix and
prefix increment while loop example:
#include<stdio.h>
int main(void) {
int i;
Page 24 of 58
i = 0;
while(i++ < 5) {
printf("%d\n", i);
}
printf("\n");
i = 0;
while(++i < 5) {
printf("%d\n", i);
}
return 0;
}
The output of the postfix and prefix increment example will look like this:
1
2
3
4
5
1
2
3
4
i++ will increment the value of i, but is using the pre-incremented value to test against < 5.
That’s why we get 5 numbers.
++i will increment the value of i, but is using the incremented value to test against < 5. That’s
why we get 4 numbers.
do
{
do something;
}
while (expression);
Do something first and then test if we have to continue. The result is that the loop always runs
once. (Because the expression test comes afterward). Take a look at an example:
#include<stdio.h>
Page 25 of 58
int main()
{
int counter, howmuch;
scanf("%d", &howmuch);
counter = 0;
do
{
counter++;
printf("%d\n", counter);
}
while ( counter < howmuch);
return 0;
}
#include<stdio.h>
int main()
{
int i;
i = 0;
while ( i < 20 )
{
i++;
if ( i == 10)
break;
}
return 0;
}
In the example above, the while loop will run, as long i is smaller then twenty. In the while loop
there is an if statement that states that if i equals ten the while loop must stop (break).
With “continue;” it is possible to skip the rest of the commands in the current loop and start from
the top again. (the loop variable must still be incremented). Take a look at the example below:
#include<stdio.h>
int main()
{
Page 26 of 58
int i;
i = 0;
while ( i < 20 )
{
i++;
continue;
printf("Nothing to see\n");
}
return 0;
}
int listofnumbers[50];
BEWARE: In C Array subscripts start at 0 and end one less than the array size. For example, in
the above case valid subscripts range from 0 to 49. This is a BIG difference between C and other
languages and does require a bit of practice to get in the right frame of mind.
thirdnumber=listofnumbers[2];
listofnumbers[5]=100;
int tableofnumbers[50][50];
int bigD[50][50][40][30]......[50];
Page 27 of 58
Elements can be accessed in the following ways:
anumber=tableofnumbers[2][3];
tableofnumbers[25][16]=100;
Strings
In C Strings are defined as arrays of characters. For example, the following defines a string of 50
characters:
char name[50];
C has no string handling facilities built in and so the following are all illegal:
char firstname[50],lastname[50],fullname[100];
However, there is a special library of string handling routines which we will come across later.
printf("s",name);
In order to allow variable length strings the 0 character is used to indicate the end of a string.
So we if we have a string, char NAME[50]; and we store the ``DAVE'' in it its contents will look
like:
Strings
Page 28 of 58
The following declaration and initialization create a string consisting of the word "Hello". To
hold the null character at the end of the array, the size of the character array containing the string
is one more than the number of characters in the word "Hello."
If you follow the rule of array initialization then you can write the above statement as follows:
Actually, you do not place the null character at the end of a string constant. The C compiler
automatically places the '\0' at the end of the string when it initializes the array. Let us try to print
above mentioned string:
#include <stdio.h>
int main ()
{
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
return 0;
}
When the above code is compiled and executed, it produces result something as follows:
Page 29 of 58
Concatenates string s2 onto the end of string s1.
3 strlen(s1);
Returns the length of string s1.
4 strcmp(s1, s2);
Returns 0 if s1 and s2 are the same; less than 0 if s1<s2; greater than 0 if s1>s2.
5 strchr(s1, ch);
Returns a pointer to the first occurrence of character ch in string s1.
6 strstr(s1, s2);
Returns a pointer to the first occurrence of string s2 in string s1.
#include <stdio.h>
#include <string.h>
int main ()
{
char str1[12] = "Hello";
char str2[12] = "World";
char str3[12];
int len ;
return 0;
}
When the above code is compiled and executed, it produces result something as follows:
You can find a complete list of c string related functions in C Standard Library
Pointers
Pointers are aptly name: they "point" to locations in memory. Think of a row of safety deposit
boxes of various sizes at a local bank. Each safety deposit box will have a number associated
with it so that you can quickly look it up. These numbers are like the memory addresses of
Page 30 of 58
variables. A pointer in the world of safety deposit box would simply be anything that stored the
number of another safety deposit box. Perhaps you have a rich uncle who stored valuables in his
safety deposit box, but decided to put the real location in another, smaller, safety deposit box that
only stored a card with the number of the large box with the real jewelry. The safety deposit box
with the card would be storing the location of another box; it would be equivalent to a pointer. In
the computer, pointers are just variables that store memory addresses, usually the addresses of
other variables.
The cool thing is that once you can talk about the address of a variable, you'll then be able to go
to that address and retrieve the data stored in it. If you happen to have a huge piece of data that
you want to pass into a function, it's a lot easier to pass its location to the function than to copy
every element of the data! Moreover, if you need more memory for your program, you can
request more memory from the system--how do you get "back" that memory? The system tells
you where it is located in memory; that is to say, you get a memory address back. And you need
pointers to store the memory address.
A note about terms: the word pointer can refer either to a memory address itself, or to a variable
that stores a memory address. Usually, the distinction isn't really that important: if you pass a
pointer variable into a function, you're passing the value stored in the pointer--the memory
address. When I want to talk about a memory address, I'll refer to it as a memory address; when I
want a variable that stores a memory address, I'll call it a pointer. When a variable stores the
address of another variable, I'll say that it is "pointing to" that variable.
C Pointer Syntax
Pointers require a bit of new syntax because when you have a pointer, you need the ability to
both request the memory location it stores and the value stored at that memory location.
Moreover, since pointers are somewhat special, you need to tell the compiler when you declare
your pointer variable that the variable is a pointer, and tell the compiler what type of memory it
points to.
/* two pointers */
int *pointer1, *pointer2;
As I mentioned, there are two ways to use the pointer to access information: it is possible to have
it give the actual address to another variable. To do so, simply use the name of the pointer
without the *. However, to access the actual memory location and the value stored there, use the
Page 31 of 58
*. The technical name for this doing this is dereferencing the pointer; in essence, you're taking
the reference to some memory address and following it, to retrieve the actual value. It can be
tricky to keep track of when you should add the asterisk. Remember that the pointer's natural use
is to store a memory address; so when you use the pointer:
call_to_function_expecting_memory_address(pointer);
then it evaluates to the address. You have to add something extra, the asterisk, in order to retrieve
the value stored at the address. You'll probably do that an awful lot. Nevertheless, the pointer
itself is supposed to store an address, so when you use the bare pointer, you get that address
back.
For example:
#include <stdio.h>
int main()
{
int x; /* A normal integer*/
int *p; /* A pointer to an integer ("*p" is an integer, so p
must be a pointer to an integer) */
The next line then passes *p into printf. *p performs the "dereferencing" operation on p; it looks
at the address stored in p, and goes to that address and returns the value. This is akin to looking
inside a safety deposit box only to find the number of (and, presumably, the key to ) another box,
which you then open.
Notice that in the above example, the pointer is initialized to point to a specific memory address
Page 32 of 58
before it is used. If this was not the case, it could be pointing to anything. This can lead to
extremely unpleasant consequences to the program. For instance, the operating system will
probably prevent you from accessing memory that it knows your program doesn't own: this will
cause your program to crash. If it let you use the memory, you could mess with the memory of
any running program--for instance, if you had a document opened in Word, you could change the
text! Fortunately, Windows and other modern operating systems will stop you from accessing
that memory and cause your program to crash. To avoid crashing your program, you should
always initialize pointers before you use them.
It is also possible to initialize pointers using free memory. This allows dynamic allocation of
memory. It is useful for setting up structures such as linked lists or data trees where you don't
know exactly how much memory will be needed at compile time, so you have to get memory
during the program's execution. We'll look at these structures later, but for now, we'll simply
examine how to request memory from and return memory to the operating system.
The function malloc, residing in the stdlib.h header file, is used to initialize pointers with
memory from free store (a section of memory available to all programs). malloc works just like
any other function call. The argument to malloc is the amount of memory requested (in bytes),
and malloc gets a block of memory of that size and then returns a pointer to the block of memory
allocated.
Since different variable types have different memory requirements, we need to get a size for the
amount of memory malloc should return. So we need to know how to get the size of different
variable types. This can be done using the keyword sizeof, which takes an expression and returns
its size. For example, sizeof(int) would return the number of bytes required to store an integer.
#include <stdlib.h>
Note that it is slightly cleaner to write malloc statements by taking the size of the variable
pointed to by using the pointer directly:
int *ptr = malloc( sizeof(*ptr) );
What's going on here? sizeof(*ptr) will evaluate the size of whatever we would get back from
dereferencing ptr; since ptr is a pointer to an int, *ptr would give us an int, so sizeof(*ptr) will
return the size of an integer. So why do this? Well, if we later rewrite the declaration of ptr the
following, then we would only have to rewrite the first part of it:
float *ptr = malloc( sizeof(*ptr) );
We don't have to go back and correct the malloc call to use sizeof(float). Since ptr would be
pointing to a float, *ptr would be a float, so sizeof(*ptr) would still give the right size!
This becomes even more useful when you end up allocating memory for a variable far after the
point you declare it:
Page 33 of 58
float *ptr;
/* hundreds of lines of code */
ptr = malloc( sizeof(*ptr) );
The concept of the null pointer is frequently used as a way of indicating a problem--for instance,
malloc returns 0 when it cannot correctly allocate memory. You want to be sure to handle this
correctly--sometimes your operating system might actually run out of memory and give you this
value!
There are few important operations, which we will do with the help of pointers very frequently. (a) we
define a pointer variable (b) assign the address of a variable to a pointer and (c) finally access the value at
the address available in the pointer variable. This is done by using unary operator * that returns the value
of the variable located at the address specified by its operand. Following example makes use of these
operations:
#include <stdio.h>
int main ()
Page 34 of 58
/* access the value using the pointer */
Functions
In C, all functions must be written to return a specific TYPE of information and to take in
specific types of data (parameters). This information is communicated to the compiler via a
function prototype.
A Prototype can occur at the top of a C source code file to describe what the function returns
and what it takes (return type and parameter list). When this is the case (occuring at the top of the
file), the function prototype should be followed by a semi-colon
The function prototype is also used at the beginning of the code for the function. Thus the
prototype can occur twice in a C source code file. When the prototype occurs with the code NO
semicolon is used.
Void Functions
If a function does not return a value, then a special "TYPE" is used to tell the computer this. The
return type is "void" (all lower case).
The first is a function that prints information for the user to read. For example (for our purposes),
the printf function is treated as a void function. (In actuality, printf returns an integer which is the
number of characters printed... but we almost always ignore this value.)
Page 35 of 58
The second use of void functions is with "reference" parameters (e.g., Arrays). A reference
parameter is not a copy of the input data, as is so often the case. A reference parameter is an
"alias" for the same bucket in memory as the input data. Thus any change made to a reference
parameter is in fact made to the original variable!
#include <stdio.h>
int main()
{
int x;
int y;
Parameters in C functions
A Parameter is the symbolic name for "data" that goes into a function. There are two types of
parameters in C: Pass by Value, Pass by Reference.
Pass by Value
Pass by Value, means that a copy of the data is made and stored by way of the name of
the parameter. Any changes to the parameter have NO affect on data in the calling
function.
Pass by Reference
A reference parameter "refers" to the original data in the calling function. Thus any
changes made to the parameter are ALSO MADE TO THE ORIGINAL variable.
1. ARRAYS
Arrays are always pass by reference in C. Any change made to the parameter
containing the array will change the value of the original array.
Page 36 of 58
2. The ampersand used in the function prototype.
To make a normal parameter into a pass by reference parameter, we use the "&
param" notation. The ampersand (&) is the syntax to tell C that any changes made
to the parameter also modify the original variable containing the data.
//
//
void
doit( int x )
x = 5;
//
//
int
main()
int z = 27;
doit( z );
Page 37 of 58
printf("z is now %d\n", z);
return 0;
Again, remember the Syntax is to use the '&' in front of the variable. For example:
//
// C using Reference Parameter!
//
void
doit( int & x )
{
x = 5;
}
//
// Test code for passing by a variable by reference
//
int
main()
{
int z = 27;
doit( z );
printf(“z is now %d\n”, z);
return 0;
}
Array Parameter Example
Arrays are always passed by reference in C. They do not use the '&' notation, but are pass by
reference none the less. For example:
void
build_array( int array_variable[], int length_of_array )
{
for (int i=0; i<length_of_array; i++)
{
array_variable[i] = i;
}
}
//
// Test code for passing an array by reference
//
Page 38 of 58
int
main()
{
int values[50];
build_array(values, 50);
return 0;
}
Structures
Structures in C are similar to records in Pascal. For example:
struct gun
{
char name[50];
int magazinesize;
float calibre;
};
NOTE: that gun is a tag for the structure that serves as shorthand for future declarations. We
now only need to say struct gun and the body of the structure is implied as we do to make
the arnies variable. The tag is optional.
Variables can also be declared between the } and ; of a struct declaration, i.e.:
struct gun
{
char name[50];
int magazinesize;
float calibre;
} arnies;
Page 39 of 58
struct's can be pre-initialised at declaration:
To access a member (or field) of a struct, C provides the . operator. For example, to
give arnie more rounds of ammunition:
arnies.magazineSize=100;
agun arnies={"Uzi",30,7};
Here gun still acts as a tag to the struct and is optional. Indeed since we have defined a new data
type it is not really of much use,
agun is the new data type. arnies is a variable of type agun which is a structure.
agun arniesguns[1000];
This gives arniesguns a 1000 guns. This may be used in the following way:
Page 40 of 58
arniesguns[50].calibre=100;
itscalibre=arniesguns[0].calibre;
assigns the calibre of Arnie's first gun to itscalibre.
Unions
A union is a variable which may hold (at different times) objects of different sizes and types. C
uses the union statement to create unions, for example:
union number
{
short shortnumber;
long longnumber;
double floatnumber;
} anumber
defines a union called number and an instance of it called anumber. number is a union tag and
acts in the same way as a tag for a structure.
printf("%ld n",anumber.longnumber);
When the C compiler is allocating memory for unions it will always reserve enough room for the
largest member (in the above example this is 8 bytes for the double).
In order that the program can keep track of the type of union variable being used at a given time
it is common to have a structure (with union embedded in it) and a variable which flags the union
type:
An example is:
typedef struct
Page 41 of 58
{ int maxpassengers;
} jet;
typedef struct
{ int liftcapacity;
} helicopter;
typedef struct
{ int maxpayload;
} cargoplane;
typedef union
{ jet jetu;
helicopter helicopteru;
cargoplane cargoplaneu;
} aircraft;
typedef struct
{ aircrafttype kind;
int speed;
aircraft description;
} an_aircraft;
This example defines a base union aircraft which may either be jet, helicopter, or
cargoplane.
In the an_aircraft structure there is a kind member which indicates which structure is being held
at the time.
Enumerated Types
Enumerated types contain a list of constants that can be addressed in integer values.
NOTE: As with arrays first enumerated name has index value 0. So mon has value 0, tues 1, and
so on.
Page 42 of 58
We can define other values:
Coercion or Type-Casting
C is one of the few languages to allow coercion, that is forcing one variable of one type to be
another type. C allows this using the cast operator (). So:
int integernumber;
float floatnumber=9.87;
integernumber=(int)floatnumber;
And:
int integernumber=10;
float floatnumber;
floatnumber=(float)integernumber;
Coercion can be used with any of the simple data types including char, so:
Page 43 of 58
int integernumber;
char letter='A';
integernumber=(int)letter;
Another use is the make sure division behaves as requested: If we have two
integers internumber and anotherint and we want the answer to be a float then :
e.g.
floatnumber =
(float) internumber / (float) anotherint;
Static Variables
A static variable is local to particular function. However, it is only initialised once (on the first
call to function).
Also the value of the variable on leaving the function remains intact. On the next call to the
function the the static variable has the same value as on leaving.
To define a static variable simply prefix the variable declaration with the static keyword. For
example:
main()
{ int i;
for (i=0;i<5;++i)
stat();
}
Page 44 of 58
stat()
{ int auto_var = 0;
auto_var, static_var);
++auto_var;
++static_var;
Output is:
auto_var = 0, static_var= 0
auto_var = 0, static_var = 1
auto_var = 0, static_var = 2
auto_var = 0, static_var = 3
auto_var = 0, static_var = 4
Clearly the auto_var variable is created each time. The static_var is created once and remembers its value.
Files
Files are the most common form of a stream.
The first thing we must do is open a file. The function fopen() does this:
fopen returns a pointer to a FILE. The name string is the name of the file on disc that we wish to
access. The mode string controls our type of access. If a file cannot be accessed for any reason
a NULL pointer is returned.
Page 45 of 58
To open a file we must have a stream (file pointer) that points to a FILE structure.
stream = fopen("myfile.dat","r");
correctly:
"r")) == NULL)
"myfile.dat");
exit(1);
......
These are similar to printf and scanf except that data is read from the stream that must have been
opened with fopen().
Page 46 of 58
The stream pointer is automatically incremented with ALL file read/write functions. We do
not have to worry about doing this.
char *string[80]
FILE *stream, *fopen();
int putc(char ch, FILE *s), int fputc(char ch, FILE *s)
getc is defined as preprocessor MACRO in stdio.h. fgetc is a C library function. Both achieve the
same result!!
fprintf(stderr,"Cannot Compute!!\n");
fscanf(stdin,"%s",string);
For Example:
Page 47 of 58
sprintf( miles_per_litre,"Miles per litre
= %2.3f", miles/full_tank);
feof()
-- returns true if the stream is currently at the end of the file. So to read a stream,fp, line
by line you could do:
while ( !feof(fp) )
fscanf(fp,"%s",line);
ferror()
-- reports on the error state of the stream and returns true if an error has occurred.
clearerr()
-- resets the error indication for a given stream.
fileno()
-- returns the integer file descriptor associated with the named stream.
This means we are now using binary (and not text) files.
Instead of file pointers we use low level file handle or file descriptors which give a unique
integer number to identify each file.
int open(char *filename, int flag, int perms) -- this returns a file descriptor or -1 for a fail.
Page 48 of 58
The flag controls file access and has the following predefined in fcntl.h:
The function:
are used to read/write a specific number of bytes from/to a file (handle) stored or to be put in the
memory location specified by buffer.
read and write return the number of bytes read/written or -1 if they fail.
#include<stdio.h>
#include<fcntl.h>
float bigbuff[1000];
{ int fd;
int bytes_read;
int file_length;
Page 49 of 58
perror("Datafile");
exit(1);
}
if ( (bytes_read = read(fd,&file_length,
sizeof(int))) == -1)
{ /* error reading file */...
exit(1);
}
if ( file_length > 999 ) {/* file too big */ ....}
if ( (bytes_read = read(fd,bigbuff,
file_length*sizeof(float))) == -1)
{ /* error reading open */...
exit(1);
}
}
fopen and freopen opens the file whose name is in the string pointed to by filename and
associates a stream with it. Both return a pointer to the object controlling the stream, or if the
open operation fails a null pointer. The error and end-of-file indicators are cleared, and if the
open operation fails error is set. freopen differs from fopen in that the file pointed to by stream is
closed first when already open and any close errors are ignored.
mode for both functions points to a string consisting of one of the following sequences:
r open a text file for reading
w truncate to zero length or create a text file for writing
a append; open or create text file for writing at end-of-file
rb open binary file for reading
wb truncate to zero length or create a binary file for writing
ab append; open or create binary file for writing at end-of-file
r+ open text file for update (reading and writing)
w+ truncate to zero length or create a text file for update
a+ append; open or create text file for update
r+b or open binary file for update (reading and writing)
rb+
w+b or truncate to zero length or create a binary file for update
wb+
Page 50 of 58
Opening a file with read mode ('r' as the first character in the mode argument) fails if the file
does not exist or cannot be read.
Opening a file with append mode ('a' as the first character in the mode argument) causes all
subsequent writes to the file to be forced to the then-current end-of-file, regardless of intervening
calls to the fseek function. In some implementations, opening a binary file with append mode ('b'
as the second or third character in the above list of mode arguments) may initially position the
file position indicator for the stream beyond the last data written, because of null character
padding.
When a file is opened with update mode ('+' as the second or third character in the above list of
mode argument values), both input and output may be performed on the associated stream.
However, output may not be directly followed by input without an intervening call to the fflush
function or to a file positioning function (fseek, fsetpos, or rewind), and input may not be
directly followed by output without an intervening call to a file positioning function, unless the
input operation encounters end-of-file. Opening (or creating) a text file with update mode may
instead open (or create) a binary stream in some implementations.
When opened, a stream is fully buffered if and only if it can be determined not to refer to an
interactive device.
Closing Files
#include <stdio.h>
The fclose function causes the stream pointed to by stream to be flushed and the associated file
to be closed. Any unwritten buffered data for the stream are delivered to the host environment to
be written to the file; any unread buffered data are discarded. The stream is disassociated from
the file. If the associated buffer was automatically allocated, it is deallocated. The function
returns zero if the stream was successfully closed or EOF if any errors were detected.
Page 51 of 58
Other file access functions
#include <stdio.h>
If stream points to an output stream or an update stream in which the most recent operation was
not input, the fflush function causes any unwritten data for that stream to be deferred to the host
environment to be written to the file. The behavior of fflush is undefined for input stream.
If stream is a null pointer, the fflush function performs this flushing action on all streams for
which the behavior is defined above.
The fflush functions returns EOF if a write error occurs, otherwise zero.
The reason for having a fflush function is because streams in C can have buffered input/output;
that is, functions that write to a file actually write to a buffer inside the FILE structure. If the
buffer is filled to capacity, the write functions will call fflush to actually "write" the data that is
in the buffer to the file. Because fflush is only called every once in a while, calls to the operating
system to do a raw write are minimized.
The fclose function causes the stream pointed to by stream to be flushed and the associated file
to be closed. Any unwritten buffered data for the stream are delivered to the host environment to
be written to the file; any unread buffered data are discarded. The stream is disassociated from
the file. If the associated buffer was automatically allocated, it is deallocated. The function
returns zero if the stream was successfully closed or EOF if any errors were detected.
Page 52 of 58
If stream points to an output stream or an update stream in which the most recent operation was
not input, the fflush function causes any unwritten data for that stream to be deferred to the host
environment to be written to the file. The behavior of fflush is undefined for input stream.
If stream is a null pointer, the fflush function performs this flushing action on all streams for
which the behavior is defined above.
The fflush functions returns EOF if a write error occurs, otherwise zero.
The fseek function sets the file position indicator for the stream pointed to by stream.
For a binary stream, the new position, measured in characters from the beginning of the file, is
obtained by adding offset to the position specified by whence. Three macros in stdio.h called
SEEK_SET, SEEK_CUR, and SEEK_END expand to unique values. If the position specified by
whence is SEEK_SET, the specified position is the beginning of the file; if whence is SEEK_END, the
specified position is the end of the file; and if whence is SEEK_CUR, the specified position is the
current file position. A binary stream need not meaningfully support fseek calls with a whence
value of SEEK_END.
For a text stream, either offset shall be zero, or offset shall be a value returned by an earlier call to
the ftell function on the same stream and whence shall be SEEK_SET.
The fseek function returns nonzero only for a request that cannot be satisfied.
The ftell function obtains the current value of the file position indicator for the stream pointed to
by stream. For a binary stream, the value is the number of characters from the beginning of the
file; for a text stream, its file position indicator contains unspecified information, usable by the
fseek function for returning the file position indicator for the stream to its position at the time of
the ftell call; the difference between two such return values is not necessarily a meaningful
measure of the number of characters written or read.
Page 53 of 58
If successful, the ftell function returns the current value of the file position indicator for the
stream. On failure, the ftell function returns -1L and stores an implementation-defined positive
value in errno.
The stdio.h library has a variety of functions that do some operation on files besides reading and writing.
The remove function causes the file whose name is the string pointed to by filename to be no longer
accessible by that name. A subsequent attempt to open that file using that name will fail, unless it
is created anew. If the file is open, the behavior of the remove function is implementation-defined.
The remove function returns zero if the operation succeeds, nonzero if it fails.
The rename function causes the file whose name is the string pointed to by old_filename to be
henceforth known by the name given by the string pointed to by new_filename. The file named
old_filename is no longer accessible by that name. If a file named by the string pointed to by
new_filename exists prior to the call to the rename function, the behavior is implementation-defined.
The rename function returns zero if the operation succeeds, nonzero if it fails, in which case if the
file existed previously it is still known by its original name.
Page 54 of 58
The fread function reads, into the array pointed to by ptr, up to nmemb elements whose size is
specified by size, from the stream pointed to by stream. The file position indicator for the stream
(if defined) is advanced by the number of characters successfully read. If an error occurs, the
resulting value of the file position indicator for the stream is indeterminate. If a partial element is
read, its value is indeterminate.
The fread function returns the number of elements successfully read, which may be less than
nmemb if a read error or end-of-file is encountered. If size or nmemb is zero, fread returns zero and
the contents of the array and the state of the stream remain unchanged.
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
The fwrite function writes, from the array pointed to by ptr, up to nmemb elements whose size is specified
by size to the stream pointed to by stream. The file position indicator for the stream (if defined) is
advanced by the number of characters successfully written. If an error occurs, the resulting value of the
file position indicator for the stream is indeterminate. The function returns the number of elements
successfully written, which will be less than nmemb only if a write error is encountered.
Exercises
1. Input two numbers and work out their sum, average and sum of the squares of the
numbers.
2. Write a program that works out the largest and smallest values from a set of 10 inputted
numbers.
3. Write a program to read a "float" representing a number of degrees Celsius, and print as a
"float" the equivalent temperature in degrees Fahrenheit. Print your results in a form such
as 100.0 degrees Celsius converts to 212.0 degrees Fahrenheit.
4. Write a program to read a number of units of length (a float) and print out the area of a
circle of that radius. Assume that the value of pi is 3.14159
Page 55 of 58
5. Given as input a floating (real) number of centimeters, print out the equivalent number of
feet (integer) and inches (floating, 1 decimal), with the inches given to an accuracy of one
decimal place.
Assume 2.54 centimeters per inch, and 12 inches per foot.
If the input value is 333.3, the output format should be:
333.3 centimeters is 10 feet 11.2 inches.
6. Given as input an integer number of seconds, print as output the equivalent time in hours,
minutes and seconds. Recommended output format is something like
7. 7322 seconds is equivalent to 2 hours 2 minutes 2 seconds.
8. Write a program to read two characters, and print their value when interpreted as a 2-digit
hexadecimal number. Accept upper case letters for values from 10 to 15.
9. Read an integer value. Assume it is the number of a month of the year; print out the name
of that month.
10. Given as input three integers representing a date as day, month, year, print out the
number day, month and year for the following day's date.
11. Typical input: 28 2 1992 Typical output: Date following 28:02:1992 is 29:02:1992
12. Read a positive integer value, and compute the following sequence: If the number is
even, halve it; if it's odd, multiply by 3 and add 1. Repeat this process until the value is 1,
printing out each value. Finally print out how many of these operations you performed.
Inital value is 9
Next value is 28
Next value is 14
Next value is 7
Next value is 22
Next value is 11
Next value is 34
Next value is 17
Next value is 52
Next value is 26
Next value is 13
Next value is 40
Next value is 20
Next value is 10
Next value is 5
Page 56 of 58
Next value is 16
Next value is 8
Next value is 4
Next value is 2
Final value 1, number of steps 19
If the input value is less than 1, print a message containing the word
Error
and perform an
exit( 0 );
13. Calculate simple interest.
14. Write a program to print the multiplication table for the given number.
15. Find whether a given number is even or odd.
16. Find the large number from the given three numbers.
17. Write a program to find the number of vowels, length of string, reverse of string
18. Write a program to find the reverse of given number
19. Write a program to find the largest and smallest element in an array.
20. Write a program to sort an array.
21. Write a program to find whether a given number is Prime or not.
22. Find whether given two strings are anagram or not.
23. Write a program to perform matrix addition, multiplication.
24. Write a program to accept a string and display its alternate characters in reverse.
25. Write a program to find factorial of given number
26. Write program to find Fibonacci series.
27. Write a program to copy the contents of one file to another file.
28. Write a program to display number in binary format.
29. Write a program to rotate, shift by n bit position right of a given unsigned char.
30. Write a program to solve the system of linear equations.
31. Convert a number in one base to another base
32. Write a program for multiple precision integer arithmetic.
33. Develop a game in which the use has to guess whether the next number is greater than the
previous number or not, if his guess is correct he won the game.
34. Write a program to maintain the data of the students.
Page 57 of 58
References
1. Brian W. Kernighan and Dennis M. Ritchie The C programming Language, Published by
Prentice-Hall in 1988 , ISBN 0-13-110362-8 (paperback), ISBN 0-13-110370-9
2. Paul Deitel, Harvey Deitel C: How to Program, 7th Edition, ISBN-13: 978-0132990448,
Deitel & Associates, Inc.
3. Balaguruswamy, Programming in ANSI C, Tata McGraw-Hill Education, 2008, ISBN
978-0-07-064822-7
4. http://www.cs.cf.ac.uk/Dave/C/CE.html
5. http://www.cprogramming.com/tutorial.html
6. http://www.tutorialspoint.com/cprogramming/
Page 58 of 58