Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

EST102: Programming in C: Files and Command Line Arguments

Download as pdf or txt
Download as pdf or txt
You are on page 1of 15

EST102 : Programming in C

Chapter 13
Files and command line arguments

Narasimhan T.

13.1 Files

So far, we have seen taking input from the user through keyboard or outputting the results
to the screen. This works fine if the frequency of I/O (input-output) operations is low. As
the volume of data to be processed increases, the I/O operations become tedious. Moreover,
if you want to repeatedly execute a program, you need to enter the input, each time you
execute it. In such situations, it becomes necessary to store the data in a manner so that
they can be easily retrieved later. One of the simplest ways for programs to organize their
data is to use data files. A file is a collection of bytes stored on a permanent medium like
a hard drive, flash memory, or CD-ROM.
Files are of two types : data files and program files. Data files store data to be processed
by a program. Program files on the other hand contain instructions or code to be executed.
Data files are further classified as text files and binary files.
A text file (also called ASCII file) stores information as ASCII characters. A text file
contains human-readable characters. A user can read the contents of a text file or edit it
using a text editor. In text files, each line of text is terminated (delimited) with a special
character known as EOL (End of Line) character. Text documents like word documents are
a good example of text files.
A binary file is a file that contains information in the binary form. Thus, such files are
not human readable but provide a better security than text files. In binary file, there is no
delimiter for a line. Binary files are faster and easier for a program to read and write than
the text files. Image files are an example of binary files. The discussion here is restricted
to that of text files.

182
13.1. FILES 183

13.1.1 File operations


The usual sequence of operations on a file (whether text or binary) is:

1. Creating/opening a file

2. I/O operations - read or write

3. Closing a file

When working with files, you need to declare a pointer of type FILE. (FILE is a prede-
fined structure that holds the relevant details about a file.) This declaration is needed for
communication between the file and the program. The pointer is called file pointer and is
declared as
FILE *fp;
where fp is the name of the pointer.

13.1.1.1 Opening and closing files


Before you can read from or write to a file, you have to open it using the fopen() function.
The syntax of fopen() is:
fp=fopen(fileName,accessMode)
where fileName specifies the name of the file you want to open and accessMode specifies the
purpose of opening the file. For example, the following code opens a file named myfile.txt
for writing:

fp=fopen("myfile.txt",'w')

The various access modes and their description are tabulated in Table 13.1.
While trying to open a file, the fopen() function returns a file pointer if successful. If
an error occurs, it returns a null pointer NULL.
Once you have performed the operations (read or write) on the file, you need to close
it. For this you use the fclose() function. The statement
fclose(fp);
closes a file whose associated file pointer is fp.

13.1.1.2 Reading and writing with files


C provides a plenty of functions to perform I/O on files. These functions can be formatted
functions or unformatted functions. Unformatted input/output transfers the internal binary
representation of the data directly between memory and the file. Formatted output converts
the internal binary representation of the data to ASCII characters which are written to the
output file. Formatted input reads characters from the input file and converts them to
internal form.
184 CHAPTER 13. FILES AND COMMAND LINE ARGUMENTS

Table 13.1: List of the different modes of opening a file

Access mode† Meaning


Opens a file for reading only. Raises an error if the
r
file does not exist.
Opens a file for writing only. Overwrites the file if
w the file exists. If the file does not exist, creates a
new empty file for writing.
Opens a file for appending (i.e., for adding new
a information at the end of the file). A new empty
file will be created if the file does not exist.
Opens a file for both reading and writing. Raises
r+
an error if the file does not exist.
Opens a file for both reading and writing. If the
w+ file already exists, it will be destroyed and a new
file is created.
Opens a file for both reading and appending. A
a+ new file will be created if the file specified does
not exist.
† - These modes may be suffixed with b like rb, w+b (or wb+) etc. to handle
binary files (generally with .dat or .bin extensions).

Writing characters to file


