ADVANCED C PROGRAMMING 3 0 0 100
Unit – I Introduction 9
Review of C fundaments – Program structure – Expressions – Control
Statements – Arrays and Strings.
Unit – II Pointers 9
Pointers – pointer Expressions – Pointers and Arrays – Multiple indirections –
Pointers to functions – dynamic allocation functions – Functions – General form
of a function – scope of functions – Function Arguments – return statements –
Recursion.
Unit – III User defined data types 9
Structures – Array of Structures – Passing Structure to Functions – Function
Pointers – Arrays and Structures within structures. Unions. Bit fields.
Enumerations.
Unit – IV File Handling 9
Files in C – File pointer – Opening, closing and Flushing files. Working with Text
files – Character input and output – EOF – Detecting of EOF using feof() function
- Working with binary files – Direct input and ouput – File of Records – Random
Access to files of records – Other File management Functions – Low level I/O.
Unit – V Advanced Features 9
Introduction – Bitwise operators – Command Line arguments – C Preprocessor –
The # and ## preprocessor Operators - Type Qualifier – Variable length
argument list – Memory models and pointers.
Total : 45
References:
1. Herbert Schildt, “The Complete Reference”, TMH, 4th ed., 2006.
2. Pradip Dey, Manas Ghosh, “Computer Fundamentals and
Programming in C”, Oxford Higher Education, Oxford University Press,
2006.
3. Behrouz A. Forouzan, Richard F. Gilberg, “A Structured Programming
Approach Using C”, Thomson Brooks / Cole, 2nd ed., 2006.
UNIT-1
Arrays
An array is a data structure process multiple elements with the same data type.
Array elements are accessed using subscript.
The valid range of subscript is 0 to size -1.
#include
main()
{
int a[5];
int i;
for(i = 0;i<5;i++)
{
a[i]=i;
}
for(i = 0;i<5;i++)
{
printf("value in array %d\n",a[i]);
}
}
Result:
value in array 0
value in array 1
value in array 2
value in array 3
value in array 4
Address of each element in an array
Array elements occupy consecutive memory locations.
#include
main()
{
int a[5];
int i;
for(i = 0;i<5;i++)
{
a[i]=i;
}
for(i = 0;i<5;i++)
{
printf("value in array %d\n",a[i]);
}
for(i = 0;i<5;i++)
{
printf("value in array %d and address is %16lu\n",a[i],&a[i]);
}
}
Result:
value in array 0
value in array 1
value in array 2
value in array 3
value in array 4
value in array 0 and address is 631656
value in array 1 and address is 631660
value in array 2 and address is 631664
value in array 3 and address is 631668
value in arra
Addition of the elements of the list
#include
#include
void main()
{
int a[5],i = 5,sum=0;
printf("Enter the elements of list \n");
int j;
for(j=0;j
#define SIZE 12
int main()
{
int a[ SIZE ] = { 1, 3, 5, 4, 7, 2, 99, 16, 45, 67, 89, 45 };
int i;
int total = 0;
for ( i = 0; i < SIZE; i++ ) {
total += a[ i ];
}
printf( "Total of array element values is %d\n", total );
return 0;
}
Result:
Total of array element values
Initializing an array using for loop
#include
int main()
{
int n[ 10 ];
int i;
/* initialize elements of array n to 0 */
for ( i = 0; i < 10; i++ ) {
n[ i ] = 0;
}
printf( "%s%13s\n", "Element", "Value" );
for ( i = 0; i < 10; i++ ) {
printf( "%7d%13d\n", i, n[ i ] );
}
return 0;
}
Result:
Element Value
0 0
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 0
Initialize the elements of array to the even integers from 2 to 20
#include
#define SIZE 10
int main()
{
int s[ SIZE ];
int j;
for ( j = 0; j < SIZE; j++ ) {
s[ j ] = 2 + 2 * j;
}
for ( j = 0; j < SIZE; j++ ) {
printf( "%7d%13d\n", j, s[ j ] );
}
return 0;
}
Result:
0 2
1 4
2 6
3 8
4 10
5 12
6 14
7 16
8 18
9 20
Use scanf to read data into array
#include
int main(void)
{
int numbers[10];
int count = 10;
long sum = 0L;
float average = 0.0f;
printf("\nEnter the 10 numbers:\n");
int i;
for(i = 0; i < count; i ++)
{
printf("%2d> ",i+1);
scanf("%d", &numbers[i]);
sum += numbers[i];
}
average = (float)sum/count;
printf("\nAverage of the ten numbers entered is: %f\n", average);
return 0;
}
Result:
Enter the 10 numbers:
1> 2
2> 3
3> 1
4> 2
5> 1
6> 1
7> 1
8> 2
9> 1
10> 1
Average of the ten numbers entered is: 1.500000
Merging of two sorted lists
#include
#include
void sort(int *,int);
void merge(int *,int *,int *,int);
void main(){
int a[5],b[5],c[10];
a[0] = 2;
a[1] = 3;
a[2] = 6;
a[3] = 1;
a[4] = 8;
b[0] = 0;
b[1] = 2;
b[2] = 8;
b[3] = 7;
b[4] = 5;
sort(a,5);
printf("The sorted list a is:\n");
int j;
for(j=0;j<5;j++)
printf("%d \n",a[j]);
sort(b,5);
printf("The sorted list b is:\n");
for(j=0;j<5;j++)
printf("%d \n",a[j]);
merge(a,b,c,5);
printf("The elements of merged list are \n");
for(j=0;j<5;j++)
printf("%d \n",a[j]);
}
void sort(int arr[] ,int k)
{
int temp;
int i,j;
for(i=0;i
#include
void read(int *,int);
void dis(int *,int);
void inverse(int *,int);
main(){
int a[5],i;
read(a,5);
dis(a,5);
inverse(a,5);
dis(a,5);
getch();
}
void read(int c[],int i)
{
int j;
printf("Enter the list \n");
for(j=0;j
#define SIZE 100
int linearSearch( const int array[], int key, int size );
int main()
{
int a[ SIZE ];
int x;
int searchKey;
int element;
for ( x = 0; x < SIZE; x++ ) {
a[ x ] = 2 * x;
}
printf( "Enter integer search key:\n" );
scanf( "%d", &searchKey );
element = linearSearch( a, searchKey, SIZE );
if ( element != -1 ) {
printf( "Found value in element %d\n", element );
}
else {
printf( "Value not found\n" );
}
return 0;
}
int linearSearch( const int array[], int key, int size )
{
int n;
for ( n = 0; n < size; ++n ) {
if ( array[ n ] == key ) {
return n;
}
}
return -1;
}
Result:
Enter integer search key:
2
Found value in element 1
Binary search of an array
#include #define SIZE 15int binarySearch( const int b[], int searchKey, int low, int high );int main() { int a[ SIZE ]; int i; int key = 10; int result = -1; for ( i = 0; i < SIZE; i++ ) { a[ i ] = 2 * i; } result = binarySearch( a, key, 0, SIZE - 1 ); if ( result != -1 ) { printf( "\n%d found in array element %d\n", key, result ); } else { printf( "\n%d not found\n", key ); } return 0;}int binarySearch( const int b[], int searchKey, int low, int high ){ int middle; while ( low <= high ) { middle = ( low + high ) / 2; if ( searchKey == b[ middle ] ) { return middle; } else if ( searchKey < b[ middle ] ) { high = middle - 1; } else { low = middle + 1; } } return -1;}
Result:
10 found in array element 5
Pass array to function
#include
#include
void read(int *,int);
void dis(int *,int);
void main()
{
int a[5],b[5],c[5],i;
printf("Enter the elements of first list \n");
read(a,5);
printf("The elements of first list are \n");
dis(a,5);
}
void read(int c[],int i)
{
int j;
for(j=0;j
#define SIZE 5
void modifyArray( int b[], int size );
void modifyElement( int e );
int main()
{
int a[ SIZE ] = { 0, 1, 2, 3, 4 };
int i;
printf( "Effects of passing entire array by reference:\n\nThe "
"values of the original array are:\n" );
for ( i = 0; i < SIZE; i++ ) {
printf( "%3d", a[ i ] );
}
printf( "\n" );
modifyArray( a, SIZE );
printf( "The values of the modified array are:\n" );
for ( i = 0; i < SIZE; i++ ) {
printf( "%3d", a[ i ] );
}
printf( "\n\n\nEffects of passing array element "
"by value:\n\nThe value of a[3] is %d\n", a[ 3 ] );
modifyElement( a[ 3 ] );
printf( "The value of a[ 3 ] is %d\n", a[ 3 ] );
return 0;
}
void modifyArray( int b[], int size )
{
int j;
for ( j = 0; j < size; j++ ) {
b[ j ] *= 2;
}
}
void modifyElement( int e )
{
printf( "Value in modifyElement is %d\n", e *= 2 );
}
Result:
Effects of passing entire array by reference:
The values of the original array are:
0 1 2 3 4
The values of the modified array are:
0 2 4 6 8
Effects of passing array element by value:
The value of a[3] is 6
Value in modifyElement is 12
The value of a[ 3 ] is 6
Strings
A string is nothing more than a character array.
All strings end with the NULL character.
Use the %s placeholder in the printf() function to display string values.
#include
main ( )
{
char *s1 = "abcd";
char s2[] = "efgh";
printf( "%s %16lu \n", s1, s1);
printf( "%s %16lu \n", s2, s2);
s1 = s2;
printf( "%s %16lu \n", s1, s1);
printf( "%s %16lu \n", s2, s2);
}
Result:
abcd 4206592
efgh 2293584
efgh 2293584
efgh 2293584
A string is an array of characters.
#include
int main(){
char myname[] = "Dan";
printf("%s \n",myname);
}
Result:
Dan
Write string in a more traditional array style
#include int main(){ char myname[] = { 'D', 'a', 'n' }; printf("%s \n",myname);}
Result:
Dan?
Strings always end with the NULL character
ASCII code for the NULL character is \0
#include int main(){ char myname[4]; myname[0] = 'D'; myname[1] = 'a'; myname[2] = 'n'; printf("%s \n",myname);}
Result:
Dan
String constants consist of text enclosed in double quotes
We must use the standard library function strcpy to copy the string constant into the variable.
To initialize the variable name to Sam.
#include
int main()
{
char name[4];
strcpy(name, "Sam");
return (0);
}
Useful string function
Function Description strcpy(string1, string2) Copy string2 into string1 strcat(string1, string2) Concatenate string2 onto the end of string1 length = strlen(string) Get the length of a string strcmp(string1, string2) 0 if string1 equals string2, otherwise nonzero
Displaying a string with a string terminator in the middle
#include
int main(void)
{
printf("The character \0 is used to terminate a string.");
return 0;
}
Result:
The character
Overwrite the newline character in string
#include
#include
#include
int main(void)
{
char text[100];
printf("\nEnter the string to be searched(less than 100 characters):\n");
fgets(text, sizeof(text), stdin);
text[strlen(text)-1] = '\0';
printf("%s",text);
}
Result:
Enter the string to be searched(less than 100 characters):
string
string
Result:
By setting first[4] to NULL ('\0'), we can shorten the string
#include
#include
int main()
{
char name[30];
strcpy(name, "Saaaaaaaaaaaaaaam");
printf("The name is %s\n", name);
name[4] = '\0';
printf("The name is %s\n", name);
return (0);
}
Result:
The name is Saaaaaaaaaaaaaaam
The name is Saaa
Read string from keyboard
#include
int main()
{
char me[20];
printf("What is your name?");
scanf("%s",&me);
printf("Darn glad to meet you, %s!\n",me);
return(0);
}
What is your name?1
Darn glad to meet you, 1!
Reading Strings
The standard function fgets can be used to read a string from the keyboard.
The general form of an fgets call is:
fgets(name, sizeof(name), stdin);
The arguments are:
name is the name of a character array.
sizeof(name) indicates the maximum number of characters to read.
stdin is the file to read.
Read a line from the keyboard and reports its length.
#include
#include
int main()
{
char line[100]; /* Line we are looking at */
printf("Enter a line: ");
fgets(line, sizeof(line), stdin);
printf("The length of the line is: %d\n", strlen(line));
return (0);
}
Result:
Enter a line: string
The length of the line is: 7
Ask the user for his first and last name.
#include
#include
int main() {
char first[100];
char last[100];
char full[200];
printf("Enter first name: ");
fgets(first, sizeof(first), stdin);
printf("Enter last name: ");
fgets(last, sizeof(last), stdin);
strcpy(full, first);
strcat(full, " ");
strcat(full, last);
printf("The name is %s\n", full);
return (0);
}
Result:
Enter first name: string
Enter last name: last
The name is string
last
Displaying a string
#include
int main(void)
{
printf("Beware the Ides of March!");
return 0;
}
String alignment
#include
int main(){
printf("%15s","right\n");
printf("%-15s","left\n");
return(0);
}
Result:
right
left
Using escape: backslash
#include
int main(void)
{
printf("If at first you don\'t succeed, try, try, try again!");
return 0;
}
Result:
If at first you don't succeed, try, try, try again!
Escape Quotations
#include
int main(void)
{
printf("\n\"It is a wise father that knows his own child.\" Shakespeare");
return 0;
}
Result:
"It is a wise father that knows his own child." Shakespeare
\\ is the escape sequence that sticks a backslash character into a string.
#include
int main()
{
printf(" \\ string.");
return 0;
}
Result:
\ string.
Joining strings without using strcat
#include
int main(void)
{
char str1[40] = "AAA";
char str2[] = "BBBB";
int str1Length = 0;
int str2Length = 0;
while (str1[str1Length])
str1Length++;
while (str2[str2Length])
str2Length++;
if(sizeof str1 < str1Length + str2Length + 1)
printf("\n str1 is too short.");
else
{
str2Length = 0;
while(str2[str2Length]){
str1[str1Length++] = str2[str2Length++];
}
str1[str1Length] = '\0';
printf("\n%s\n", str1 );
}
return 0;
}
Result:
AAABBBB
Lengths of strings
#include
int main(void)
{
char str1[] = "AAA";
int count = 0;
while (str1[count] != '\0') /* Increment count till we reach the string terminating character.*/
count++;
printf("\nThe length of the string \"%s\" is %d characters.", str1, count);
return 0;
}
Result:
The length of the string "AAA" is 3 characters
Copying a string using array notation and pointer notation
#include
void copy1( char *s1, const char *s2 );
void copy2( char *s1, const char *s2 );
int main()
{
char string1[ 10 ];
char *string2 = "Hello";
char string3[ 10 ];
char string4[] = "Good Bye";
copy1( string1, string2 );
printf( "string1 = %s\n", string1 );
copy2( string3, string4 );
printf( "string3 = %s\n", string3 );
return 0;
}
void copy1( char *s1, const char *s2 )
{
int i;
for ( i = 0; ( s1[ i ] = s2[ i ] ) != '\0'; i++ ) {
;
}
}
void copy2( char *s1, const char *s2 ) {
for ( ; ( *s1 = *s2 ) != '\0'; s1++, s2++ ) {
;
}
}
Result:
string1 = Hello
string3 = Good Bye
Take a first name and a last name and combines the two strings
#include
#include
int main()
{
char first[100];
char last[100];
char full_name[200];
strcpy(first, "first");
strcpy(last, "last");
strcpy(full_name, first);
strcat(full_name, " ");
strcat(full_name, last);
printf("The full name is %s\n", full_name);
return (0);
}
Result:
The full name is first last
Pass string to a function
#include
int main ( )
{
char s1[6] = "abcde ";
print_str(s1);
}
int print_str(char s1[]) {
printf("%s \n", s1);
}
Arrays of strings
#include
int main(void)
{
char str[][40] = { "AAA",
"BBBBBBBB"
};
int strLength[] = {0, 0};
int i;
for(i = 0 ; i<2 ; i++){
while (str[i][strLength[i]])
strLength[i]++;
}
if(sizeof str[0] < strLength[0] + strLength[1] + 1){
printf("\nNo enough space");
}else{
strLength[1] = 0;
while((str[0][strLength[0]++] = str[1][strLength[1]++]));
printf("\n%s\n", str[0]);
}
return 0;
}
Result:
AAABBBBBBBB
Find occurrences of one string in another
#include
#include
#include
int main(void)
{
char text[100];
char substring[40];
printf("\nEnter the string to be searched(less than 100 characters):\n");
fgets(text, sizeof(text), stdin);
printf("\nEnter the string sought (less than 40 characters ):\n");
fgets(substring, sizeof(substring), stdin);
/* overwrite the newline character in each string */
text[strlen(text)-1] = '\0';
substring[strlen(substring)-1] = '\0';
int i;
for(i = 0 ; (text[i] = toupper(text[i])) ; i++);
for(i = 0 ; (substring[i] = toupper(substring[i])) ; i++);
printf("\nThe second string %s found in the first.",((strstr(text, substring) == NULL) ? "was not" : "was"));
return 0;
}
Result:
Enter the string to be searched(less than 100 characters):
string
Enter the string sought (less than 40 characters ):
str
The second string was found in the first.
The functional approach to string sorting
#include
#include
#include
#include
bool str_in(const char **); /* Function prototype for str_in */
void str_sort(const char *[], int); /* Function prototype for str_sort */
void swap( void **p1, void **p2); /* Swap two pointers */
void str_out(char *[], int); /* Function prototype for str_out */
const size_t BUFFER_LEN = 256;
const size_t NUM_P = 50;
/* Function main - execution starts here */
int main(void)
{
char *pS[NUM_P]; /* Array of string pointers */
int count = 0; /* Number of strings read */
printf("\nEnter successive lines, pressing Enter at the end of"
" each line.\nJust press Enter to end.\n");
for(count = 0; count < NUM_P ; count++) /* Max of NUM_P strings */
if(!str_in(&pS[count])) /* Read a string */
break; /* Stop input on 0 return */
str_sort( pS, count); /* Sort strings */
str_out( pS, count); /* Output strings */
return 0;
}
/*******************************************************
* String input routine *
* Argument is a pointer to a pointer to a constant *
* string which is const char** *
* Returns false for empty string and returns true *
* otherwise. If no memory is obtained or if there *
* is an error reading from the keyboard, the program *
* is terminated by calling exit(). *
*******************************************************/
bool str_in(const char **pString)
{
char buffer[BUFFER_LEN]; /* Space to store input string */
if(gets(buffer) == NULL ) /* NULL returned from gets()? */
{
printf("\nError reading string.\n");
exit(1); /* Error on input so exit */
}
if(buffer[0] == '\0') /* Empty string read? */
return false;
*pString = (char*)malloc(strlen(buffer) + 1);
if(*pString == NULL) /* Check memory allocation */
{
printf("\nOut of memory.");
exit(1); /* No memory allocated so exit */
}
strcpy(*pString, buffer); /* Copy string read to argument */
return true;
}
/****************************************************
* String sort routine *
* First argument is array of pointers to strings *
* which is of type char*[]. *
* Second argument is the number of elements in the *
* pointer array - i.e. the number of strings *
****************************************************/
void str_sort(const char *p[], int n)
{
char *pTemp = NULL; /* Temporary pointer */
bool sorted = false; /* Strings sorted indicator */
while(!sorted) /* Loop until there are no swaps */
{
sorted = true; /* Initialize to indicate no swaps */
for(int i = 0 ; i 0)
{
sorted = false; /* indicate we are out of order */
swap(&p[i], &p[i+1]); /* Swap the pointers */
}
}
}
/****************************************************
* String output routine *
* First argument is an array of pointers to *
* strings which is the same as char** *
* The second argument is a count of the number of *
* pointers in the array i.e. the number of strings *
****************************************************/
void str_out(char *p[] , int n)
{
printf("\nYour input sorted in order is:\n\n");
for (int i = 0 ; i
#include
/* A Quicksort for strings. */
void quick_string(char items[][10], int count)
{
qs_string(items, 0, count-1);
}
int qs_string(char items[][10], int left, int right)
{
register int i, j;
char *x;
char temp[10];
i = left; j = right;
x = items[(left+right)/2];
do {
while((strcmp(items[i],x) < 0) && (i < right)) i++;
while((strcmp(items[j],x) > 0) && (j > left)) j--;
if(i <= j) {
strcpy(temp, items[i]);
strcpy(items[i], items[j]);
strcpy(items[j], temp);
i++; j--;
}
} while(i <= j);
if(left < j) qs_string(items, left, j);
if(i < right) qs_string(items, i, right);
}
char str[][10] = { "one",
"two",
"three",
"four"
};
int main(void)
{
int i;
quick_string(str, 4);
for(i=0; i<4; i++) printf("%s ", str[i]);
return 0;
}
Control Structures
Sequential structures
Selection structure
if and switch.
The statements are enclosed within a block marked by '{' and '}'
Each executable statement is terminated by ';'
iteration statements:
for loop.
The continue statement
The break statement
Breaking out of a for loop
while loop.
Between a while loop and a for loop
Put function into while loop condition statement
While loop and sum integers
while loop nested in a for loop
do...while loop
Reversing the digits: do while loop
Read number in a range
Nest for loop inside do while loop
if statement
To execute only one statement, opening and closing braces are not required
The if statement: a compound statement
If with else statement
The if-else-if statement
if statement with two else statements
if statement: compare the value from user input
Using nested ifs
Use compound conditions to check for upper and lowercase letters
Checking for a Range of Values
Use isdigit Function in if statement
Operators Used in if Comparisons
if Comparisons and Their Opposites
The switch statement
In the absence of a break statement, all statements that are followed by matched cases are executed.
break statement stops evaluating any further case statements.
Confused if statement
Control Structures
Control structures: sequential, selection, iteration and encapsulation.
A sequential structure is one in which instructions are executed in sequence. For example,
Ex 1:
# include
main()
{
int i=0, j =1;
printf("A");
i = i + 1;
printf("B");
j = j + 1;
printf("C");
}
Result:
ABC
Selection structure
The sequence of the instruction is determined by the condition.
The statements in this category are if and switch.
Ex 2:
# include
main(){
int i=0, j =1;
if (i > j){
i = i + 1;
printf("a");
}
else{
printf("b");
j = j +1;
}
}
Result:
B
The statements are enclosed within a block marked by '{' and '}'
Ex 3:
#include
main(){
printf("Hi \n");
printf("Hello \n");
}
Result:
Hi
Hello
Each executable statement is terminated by ';'
Ex 4:
#include
main(){
printf("Hi \n");
}
Result:
Hi
Loop statements in C
C has provided three types of iteration statements:
for loop.
while loop.
do...while loop.
The continue statement
continue statement breaks the current iteration.
#include
main(){
int i;
for(i = 0; i < 11; i++){
if ((i == 4) || (i == 7)) {
continue;
}
printf(" the value of i is %d\n", i);
}
}
Result:
the value of i is 0
the value of i is 1
the value of i is 2
the value of i is 3
the value of i is 5
the value of i is 6
the value of i is 8
the value of i is 9
the value of i is 10
The break statement
break statement can break any type of loop.
#include
main(){
int i = 0;
while (1)
{
i = i + 1;
printf(" the value of i is %d\n",i);
if (i>5) {
break;
}
}
}
Result:
the value of i is 1
the value of i is 2
the value of i is 3
the value of i is 4
the value of i is 5
the value of i is 6
Breaking out of a for loop
#include
int main()
{
char ch;
puts("Start typing");
puts("Press ~ then Enter to stop");
for(;;)
{
ch=getchar();
if(ch=='~')
{
break;
}
}
printf("Thanks!\n");
return(0);
}
Result:
Start typing
Press ~ then Enter to stop
12312
1
231
12
12
3~
Thanks!
The do...while loop
The do...while loop checks the conditional expression only after the repetition part is executed.
The do...while loop is used when you want to execute the loop body at least once.
The general form of the do...while loop is
do {
repetition part;
} while (expr);
#include
main(){
int i,n = 5;
i = 0;
do{
printf("the numbers are %d \n",i);
i = i +1;
}while( i
int main(void)
{
int number = 123;
int rightMostNumber = 0;
int temp = 0;
temp = number;
do
{
rightMostNumber = 10*rightMostNumber + temp % 10;
temp = temp/10;
} while (temp);
printf ("\nThe number %d reversed is %d\n", number, rightMostNumber );
return 0;
}
Result:
The number 123 reversed is 321
Read number in a range
#include
int main(){
printf("Please enter the number to start\n");
printf("the countdown (1 to 100):");
int start;
scanf("%d",&start);
do {
printf("%d",start);
}while(start<1 || start>100);
}
Result:
Please enter the number to start
the countdown (1 to 100):12
12
Nest for loop inside do while loop
#include
int main()
{
int start = 10;
long delay = 1000;
do
{
printf(" %d\n",start);
start--;
for(delay=0;delay<100000;delay++); /* delay loop */
}
while(start>0);
printf("Zero!\nBlast off!\n");
return(0);
}
Result:
10
9
8
7
6
5
4
3
2
1
Zero!
Blast off!
The while loop
The general format for a while loop is
while (condition) {
simple or compound statement (body of the loop);
}
#include
main(){
int i = 0;
while (i<5){
printf(" the value of i is %d\n", i);
i = i + 1;
}
}
Result:
the value of i is 0
the value of i is 1
the value of i is 2
the value of i is 3
the value of i is 4
Between a while loop and a for loop
for(A;B;C){
printf("%d\t",i);
}
It becomes
A;
while(B)
{
printf("%d\t",i);
C;
}
Put function into while loop condition statement
#include
int main()
{
puts("Start typing.");
puts("Press ~ then Enter to stop");
while(getchar() != '~')
;
printf("Thanks!\n");
return(0);
}
Result:
Start typing.
Press ~ then Enter to stop
a
a
a
a
a
a~
Thanks!
While loop and sum integers
#include
int main(void)
{
long sum = 0L;
int i = 1;
int count = 0;
printf("\nEnter the number of integers you want to sum: ");
scanf(" %d", &count);
while(i <= count){
sum += i++;
}
printf("Total of the first %d numbers is %ld\n", count, sum);
return 0;
}
Result:
Enter the number of integers you want to sum: 1
Total of the first 1 numbers is 1
while loop nested in a for loop
#include
int main(void)
{
long sum = 1L;
int j = 1;
int count = 10;
int i;
for(i = 1 ; i <= count ; i++)
{
sum = 1L;
j=1;
printf("\n1");
while(j < i){
sum += ++j;
printf("+%d", j);
}
printf(" = %ld\n", sum);
}
return 0;
}
Result:
1 = 1
1+2 = 3
1+2+3 = 6
1+2+3+4 = 10
1+2+3+4+5 = 15
1+2+3+4+5+6 = 21
1+2+3+4+5+6+7 = 28
1+2+3+4+5+6+7+8 = 36
1+2+3+4+5+6+7+8+9 = 45
1+2+3+4+5+6+7+8+9+10 = 55
if statement
To conditionally execute statements, you can use the if or the if...else statement.
The general form of the if statement is
if(expr) {
s1 ;
s2 ;
....
}
expr is a Boolean expression that returns true (nonzero) or false (zero).
#include
main(){
int i = 3,j = 5;
if(i < j){
printf("i < j \n");
}
}
Result:
i < j
To execute only one statement, opening and closing braces are not required
#include
main(){
int i = 5;
if(i > 0)
printf(" i > 0. \n");
}
Result:
i > 0.
The if statement: a compound statement
If a compound statement is used, it must be enclosed in opening and closing braces.
#include
main()
{
int i=5, j =1;
if (i > j){
i = i + 1;
printf("%d",i);
}
else
j = j +1;
}
Result:
6
If with else statement
The general format for an if-else statement is
if (condition)
simple or compound statement
else
simple or compound statement.
#include
main(){
int i = 5;
if(i > 0){
printf(" i > 0. \n");
}else{
printf(" i < 0. \n");
}
}
Result:
i > 0.
The if-else-if statement
The general format for the if-else if statement is:
if (condition 1)
simple or compound statement
else if (condition 2)
simple or compound statement
else if ( condition 3)
simple or compound statement
.....
else if ( conditon n )
simple or compound statement
#include
main(){
int i = 2;
if(i == 0){
printf(" i == 0. \n");
}else if(i == 1){
printf(" i == 1. \n");
}else if(i == 2){
printf(" i == 2. \n");
}
}
Result:
i == 2.
if statement with two else statements
#include
#include
int main()
{
char num[2];
int number;
printf("Enter a number from 0 to 9:");
gets(num);
number=atoi(num);
if(number<5)
{
printf("That number is less than 5!\n");
}
else if(number==5)
{
printf("You typed in 5!\n");
}
else
{
printf("That number is more than 5!\n");
}
return(0);
}
Result:
Enter a number from 0 to 9:2
That number is less than 5!
if statement: compare the value from user input
#include
int main(void)
{
int number = 0;
printf("\nEnter an integer between 1 and 10: ");
scanf("%d",&number);
if (number > 5)
printf("You entered %d which is greater than 5\n", number);
if (number < 6)
printf("You entered %d which is less than 6\n", number);
return 0;
}
Result:
Enter an integer between 1 and 10: 5
You entered 5 which is less than 6
Using nested ifs
#include
#include
int main(void)
{
long test = 0L;
if( test % 2L == 0L) {
printf("The number %ld is even", test);
if ( (test/2L) % 2L == 0L)
{
printf("\nHalf of %ld is also even", test);
printf("\nThat's interesting isn't it?\n");
}
}
else
printf("The number %ld is odd\n", test);
return 0;
}
Result:
The number 0 is even
Half of 0 is also even
That's interesting isn't it?
Use compound conditions to check for upper and lowercase letters
#include
main(){
char cResponse = '\0';
printf("Enter the letter A: ");
scanf("%c", &cResponse);
if ( cResponse== 'A' || cResponse == 'a' )
printf("\nCorrect response\n");
else
printf("\nIncorrect response\n");
}
Result:
Enter the letter A: 1
Incorrect response
Checking for a Range of Values
#include
main()
{
int iResponse = 0;
printf("Enter a number from 1 to 10: ");
scanf("%d", &iResponse);
if ( iResponse < 1 || iResponse > 10 )
printf("\nNumber not in range\n");
else
printf("\nThank you\n");
}
Result:
Enter a number from 1 to 10: 2
Thank you
Use isdigit Function in if statement
#include
#include
main()
{
char cResponse = '\0';
printf("\nPlease enter a letter: ");
scanf("%c", &cResponse);
if ( isdigit(cResponse)== 0 )
printf("\nThank you\n");
else
printf("\nYou did not enter a letter\n");
}
Result:
Please enter a letter: 1
You did not enter a letter
Operators Used in if Comparisons
Comparison Meaning or Pronunciation "True" Example < Less than 1 < 5, 8 < 9 == Equal to 7 == 7, 1 == 1 > Greater than 7 > 5, 10 > 0 <= Less than or equal to 4 <= 5, 8 <= 8 >= Greater than or equal to 6 >= 5, 2 >= 2 != Not equal to 1 != 0, 1 != 3.99
if Comparisons and Their Opposites
if Comparison else Statement Executed By This Condition < >= == != > <= <= >
The switch statement
To take one of a number of possible actions.
switch is preferred over multiple if...else statements.
The general form of a switch statement is
switch(switch_expr)
{
case constant expr1 : S1;
S2;
break;
case constant expr1 : S3;
S4;
break;
.....
default : S5;
S6;
break;
}
The clause 'default' is optional.
#include
main(){
int i,n = 5;
for(i = 1; i
main(){
int i= 6;
switch(i%2)
{
case 0 : printf("the number %d is even \n",i);
case 1 : printf("the number %d is odd \n",i);
break;
}
}
Result:
the number 1 is odd
the number 2 is even
the number 3 is odd
the number 4 is even
break statement stops evaluating any further case statements.
#include
main(){
int iResponse = 0;
printf("\nPlease select a category (1-4): ");
scanf("%d", &iResponse);
switch (iResponse) {
case 1:
printf("\nYou selected 1\n");
break;
case 2:
printf("You selected 2\n");
break;
case 3:
printf("You selected 3\n");
break;
case 4:
printf("You selected 4\n");
break;
}
}
Result:
Please select a category (1-4): 2
You selected 2
Confused if statement
#include
#include
int main(void)
{
int age = 24;
int college = 1;
int subject = 2;
bool interview = false;
if((age>25 && subject==1) && (college==3 || college==1))
interview = true;
if(college==2 &&subject ==1)
interview = true;
if(college==1 && subject==2 && !(age>28))
interview = true;
if(college==2 && (subject==2 || subject==3) && age>25)
interview = true;
if(interview)
printf("\n\nGive 'em an interview");
else
printf("\n\nReject 'em");
return 0;
}
Result:
Give 'em an interview
Use switch to simplify the logic
#include
int main(void)
{
int choice = 2;
if((choice>10) || (choice <1)){
choice = 11;
}
switch(choice)
{
case 7:
printf("\nCongratulations!");
break;
case 2:
printf("\nA");
break;
case 8:
printf("\nB");
break;
case 11:
printf("\nC");
default:
printf("\nSorry, you lose.\n");
break;
}
return 0;
}
A
Two cases, one action
#include
int main(void)
{
char answer = 0;
printf("Enter Y or N: ");
scanf(" %c", &answer);
switch (answer)
{
case 'y': case 'Y':
printf("\nYou responded in the affirmative.");
break;
case 'n': case 'N':
printf("\nYou responded in the negative.");
break;
default:
printf("\nYou did not respond correctly...");
break;
}
return 0;
}
Enter Y or N: N
You responded in the negative.
Nest if statement in case statement
#include
#include
int main(void)
{
double number1 = 3.0;
double number2 = 4.0;
char operation = '+';
char reply = 0;
switch(operation)
{
case '+':
printf("= %lf\n", number1 + number2);
break;
case '-':
printf("= %lf\n", number1 - number2);
break;
case '*':
printf("= %lf\n", number1 * number2);
break;
case '/':
if(number2 == 0)
printf("\n\n\aDivision by zero error!\n");
else
printf("= %lf\n", number1 / number2);
break;
case '%':
if((long)number2 == 0)
printf("\n\n\aDivision by zero error!\n");
else
printf("= %ld\n", (long)number1 % (long)number2);
break;
default:
printf("\n\n\aIllegal operation!\n");
break;
}
return 0;
}
= 7.000000
Use the switch structure to evaluate a user's response from a menu (without break).
#include
main(){
int iResponse = 0;
printf("\nPlease select a category (1-4): ");
scanf("%d", &iResponse);
switch (iResponse) {
case 1:
printf("\nYou selected 1\n");
case 2:
printf("You selected 2\n");
case 3:
printf("You selected 3\n");
case 4:
printf("You selected 4\n");
} //end switch
} //end main function
Please select a category (1-4): 1
You selected 1
You selected 2
You selected 3
You selected 4
Use switch structure to evaluate characters
#include
main(){
char iResponse = 'A';
printf("input(a or A or B or b or c or C):");
scanf("%d", &iResponse);
switch (iResponse) {
case 'a': case 'A':
printf ("\nYou selected the character a or A\n");
break;
case 'b': case 'B':
printf("You selected the character b or B\n");
break;
case 'c': case 'C':
printf("You selected the character c or C\n");
break;
}
}
for LOOP
The for loop is usually used when the number of iterations is predetermined.
The format of the for loop is
for (expr1;expr2;expr3){
s1;
s2 ;
}
expr1 is executed only once before looping.
expr2 is a Boolean expression. If not given, it is assumed to be true.
If expr2 is false, the loop is terminated.
After execution of the repeat section, expr3 is executed
The expressions expr1, expr2 and expr3 are all optional.
#include
main(){
int i,n = 5;
for(i = 0; i < n; i = i+1){
printf("the numbers are %d \n",i);
}
}
the numbers are 0
the numbers are 1
the numbers are 2
the numbers are 3
the numbers are 4
Omit all three parts in for loop
#include
int main()
{
printf("~ to exit");
for(;;)
{
char ch=getchar();
if(ch=='~')
{
break;
}
}
}
~ to exit123
~
The for loop with a comma operator
#include
main(){
int i, j;
for (i = 0, j = 10; i < 3 && j > 8; i++, j--){
printf (" the value of i and j %d %d\n",i, j);
}
}
the value of i and j 0 10
the value of i and j 1 9
Initialize loop control variable outside the for statement
#include int main(void){ int count = 1; for( ; count <= 10 ; ++count) printf("\n%d", count); printf("\nWe have finished.\n"); return 0;}
1
2
3
4
5
6
7
8
9
10
We have finished. Use for loop to print a rectangle
#include int main(void){ printf("\n**************"); for(int count = 1 ; count <= 8 ; ++count) printf("\n* *"); printf("\n**************\n"); return 0;}
**************
* *
* *
* *
* *
* *
* *
* *
* *
**************
Sum integers in for statement
#include
int main(void)
{
long sum = 0L;
int count = 0;
printf("\nEnter the number of integers you want to sum: ");
scanf(" %d", &count);
for (int i = 1 ; i<= count ; sum += i++ );
printf("\nTotal of the first %d numbers is %ld\n", count, sum);
return 0;
}
Enter the number of integers you want to sum: 112
Total of the first 112 numbers is 6328
for loop backward
#include
int main(void)
{
long sum = 0L;
int count = 10;
int i;
for (i = count ; i >= 1 ; sum += i-- );
printf("\nTotal of the first %d numbers is %ld\n", count, sum);
return 0;
}
Total of the first 10 numbers is 55
indefinite loop: empty for
#include #include /* For tolower() function */int main(void){ char answer = 'N'; printf("\nThis program calculates the average of any number of values."); for( ;; ) /* Indefinite loop */ { printf("Do you want to enter another value? (Y or N): "); scanf(" %c", &answer ); if( tolower(answer) == 'n' ){ break; } } return 0;}
This program calculates the average of any number of values.Do you want to enter another value? (Y o
r N): N Nest if statement in for loop
#include int main(void){ int chosen = 15; int guess = 0; int count = 3; printf("\nA Number.\n"); for( ; count>0 ; --count) { printf("\nYou have %d tr%s left.", count, count == 1 ? "y" : "ies"); printf("\nEnter a guess: "); scanf("%d", &guess); if (guess == chosen) { printf("\nYou guessed it!\n"); return 0; } if(guess<1 || guess > 20) printf("between 1 and 20.\n "); else printf("Sorry. %d is wrong.\n", guess); } printf("\nYou have had three tries and failed. The number was %d\n", chosen); return 0;}
A Number.
You have 3 tries left.
Enter a guess: 1
Sorry. 1 is wrong.
You have 2 tries left.
Enter a guess: 2
Sorry. 2 is wrong.
You have 1 try left.
Enter a guess: 3
Sorry. 3 is wrong.
You have had three tries and failed. The number was 15
Nest for loop: two different control variables
#include
int main(void)
{
long sum = 0L;
int count = 10;
int i,j;
for(i = 1 ; i <= count ; i++ ){
sum = 0L;
for(j = 1 ; j <= i ; j++ )
sum += j;
printf("\n%d\t%ld", i, sum);
}
return 0;
}
1 1
2 3
3 6
4 10
5 15
6 21
7 28
8 36
9 45
10 55
Use char variable to control for loop
#include
int main()
{
char b,a='a' ;
for(b='A';b<'K';b++) {
printf("%d - %c ",a,b);
}
putchar('\n'); /* end of line */
return(0);
}
97 - A 97 - B 97 - C 97 - D 97 - E 97 - F 97 - G 97 - H 97 - I 97 - J
Continue a for loop
#include
int main(){
int x=0;
for(;;) {
x++;
if(x<=5) {
printf("%d, ",x);
continue;
}
printf("%d is greater than 5!\n",x);
break;
}
return(0);
}
1, 2, 3, 4, 5, 6 is greater than 5!
Unit-2
Pointers
Pointers are used manipulate the computer's memory.
Pointers are declared by using the asterisk(*).
The following line declares an integer pointer, s:
int *s;
The ampersand & is used to get the address.
Address and Pointers
Address
Each variable has two attributes: address and value.
The address is the location in memory.
In that locaton, the value is stored.
During the lifetime of the variable, the address is not changed but the value may change.
Pointers
A pointer is a variable whose value is an address.
A pointer to an integer is a variable that can store the address of that integer.
Using Pointers
Define a pointer: include a * before the name of the variable.
Get the address: use &.
#include
main ()
{
int i;
int * ia;
i = 10;
ia = &i;
printf (" The address of i is %8u \n", ia);
printf (" The value at that location is %d\n", i);
printf (" The value at that location is %d\n", *ia);
*ia = 50;
printf ("The value of i is %d\n", i);
}
Result:
The address of i is 631672
The value at that location is 10
The value at that location is 10
The value of i is 50
Using the & and * operators
#include
int main()
{
int a; /* a is an integer */
int *aPtr; /* aPtr is a pointer to an integer */
a = 7;
aPtr = &a; /* aPtr set to address of a */
printf( "The address of a is %p"
"\nThe value of aPtr is %p", &a, aPtr );
printf( "\n\nThe value of a is %d"
"\nThe value of *aPtr is %d", a, *aPtr );
printf( "\n\nShowing that * and & are complements of "
"each other\n&*aPtr = %p"
"\n*&aPtr = %p\n", &*aPtr, *&aPtr );
return 0;
}
Result:
The address of a is 9a37c
The value of aPtr is 9a37c
The value of a is 7
The value of *aPtr is 7
Showing that * and & are complements of each other
&*aPtr = 9a37c
*&aPtr = 9a37c
Assign NULL to pointer
#include
int main(void)
{
int number = 0;
int *pointer = NULL;
number = 10;
printf("\nnumber's address: %p", &number); /* Output the address */
printf("\nnumber's value: %d\n\n", number); /* Output the value */
return 0;
}
Result:
number's address: 9a378
number's value: 10
Store the address of number in pointer
#include
int main(void)
{
int number = 0;
int *pointer = NULL;
number = 10;
pointer = &number; /*Store the address of number in pointer */
printf("pointer's address: %p", &pointer);
return 0;
}
Result:
pointer's address: 9a378
Change value of variable through pointer
#include
int main(void)
{
long num1 = 0;
long num2 = 0;
long *pnum = NULL;
pnum = &num1;
*pnum = 2;
++num2;
num2 += *pnum;
pnum = &num2;
++*pnum;
printf ("\nnum1 = %ld num2 = %ld *pnum = %ld *pnum + num2 = %ld\n",
num1, num2, *pnum, *pnum + num2);
return 0;
}
Result:
num1 = 2 num2 = 4 *pnum = 4 *pnum + num2 = 8
When the pointer is incremented by an increment operator, it is always right incremented.
#include
main(){
int a[5];
int i;
for(i = 0;i<5;i++){
a[i]=i;
}
int *b;
b=a;
for(i = 0;i<5;i++)
{
printf("value in array %d and address is %16lu\n",*b,b);
b++;
}
}
#include
main(){
long a[5];
int i;
for(i = 0;i<5;i++) {
a[i]=i;
}
long *b;
b=a;
for(i = 0;i<5;i++)
{
printf("value in array %d and address is %16lu\n",*b,b);
b++;
}
}
Result:
value in array 0 and address is 631652
value in array 1 and address is 631656
value in array 2 and address is 631660
value in array 3 and address is 631664
value in array 4 and address is 631668
Pointer arrays
In the pointer array, the array elements is the pointer.
#include
main(){
int *a[5];
int i1=4,i2=3,i3=2,i4=1,i5=0;
a[0]=&i1;
a[1]=&i2;
a[2]=&i3;
a[3]=&i4;
a[4]=&i5;
printf("Address Address in array Value\n");
int j;
for(j=0;j<5;j++)
{
printf("%16u %16u %d\n",
a[j],a[j],a[j]);
}
printf("using pointer\n");
int *b;
b = a;
for( j=0;j<5;j++)
{
printf("value of elements %d %16lu\n",*b,*b,b);
b++;
}
}
Result:
value in array 2
value in array 2
value in array 2
value in array 2
value in array 2
value in array 2
value in array 2 and address is 631648
value in array 2 and address is 631652
value in array 2 and address is 631656
value in array 2 and address is 631660
value in array 2 and address is 631664
value in array 2 and address is 631668
Pointer/offset notation
#include
int main()
{
int b[] = { 10, 20, 30, 40 };
int *bPtr = b;
int i;
int offset;
printf( "\nPointer/offset notation\n" );
for ( offset = 0; offset < 4; offset++ ) {
printf( "*( bPtr + %d ) = %d\n", offset, *( bPtr + offset ) );
}
return 0;
}
Result:
Pointer/offset notation
*( bPtr + 0 ) = 10
*( bPtr + 1 ) = 20
*( bPtr + 2 ) = 30
*( bPtr + 3 ) = 40
Output the size of a pointer
#include
int main(void)
{
int number = 0;
int *pointer = NULL;
number = 10;
pointer = &number;
printf("\npointer's size: %d bytes", sizeof(pointer)); /* Output the size */
return 0;
}
Result:
pointer's size: 4 bytes
Pointer subscript notation
#include
int main()
{
int b[] = { 10, 20, 30, 40 };
int *bPtr = b;
int i;
int offset;
printf( "\nPointer subscript notation\n" );
for ( i = 0; i < 4; i++ ) {
printf( "bPtr[ %d ] = %d\n", i, bPtr[ i ] );
}
return 0;
}
Result:
Pointer subscript notation
bPtr[ 0 ] = 10
bPtr[ 1 ] = 20
bPtr[ 2 ] = 30
bPtr[ 3 ] = 40
Attempting to modify a constant pointer to non-constant data
ptr is a constant pointer to an integer that can be modified through ptr.
ptr always points to the same memory location.
#include
int main()
{
int x;
int y;
int * const ptr = &x;
*ptr = 7; /* allowed: *ptr is not const */
// ptr = &y; /* error: ptr is const; cannot assign new address */
return 0;
}
Attempting to modify data through a non-constant pointer to constant data.
xPtr cannot be used to modify the value of the variable to which it points.
#include
void f( const int *xPtr );
int main()
{
int y;
f( &y );
return 0;
}
void f( const int *xPtr )
{
//*xPtr = 100; /* error: cannot modify a const object */
}
A non-constant pointer to constant data
#include
void printCharacters( const char *sPtr );
int main()
{
char string[] = "print characters of a string";
printf( "The string is:\n" );
printCharacters( string );
printf( "\n" );
return 0;
}
void printCharacters( const char *sPtr )
{
for ( ; *sPtr != '\0'; sPtr++ ) {
printf( "%c", *sPtr );
}
}
Result:
The string is:
print characters of a string
Memory Allocation
The functions for allocation of memory: malloc, relloc, and calloc.
The functions return the pointers to void, which can be typecast to any data type.
These functions take the input as the size of memory requirement.
#include
#include
main(){
int *base;
int i,j;
int cnt=0;
int sum=0;
printf("how many integers you have to store \n");
scanf("%d",&cnt);
base = (int *)malloc(cnt * sizeof(int));
printf("the base of allocation is %16lu \n",base);
if(!base)
printf("unable to allocate size \n");
else {
for(j=0;j
#include
main()
{
int *base;
int i,j;
int cnt=0;
int sum=0;
printf("how many integers you have to store \n");
scanf("%d",&cnt);
base = (int *)malloc(cnt * sizeof(int));
printf("the base of allocation is %16lu \n",base);
if(!base){
printf("unable to allocate size \n");
}
else
{
for(j=0;j
int add(int k,int m);
main()
{
int k ,i,m;
m=2;
k=3;
i=add(k,m);
printf("The value of addition is %d\n",i);
}
int add(int pk,int pm)
{
if(pm==0)
return(pk);
else
return(1+add(pk,pm-1));
}
Result:
The value of addition is 5
Calculate factorials using recursion
#include
unsigned long factorial(unsigned long);
int main(void)
{
unsigned long number = 0L;
printf("\nEnter an integer value: ");
scanf(" %lu", &number);
printf("\nThe factorial of %lu is %lu\n", number, factorial(number));
return 0;
}
unsigned long factorial(unsigned long n)
{
if(n < 2L)
return n;
else
return n*factorial(n - 1L);
}
Recursive fibonacci function
#include
long fibonacci( long n );
int main()
{
long result;
long number;
printf( "Enter an integer: " );
scanf( "%ld", &number );
result = fibonacci( number );
printf( "Fibonacci( %ld ) = %ld\n", number, result );
return 0;
}
long fibonacci( long n )
{
if ( n == 0 || n == 1 ) {
return n;
}
else {
return fibonacci( n - 1 ) + fibonacci( n - 2 );
}
}
Result:
Enter an integer: 3
Fibonacci( 3 ) = 2
Function
Functions provides modularity to the software.
#include
int add (int x, int y) {
int z;
z = x + y;
return (z);
}
main ()
{
int i, j, k;
i = 10;
j = 20;
k = add(i, j);
printf ("The value of k is %d\n", k);
}
The value of k is 30
Syntax of function definition
The general format of a function is
{
local definitions;
statements;
Return value;
}
#include
int f1 (int j, int f){
int k;
k = j + f;
return k;
}
main(){
int i=3;
int j = 6;
int k = f1(i,j);
printf("%d",k);
}
9
Function prototype
#include
int change(int number); /*Function prototype */
int main(void)
{
int number = 10;
int result = 0;
result = change(number);
printf("\nIn main, result = %d\tnumber = %d", result, number);
return 0;
}
int change(int number)
{
number = 2 * number;
printf("\nIn function change, number = %d\n", number);
return number;
}
In function change, number = 20
In main, result = 20 number = 10
Function is defined after main: prototype the function
#include
f1(int *k);
main ( ){
int i;
i = 0;
printf (" The value of i before call %d \n", i);
f1 (&i);
printf (" The value of i after call %d \n", i);
}
f1(int *k)
{
*k = *k + 10;
}
The value of i before call 0
The value of i after call 10
Function is defined above the function main: it is not necessary to prototype the function
#include
void f1(int *k)
{
*k = *k + 10;
}
main ( ){
int i;
i = 0;
printf (" The value of i before call %d \n", i);
f1 (&i);
printf (" The value of i after call %d \n", i);
}
The value of i before call 0
The value of i after call 10
Function calls function
#include
f1 (void)
{
printf ("f1-1 \n");
f2 ( );
printf ("f1-2 \n");
}
f2 ()
{
printf ("f2 \n");
}
main ( )
{
printf ("1 \n");
f1 ( );
printf ("2 \n");
}
1
f1-1
f2
f1-2
2
Parameter passing
Information can be passed into function.
#include
main ( )
{
int i;
i = 0;
printf (" The value of i before call %d \n", i);
f1 (i);
printf (" The value of i after call %d \n", i);
}
f1 (int k)
{
k = k + 10;
}
The value of i before call 0
The value of i after call 0
Call by reference
#include
main ( )
{
int i;
i = 0;
printf (" The value of i before call %d \n", i);
f1 (&i);
printf (" The value of i after call %d \n", i);
}
f1(int *k)
{
*k = *k + 10;
}
The value of i before call 0
The value of i after call 10
Pass variables to function
#include
float average(float x, float y)
{
return (x + y)/2.0f;
}
int main(void)
{
float value1 = 1.0F;
float value2 = 2.0F;
float value3 = 0.0F;
value3 = average(value1, value2);
printf("\nThe average is: %f\n", value3);
return 0;
}
The average is: 1.500000
Use pointer as function parameter
#include
int change(int* pnumber); /* Function prototype */
int main(void)
{
int number = 10;
int *pnumber = &number;
int result = 0;
result = change(pnumber);
printf("\nIn main, result = %d\tnumber = %d", result, number);
return 0;
}
int change(int *pnumber)
{
*pnumber *= 2;
printf("\nIn function change, *pnumber = %d\n", *pnumber );
return *pnumber;
}
In function change, *pnumber = 20
In main, result = 20 number = 20
Cube a variable using call-by-value
#include
int cubeByValue( int n );
int main()
{
int number = 5;
printf( "The original value of number is %d", number );
/* pass number by value to cubeByValue */
number = cubeByValue( number );
printf( "\nThe new value of number is %d\n", number );
return 0;
}
int cubeByValue( int n ) {
return n * n * n;
}
The original value of number is 5
The new value of number is 125
Cube a variable using call-by-reference with a pointer argument
#include
void cubeByReference( int *nPtr );
int main()
{
int number = 5;
printf( "The original value of number is %d", number );
cubeByReference( &number );
printf( "\nThe new value of number is %d\n", number );
return 0;
}
void cubeByReference( int *nPtr )
{
*nPtr = *nPtr * *nPtr * *nPtr; /* cube *nPtr */
}
The original value of number is 5
The new value of number is 125
Pointing to functions
#include
int sum(int x, int y)
{
return x + y;
}
int product(int x, int y)
{
return x * y;
}
int difference(int x, int y)
{
return x - y;
}
int main(void)
{
int a = 10;
int b = 5;
int result = 0;
int (*pfun)(int, int); /* Function pointer declaration */
pfun = sum;
result = pfun(a, b); /* Call sum() through pointer */
printf("\npfun = sum result = %d", result);
pfun = product;
result = pfun(a, b); /* Call product() through pointer */
printf("\npfun = product result = %d", result);
pfun = difference;
result = pfun(a, b); /* Call difference() through pointer */
printf("\npfun = difference result = %d\n", result);
return 0;
}
pfun = sum result = 15
pfun = product result = 50
pfun = difference result = 5
Arrays of Pointers to functions
#include
int sum(int x, int y){
return x + y;
}
int product(int x, int y){
return x * y;
}
int difference(int x, int y){
return x - y;
}
int main(void){
int a = 10;
int b = 5;
int result = 0;
int (*pfun[3])(int, int); /* Function pointer array declaration */
/* Initialize pointers */
pfun[0] = sum;
pfun[1] = product;
pfun[2] = difference;
int i;
for(i = 0 ; i < 3 ; i++)
{
result = pfun[i](a, b); /* Call the function through a pointer */
printf("\nresult = %d", result); /* Display the result */
}
return 0;
}
result = 15
result = 50
result = 5
Using array of pointers to functions in one statement
#include
int sum(int x, int y){
return x + y;
}
int product(int x, int y){
return x * y;
}
int difference(int x, int y){
return x - y;
}
int main(void){
int a = 10;
int b = 5;
int result = 0;
int (*pfun[3])(int, int); /* Function pointer array declaration */
/* Initialize pointers */
pfun[0] = sum;
pfun[1] = product;
pfun[2] = difference;
/* Call all three functions through pointers in an expression */
result = pfun[1](pfun[0](a, b), pfun[2](a, b));
printf("\n\nThe product of the sum and the difference = %d\n",
result);
return 0;
}
The product of the sum and the difference = 75
Passing a pointer of a function to another function
/*
Beginning C: From Novice to Professional, Fourth Edition
By Ivor Horton
ISBN: 1-59059-735-4
640 pp.
Published: Oct 2006
*/
#include
int any_function(int(*pfun)(int, int), int x, int y){
return pfun(x, y);
}
int sum(int x, int y){
return x + y;
}
int product(int x, int y){
return x * y;
}
int difference(int x, int y){
return x - y;
}
int main(void){
int a = 10;
int b = 5;
int result = 0;
int (*pf)(int, int) = sum; /* Pointer to sum function */
result = any_function(pf, a, b);
printf("\nresult = %d", result );
result = any_function(product,a, b);
printf("\nresult = %d", result );
printf("\nresult = %d\n", any_function(difference, a, b));
return 0;
}
result = 15
result = 50
result = 5
If the function does not return any value
Set the return data type as void.
#include
void add() {
printf("asdfasdf");
}
main ()
{
add();
add();
add();
}
asdfasdfasdfasdfasdfasdf
Return value as pointer
#include
long *myFunction(long* pPay);
int main(void)
{
long your_pay = 30000L;
long *pold_pay = &your_pay;
long *pnew_pay = NULL;
pnew_pay = myFunction( pold_pay );
printf("\nOld pay = $%ld", *pold_pay);
printf(" New pay = $%ld\n", *pnew_pay);
return 0;
}
long *myFunction(long *pPay)
{
*pPay += 10000L;
return pPay;
}
Old pay = $40000 New pay = $40000
Functions That Return value
#include
#include
int getval(void);
int main()
{
int weight;
weight=getval();
return(0);
}
int getval(void)
{
char input[20];
int x;
printf("some integer:");
gets(input);
x=atoi(input);
return(x);
}
some integer:123
va_arg, va_copy, va_start, and va_end
Item Value Header file stdarg.h Declartion type va_arg(va_list argptr, type);void va_copy(va_list target, va_list source);void va_end(va_list argptr);void va_start(va_list argptr, last_parm);
Use va_arg(), va_start(), and va_end() macros together to pass a variable number of arguments to a
function. For example, printf(). The type va_list is defined by .
#include
#include
double sum_series(int num, ...);
/* Variable length argument example - sum a series. */
int main(void)
{
double d;
d = sum_series(5, 0.5, 0.25, 0.125, 0.0625, 0.03125);
printf("Sum of series is %f.\n", d);
return 0;
}
double sum_series(int num, ...)
{
double sum=0.0, t;
va_list argptr;
/* initialize argptr */
va_start(argptr, num);
/* sum the series */
for( ; num; num--) {
t = va_arg(argptr, double); /* get next argument */
sum += t;
}
/* do orderly shutdown */
va_end(argptr);
return sum;
}
Sum of series is 0.968750.
Unit-III
USER DEFINED DATATYPES
Structure:
1. 1. Introduction Structures
Combine variables into a single package called a structure.
Structures are declared by using the struct keyword.
struct sampleName{ int a; char b;}
This structure is named sampleName.
It contains two variables: an integer named a and a character named b.
The above command only creates the structure.(it doesn't declare any variables.)
The following line declares a structure variable named s1.
struct sample s1; Items within the structure are referred to by using dot notation.
printf("Character 1 is %s\n",g1.name);
Define a structure for recording students
#include struct student{ char *name; float marks;} student1, student2;int main ( ){
struct student student3; student1.name = "Tom"; student2.marks = 99.9; printf (" Name is %s \n", student1.name); printf (" Marks are %f \n", student2.marks);}
Name is Tom
Marks are 99.900002
Arrays of structure:
It is possible to define a array of structures for example if we are maintaining information of all the students in the college and if 100 students are studying in the college. We need to use an array than single variables. We can define an array of structures as shown in the following example: structure information { int id_no; char name[20]; char address[20]; char combination[3]; int age; } student[100]; An array of structures can be assigned initial values just as any other array can. Remember that each element is a structure that must be assigned corresponding initial values as illustrated below. #include< stdio.h > { struct info { int id_no; char name[20]; char address[20]; char combination[3]; int age; } struct info std[100]; int I,n; printf(“Enter the number of students”); scanf(“%d”,&n); printf(“ Enter Id_no,name address combination age\m”); for(I=0;I < n;I++) scanf(%d%s%s%s%d”,&std[I].id_no,std[I].name,std[I].address,std[I].combination,&std[I].age); printf(“\n Student information”); for (I=0;I< n;I++) printf(“%d%s%s%s%d\n”, ”,std[I].id_no,std[I].name,std[I].address,std[I].combination,std[I].age); }
Passing structure to functions:
We can pass structures as arguments to functions. Unlike array names however, which always point to the start of the array, structure names are not pointers. As a result, when we change structure parameter inside a function, we don’t effect its corresponding argument.
Passing structure to elements to functions
Passing entire function to functions
Passing structure to elements to functions: A structure may be passed into a function as individual member or a separate variable. A program example to display the contents of a structure passing the individual elements to a function is shown below. # include < stdio.h > void main() { int emp_id; char name[25]; char department[10]; float salary; }; static struct emp1={125,”sampath”,”operator”,7500.00}; /* pass only emp_id and name to display function*/ display(emp1.emp_id,emp1.name); } /* function to display structure variables*/ display(e_no,e_name) int e_no,e_name; { printf(“%d%s”,e_no,e_name); in the declaration of structure type, emp_id and name have been declared as integer and character array. When we call the function display() using display(emp1.emp_id,emp1.name); we are sending the emp_id and name to function display(0); it can be immediately realized that to pass individual elements would become more tedious as the number of structure elements go on increasing a better way would be to pass the entire structure variable at a time.
Passing entire function to functions:
In case of structures having to having numerous structure elements passing these individual elements would be a tedious task. In such cases we may pass whole structure to a function as shown below: # include stdio.h> { int emp_id; char name[25]; char department[10]; float salary; }; void main() { static struct employee emp1= { 12, “sadanand”, “computer”, 7500.00 }; /*sending entire employee structure*/ display(emp1); } /*function to pass entire structure variable*/ display(empf) struct employee empf { printf(“%d%s,%s,%f”, empf.empid,empf.name,empf.department,empf.salary); }
Structure within a structure:
A structure may be defined as a member of another structure. In such structures the declaration of the embedded structure must appear before the declarations of other structures. struct date { int day; int month; int year; }; struct student { int id_no; char name[20]; char address[20]; char combination[3]; int age; structure date def; structure date doa; }oldstudent, newstudent;
the sturucture student constains another structure date as its one of its members.
Union:
The uses of union are few and far between. On most computers, the size of a pointer and an int are usually the same- this is because both usually fit into a register in the CPU. So if you want to do a quick and dirty cast of a pointer to an int or the other way, declare a union.
union intptr { int i; int * p;};union intptr x; /*declare a union variable identifier*/x.i = 1000; /*Assigning a value to I */*(x.p)=90; /* puts 90 at location 1000 */
Union in Structure:
Another use of a union is in a command or message protocol where different size messages are sent and received. Each message type will hold different information but each will have a fixed part (probably a struct) and a variable part bit. This is how you might implement it..
struct head { int id; int response; int size;};struct msgstring50 { struct head fixed; char message[50];}struct struct msgstring80 { struct head fixed; char message[80];} struct msgint10 { struct head fixed; int message[10];}struct msgack { struct head fixed; int ok;}union messagetype { struct msgstring50 m50; struct msgstring80 m80; struct msgint10 i10; struct msgack ack;}
In practice, although the unions are the same size, it makes sense to only send the meaningful data and not wasted space. A msgack is just 16 bytes in size while a msgstring80 is 92 bytes. So when a messagetype variable is initialized, it has its size field set according to which type it is. This can then be used by other functions to transfer the correct number of bytes.
union messagetype ackmsg;ackmsg.fixed.size = sizeof(msgack) ; /* 16 */
BIT FIELDSConsider the following data elements defined for a PABX telephone system.
flag = 1 bit
off_hook = 1 bit
status = 2 bits
In C, these can be defined as a structure, and the number of bits each occupy can be specified.
struct packed_struct {
unsigned int flag:1;
unsigned int off_hook:1;
unsigned int status:2;
} packed_struct1;
The :1 following the variable flag indicates that flag occupies a single bit. The C compiler will assign all the above fields into a single word.
Assignment is as follows,
packed_struct1.flag = 0;
packed_struct1.status = 3;
if( packed_struct1.flag )
.............
Fig. 1. Example of combined union/bitfield usage. From OKL4 2.1, ”include/caps.h”, lines 92-100.
Consider, as an example, a pixeldefinition in some 16 bits ARGB format:#include #include enum months { JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC };int main(){ enum months month; const char *monthName[] = { "", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; for ( month = JAN; month <= DEC; month++ ) { printf( "%2d%11s\n", month, monthName[ month ] ); } return 0;}Result:
1 January
2 February
3 March
4 April
5 May
6 June
7 July
8 August
9 September
10 October
11 November
12 December
Unit-IV
File Handling
4.1 Files in C
File handling in C Language
In this section, we will discuss about files which are very important for large-scale data processing. Data are stored in data files and programs are stored in program files.
What is a File?
Abstractly, a file is a collection of bytes stored on a secondary storage device, which is generally a disk of some kind. The collection of bytes may be interpreted, for example, as characetrs, words, lines, paragraphs and pages from a textual document; fields and records belonging to a database; or pixels from a graphical image. The meaning attached to a particular file is determined entirely by the data structures and operations used by a program to process the file. It is conceivable (and itsometimes happens) that a graphics file will be read and displayed by a program designed to process textual data. The result is that no meaningful output occurs (probably) and this is to be expected. A file is simply a machine decipherable storage media where programs and data are stored for machine usage.
Essentially there are two kinds of files that programmers deal with text files and binary files. These two classes of files will be discussed in the following sections.
ASCII Text files
A text file can be a stream of characters that a computer can process sequentially. It is not only processed sequentially but only in forward direction. For this reason a text file is usually opened for only one kind of operation (reading, writing, or appending) at any given time.
Similarly, since text files only process characters, they can only read or write data one character at a time. (In C Programming Language, Functions are provided that deal with lines of text, but these still essentially process data one character at a time.) A text stream in C is a special kind of file. Depending on the requirements of the operating system, newline characters may be converted to or from carriage-return/linefeed combinations depending on whether data is being written to, or read from, the file. Other character conversions may also occur to satisfy the storage requirements of the operating system. These translations occur transparently and they occur because the programmer has signalled the intention to process a text file.
Binary files
A binary file is no different to a text file. It is a collection of bytes. In C Programming Language a byte and a character are equivalent. Hence a binary file is also referred to as a character stream, but there are two essential differences.
No special processing of the data occurs and each byte of data is transferred to or from the disk unprocessed.
C Programming Language places no constructs on the file, and it may be read from, or written to, in any manner chosen by the programmer.
Binary files can be either processed sequentially or, depending on the needs of the application, they can be processed using random access techniques. In C Programming Language, processing a file using random access techniques involves moving the current file position to an appropriate place in the file before reading or writing data. This indicates a second characteristic of binary files – they a generally processed using read and write operations simultaneously.
For example, a database file will be created and processed as a binary file. A record update operation will involve locating the appropriate record, reading the record into memory, modifying it in some way, and finally writing the record back to disk at its appropriate location in the file. These kinds of operations are common to many binary files, but are rarely found in applications that process text files.
C File Handling - File Pointers
C communicates with files using a new datatype called a file pointer. This type is defined within stdio.h, and written as FILE *. A file pointer called output_file is declared in a statement like
FILE *output_file;
When accessing files through C, the first necessity is to have a way to access the files. For C File I/O you need to use a FILE pointer, which will let the program keep track of the file being accessed. (You can think of it as the memory address of the file or the location of the file).For example:
FILE *fp;
To open a file you need to use the fopen function, which returns a FILE pointer. Once you've opened a file, you can use the FILE pointer to let the compiler perform input and output functions on the file.
FILE *fopen(const char *filename, const char *mode);
In the filename, if you use a string literal as the argument, you need to remember to use double backslashes rather than a single backslash as you otherwise risk an escape character such as \t. Using double backslashes \\ escapes the \ key, so the string works as it is expected. Your users, of course, do not need to do this! It's just the way quoted strings are handled in C and C++. fopen()
Item Value Header #include Declaration FILE *fopen(const char *fname, const char *mode); Function opens a file by *fname Return returns a FILE pointer on success or NULL pointer on failure The legal values for mode.
Mode
Meaning
"r"
Open text file for reading
"w"
Create a text file for writing
"a"
Append to text file
"rb"
Open binary file for reading
"wb"
Create binary file for writing
"ab"
Append to a binary file
"r+"
Open text file for read/write
"w+"
Create text file for read/write
"a+"
Open text file for read/write
"rb+" or "r+b"
Open binary file for read/write
"wb+" or "w+b"
Create binary file for read/write
"ab+" or "a+b"
Open binary file for read/write
The correct method of opening a file:
#include #include int main(int argc, char *argv[]) { FILE *fp; if ((fp = fopen("test", "w"))==NULL) { printf("Cannot open file.\n"); exit(1); } fclose(fp); }
This fragment opens a file called TEST for binary read/write operations:
#include #include int main(int argc, char *argv[]) { FILE *fp; if((fp=fopen("test", "rb+"))==NULL) { printf("Cannot open file.\n"); exit(1); } fclose(fp); }
FCLOSE - flush and close a file.
(ANSI Standard)
"fclose" flushes any buffers maintained for the given file and closes the file. Buffers allocated by the standard I/O system are freed.
Fclose
Item Value Header file stdio.h Declaration int fclose(FILE *stream); Function Closes the file and flushes its buffer. Trying to close a file that has already been closed is an error. Return value If successful, zero is returned, or EOF is returned. #include #include int main(void) { FILE *fp; if((fp=fopen("test", "rb"))==NULL) { printf("Cannot open file.\n"); exit(1); } if(fclose(fp)) printf("File close error.\n"); return 0; }
FFLUSH - flush an output stream.(ANSI Standard)
Fflush
Item Value Header #include Declaration int fflush(FILE *stream); Function force the buffer contents to be written to the file. Return 0 on success or EOF on error. #include #include int main(void){ FILE *fp;
if((fp=fopen("test", "rb"))==NULL) { printf("Cannot open file.\n"); exit(1); } char ch = 'C'; int i; for(i=0; i<5; i++) { fwrite(ch, sizeof(ch), 1, fp); fflush(fp); } fclose(fp); return 0; }
Character input/output:(textfiles)
getchar()
putchar()
getc()
putc()
fgetc()
fputc()
ungetc()
These functions are declared in the header file `stdio.h'.
Function: int getchar (void)
The getchar function is equivalent to getc with stdin as the value of the stream argument.
Getchar()
Item Value
Header file stdio.h Declaration int getchar(void); Function read a character from stdin. Return returns EOF on error. Read characters from stdin into the array s until the user presses ENTER
#include int main(void) { char s[256], *p; p = s; printf("input char:"); while((*p++ = getchar())!= '\n'); *p = '\0'; /* add null terminator */ printf(s); return 0; }
input char:123
123
putchar()
Item Value Header file stdio.h Declaration int putchar(int ch); Function output character to stdout. Return returns the character written if successful or EOF on error. #include int main(void){ char *str = "www.java2s.com"; for(; *str; str++){ putchar(*str); }}
Result:
www.java2s.com
getc()
Item Value Header file stdio.h Declaration int getc(FILE *stream); Function reads a character from stream. Return returns EOF on file end or error. When working with binary files, you must use ferror() to check errors.
The functions getc() and fgetc() are identical except that in most implementations getc() is defined as a macro.
#include #include int main(int argc, char *argv[]) { FILE *fp; char ch; if((fp=fopen("test", "r"))==NULL) { printf("Cannot open file.\n"); exit(1); } while((ch=getc(fp))!=EOF) { printf("%c", ch); } fclose(fp); return 0; }
putc()
Item Value Header file stdio.h Declaration int putc(int ch, FILE *stream); Function writes a character to the output stream. Return returns the character written on success and EOF on error. For binary mode, you can use ferror() to determine whether an error has occurred.
#include int main(void){ FILE *fp; if((fp=fopen("test", "w"))==NULL) { printf("Cannot open file.\n"); exit(1); } char *str = "www.java2s.com"; for(; *str; str++){ putc(*str, fp); } }
fgetc()
Item Value Header #include Declaration int fgetc(FILE *stream); Function gets the next character from the stream and increments the file position pointer. Return EOF: if the end of the file is reached.
When working with binary files
use feof() to check for the end of the file.
use ferror() to check for file errors.
#include #include int main(int argc, char *argv[]) { FILE *fp; char ch; if((fp=fopen("test","r"))==NULL) { printf("Cannot open file.\n"); exit(1); } while((ch=fgetc(fp)) != EOF) { printf("%c", ch); } fclose(fp); return 0; }
fputc()
Value Item Header file stdio.h Declaration int fputc(int ch, FILE *stream); Function writes the character 'ch' to the stream. Return returns the value of the character written on success or EOF on failure. #include #include int main(void) { FILE *fp; if((fp=fopen("test", "wb"))==NULL) { printf("Cannot open file.\n"); exit(1); } char *str = "www.java2s.com"; while(*str){ if(!ferror(fp)) { fputc(*str++, fp); } } fclose(fp); }
ungetc()
Item Value Header file stdio.h Declaration int ungetc(int ch, FILE *stream); Function Put the character ch back to the input stream stream. This character will be obtained by the next read operation on stream. Return returns ch on success or EOF on failure. A call to fflush(), fseek(), or rewind() discards the character.
You may not unget an EOF.
#include int main (){ FILE * fp; int c; char buffer [256]; fp = fopen ("test.txt","rt"); if (fp==NULL) perror ("Error opening file"); else { while (!feof (fp)) { c=getc (fp); if (c == '#') ungetc ('@',fp); else ungetc (c,fp); fgets (buffer,255,fp); fputs (buffer,stdout); } } return 0; }
Detecting of EOF using feof() function:
feof()
Item Value Header #include Declaration int feof(FILE *stream); Function determines whether the end of the file has been reached. Return A nonzero value: if the file pointer is at the end of the file. zero: otherwise.
#include #include int main(void){ FILE *fp; if((fp=fopen("test", "rb"))==NULL) { printf("Cannot open file.\n"); exit(1); } while(!feof(fp)) { char ch = getc(fp); printf("%c",ch); } fclose(fp); }
Block Input/Output or direct input/output
For binary File I/O you use fread and fwrite.
fread():
Item Value Header file stdio.h Declaration size_t fread(void *buf, size_t size, size_t count, FILE *stream); Function reads count number of objects by size and stores them in *buf. Return returns the number of items actually read. Use feof() to determine the end of file.
Use ferror() to determine the error.
#include
#include int main(void) { FILE *fp; float bal[5] = { 1.1F, 2.2F, 3.3F, 4.4F, 5.5F }; int i; if((fp=fopen("test", "wb"))==NULL) { printf("Cannot open file.\n"); exit(1); } if(fwrite(bal, sizeof(float), 5, fp) != 5) printf("File read error."); fclose(fp); if((fp=fopen("test", "rb"))==NULL) { printf("Cannot open file.\n"); exit(1); } if(fread(bal, sizeof(float), 5, fp) != 5) { if(feof(fp)) { printf("Premature end of file."); }else { printf("File read error."); } } fclose(fp); for(i=0; i<5; i++){ printf("%f ", bal[i]); } return 0; }
1.100000 2.200000 3.300000 4.400000 5.500000
fwrite():
Item Value Header file stdio.h Declaration size_t fwrite(const void *buf, size_t size, size_t count, FILE *stream); Function writes count number of objects. Return returns the number of items written on success. Fewer items written means failure. #include #include int main(void) { FILE *fp; float f=12.23; if((fp=fopen("test", "wb"))==NULL) { printf("Cannot open file.\n"); exit(1); } fwrite(&f, sizeof(float), 1, fp); fclose(fp); return 0; }
Random accessfile processing:
ftell()
rewind()
fseek()
ftell():
Item Value Header file stdio.h Declaration long int ftell(FILE *stream); Function returns the value for the file position pointer. Valid for binary file and invalid for text file. Return returns -1 on failure. #include #include int main(void){ FILE *fp; if((fp=fopen("test", "rb")) == NULL) { printf("Cannot open file.\n"); exit(1); } int i; if((i=ftell(fp)) == -1L) printf("A file error has occurred.\n"); fclose(fp); }
2.rewind():
Item Value Header file stdio.h Declaration void rewind(FILE *stream); Function moves the file position pointer back to the start. #include #include int main(int argc, char *argv[]) { FILE *fp; if((fp=fopen("test", "r"))==NULL) { printf("Cannot open file.\n"); exit(1); } while(!feof(fp)){ putchar(getc(fp)); } rewind(fp); while(!feof(fp)){ putchar(getc(fp)); } fclose(fp); }
3.fseek():
Item Value Header file stdio.h Declaration int fseek(FILE *stream, long int offset, int origin); Function moves the file position pointer. Return zero on success or nonzero on failure. 'origin' must be one of:
Name Meaning SEEK_SET Seek from start of file SEEK_CUR Seek from current location SEEK_END Seek from end of file For a text file, origin must be SEEK_SET and offset must be a value obtained by calling ftell(), or zero.
#include #include struct fullname { char firstName[40]; char lastName[10]; } info; int main(void){ FILE *fp; if((fp=fopen("test", "rb")) == NULL) { printf("Cannot open file.\n"); exit(1); } int client_num = 10; /* find the proper structure */ fseek(fp, client_num*sizeof(struct fullname), SEEK_SET); /* read the data into memory */ fread(&info, sizeof(struct fullname), 1, fp); fclose(fp); }
Other file management function:
ferror()
clearer()
feof()
remove()
rename()
tmpfile()
fprintf()
fscanf()
ferror():
Item Value Header #include Declaration int ferror(FILE *stream); Function checks for a file error. Return 0: no error has occurred. Nonzero: an error has occurred. Use the perror() function to find out more about the error.
#include #include int main(void){ FILE *fp; if((fp=fopen("test", "rb"))==NULL) { printf("Cannot open file.\n"); exit(1); } putc('C', fp); if(ferror(fp)) { printf("File Error\n"); exit(1); } fclose(fp); return 0; }
Clearerr():
Item Value Header file stdio.h Declaration void clearerr(FILE *stream); Function Reset (set to zero) the error flag. The end-of-file indicator is also reset. #include #include int main(int argc, char *argv[]) { FILE *in, *out; char ch; if((in=fopen("inFile.txt", "rb")) == NULL) { printf("Cannot open input file.\n"); exit(1); } if((out=fopen("outFile.txt", "wb")) == NULL) { printf("Cannot open output file.\n"); exit(1); } while(!feof(in)) { ch = getc(in); if(ferror(in)) { printf("Read Error"); clearerr(in); break; } else { if(!feof(in)) putc(ch, out); if(ferror(out)) { printf("Write Error"); clearerr(out); break; } } } fclose(in); fclose(out); return 0; }
feof()
Item Value Header #include Declaration int feof(FILE *stream); Function determines whether the end of the file has been reached. Return A nonzero value: if the file pointer is at the end of the file. zero: otherwise. #include #include int main(void){ FILE *fp; if((fp=fopen("test", "rb"))==NULL) { printf("Cannot open file.\n"); exit(1); } while(!feof(fp)) { char ch = getc(fp); printf("%c",ch); } fclose(fp); }
remove():
Item Value Header file stdio.h Declaration int remove(const char *fname); Function delete file by *fname. Return returns zero on success or nonzero on error. #include int main(int argc, char *argv[]) { if(remove("test")) printf("Remove Error"); return 0; }
rename():
Item Value Header file stdio.h Declaration int rename(const char *oldfname, const char *newfname); Function changes the file name. Return returns zero on success or nonzero on error. #include int main(int argc, char *argv[]) { if(rename("oldName", "newName") != 0){ printf("Rename Error"); } return 0; }
Tmpfile():
Item Value Header file stdio.h Declaration FILE *tmpfile(void); Function opens a temporary binary file for read/write operations and returns a pointer to the stream. Return returns a null pointer on failure.
The temporary file created by tmpfile() is automatically removed when the file is closed or when the program terminates.
You can open TMP_MAX temporary files (up to the limit set by FOPEN_MAX).
#include int main(void){ FILE *temp; if((temp=tmpfile())==NULL) { printf("Cannot open temporary work file.\n"); exit(1); }}
fprintf():
Item Value Header #include Declaration int fprintf(FILE *stream, const char *format, ...); Function outputs the values to the stream. Return returns the number of characters actually printed on success or a negative number on failure. The format control string are identical to those in printf();
#include #include int main(void) { FILE *fp; if((fp=fopen("test", "wb"))==NULL) { printf("Cannot open file.\n"); exit(1); } fprintf(fp, "this is a test %d %f", 10, 20.01); fclose(fp); return 0; }
fscanf ():
Item Value Header file stdio.h Declaration int fscanf(FILE *stream, const char *format, ...); Function It works exactly like the scanf() function except that it reads from the stream. Return returns the number of arguments actually assigned values or EOF on failure.
#include
#include
int main(void)
{
FILE *fp;
float bal[5] = { 1.1F, 2.2F, 3.3F, 4.4F, 5.5F };
int i;
if((fp=fopen("test", "wb"))==NULL) {
printf("Cannot open file.\n");
exit(1);
}
if(fwrite(bal, sizeof(float), 5, fp) != 5){
printf("File read error.");
}
fclose(fp);
char str[80];
float f;
fscanf(fp, "%s%f", str, &f);
fclose(fp);
}
Low-Level Input/Output
Low-Level Input/Output describes functions for performing low-level input/output operations on file descriptors. These functions include the primitives for the higher-level I/O functions described in section Input/Output on Streams, as well as functions for performing low-level control operations for which there are no equivalents on streams.
Stream-level I/O is more flexible and usually more convenient; therefore, programmers generally use the descriptor-level functions only when necessary. These are some of the usual reasons:
For reading binary files in large chunks.
For reading an entire file into core before parsing it.
To perform operations other than data transfer, which can only be done with a descriptor. (You can use fileno to get the descriptor corresponding to a stream.)
To pass descriptors to a child process. (The child can create its own stream to use a descriptor that it inherits, but cannot inherit a stream directly.)
Opening and Closing Files
This section describes the primitives for opening and closing files using file descriptors. The open and creat functions are declared in the header file `fcntl.h', while close is declared in `unistd.h'.
Function: int open (const char *filename, int flags[, mode_t mode])
The open function creates and returns a new file descriptor for the file named by filename. Initially, the file position indicator for the file is at the beginning of the file. The argument mode is used only when a file is created, but it doesn't hurt to supply the argument in any case.
The flags argument controls how the file is to be opened. This is a bit mask; you create the value by the bitwise OR of the appropriate parameters (using the `|' operator in C).
The flags argument must include exactly one of these values to specify the file access mode:
O_RDONLY
Open the file for read access.
O_WRONLY
Open the file for write access.
O_RDWR
Open the file for both reading and writing.
The open function is the underlying primitive for the fopen and freopen functions, that create streams.
Obsolete function: int creat (const char *filename, mode_t mode)
This function is obsolete. The call
creat (filename, mode)
is equivalent to
open (filename, O_WRONLY | O_CREAT | O_TRUNC, mode)
Function: int close (int filedes)
The function close closes the file descriptor filedes. Closing a file has the following consequences:
The file descriptor is deallocated.
Any record locks owned by the process on the file are unlocked.
When all file descriptors associated with a pipe or FIFO have been closed, any unread data is discarded.
The normal return value from close is 0; a value of -1 is returned in case of failure.
To close a stream, call fclose instead of trying to close its underlying file descriptor with close. This flushes any buffered output and updates the stream object to indicate that it is closed.
Input and Output Primitives
This section describes the functions for performing primitive input and output operations on file descriptors: read, write, and lseek. These functions are declared in the header file `unistd.h'.
Function: ssize_t read (int filedes, void *buffer, size_t size)
The read function reads up to size bytes from the file with descriptor filedes, storing the results in the buffer. (This is not necessarily a character string and there is no terminating null character added.)
The return value is the number of bytes actually read. This might be less than size; for example, if there aren't that many bytes left in the file or if there aren't that many bytes immediately available. The exact behavior depends on what kind of file it is. Note that reading less than size bytes is not an error.
A value of zero indicates end-of-file (except if the value of the size argument is also zero). This is not considered an error. If you keep calling read while at end-of-file, it will keep returning zero and doing nothing else.
If read returns at least one character, there is no way you can tell whether end-of-file was reached. But if you did reach the end, the next read will return zero.
In case of an error, read returns -1.
Data Type: ssize_t
This data type is used to represent the sizes of blocks that can be read or written in a single operation. It is similar to size_t, but must be a signed type.
Function: ssize_t write (int filedes, const void *buffer, size_t size)
The write function writes up to size bytes from buffer to the file with descriptor filedes. The data in buffer is not necessarily a character string and a null character output like any other character.
The return value is the number of bytes actually written. This is normally the same as size, but might be less (for example, if the physical media being written to fills up).
In the case of an error, write returns -1.
Setting the File Position of a Descriptor
Just as you can set the file position of a stream with fseek, you can set the file position of a descriptor with lseek. This specifies the position in the file for the next read or write operation. See section File Positioning, for more information on the file position and what it means.
To read the current file position value from a descriptor, use lseek (desc, 0, SEEK_CUR).
Function: off_t lseek (int filedes, off_t offset, int whence)
The lseek function is used to change the file position of the file with descriptor filedes.
The whence argument specifies how the offset should be interpreted in the same way as for the fseek function, and can be one of the symbolic constants SEEK_SET, SEEK_CUR, or SEEK_END.
SEEK_SET
Specifies that whence is a count of characters from the beginning of the file.
SEEK_CUR
Specifies that whence is a count of characters from the current file position. This count may be positive or negative.
SEEK_END
Specifies that whence is a count of characters from the end of the file. A negative count specifies a position within the current extent of the file; a positive count specifies a position past the current end. If you set the position past the current end, and actually write data, you will extend the file with zeros up to that position.
The return value from lseek is normally the resulting file position, measured in bytes from the beginning of the file. You can use this feature together with SEEK_CUR to read the current file position.
You can set the file position past the current end of the file. This does not by itself make the file longer; lseek never changes the file. But subsequent output at that position will extend the file's size.
If the file position cannot be changed, or the operation is in some way invalid, lseek returns a value of -1.
The lseek function is the underlying primitive for the fseek, ftell and rewind functions, which operate on streams instead of file descriptors.
You can have multiple descriptors for the same file if you open the file more than once, or if you duplicate a descriptor with dup. Descriptors that come from separate calls to open have independent file positions; using lseek on one descriptor has no effect on the other. For example,
{
int d1, d2;
char buf[4];
d1 = open ("foo", O_RDONLY);
d2 = open ("foo", O_RDONLY);
lseek (d1, 1024, SEEK_SET);
read (d2, buf, 4);
}
will read the first four characters of the file `foo'. (The error-checking code necessary for a real program has been omitted here for brevity.)
By contrast, descriptors made by duplication share a common file position with the original descriptor that was duplicated. Anything which alters the file position of one of the duplicates, including reading or writing data, affects all of them alike. Thus, for example,
{
int d1, d2, d3;
char buf1[4], buf2[4];
d1 = open ("foo", O_RDONLY);
d2 = dup (d1);
d3 = dup (d2);
lseek (d3, 1024, SEEK_SET);
read (d1, buf1, 4);
read (d2, buf2, 4);
}
will read four characters starting with the 1024'th character of `foo', and then four more characters starting with the 1028'th character.
Data Type: off_t
This is an arithmetic data type used to represent file sizes. In the GNU system, this is equivalent to fpos_t or long int.
These three aliases for the `SEEK_...' constants exist for the sake of compatibility with older BSD systems. They are defined in two different header files: `fcntl.h' and `sys/file.h'.
L_SET
An alias for SEEK_SET.
L_INCR
An alias for SEEK_CUR.
L_XTND
An alias for SEEK_END.
Descriptors and Streams
Given an open file descriptor, you can create a stream for it with the fdopen function. You can get the underlying file descriptor for an existing stream with the fileno function. These functions are declared in the header file `stdio.h'.
Function: FILE * fdopen (int filedes, const char *opentype)
The fdopen function returns a new stream for the file descriptor filedes.
The opentype argument is interpreted in the same way as for the fopen function (see section Opening Streams), except that the `b' option is not permitted; this is because GNU makes no distinction between text and binary files. Also, "w" and "w+" do not cause truncation of the file; these have affect only when opening a file, and in this case the file has already been opened. You must make sure that the opentype argument matches the actual mode of the open file descriptor.
The return value is the new stream. If the stream cannot be created (for example, if the modes for the file indicated by the file descriptor do not permit the access specified by the opentype argument), a null pointer is returned instead.
For an example showing the use of the fdopen function, see section Creating a Pipe.
Function: int fileno (FILE *stream)
This function returns the file descriptor associated with the stream stream. If an error is detected (for example, if the stream is not valid) or if stream does not do I/O to a file, fileno returns -1.
There are also symbolic constants defined in `unistd.h' for the file descriptors belonging to the standard streams stdin, stdout, and stderr; see section Standard Streams.
STDIN_FILENO
This macro has value 0, which is the file descriptor for standard input.
STDOUT_FILENO
This macro has value 1, which is the file descriptor for standard output.
STDERR_FILENO
This macro has value 2, which is the file descriptor for standard error output.
Precautions for Mixing Streams and Descriptors
You can have multiple file descriptors and streams (let's call both streams and descriptors "channels" for short) connected to the same file, but you must take care to avoid confusion between channels. There are two cases to consider: linked channels that share a single file position value, and independent channels that have their own file positions.
It's best to use just one channel in your program for actual data transfer to any given file, except when all the access is for input.
Linked Channels
Channels that come from a single opening share the same file position; we call them linked channels. Linked channels result when you make a stream from a descriptor using fdopen, when you get a descriptor from a stream with fileno, and when you copy a descriptor with dup or dup2. For files that don't support random access, such as terminals and pipes, all channels are effectively linked. On random-access files, all append-type output streams are effectively linked to each other.
If you have been using a stream for I/O, and you want to do I/O using another channel (either a stream or a descriptor) that is linked to it, you must first clean up the stream that you have been using. See section Cleaning Streams.
Terminating a process, or executing a new program in the process, destroys all the streams in the process. If descriptors linked to these streams persist in other processes, their file positions become undefined as a result. To prevent this, you must clean up the streams before destroying them.
Independent Channels
When you open channels (streams or descriptors) separately on a seekable file, each channel has its own file position. These are called independent channels.
The system handles each channel independently. Most of the time, this is quite predictable and natural (especially for input): each channel can read or write sequentially at its own place in the file. The precautions you should take are these:
You should clean an output stream after use, before doing anything else that might read or write from the same part of the file.
You should clean an input stream before reading data that may have been modified using an independent channel. Otherwise, you might read obsolete data that had been in the stream's buffer.
Cleaning Streams
On the GNU system, you can clean up any stream with fclean:
Function: int fclean (stream)
Clean up the stream stream so that its buffer is empty. If stream is doing output, force it out. If stream is doing input, give the data in the buffer back to the system, arranging to reread it.
On other systems, you can use fflush to clean a stream in most cases.
You can skip the fclean or fflush if you know the stream is already clean. A stream is clean whenever its buffer is empty. For example, an unbuffered stream is always clean. An input stream that is at end-of-file is clean. A line-buffered stream is clean when the last character output was a newline.
Block Input/Output or direct input/output
For binary File I/O you use fread and fwrite.
fread():
Item Value Header file stdio.h Declaration size_t fread(void *buf, size_t size, size_t count, FILE *stream); Function reads count number of objects by size and stores them in *buf. Return returns the number of items actually read. Use feof() to determine the end of file.
Use ferror() to determine the error.
#include
#include int main(void) { FILE *fp; float bal[5] = { 1.1F, 2.2F, 3.3F, 4.4F, 5.5F }; int i; if((fp=fopen("test", "wb"))==NULL) { printf("Cannot open file.\n"); exit(1); } if(fwrite(bal, sizeof(float), 5, fp) != 5) printf("File read error."); fclose(fp); if((fp=fopen("test", "rb"))==NULL) { printf("Cannot open file.\n"); exit(1); } if(fread(bal, sizeof(float), 5, fp) != 5) { if(feof(fp)) { printf("Premature end of file."); }else { printf("File read error."); } } fclose(fp); for(i=0; i<5; i++){ printf("%f ", bal[i]); } return 0; }
1.100000 2.200000 3.300000 4.400000 5.500000
fwrite():
Item Value Header file stdio.h Declaration size_t fwrite(const void *buf, size_t size, size_t count, FILE *stream); Function writes count number of objects. Return returns the number of items written on success. Fewer items written means failure. #include #include int main(void) { FILE *fp; float f=12.23; if((fp=fopen("test", "wb"))==NULL) { printf("Cannot open file.\n"); exit(1); } fwrite(&f, sizeof(float), 1, fp); fclose(fp); return 0; }
Random accessfile processing:
ftell()
rewind()
fseek()
ftell():
Item Value Header file stdio.h Declaration long int ftell(FILE *stream); Function returns the value for the file position pointer. Valid for binary file and invalid for text file. Return returns -1 on failure. #include #include int main(void){ FILE *fp; if((fp=fopen("test", "rb")) == NULL) { printf("Cannot open file.\n"); exit(1); } int i; if((i=ftell(fp)) == -1L) printf("A file error has occurred.\n"); fclose(fp); }
2.rewind():
Item Value Header file stdio.h Declaration void rewind(FILE *stream); Function moves the file position pointer back to the start. #include #include int main(int argc, char *argv[]) { FILE *fp; if((fp=fopen("test", "r"))==NULL) { printf("Cannot open file.\n"); exit(1); } while(!feof(fp)){ putchar(getc(fp)); } rewind(fp); while(!feof(fp)){ putchar(getc(fp)); } fclose(fp); }
3.fseek():
Item Value Header file stdio.h Declaration int fseek(FILE *stream, long int offset, int origin); Function moves the file position pointer. Return zero on success or nonzero on failure. 'origin' must be one of:
Name Meaning SEEK_SET Seek from start of file SEEK_CUR Seek from current location SEEK_END Seek from end of file For a text file, origin must be SEEK_SET and offset must be a value obtained by calling ftell(), or zero.
#include #include struct fullname { char firstName[40]; char lastName[10]; } info; int main(void){ FILE *fp; if((fp=fopen("test", "rb")) == NULL) { printf("Cannot open file.\n"); exit(1); } int client_num = 10; /* find the proper structure */ fseek(fp, client_num*sizeof(struct fullname), SEEK_SET); /* read the data into memory */ fread(&info, sizeof(struct fullname), 1, fp); fclose(fp); }
Other file management function:
ferror()
clearer()
feof()
remove()
rename()
tmpfile()
fprintf()
fscanf()
ferror():
Item Value Header #include Declaration int ferror(FILE *stream); Function checks for a file error. Return 0: no error has occurred. Nonzero: an error has occurred. Use the perror() function to find out more about the error.
#include #include int main(void){ FILE *fp; if((fp=fopen("test", "rb"))==NULL) { printf("Cannot open file.\n"); exit(1); } putc('C', fp); if(ferror(fp)) { printf("File Error\n"); exit(1); } fclose(fp); return 0; }
Clearerr():
Item Value Header file stdio.h Declaration void clearerr(FILE *stream); Function Reset (set to zero) the error flag. The end-of-file indicator is also reset. #include #include int main(int argc, char *argv[]) { FILE *in, *out; char ch; if((in=fopen("inFile.txt", "rb")) == NULL) { printf("Cannot open input file.\n"); exit(1); } if((out=fopen("outFile.txt", "wb")) == NULL) { printf("Cannot open output file.\n"); exit(1); } while(!feof(in)) { ch = getc(in); if(ferror(in)) { printf("Read Error"); clearerr(in); break; } else { if(!feof(in)) putc(ch, out); if(ferror(out)) { printf("Write Error"); clearerr(out); break; } } } fclose(in); fclose(out); return 0; }
feof()
Item Value Header #include Declaration int feof(FILE *stream); Function determines whether the end of the file has been reached. Return A nonzero value: if the file pointer is at the end of the file. zero: otherwise. #include #include int main(void){ FILE *fp; if((fp=fopen("test", "rb"))==NULL) { printf("Cannot open file.\n"); exit(1); } while(!feof(fp)) { char ch = getc(fp); printf("%c",ch); } fclose(fp); }
remove():
Item Value Header file stdio.h Declaration int remove(const char *fname); Function delete file by *fname. Return returns zero on success or nonzero on error. #include int main(int argc, char *argv[]) { if(remove("test")) printf("Remove Error"); return 0; }
rename():
Item Value Header file stdio.h Declaration int rename(const char *oldfname, const char *newfname); Function changes the file name. Return returns zero on success or nonzero on error. #include int main(int argc, char *argv[]) { if(rename("oldName", "newName") != 0){ printf("Rename Error"); } return 0; }
Tmpfile():
Item Value Header file stdio.h Declaration FILE *tmpfile(void); Function opens a temporary binary file for read/write operations and returns a pointer to the stream. Return returns a null pointer on failure.
The temporary file created by tmpfile() is automatically removed when the file is closed or when the program terminates.
You can open TMP_MAX temporary files (up to the limit set by FOPEN_MAX).
#include int main(void){ FILE *temp; if((temp=tmpfile())==NULL) { printf("Cannot open temporary work file.\n"); exit(1); }}
fprintf():
Item Value Header #include Declaration int fprintf(FILE *stream, const char *format, ...); Function outputs the values to the stream. Return returns the number of characters actually printed on success or a negative number on failure. The format control string are identical to those in printf();
#include #include int main(void) { FILE *fp; if((fp=fopen("test", "wb"))==NULL) { printf("Cannot open file.\n"); exit(1); } fprintf(fp, "this is a test %d %f", 10, 20.01); fclose(fp); return 0; }
fscanf ():
Item Value Header file stdio.h Declaration int fscanf(FILE *stream, const char *format, ...); Function It works exactly like the scanf() function except that it reads from the stream. Return returns the number of arguments actually assigned values or EOF on failure.
#include
#include
int main(void)
{
FILE *fp;
float bal[5] = { 1.1F, 2.2F, 3.3F, 4.4F, 5.5F };
int i;
if((fp=fopen("test", "wb"))==NULL) {
printf("Cannot open file.\n");
exit(1);
}
if(fwrite(bal, sizeof(float), 5, fp) != 5){
printf("File read error.");
}
fclose(fp);
char str[80];
float f;
fscanf(fp, "%s%f", str, &f);
fclose(fp);
}
Low-Level Input/Output
Low-Level Input/Output describes functions for performing low-level input/output operations on file descriptors. These functions include the primitives for the higher-level I/O functions described in section Input/Output on Streams, as well as functions for performing low-level control operations for which there are no equivalents on streams.
Stream-level I/O is more flexible and usually more convenient; therefore, programmers generally use the descriptor-level functions only when necessary. These are some of the usual reasons:
For reading binary files in large chunks.
For reading an entire file into core before parsing it.
To perform operations other than data transfer, which can only be done with a descriptor. (You can use fileno to get the descriptor corresponding to a stream.)
To pass descriptors to a child process. (The child can create its own stream to use a descriptor that it inherits, but cannot inherit a stream directly.)
Opening and Closing Files
This section describes the primitives for opening and closing files using file descriptors. The open and creat functions are declared in the header file `fcntl.h', while close is declared in `unistd.h'.
Function: int open (const char *filename, int flags[, mode_t mode])
The open function creates and returns a new file descriptor for the file named by filename. Initially, the file position indicator for the file is at the beginning of the file. The argument mode is used only when a file is created, but it doesn't hurt to supply the argument in any case.
The flags argument controls how the file is to be opened. This is a bit mask; you create the value by the bitwise OR of the appropriate parameters (using the `|' operator in C).
The flags argument must include exactly one of these values to specify the file access mode:
O_RDONLY
Open the file for read access.
O_WRONLY
Open the file for write access.
O_RDWR
Open the file for both reading and writing.
The open function is the underlying primitive for the fopen and freopen functions, that create streams.
Obsolete function: int creat (const char *filename, mode_t mode)
This function is obsolete. The call
creat (filename, mode)
is equivalent to
open (filename, O_WRONLY | O_CREAT | O_TRUNC, mode)
Function: int close (int filedes)
The function close closes the file descriptor filedes. Closing a file has the following consequences:
The file descriptor is deallocated.
Any record locks owned by the process on the file are unlocked.
When all file descriptors associated with a pipe or FIFO have been closed, any unread data is discarded.
The normal return value from close is 0; a value of -1 is returned in case of failure.
To close a stream, call fclose instead of trying to close its underlying file descriptor with close. This flushes any buffered output and updates the stream object to indicate that it is closed.
Input and Output Primitives
This section describes the functions for performing primitive input and output operations on file descriptors: read, write, and lseek. These functions are declared in the header file `unistd.h'.
Function: ssize_t read (int filedes, void *buffer, size_t size)
The read function reads up to size bytes from the file with descriptor filedes, storing the results in the buffer. (This is not necessarily a character string and there is no terminating null character added.)
The return value is the number of bytes actually read. This might be less than size; for example, if there aren't that many bytes left in the file or if there aren't that many bytes immediately available. The exact behavior depends on what kind of file it is. Note that reading less than size bytes is not an error.
A value of zero indicates end-of-file (except if the value of the size argument is also zero). This is not considered an error. If you keep calling read while at end-of-file, it will keep returning zero and doing nothing else.
If read returns at least one character, there is no way you can tell whether end-of-file was reached. But if you did reach the end, the next read will return zero.
In case of an error, read returns -1.
Data Type: ssize_t
This data type is used to represent the sizes of blocks that can be read or written in a single operation. It is similar to size_t, but must be a signed type.
Function: ssize_t write (int filedes, const void *buffer, size_t size)
The write function writes up to size bytes from buffer to the file with descriptor filedes. The data in buffer is not necessarily a character string and a null character output like any other character.
The return value is the number of bytes actually written. This is normally the same as size, but might be less (for example, if the physical media being written to fills up).
In the case of an error, write returns -1.
Setting the File Position of a Descriptor
Just as you can set the file position of a stream with fseek, you can set the file position of a descriptor with lseek. This specifies the position in the file for the next read or write operation. See section File Positioning, for more information on the file position and what it means.
To read the current file position value from a descriptor, use lseek (desc, 0, SEEK_CUR).
Function: off_t lseek (int filedes, off_t offset, int whence)
The lseek function is used to change the file position of the file with descriptor filedes.
The whence argument specifies how the offset should be interpreted in the same way as for the fseek function, and can be one of the symbolic constants SEEK_SET, SEEK_CUR, or SEEK_END.
SEEK_SET
Specifies that whence is a count of characters from the beginning of the file.
SEEK_CUR
Specifies that whence is a count of characters from the current file position. This count may be positive or negative.
SEEK_END
Specifies that whence is a count of characters from the end of the file. A negative count specifies a position within the current extent of the file; a positive count specifies a position past the current end. If you set the position past the current end, and actually write data, you will extend the file with zeros up to that position.
The return value from lseek is normally the resulting file position, measured in bytes from the beginning of the file. You can use this feature together with SEEK_CUR to read the current file position.
You can set the file position past the current end of the file. This does not by itself make the file longer; lseek never changes the file. But subsequent output at that position will extend the file's size.
If the file position cannot be changed, or the operation is in some way invalid, lseek returns a value of -1.
The lseek function is the underlying primitive for the fseek, ftell and rewind functions, which operate on streams instead of file descriptors.
You can have multiple descriptors for the same file if you open the file more than once, or if you duplicate a descriptor with dup. Descriptors that come from separate calls to open have independent file positions; using lseek on one descriptor has no effect on the other. For example,
{
int d1, d2;
char buf[4];
d1 = open ("foo", O_RDONLY);
d2 = open ("foo", O_RDONLY);
lseek (d1, 1024, SEEK_SET);
read (d2, buf, 4);
}
will read the first four characters of the file `foo'. (The error-checking code necessary for a real program has been omitted here for brevity.)
By contrast, descriptors made by duplication share a common file position with the original descriptor that was duplicated. Anything which alters the file position of one of the duplicates, including reading or writing data, affects all of them alike. Thus, for example,
{
int d1, d2, d3;
char buf1[4], buf2[4];
d1 = open ("foo", O_RDONLY);
d2 = dup (d1);
d3 = dup (d2);
lseek (d3, 1024, SEEK_SET);
read (d1, buf1, 4);
read (d2, buf2, 4);
}
will read four characters starting with the 1024'th character of `foo', and then four more characters starting with the 1028'th character.
Data Type: off_t
This is an arithmetic data type used to represent file sizes. In the GNU system, this is equivalent to fpos_t or long int.
These three aliases for the `SEEK_...' constants exist for the sake of compatibility with older BSD systems. They are defined in two different header files: `fcntl.h' and `sys/file.h'.
L_SET
An alias for SEEK_SET.
L_INCR
An alias for SEEK_CUR.
L_XTND
An alias for SEEK_END.
Descriptors and Streams
Given an open file descriptor, you can create a stream for it with the fdopen function. You can get the underlying file descriptor for an existing stream with the fileno function. These functions are declared in the header file `stdio.h'.
Function: FILE * fdopen (int filedes, const char *opentype)
The fdopen function returns a new stream for the file descriptor filedes.
The opentype argument is interpreted in the same way as for the fopen function (see section Opening Streams), except that the `b' option is not permitted; this is because GNU makes no distinction between text and binary files. Also, "w" and "w+" do not cause truncation of the file; these have affect only when opening a file, and in this case the file has already been opened. You must make sure that the opentype argument matches the actual mode of the open file descriptor.
The return value is the new stream. If the stream cannot be created (for example, if the modes for the file indicated by the file descriptor do not permit the access specified by the opentype argument), a null pointer is returned instead.
For an example showing the use of the fdopen function, see section Creating a Pipe.
Function: int fileno (FILE *stream)
This function returns the file descriptor associated with the stream stream. If an error is detected (for example, if the stream is not valid) or if stream does not do I/O to a file, fileno returns -1.
There are also symbolic constants defined in `unistd.h' for the file descriptors belonging to the standard streams stdin, stdout, and stderr; see section Standard Streams.
STDIN_FILENO
This macro has value 0, which is the file descriptor for standard input.
STDOUT_FILENO
This macro has value 1, which is the file descriptor for standard output.
STDERR_FILENO
This macro has value 2, which is the file descriptor for standard error output.
Precautions for Mixing Streams and Descriptors
You can have multiple file descriptors and streams (let's call both streams and descriptors "channels" for short) connected to the same file, but you must take care to avoid confusion between channels. There are two cases to consider: linked channels that share a single file position value, and independent channels that have their own file positions.
It's best to use just one channel in your program for actual data transfer to any given file, except when all the access is for input.
Linked Channels
Channels that come from a single opening share the same file position; we call them linked channels. Linked channels result when you make a stream from a descriptor using fdopen, when you get a descriptor from a stream with fileno, and when you copy a descriptor with dup or dup2. For files that don't support random access, such as terminals and pipes, all channels are effectively linked. On random-access files, all append-type output streams are effectively linked to each other.
If you have been using a stream for I/O, and you want to do I/O using another channel (either a stream or a descriptor) that is linked to it, you must first clean up the stream that you have been using. See section Cleaning Streams.
Terminating a process, or executing a new program in the process, destroys all the streams in the process. If descriptors linked to these streams persist in other processes, their file positions become undefined as a result. To prevent this, you must clean up the streams before destroying them.
Independent Channels
When you open channels (streams or descriptors) separately on a seekable file, each channel has its own file position. These are called independent channels.
The system handles each channel independently. Most of the time, this is quite predictable and natural (especially for input): each channel can read or write sequentially at its own place in the file. The precautions you should take are these:
You should clean an output stream after use, before doing anything else that might read or write from the same part of the file.
You should clean an input stream before reading data that may have been modified using an independent channel. Otherwise, you might read obsolete data that had been in the stream's buffer.
Cleaning Streams
On the GNU system, you can clean up any stream with fclean:
Function: int fclean (stream)
Clean up the stream stream so that its buffer is empty. If stream is doing output, force it out. If stream is doing input, give the data in the buffer back to the system, arranging to reread it.
On other systems, you can use fflush to clean a stream in most cases.
You can skip the fclean or fflush if you know the stream is already clean. A stream is clean whenever its buffer is empty. For example, an unbuffered stream is always clean. An input stream that is at end-of-file is clean. A line-buffered stream is clean when the last character output was a newline.
Unit –V
Advanced Features
Bitwise operator:
Bitwise operators only work on limited types: int and char (and variations of int). You can, with some casting, make it work on other types. These operators, in conjunction with bitshift operators allow you to access and modify bits.
There are six bit operators:
bitwise AND(&)
bitwise OR(|)
bitwise XOR(^)
bitwise complement(~)
left shift(<<)
right shift(>>)
Uses of Bitwise Operations
Occasionally, you may want to implement a large number of Boolean variables, without using a lot of space.
A 32-bit int can be used to stored 32 Boolean variables. Normally, the minimum size for one Boolean variable is one byte. All types in C must have sizes that are multiples of bytes. However, only one bit is necessary to represent a Boolean value.
You can also use bits to represent elements of a (small) set. If a bit is 1, then element i is in the set, otherwise it's not.
You can use bitwise AND to implement set intersection, bitwise OR to implement set union.
Bitwise Program
Example1:
# includemain(){ char c1 = 1,c2 = 2,c3 = 3; c3 = c1 & c2; printf("\n Bitwise AND i.e. c1 & c2 = %c",c3); c3 = c1 | c2; printf("\n Bitwise OR i.e. c1 | c2 = %c",c3); c3 = c1 ^ c2; printf("\n Bitwise XOR i.e. c1 ^ c2 = %c",c3); c3 = ~c1; printf("\n ones complement of c1 = %c",c3); c3 = c1<<2; printf("\n left shift by 2 bits c1 << 2 = %c",c3); c3 = c1>>2; printf("\n right shift by 2 bits c1 >> 2 = %c",c3);}
Result:
Bitwise AND i.e. c1 & c2 =
Bitwise OR i.e. c1 | c2 =
Bitwise XOR i.e. c1 ^ c2 =
ones complement of c1 = ?
left shift by 2 bits c1 << 2 =
right shift by 2 bits c1 >> 2 =
Example2:
Bitwise or: c1 | c2
# includemain(){ char c1 = 4,c2 =6 ,c3 = 3; c3 = c1 | c2; printf("\n Bitwise OR i.e. c1 | c2 = %c",c3);}
Result:
Bitwise OR i.e. c1 | c2 = ?
Suppose c1 = 4, c2 = 6;
The value of c1 | c2 is interpreted as follows:
0000 0100 | 0000 0110 ----------- 0000 0110
Example3:
Bitwise XOR: c1 ^ c2
# includemain(){ char c1 = 4,c2 = 6,c3 = 3; c3 = c1 ^ c2; printf("\n Bitwise XOR i.e. c1 ^ c2 = %c",c3);}
Suppose c1 = 4, c2 = 6;
The value of c1 ^ c2 is interpreted as follows:
0000 0100
^ 0000 0110
----------
0000 0010
Example4:
Complement: ~
# includemain(){ char c1 = 4,c2 = 6,c3 = 3; c3 = ~c1; printf("\n ones complement of c1 = %c",c3);}
Suppose c1 = 4, c2 = 6;
The value of ~ c1 is interpreted as follows:
~ 0000 0100 ---------- 1111 1011
Example5:
Right shift operation
# includemain(){ char c1 = 1,c2 = 2,c3 = 3; c3 = c1>>2; printf("\n right shift by 2 bits c1 >> 2 = %c",c3);}
Example6:
To divide value by 4
#include int main()
{ int x, y = 8; x = y >> 2; printf("%d",x); x = y/4; printf("%d",x);}
example 7:
A special feature of the >> and <<: perform superfast binary division and multiplication.
#include
int main()
{
int x, y = 6;
x = y >> 1;
printf("%d",x);
x = y/2;
printf("%d",x);
}
Type Qualifier:
Const
Volatile
Constants
Ex 1:
#include main(){ const int x = 20; const float PI = 3.14; printf("\nConstant values are %d and %.2f\n", x, PI);}
Result:
Constant values are 20 and 3.14
Ex 2:
Define constant float value using const
#include int main(void){ float diameter = 0.0f; float radius = 0.0f; const float Pi = 3.14159f; printf("Input the diameter of the table:"); scanf("%f", &diameter); radius = diameter/2.0f; printf("\nThe circumference is %.2f", 2.0f*Pi*radius); printf("\nThe area is %.2f", Pi*radius*radius); return 0;}
Result:
Input the diameter of the table:123
The circumference is 386.42
The area is 11882.28
Constants and Variables with macro:
#include #define SPEED 55 int main(){ printf("SPEED %i.\n",SPEED); printf("SPEED+15 %i.\n",SPEED+15); printf(" %i MPH sign?\n",SPEED); return(0);}
Result:
SPEED 55.
SPEED+15 70.
55 MPH sign?
volatile :
The volatile type qualifier directs the compiler not to perform certain optimizations on an object because that object can have its value altered in ways beyond the control of the compiler.
Specifically, when an object's declaration includes the volatile type qualifier, optimizations that would delay any references to (or modifications of) the object will not occur across sequence points. A sequence point is a point in the execution process when the evaluation of an expression is complete, and all side-effects of previous evaluations have occurred.
The volatile type qualifier is useful for controlling access to memory-mapped device registers, as well as for providing reliable access to memory locations used by asynchronous processes.
Table 3-2 Declarations using const and volatile
Declaration Meaning volatile int vol_int; Declares a volatile int variable. const int *ptr_to_const_int;
int const *ptr_to_const_int; Both declare a variable pointer to a constant int. int *const const_ptr_to_int Declares a constant pointer to a variable int. int *volatile vpi, *pi; Declares two pointers: vpi is a volatile pointer to an int; pi is a pointer to an int. int const *volatile vpci; Declares a volatile pointer to a constant int. const *pci; Declares a pointer to a constant int. Since no type specifier was given, it defaults to int.
Variable Length Argument list:
Ex:
Calculate an average using variable argument lists
#include
#include
double average(double v1 , double v2,...); /* Function prototype */
int main(void)
{
double Val1 = 10.5, Val2 = 2.5;
int num1 = 6, num2 = 5;
long num3 = 12, num4 = 20;
printf("\n Average = %lf", average(Val1, 3.5, Val2, 4.5, 0.0));
printf("\n Average = %lf", average(1.0, 2.0, 0.0));
printf("\n Average = %lf\n", average( (double)num2, Val2,(double)num1,
(double)num4,(double)num3, 0.0));
return 0;
}
/* Function to calculate the average of a variable number of arguments */
double average( double v1, double v2,...)
{
va_list parg; /* Pointer for variable argument list */
double sum = v1+v2; /* Accumulate sum of the arguments */
double value = 0; /* Argument value */
int count = 2; /* Count of number of arguments */
va_start(parg,v2); /* Initialize argument pointer */
while((value = va_arg(parg, double)) != 0.0)
{
sum += value;
count++;
}
va_end(parg); /* End variable argument process */
return sum/count;
}
Result:
Average = 5.250000
Average = 1.500000
Average = 9.100000
C Language - The Preprocessor
The Preprocessor
A unique feature of c language is the preprocessor. A program can use the tools provided by preprocessor to make his program easy to read, modify, portable and more efficient.
Preprocessor is a program that processes the code before it passes through the compiler. It operates under the control of preprocessor command lines and directives. Preprocessor directives are placed in the source program before the main line before the source code passes through the compiler it is examined by the preprocessor for any preprocessor directives. If there is any appropriate actions are taken then the source program is handed over to the compiler.
Preprocessor directives follow the special syntax rules and begin with the symbol #bin column1 and do not require any semicolon at the end. A set of commonly used preprocessor directives
Preprocessor directives:
Directive Function #define Defines a macro substitution #undef Undefines a macro #include Specifies a file to be included #ifdef Tests for macro definition #endif Specifies the end of #if #ifndef Tests whether the macro is not def #if Tests a compile time condition #else Specifies alternatives when # if test fails The preprocessor directives can be divided into three categories 1. Macro substitution division 2. File inclusion division 3. Compiler control division
Macros:
Macro substitution is a process where an identifier in a program is replaced by a pre defined string composed of one or more tokens we can use the #define statement for the task.
It has the following form
#define identifier string
The preprocessor replaces every occurrence of the identifier int the source code by a string. The definition should start with the keyword #define and should follow on identifier and a string with at least one blank space between them. The string may be any text and identifier must be a valid c name. There are different forms of macro substitution. The most common form is 1. Simple macro substitution 2. Argument macro substitution 3. Nested macro substitution
Simple macro substitution:
Simple string replacement is commonly used to define constants example:
#define pi 3.1415926
Writing macro definition in capitals is a convention not a rule a macro definition can include more than a simple constant value it can include expressions as well. Following are valid examples:
#define AREA 12.36
ex:1
You can use preprocessor to define constant and substitution.
#include
#define const 5
main(){
int i= 4;
i = i * const;
printf("%d \n", i);
}
Result:
20
Use preprocessor to define integer and string
#include
#define VAL 35
#define HELLO "HELLO"
main ()
{ int res;
res = VAL-5;
printf ("res = VAL-5: res == %d\n", res);
printf ("%s",HELLO);
}
Result:
res = VAL-5: res == 30
HELLO
Use #define to define constant
#include
#define TRUE 1
#define FALSE 0
#define BS '\b'
#define TAB '\011'
main(){
printf("%d",TRUE);
printf("%d",FALSE);
printf("%c",BS);
printf("%d",TAB);
}
Result:
19
#undef
To undefine the value defined by '#define' and specify a new value.
#include
#define VAL 40;
#undef VAL
#define VAL 50
main()
{
printf ("%d\n", VAL);
}
Result:
50
Macros as arguments:
The preprocessor permits us to define more complex and more useful form of replacements it takes the following form.
# define identifier(f1,f2,f3…..fn) string.
Notice that there is no space between identifier and left parentheses and the identifier f1,f2,f3 …. Fn is analogous to formal arguments in a function definition.
There is a basic difference between simple replacement discussed above and replacement of macro arguments is known as a macro call
A simple example of a macro with arguments is
# define CUBE (x) (x*x*x)
If the following statements appears later in the program,
volume=CUBE(side);
The preprocessor would expand the statement to
volume =(side*side*side)
Ex:
MACRO
Replacement of the identifier by using a statement or expression.
#define CUBE(x) x*x*x
#include
main (){
int k = 5;
int j = 0;
j = CUBE(k);
printf ("value of j is %d\n", j);
}
Result:
value of j is 125
MACRO AND FUNCTION
Macro just indicates replacement, not the function call.
#include
#define add(x1, y1) x1 + y1
#define mult(x1,y1) x1 * y1
main ()
{
int a,b,c,d,e;
a = 2;
b = 3;
c = 4;
d = 5;
e = mult(add(a, b), add(c, d));
// mult(a+b, c+d)
// a+b * c+d
printf ("The value of e is %d\n", e);
}
Result:
The value of e is 19
Nesting of macros:
We can also use one macro in the definition of another macro. That is macro definitions may be nested. Consider the following macro definitions
# define SQUARE(x)((x)*(x))
File inclusion:
The preprocessor directive "#include file name” can be used to include any file in to your program if the function s or macro definitions are present in an external file they can be included in your file In the directive the filename is the name of the file containing the required definitions or functions alternatively the this directive can take the form
#include< filename >
Without double quotation marks. In this format the file will be searched in only standard directories. Preprocessing
Compiler control division (or) Conditional Compilation:
#if
To define more generalized conditions.
Multiple conditions are connected by relational operators such as AND(&&), OR(||).
#define USA 1
// #define EUP 1
#include
#if ((1>0) && defined USA)
#define currency_rate 46
#endif
#if (defined (EUP))
#define currency_rate 100
#endif
main()
{
int rs;
rs = 10 * currency_rate;
printf ("%d\n", rs);
}
Result:
460
#ifdef
The ifdef directive makes substitutions based on whether a particular identifier is defined.
#define USA 1
// #define EUP 1
#include
#ifdef USA
#define currency_rate 46
#endif
#ifdef EUP
#define currency_rate 100
#endif
main()
{
int rs;
rs = 10 * currency_rate;
printf ("%d\n", rs);
}
460
#ifelif
ifelif allows us to take one action for multiple decision entries.
#define USA 1
#define EUP 1
#include
#if (defined (USA))
#define currency_rate 46
#elif (defined (EUP))
#define currency_rate 100
#else
#define currency_rate 1
#endif
main()
{
int rs;
rs = 10 * currency_rate;
printf ("%d\n", rs);
}
Result:
460
#ifelse
Use ifelse to define an action if the condition is not true.
#define USA 1
#define EUP 1
#include
#if (defined (USA))
#define currency_rate 46
#else
#define currency_rate 100
#endif
main()
{
int rs;
rs = 10 * currency_rate;
printf ("%d\n", rs);
}
Result:
460
#ifndef
#ifndef is used to check whether a particular symbol is defined.
#define USA 1//#define EUP 1#include #ifndef USA #define currency_rate 100 #endif #ifndef EUP #define currency_rate 46#endif main(){ int rs; rs = 10 * currency_rate; printf ("%d\n", rs);}
Result:
460
#line
Define arbitrary line numbers for the source lines.
Using the #line directive, you can specify an arbitrary line number at any point.
The compiler then uses that line number for subsequent counts.
#include main(){ printf("A\n"); #line 100 printf("B\n"); printf("C FILE %s LINE %d\n", __FILE__, __LINE__ ); #line 200 printf("D\n"); printf("E\n");}
Result:
A
B
C FILE line0.c LINE 101
D
E
Error directive
specify an error message
//#define USA 1//#define EUP 1#include #if (!defined (USA) || !defined (EUP)) #error ERROR: NO_CURRENCY rate is specified.#endifmain(){ int rs; rs = 10; printf ("%d\n", rs);}
ERRORDIRECTIVE0.c:8:5: error: #error ERROR: NO_CURRENCY rate is specified.
__FILE__: indicate the file name
#include main(){ printf("C FILE %s LINE %d\n", __FILE__, __LINE__ );}
Result:
C FILE FILEindicatethefilename0.c LINE 6
__LINE__: indeicate the current line number
#include