You are on page 1of 111

C PROGRAMMING CHARACTERISTICS

Correctness- The extent to which a program


satisfies its specification and fulfills the customers mission objectives .

Reliability- The extent to which a program can


be expected to perform its intended function with required precision .

Efficiency- The amount of computing resources


and code required by a program to perform its function.

Integrity-The extent to which the access to data

by unauthorized persons, can be controlled. Usability- The effort required to learn, operate, prepare input, and interpret output of the program. Maintainability -The effort required to locate and fix an error in a program. Flexibility- The effort required to modify an operations program. Testability-The effort required to test a program to ensure that it performs its intended function.

How to achieve the good programming goals

Analyze the program carefully. Break the program into small modules called building blocks. Use meaningful names for variables and functions. Follow uniform naming conventions. Let each block do only its specified task and nothing else. Every building block should have a header information block. At least 30 % of the statements should be commented. Comments should be short and enlightening

DATA TYPES AND OPERATORS

char : A single byte, capable of holding one character in the local character set. int : An integer, typically reflecting the natural size of integers on the host machine. float : A single precision floating point. double: Double precision floating point. To accept and print a double in a program

In addition there are a number of qualifiers that con be applied to these basic types. short and long to integers These qualifiers provide different lengths of integers, short is often 16 bits and long 32 bits, and int either 16 or 32 bits depending on the compiler. signed and unsigned to integer or character and long double specifies extended precision floating point.

OPERATORS

Arithmetic operators. Relational operators and logical operators. Increment and decrement operators . Bitwise operators. Assignment operator Ternary operator or conditional operator.

Arithmetic operators

The arithmetic operators in C are +, addition -, subtraction * , multiplication /, division. There is a % operator called modulus operator.

Relational operators

The relational operators are > (greater than ), < ( lesser than ), >= (greater than or equal to), '<= (lesser than or equal to), == (equal to) and != (not equal to) The result of two values connected by these operators is either true (non-zero) or false (O).

Logical operators

The logical operators are && (and) and II (inclusive or) . Expressions connected by logical operators are evaluated from left to right and evaluation is stopped as soon as truth or falsehood of the result is known.

Increment and decrement operators

Two unusual operators ++ and are provided by C for incrementing and decrementing variables
The ++ operator (incrementing operator) when used with the variable adds 1 to the variable . The -- operator (decrementing operator) when used with the variable subtracts 1 from the variable .

The incremental operators can be used either as prefix operators, where the operation is done before the value of the variable is used, or as postfix operators where the operation is done after the value of the variable is used

Assignment Operator

The assignment operator is = .This operator copies the value on the righthand side into the variable or the address on the left hand side .The result of the operation has a value, which is the value that is transferred and which can be used in other expressions.

Conditional operator

Conditional expressions are a shorthand way of selecting one out of the two values based on the value of another expression. The syntax is :

exp1 ? exp2 : exp3 If expression exp1 is true than the result is value of expression exp2 otherwise it is the value of expression exp3.

CONTROL FLOW STATEMENTS

Control flow statements in a language specify the computational order in the program.

The commonly used control flow statements in C are

conditional : if-else, else-if, switch Loops: for, while, do-while.

If-Else

This is used to express decisions. The if statement has the following syntax, If (expression) statement1 ; else statement2 ; The expression is evaluated, if it is true, statement l is executed . If it is false, and if there is an else part (the else part being optional) statement2 is executed instead.

Else-if

A multiway decision is written using elseif. if (expression 1) statement1; else if(expression2) statement2; else if(expression3) statement3 ; else statement4;

Switch

The switch statement is a multiway decision based on a single expression. switch (expression) case constant_expression : statements case constant_expression : statements case constant_expression : statements default : statements

While

The while loop has the form :


while ( expression ) statements ;

where statements will be executed as long as expression evaluates to a non-zero value

FOR STATEMENT

The for statement has the following syntax : for( expression 1; expression2 ; expression3) statements ; Expression l and expression3 are assignments and expression2 is a relational expression. Ali three expressions are optional ; however the semicolons are not.

The for statement is equivalent to the following while loop : expression 1 ; while ( expression 2) statement ; expression 3 ;

Do-While