The putc() function writes characters to a file opened for writing. The syntax is
putc(ch,fp);
where fp is the pointer associated with the file to which the character ch is to be written.
If a putc() operation is successful, it returns the character written. Otherwise, it returns
a special value called EOF (End Of File).
Example 13.1. The program below writes a collection of characters one by one to a file.
#include<stdio.h>
main()
{
FILE *fp;
int count,i;char c;
fp=fopen("sample1.txt","w");
if(fp==NULL)
printf("Sorry! Error in opening file\n");
else
{
printf("How many characters you want to enter?\n");
scanf("%d",&count);
for(i=0;i<count;i++)
13.1. FILES 185

{
printf("Enter a character\n");
scanf(" %c",&c);
putc(c,fp);
}
fclose(fp);
}
}

Reading characters from file


The getc() function reads characters from a file opened in read mode. The syntax is
ch = getc(fp);
where ch is the integer equivalent of the character read from the file whose pointer is fp.
The getc() function returns an EOF when the end of the file has been reached.

Example 13.2. This code reads all characters in a file one by one and prints them until
the end of the file is reached.
#include<stdio.h>
main()
{
FILE *fp;
int ch;
fp=fopen("sample.txt","r");
if(fp==NULL)
printf("Sorry! Error in opening file\n");
else
{
ch = getc(fp);
while (ch != EOF)
{
putchar(ch);
ch = getc(fp);
}
fclose(fp);
}
}

Using feof()
getc() returns EOF when it reaches the end of the file. When an error occurs during read
operation, then also getc() returns EOF. Thus, using only the return value of getc(), it is
impossible to know which occurred. To solve this problem, C includes the function feof(),
186 CHAPTER 13. FILES AND COMMAND LINE ARGUMENTS

which determines when the end of the file has been encountered. feof() returns 1 if the
end of the file has been reached; otherwise, it returns zero. Therefore, to read the characters
from a file to its end, you can use the code:
while(feof(fp)!=0)
ch = getc(fp);

Working with strings


C provides the functions fgets() and fputs() to read and write character strings from
and to a file. The syntax of fputs() is
fputs(str,fp);
where str is the string to be written to the file whose pointer is fp. The function returns
EOF if an error occurs.
Example 13.3. This example illustrates the use of fputs() function to write a string to
a file.
#include<stdio.h>
main()
{
FILE *fp;
int count,i;char str[15];
fp=fopen("sampleStrP.txt","w");
if(fp==NULL)
printf("Sorry! Error in opening file\n");
else
{
printf("Enter a string\n");
scanf(" %s",str);
fputs(str,fp);
fclose(fp);
}
}

The syntax of fgets() is
fgets(str,length,fp);
The fgets() function reads a string from the specified file (whose pointer is fp) until either
a newline character is read or length − 1 characters have been read. If a newline is read,
it will be part of the string. The function returns the string str if successful and a null
pointer if an error occurs.
Example 13.4. Here is how you read strings from a file using fgets().
13.1. FILES 187

#include<stdio.h>
main()
{
FILE *fp;
char str[50];
fp=fopen("sample.txt","r");
if(fp==NULL)
printf("Sorry! Error in opening file\n");
else
{
while ((fgets(str,50,fp))!=NULL)
printf("%s",str);
fclose(fp);
}
}

Reading and writing integers


The putw() function is used to write integers to the file. The syntax is
putw(num, fp);
The putw() function takes two arguments, first is an integer value num to be written to
the file and second, fp is the corresponding file pointer. Similarly getw() is used to read
integers from a file. The syntax is
n=getw(fp);
The getw() function takes the file pointer as argument from where the integer value will
be read and returns the read value n. It returns EOF if it has reached the end of file.

Example 13.5. The program below inputs numbers from the user and writes them to a
file. Later the numbers are printed by reading from the file.
#include<stdio.h>
main()
{
FILE *fp;
int num,count,i;
printf("How many numbers?");
scanf("%d",&count);
fp=fopen("file.txt","w");
if(fp==NULL)
printf("Sorry! Error in opening file\n");
else
{
for(i=0;i<count;i++)
188 CHAPTER 13. FILES AND COMMAND LINE ARGUMENTS

{
printf("Enter any number:\n");
scanf("%d",&num);
putw(num,fp);
}
fclose(fp);
}
fp=fopen("file.txt","r");
if(fp==NULL)
printf("Sorry! Error in opening file\n");
else
{
num=getw(fp);
while(num!=EOF)
{
printf("%d ",num);
num=getw(fp);
}
fclose(fp);
}
}

Working with blocks of data


When processing large amounts of data, it is often easier to group information together,
instead of dealing with lots of individual variables. For example, when you are dealing with
structure variables, it would be beneficial to read/write the structure data at a single step.
To read and write data that are longer than 1 byte, the C language provides the functions:
fread() and fwrite(). These functions allow the reading and writing of blocks of any
type of data.
The syntax of fwrite() is
fwrite(addr,size,count,fptr)
where

• addr denotes the address of the data block (structure variable) whose contents are to
be written to file.

• size denotes the size of the block.

• count denotes the number of data blocks (number of structure variables) that you
need to write.

• fptr represents the file pointer associated with the file to which you are going to write
data.
13.1. FILES 189

Similarly fread() is used to read blocks of data from a file. The syntax of fread() is same
as that of fwrite():
fread(addr,size,count,fptr)
where

• addr denotes the address of the data block (structure variable) to which data from
the file will be written.

• size denotes the size of the block.

• count denotes the number of data blocks (number of structure variables) whose con-
tents you are reading.

• fptr represents the file pointer associated with the file from which you are reading
data.

Example 13.6. This example inputs the details of a bank customer and writes to the file.
Later, the contents are being read from the file and printed out.
#include<stdio.h>
typedef struct
{
char name[15];
int accNo;
float balance;
}account;
main()
{
account acc;
FILE *fp;
fp=fopen("struct.txt","w");
if(fp==NULL)
printf("Sorry! Error in opening file\n");
else
{
printf("Enter customer name\n");
scanf(" %s",acc.name);
printf("Enter account number\n");
scanf("%d",&acc.accNo);
printf("Enter balance\n");
scanf("%f",&acc.balance);
fwrite (&acc, sizeof(account), 1, fp); /*count is 1 because you are
writing the contents of only 1 struct variable*/
fclose(fp);
}
fp=fopen("struct.txt","r");
190 CHAPTER 13. FILES AND COMMAND LINE ARGUMENTS

if(fp==NULL)
printf("Sorry! Error in opening file\n");
else
{
fread(&acc, sizeof(account), 1, fp);
printf("Customer name: %s\n",acc.name);
printf("Account number: %d\n",acc.accNo);
printf("Balance: %f\n",acc.balance);
fclose(fp);

}
}