The do-while loop in C provides a loop termination at the end of the loop. Its syntax is do statement while( expression ); while statement will be executed at least once and then as long as expression remains non-zero thereafter.

Break

The 'break statement provides an early exit from for, while and do loops, just as from switch A break, causes the innermost loop or switch to be exited immediately.

Continue
The continue statement will result in the next iteration of the enclosing for, while or do loop to execute. The continue statement applies only to loops and not to switch.

Goto

C does contain the goto statement but since its use is not looked upon with favor, it will not be discussed in detail . Goto abandons processing in same deeply nested structure such as coming out of two or more loops at once which is not possible by break Its syntax is : goto NAME; NAME : statement The goto statement transfers control directly to the statement !hat has NAME as its label.

In programming we normally break a task into separate functions because it is easier to deal with smaller tasks that may be independent of other parts of the program. A normal C program is a collection of functions. The main program, called main, is a function that may invoke other functions. A function will process information passed to it from the, calling portion of the program, and return a single value. Information is passed to the function via special identifiers called arguments also called parameters and returned via the return statement.

FUNCTIONS

Call by Value

C passes arguments to functions by value. That is, C makes a copy of the argument and passes the copy to the function. If the function modifies a parameter, the function is modifying only a copy of the original argument.

Call by Reference

Often we want the function to have access to the original argument in the invoking function instead of its copy. In this case we pass the argument by reference; that is, we pass the address of the argument as a parameter for the function. Since the function has the address of the actual argument, it can change the value of this argument.

STORAGE CLASSES

Automatic Variables External Variables Static Variables

Automatic Variables

These variables are always declared within a function and are local to the function in which they are declared. Their scope is confined only to that function. Any variable declared within a function is an automatic variable unless a different storage-class is included within the declaration

External Variables

These variables are not confined to single functions. Their scope extends from the point of definition through the remainder of' the program. They are also called global variables, They can be accessed from any function that falls within the scope of the, entire program. They are permanent so they retain values from one function invocation to the next.

Static Variables

The variables which retain their values throughout the life of the program are called static variables. lf a function is exited and re-entered later the static variables defined within that function, will retain their farmer values. Static variables are defined within individual functions and have same scope as automatic variables.

Pointers

What is a pointer? A pointer is a group of memory locations that stores the address of another memory location.

The operators used here are the unary operators * and & . The unary operator * is the indirection or dereferencing operator ; when applied to a pointer , it accesses the object the pointer points to .

The unary operator & gets the address of the memory location where a variable resides. e.g. &a gets the memory address of the variable a .

Declaration of pointers

Pointers are declared using following syntax :


char a[10],ch; int *p;i=NULL /* pi is a pointer to integer, initialized to null so that it does not point to any arbitrary memory location */

char *pca= a; /* pca is a pointer to char , initialised to point to the first element of array a[10] i.e a[0]*/
float *pf; /* un-initialized pointer . Often the cause of errors. */ char *pc=&ch; /* pc is a pointer to char , initialized to point to ch */

the unary operator & gives the address of an object It cannot be applied to expressions, constants or register variables.

Examples :
int x=1,y=2; /* x and y are integers and initialised to 1 and 2 respectively */ int *ip; /* ip is a pointer to int or *ip is an integer */ ip = &x; /* ip now points to x */

y = *ip; /* The value of y is now 1(the value of x) */ *ip = 0; /* x is now zero (since ip was pointing to x) */ a pointer to void is used to hold any type of pointer but cannot be dereferenced itself .

Precedence of Address and Dereferencing Operators

& and dereferencing * operators have equal precedence. they associate from right to left. You have to be careful when you mix * with ++ or -- in a pointer expression.

The unary operators * and & bind more tightly than arithmetic operators , so the assignment y = *ip + 1 takes whatever ip points at , adds 1 , and assigns the result to y . This can be understood as

Before y = *ip + 1 +1

After y = *ip

ip

4000

ip

4000

4000 2

4000

Difference between pointers and ordinary variables

For ordinary variables the C compiler allocates memory on its own at compilation time. memory location by assigning the address of some other variable to the pointer or by allocating memory when the program runs.

Allocation of memory is done by using the C function malloc . The syntax of malloc is: pointer=(datatype *) malloc (size of memory to be allocated) e.g. to allocate 10 bytes of memory to the pointer to integer *ip: ip=(int *) malloc (10); e.g. to free the memory allocated to the pointer to integer *ip: free(ip);

C Memory model

The C language views a programs memory as being divided into three pieces : Text Area : The area for the program code(instructions). Data Area : For static variables and data. Dynamic Area : For the automatic variables ,for dynamic allocation and for function call bookkeeping.

The following diagram shows a conceptual model of the memory layout for a C program. Text Data Dynamic

Besides the instructions which make up the program , other items may also be placed into the text area. Constant items such as strings , jump tables for switch statements , and floating point constants are occasionally also allocated in the text area. The text section is not modifiable.

Data objects which have a lifetime that persists for the entire program are placed in the data area. In many implementations , strings , floating point constants , and switch tables are also placed in this area. The data area is sometimes divided into two sections , an area for explicitly initialised data and an area for uninitialised global and static data.

The dynamic area includes automatic variables , function housekeeping information , and storage which is used when objects are created using the memory allocation routines. The dynamic area is often divided into two sections . The first is the stack .

The stack is the area where automatic variables are dynamically allocated for each function when the function is invoked. The stack is also the area where , in almost all systems , the actual arguments are pushed for function calls.

Function housekeeping information is also pushed onto the stack when the called function is entered. The stack is also the area where compiler-generated temporaries (used during complex computations and some optimizations) are kept. The second part of the dynamic data area is the heap , where user controlled dynamic space allocations take place.

A simplified memory model can be considered for the understanding of pointer concepts as below: Stack : The definition given earlier holds true here too. Heap: This definition will be slightly modified . It is the entire memory not allocated to the stack and not in use by the Operating System . Memory from the heap is allocated by the Operating System .

The pointer concepts can best be understood by the following example program: #include<stdio.h> int Y; void main() { int X,*pX,**pX; X = 10; Y = 1000; pX = &X; ppX = &pX; f1(pX); printf(%d,*pX); f2(pX); printf(%d,*pX); f3(ppX); printf(%d,*pX); f4(ppX); printf(%d,*pX); f5(ppX); printf(%d,*pX); }

MACROS
#include <stdio.h> #define area length*width main ( ) { int length, width; printf (length = ); scanf (%d, &length); printf (width = ); scanf (%d, &width); printf (area = %d, area); }

The scope of a macro definition extends from its point of definition to the end of the file. A macro defined in one file is not recognized within another file.

Multiline macros can be defined by placing a backward slash (\) at the end of each line except the last. This feature permits a single macro (i.e., a single identifier) to represent a compound statement.

A macro definition may include arguments, which are enclosed in parentheses. The left parenthesis must appear immediately after the macro name, i.e. there can be no space separating the macro name from the left parenthesis. When a macro is defined in this manner, its appearance within a program resembles a function call.

Macros are sometimes used in place of functions within a program. The use of a macro in place of a function eliminates the time delays associated with the function calls. If a program contains many repeated functions calls, the time saving resulting from the use of macros can become significant.

On the other hand a program that contains several references to the same macro may become unreasonably long. We are therefore faced with a tradeoff between execution speed and size of the compiled object program.

The use of a macro is most advantageous in applications where there are relatively few function calls but the functions is called repeatedly (e.g., a single function call within a loop). When passing arguments to a macro, the number of arguments will be checked, but their data types will not. Thus, there is less error checking than with a function call.

A macro identifier is not associated with an address, so that a macro cannot be utilized as a pointer. Thus, a macro identifier cannot be passed to a function as an argument in the same sense that a function can be passed to another function as an argument . Moreover, a macro cannot call itself recursively.

FILES

Many applications require that information be written to or read from an auxillary storage device. Such information is stored on the device in the form of a data file.Data files allow us to store information permanently and to access and alter the information whenever necessary.

There are two types of data files called stream-oriented(or standard) data files and system-oriented(or low-level) data files.

Stream-oriented data files


Opening and Closing a file FILE *ptvar; where FILE is of structure type which establishes the buffer area and ptvar is a pointer variable that indicates the beginning of the buffer area.