Formatted functions
If you need to handle multiple data items and that too of mixed types (char, int, float etc.),
you should use fprintf() and fscanf(). The fprintf() function is used to write mixed
type data items into a file. Its syntax is
fprintf(fp,format-string,var-list);
where fp is the file pointer, format-string is the list of format specifiers and var-list
is the list of variables whose values are to be written to file. Thus fprintf() function is
similar to printf() function except the first argument which is a file pointer.
The fscanf() function is used to read mixed type data from the file. The syntax is similar
to that of fprintf():
fscanf(fp,format-string,addr-list);
where fp and format-string have same meanings as with fprintf(); addr-list denotes
the lists of addresses of variables which will hold the values that are read from the file.
Example 13.7. The code below inputs the details of a student and writes them to a file.
The details are then printed by reading from the file.
#include<stdio.h>
main()
{
int m1,m2,roll,n,i;
char name[15];
FILE *fp;
fp=fopen("marks.txt","w");
if(fp==NULL)
printf("Sorry! Error in opening file\n");
else
{
printf("Number of students please\n");
13.1. FILES 191

scanf("%d",&n);
for(i=0;i<n;i++)
{
printf("Enter the details of student %d\n",i+1);
scanf(" %s %d %d %d",name,&roll,&m1,&m2);
fprintf(fp,"%s %d %d %d",name,roll,m1,m2);
}
fclose(fp);
}
fp=fopen("marks.txt","r");
if(fp==NULL)
printf("Sorry! Error in opening file\n");
else
{
for(i=0;i<n;i++)
{
printf("Details of student %d\n",i+1);
fscanf(fp,"%s %d %d %d",name,&roll,&m1,&m2);
printf("Name: %s\n",name);
printf("Roll: %d\n",roll);
printf("Marks: %d and %d\n",m1,m2);
}
fclose(fp);
}
}

13.1.2 Random access to files


If you want to access specific locations in a file, C supports three functions for random
access to files.

13.1.2.1 ftell()
This function tells the current position of the file pointer in the file. It takes a file pointer as
argument and returns the byte location of current position of the pointer. The statement
len = ftell(fp);
means that the file pointer is currently at byte numbered len. i.e., bytes 0 to len - 1 are
to the left of the current pointer position.

13.1.2.2 rewind()
The rewind() function resets the file pointer to the beginning of the file with the pointer
specified as its argument. That is, it “rewinds” the file. Its syntax is:
192 CHAPTER 13. FILES AND COMMAND LINE ARGUMENTS

rewind(fp);

where fp is a file pointer. Thus, after executing the statements,


rewind(fp);
n=ftell(fp);

the value of n will be zero (indicating the beginning of file).

13.1.2.3 fseek()

fseek() is used to move the file pointer to a desired location in the file. Its syntax is:
fseek(fp,offset,position);

where

• fp is the file pointer.

• offset is the number of bytes fp is to be moved.

• position denotes the position from which the file pointer is moved.

position can take three values:

• 0 – beginning of file

• 1 – current position

• 2 – end of the file

position can also be specified in terms of constants rather than in terms of integers as
follows:

• SEEK_SET – beginning of file

• SEEK_CUR – current position

• SEEK_END – end of the file

offset can be positive or negative. If it is positive, the file pointer is moved in forward
direction. If it is negative, file pointer is moved backwards.

Example 13.8. This example shows some usages of fseek() function and their interpre-
tations.
13.2. COMMAND LINE ARGUMENTS 193

fseek(fp,0,0) − Moves fp zero bytes from the beginning of the file. In other
words, it moves the file pointer to start of the file.
fseek(fp,0,SEEK_CUR) − Moves fp zero bytes from current position. In other words,
the pointer stays in its current position.
fseek(fp,0,SEEK_END) − Moves fp to the file end.
fseek(fp,m,SEEK_SET) − Moves fp m bytes from the beginning – sets the pointer at
(m + 1)th byte in the file.
fseek(fp,m,1) − Moves fp forward by m bytes from current position.
fseek(fp,-m,1) − Moves fp backward by m bytes from current position.
fseek(fp,-m,2) − Moves fp backward by m bytes from end of the file.


This function returns zero if successful, or else it returns a non-zero value.

13.2 Command line arguments