The pointer ptvar is referred to as stream pointer. The library functions fopen and fclose are used to open and close a file. fopen:syntax ptvar=fopen(file_name,file_type); file_type represents the manner in which the data file will be utilized.

The file_type must be one of the strings as shown in the table: r Open an existing file for reading only. w Open a new file for writing only(if the file exists it will be destroyed and a new file will be created in its place) a Open an existing file for adding new information at the end of the file.If the file does not exist a new file is created.

r+ Open an existing file for both reading and writing. w+ Open a new file for both reading and writing(if the file already exists it will be destroyed and a new file will be created in its place) a+ Open an existing file for both reading and appending.A new file will be created if the file does not exist.

Stream-oriented data files can be further divided into two categories: 1. Formatted data files 2. Unformatted data files

Formatted data files These files comprise of consecutive characters.


The following functions are available for these files:

1. int fgetc(FILE *stream) This reads a character from a data file. This function returns the: next character of stream or EOF if end of file or error occurs.

2. int fputc(int c,FILE *stream) This function writes a character c to a data file . It returns: the character written or EOF if end of file for error

A simple program #include<stdio.h> main() { FILE *fp; /*define a pointer to a predefined structure FILE */ char c; fp=fopen(test.dat,w); /*open the file for writing only*/ do { c=getchar(); fputc(c,fp); /* write the contents of c into the file*/ }while(c!=\n); fclose(fp); /*close the data file*/

type

fp=fopen(test.dat,r); /*open the file for reading only*/ if(fp==NULL) printf(cannot open file); do { c=fgetc(fp); /* read character by character from file */ putc(c); }while(c!=\n); fclose(fp); }

3. char *fgets(char *s,int n,FILE *stream) This function reads at most the next n-1 characters into the array s,stopping if a newline is encountered ;the newline is included in the array,which is terminated by \0. It returns: the array s or NULL if end of file or error occurs

4. int fputs(const char *s,FILE *stream) This function writes the string s on stream It returns non-negative or EOF for an error Like the above example for fgetc() and fputc() these two functions can also be used.

When data files contain records that include various combinations of numeric and character information the functions fscanf and fprintf can be used.They are analogous to the scanf and printf functions.
int fscanf(FILE *stream,const char *format,......) It permits formatted data to be read from a data file.

Consider an example #include <stdlib.h> #include <stdio.h> int main(void) { int i; printf("Input an integer: "); /* read an integer from the standard input stream */ if (fscanf(stdin, "%d", &i)) printf("The integer read was: %i\n", i); else { fprintf(stderr, "Error reading an integer from stdin.\n"); exit(1); } return 0; }

6.int fprintf(FILE *stream,const char *format,.....) It permits formatted data to be written to a data file.

Consider an example: #include <stdio.h> int main(void) { FILE *stream; int i = 100; char c = 'C'; float f = 1.234; stream = fopen("DUMMY.FIL", "w+"); /* open a file for update */ fprintf(stream, "%d %c %f", i, c, f); /* write some data to the file */ fclose(stream); /* close the file */ return 0; }

Unformatted data files These files comprise of blocks of data containing contiguous bytes of information. These blocks represent more complex data structures such as arrays and structures. Hence,it may be desirable to read the entire block from the data file or write the entire block to the data file rather than reading or writing the individual components within each block seperately.

The library functions fread and fwrite are intended to be used in situation of this type. 1. size_t fread(void *ptr,size_t size,size_t nobj,FILE *stream)
fread reads from stream into the array ptr at most non objects of size size. fread returns the number of objects read ;this may be less than the number requested. feof and ferror must be used to determine status.

2. size_t fwrite(const void *ptr,size_t size,size_t nobj,FILE *stream) fwrite writes from array ptr ,nobj objects of size size on stream. It returns the number of objects written ;which is less than nobj on error. End of file is detected using feof library .This function returns a nonzero value (TRUE) if an end-of-file condition has been detected and a value of zero(FALSE) if an end-of-file is not detected.

Data Structures

Languages provides the intial level of abstraction by giving you different fundamental data types so that you can access data. A data type is a term which refers to the kinds of data that variables may hold in a programming language. A data structure is a group of items in which each item is identified by its own identifier,each of which is known as a member of the structure.The common data structures available are : stacks,queues,lists and trees.

STACK

The list that grows and shrinks at same end Stack uses LAST IN FIRST OUT.

Functions necessary to implement a stack :

#include<stdio.h> #define STACK_SIZE 20 int stack[STACK_SIZE]; integers*/ int top=-1;

/*space for stacking /*top_of_stack is

defined as global variable for a global stack */ /*Function to check whether the stack is full */ int stack_full() { if(top==STACK_SIZE) return(1); else return(0); }

/* Function to check whether the stack is empty */ int stack_empty() { if(top==-1) return(1); else return(0); } /*Function to push or add an element on the stack.*/ void push(int number) { stack[++top]=number; /*add element on top of stack */ }

/* Function to pop an element from the stack*/ int pop() { int number; number=stack[top]; /*remove top element from stack */ top--; return(number); }

QUEUE

List that grows from one end and shrinks from the other Queues use FIRST IN FIRST OUT.

A queue is an ordered collection of items from which items may be deleted at one end (called the front of the queue) and into which items may be inserted at the other end (called the rear of the queue).

/* Function to determine status of queue i.e. if (FRONT = REAR) */ int is_q_empty() { if(rear==front) return(1); else return(0); }

/*Function to determine status of queue i.e. if (REAR > MAX) */ int is_q_full() { if(rear==n) return(1); else return(0); }

/* Function to add an element to the queue*/

void addq(int item) { if (!is_q_full()) q[++rear] = item; }

/* Function to delete an element from the queue*/ int deleteq(void) { if (!is_q_empty()) return q[++front]; }

Circular Queue

Is same as queue but when the rear pointer reaches the end of the queue and if there is space available at the front of the queue then insertion of elements begin from the front of the queue.

/* Function to add an element to the circular queue*/ void addsq(int item) { rear = (rear+1) % n; /* Advance Rear Clockwise */ if (!is_q_full()) q[rear] = item; /* Insert In The Queue */ }

/* Function to delete an element from the circular queue*/ int deleteq(void) { if (!is_q_empty()) { front = (front + 1) % n; /* Advance Front

Clockwise*/ return q[front];

LINKED LISTS

Linked list is used where arrays fall short. This happens because rays are to be declared before program starts execution, i.e it is a static declaration. Lists can insert and delete new elements at any arbitrary position.

In 'C' a linked list can be very easily structured, with the use of self referential structures. A global pointer variable list_header is used to point to the linked list.

This list pointer should always point to the starting node so that one can traverse along the list in one direction. typedef struct list { int data ; /*all the data fields*/ struct list *next ; } List;

Pictorial representation of a linked list


NULL Head

Data Part

Pointer Part

Functions required to implement a linked list are: 1>empty_list() Checks whether the list is empty. 2>list_node() Function to allocate a node and to initialize it. 3>insert() To insert a node in the list. 4>delete() To delete a node from the list. 5>print() To print the contents of the list in sequential order. 6>free() To free all the elements of the list.

Example source code for these operations typedef struct list { int data ; /*all the data fields*/ struct list *next ; } List;

List *list_header=NULL; /*Function to check whether the list is empty*/ int empty_list() { if(list_header == NULL) return(1); else return(0); }

/*Function to allocate a node and to initialize it*/ List *list_node(int no) { List *l; l=(List *)malloc(sizeof(List)); l->num=no; l->next=NULL; return(l); }

/*Function to add a new node at the beginning of the list */ void insert(int no) { List *l; l=list_node(no); l->next=list_header; list_header=l; }

/*Function to delete first element from the list */ void delete(int *no) { List *temp; *no=list_header->num; temp=list_header->next; free(list_header); list_header=temp; }

/*Function to print the value of of every node*/ void print() { List *t; for(t=list_header;t!=NULL;t=t->next) printf(%d,t->num); }

/*Function to free memory allocated dynamically*/ void free() { List *t,*tmp; for(t=list_header;t!=NULL;t=t->next) { tmp=t->next; free(t); t=tmp; } }

DOUBLY LINKED LISTS

To traverse in both directions in a link list, you will have to keep one more reference for the previous structure. For example: struct double { int data; struct double *next; struct double *previous; };

You might also like