Sometimes it is useful to pass information into a program when you run it. Generally, you
pass information into the main() function via command line arguments. These arguments
let you control your program from outside instead of hard coding those values inside the
code. Typically command line arguments are strings that follow the command ./a.out on
the terminal when you run a program. (The discussion here is restricted to the way you
run programs on Linux.)
The main() has two special built-in arguments, argc and argv, to receive command
line arguments. The argc parameter holds the number of arguments on the command line
and is an integer. It is always at least 1 because the ./a.out command itself is the first
argument. The argv parameter is an an array of character pointers. Each element in this
array points to a command line argument. More precisely, the strings at the command line
are stored in memory and address of the first string is stored in argv[0], address of the
second string is stored in argv[1] and so on. Typically, when you run programs on Linux,
argv[0] is ./a.out.
Example 13.9. Here is a simple example that uses a command line argument. It prints
Hello and your name on the screen, if you specify your name as a command line argument.
#include<stdio.h>
main(int argc,char *argv[])
{
printf("Hello %s",argv[1]);
}
If you run the above code as follows:
./a.out Narasimhan
the output will be
194 CHAPTER 13. FILES AND COMMAND LINE ARGUMENTS

Hello Narasimhan

Example 13.10. This program receives command line arguments when the program is
executed and then displays the number of arguments entered and their values.
#include<stdio.h>
#include<stdlib.h>
main(int argc,char *argv[])
{
int i;
printf("argc is %d\n",argc);
for(i=0;i<argc;i++)
printf("argv[%d] is %s\n",i,argv[i]);
}
If you run the above code as:
./a.out S2 CSE
the output is
argc is 3
argv[0] is ./a.out
argv[1] is S2
argv[2] is CSE

13.3 Programming examples


Program 13.82. To receive name, roll number and age of a student as command line
arguments and then print them.
#include<stdio.h>
#include<stdlib.h>
main(int argc,char *argv[])
{
printf("STUDENT DETAILS\n");
if(argc<4) //You expect three values other than ./a.out
printf("Insufficient number of arguments\n");
else
{
printf("Name:%s\n",argv[1]);
printf("Roll:%s\n",argv[2]);
printf("Age:%s\n",argv[3]);
}
}
13.3. PROGRAMMING EXAMPLES 195

Recall every command line argument is a string. Thus roll number and age are interpreted
as string constants and hence %s is used while printing them.
Program 13.83. To add two numbers received as command line arguments.

#include<stdio.h>
#include<stdlib.h>
main(int argc,char *argv[])
{
int a,b;
a=atoi(argv[1]);
b=atoi(argv[2]);
printf("The sum is %d",a+b);
}

Since the numbers are received as command line arguments, they will be string constants.
To convert them to integers, the function atoi() is used. For this, the stdlib header file
is required.
Program 13.84. Input integers to a file “numbers.txt”. Read from this file and write
the even numbers to another file “even.txt” and odd numbers to a third file “odd.txt”.
Finally print the odd and even numbers separately by reading from corresponding files.
#include<stdio.h>
main()
{
FILE *fpn,*fpe,*fpo;
int num,count,i;
fpn=fopen("numbers.txt","w");
fpe=fopen("even.txt","w");
fpo=fopen("odd.txt","w");
if(fpn==NULL||fpe==NULL||fpo==NULL)
printf("Sorry!Error in opening file\n");
else
{
printf("How many integers you want to enter?\n");
scanf("%d",&count);
printf("Enter the integers\n");
for(i=0;i<count;i++)
{
scanf("%d",&num);
putw(num,fpn);
}
fclose(fpn);
fpn=fopen("numbers.txt","r");
num=getw(fpn);
while(num!=EOF)
196 CHAPTER 13. FILES AND COMMAND LINE ARGUMENTS

{
if(num%2==0)
putw(num,fpe);
else
putw(num,fpo);
num=getw(fpn);
}
fclose(fpo);
fclose(fpe);
fpe=fopen("even.txt","r");
fpo=fopen("odd.txt","r");
printf("Contents of file with even numbers\n");
num=getw(fpe);
while(num!=EOF)
{
printf("%d ",num);
num=getw(fpe);
}
printf("\nContents of file with odd numbers\n");
num=getw(fpo);
while(num!=EOF)
{
printf("%d ",num);
num=getw(fpo);
}
fclose(fpo);
fclose(fpe);
fclose(fpn);
}
}

You might also like