0% found this document useful (0 votes)
65 views19 pages

Unit 4 (C)

This document provides an overview of file management in C, including defining and opening files, input/output operations on files like getc(), putc(), fprintf(), and fscanf(), error handling, random access using fseek(), getting the file position with ftell(), and resetting with rewind(). It also discusses command line arguments, where the number of arguments is stored in argc and the array of argument strings is stored in argv.

Uploaded by

dharmesh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
65 views19 pages

Unit 4 (C)

This document provides an overview of file management in C, including defining and opening files, input/output operations on files like getc(), putc(), fprintf(), and fscanf(), error handling, random access using fseek(), getting the file position with ftell(), and resetting with rewind(). It also discusses command line arguments, where the number of arguments is stored in argc and the array of argument strings is stored in argv.

Uploaded by

dharmesh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 19

ADVANCED PROGRAMMING LANGUAGE ‘C’- 201 (SEM -II)

UNIT-4

Unit-IV (17 Marks)


File Management in C:
Introduction, Defining and opening a file, Closing a file, Input / Output operations on files,
Error handling during I/O operations, Random access files, Command line arguments.
Dynamic Memory Allocation
Introduction, Dynamic Memory allocation, Memory allocation functions
The Preprocessors:
Introduction, Macro Substitution, File inclusion, Compiler control directives

File Management in C

A file is nothing but collection of data and information that can be stored
in storage device such as hard disk .

 The console oriented I/O operation pose two major problems.


1. It becomes awkward and time consuming to handle large
volumes of the data through terminals.
2. The entire data is lost when either the program is terminated or
the computer is termed off.

 It is therefore necessary to have a more flexible approach where data


can be stored on the disk and read whenever necessary, without
destroying the data.

 This method employs the concept of files to store data. A file is a place
on the disk where a group of related data is stored.

 Following are the sequence of operations for operating a file


o naming file
o opening a file
o reading data from file
o writing data to file
o closing file

Shree R. K. Patel BCA College, Nanikadi[1]


ADVANCED PROGRAMMING LANGUAGE ‘C’- 201 (SEM -II)
UNIT-4
File I/O functions
Function name operation
fopen() create a new file for use
opens a existing file for use

fclose() close a file which has opened for use


getc() reads a character from a file
putc() writes a character to a file
fprintf() writes a set of data values to a file
fscanf() reads a set of data values from a file
getw() reads an integer from a file
putw() writes an integer to a file
fseek() sets the position to a desired point in the file
ftell() gives the current position in the file
(in terms to bytes from the start)
Rewind() sets the position to the beginning of the file

Defining and opening file:

 To store data in file in the secondary memory, we must specify


certain things about the file, to the operating system. They include.
1. file name
2. data structure
3. purpose
 filename is a string of characters that make up a valid filename for
the operating system. It contains two parts, a primary name and
an optional period with the extension. for examples harsh.txt
 data structure of a file is defined as FILE in the library of standard
I/O function definition. FILE is a defined data type.
 Syntax for defining and opening file:

FILE *f1;
f1 = fopen(―filename‖ ,‖ mode‖ );

f1 as a ―pointer to the data type FILE‖ . The second statement


opens the file named filename and assign an identifier to the FILE type pointer
f1.

Shree R. K. Patel BCA College, Nanikadi[2]


ADVANCED PROGRAMMING LANGUAGE ‘C’- 201 (SEM -II)
UNIT-4
Mode for fopen() to open a file:

 r : open the file for reading only.


 w : create & open the file for writing only, if is already exist, it will
overwritten
 a : append open file for writing at end of file(create for writing if
does not
exist).

When typing to open a file, one of the following things may happen.
1. if the purpose is ―reding” and if it exist, then the file is opened
with the current contents safe, otherwise an error occurs.
2. when the mode is ―writing‖ a file with the specified name is
created if the file does not exist. The contents are deleted. If the
file already exist.
3. when the purpose is ―appending‖ the file is opened with current
contents safe. A file with the specified name is created if the file
does not exist.

e.g. FILE f1, f2;


f1=fopen(“data”,”r”);
f2=fopen(“result”,”w”);
The file data is opened for reading and result is opened for
writing.

Many recent compilers includes additional mode of operation.


 r+ : open an existing file for both reading and writing.
 w+ : create a new file for update. It it already exist, it will
overwritten.
 a+ : open for append; open for update at end of file

Closing a file:

A file must be closed as soon as all operation on it have been cimpleted.


Syntax:
fclose (filename);

Input/Output operation on files

 The getc and putc functions:


 These are similar to getchar() and putchar() functions and handle one
character at a time

Shree R. K. Patel BCA College, Nanikadi[3]


ADVANCED PROGRAMMING LANGUAGE ‘C’- 201 (SEM -II)
UNIT-4
 The file pointer moves by one character position for every
operation of getc or putc. The getc will return an end of file
maker EOF, when end of the file has been reached. There fore
the reading should be terminated when EOF is encountered.

The getw and putw functions:

 The getw and putw are integer-oriented functions. They are


similer to the getc and putc functions and are used to read and
write integer values.
 These functions would be useful when we deal with only integer
data.
Syntax: putw(integer,f1); getw(f1);
The fprintf and fscanf functions:

The function fprintf and fscanf perform I/O operations that are
identical to the familiar printf and scanf functions, except they
are work on files.

Syntx of fprintf:

fprintf(f1,‖ control string‖ ,list);


Where f1 is a file pointer associated with a file that has been
opened for writing.
e.g. fprintf(f1,‖ %s%d%f‖ ,name,age,7.5);

Syntx of fscanf:

fscanf(f1,‖ control string‖ ,list);


The statement would cause the reading of the items in the list
from the file specified by f1.

e.g. fscanf(f1,‖ %s%d‖ ,name,&age);


Error handling during I/O Operations:

It is possible that an error may occur during I/O operations on a


file. Typical error situations include:
1. trying to read beyond the end-of –file mark.
2. device overflow.
3. trying to use a file that has not been opened.
4. trying to perform an operation on a file, when the file is opened
for another type of operation.
5. opening a file with an invalid filename.

Shree R. K. Patel BCA College, Nanikadi[4]


ADVANCED PROGRAMMING LANGUAGE ‘C’- 201 (SEM -II)
UNIT-4
6. attempting to write to a write-protected file.

Random access using fseek():

 When a file is opened, the ―current position‖ or offset is always


at the beginning of the file.
 The C library provides a function that facilities random shifting
of the pointer ―position‖ or ―offset‖
 fseek(f1,offset,position);
 F1 is the file pointer
 Offset is a long int that specifies the number of bytes that have
to be shifted.
 An integer specifying the position on the file from where the
offset would be effective. The three values it can take are

0 - beginning of the file


1 - current position
2 - end of the file
e.g. fseek(f1,0,0);
 shift zero bytes from beginning of the file, this statement is
actually inessential as soon as a file is opened, the file pointer is
always positioned at the beginning of the file.

The ftell() function:

Then function return the current offset position in the file, for
example as soon as a file is opened this function return 1.
Long int position = ftell(f1);

The rewind() function:

The function enables repositioning of the pointer at the beginning


of the file
rewind(file_pointer);
After rewind is performed, the current position becomes 0

Command line arguments:

What is command line argument?


It is a parameter supplied to a program when the program is
invoked. This parameter may represent a filename the program
should process.

Shree R. K. Patel BCA College, Nanikadi[5]


ADVANCED PROGRAMMING LANGUAGE ‘C’- 201 (SEM -II)
UNIT-4
E.g. if we want to execute a program to copy the contents of a file
named xfile to another one named yfile, then we may use a
command line like
c>program xfile yfile
we know that every C program should have one main function and
that it marks the beginning of the program. but what we have not
mentioned so far is that it can also take arguments like other
functions.
In fact main can take two arguments called argc and argv
and the information contained in the command line is passed on to
the program through these arguments, when main is called by
system.
The variable argc is an argument counter that counts the
number of arguments on the command line. The argv is an
argument vector and represent an array of character pointers argc.
For instance, for the command line given above, argc is three and
argv is an array of three pointers to strings as shown below:
argv[0] program
argv[1] xfile
argv[2] yfile
In order to access the command line arguments, we must declare
the main function and its parameters as follows:
main(argc,argv)
Int argc;
char *argv[];
{
……
……
}
The first parameter in the command line is always the program
name and therefore argv[0] always represent the program name.

Shree R. K. Patel BCA College, Nanikadi[6]


ADVANCED PROGRAMMING LANGUAGE ‘C’- 201 (SEM -II)
UNIT-4
Dynamic Memory Allocation:

The C programming language manages memory statically, automatically, or


dynamically. Static-duration variables are allocated in main (fixed) memory
and persist for the lifetime of the program; automatic-duration variables
are allocated on the stack and come and go as functions are called and
return. For static-duration and automatic-duration variables, the size of
the allocation is required to be compile-time constant. If the required size
is not known until run-time (for example, if data of arbitrary size is being
read from the user or from a disk file), then using fixed-size data objects
is inadequate.

Types of Memory allocation:

Memory allocation can be done programmatically in two ways.

(1). Compile Time or Static Time (2). Run Time or Dynamic Allocation

(1). Compile Time or Static Time :


In this type of allocation , the required amount of memory is
allocated to the program elements at smart of the program ( writing of
Program ). Here memory to be allocated to the variable is Fixed and
determines by the compiler at the compile time
e.g int a [20];
(2). Run Time or Dynamic Allocation :
When memory is allocated to the variable during run time is called
memory allocation . There are two basic functions used in the memory
allocation .

As we begin doing dynamic memory allocation, we'll begin to see (if we


haven't seen it already) what pointers can really be good for. Many of the
pointer examples in the previous chapter (those which used pointers to
access arrays) didn't do all that much for us that we couldn't have done
using arrays. However, when we begin doing dynamic memory allocation,
pointers are the only way to go, because what malloc returns is a pointer
to the memory it gives us. (Due to the equivalence between pointers and
arrays, though, we will still be able to think of dynamically allocated
regions of storage as if they were arrays, and even to use array-like
subscripting notation on them.)
You have to be careful with dynamic memory allocation. malloc operates
at a pretty ``low level''; you will often find yourself having to do a certain
amount of work to manage the memory it gives you. If you don't keep
accurate track of the memory which malloc has given you, and the

Shree R. K. Patel BCA College, Nanikadi[7]


ADVANCED PROGRAMMING LANGUAGE ‘C’- 201 (SEM -II)
UNIT-4
pointers of yours which point to it, it's all too easy to accidentally use a
pointer which points ``nowhere'', with generally unpleasant results. (The
basic problem is that if you assign a value to the location pointed to by a
pointer:
*p = 0;
and if the pointer p points ``nowhere'', well actually it can be construed
to point somewhere, just not where you wanted it to, and that
``somewhere'' is where the 0 gets written. If the ``somewhere'' is memory
which is in use by some other part of your program, or even worse, if the
operating system has not protected itself from you and ``somewhere'' is
in fact in use by the operating system, things could get ugly.)

Memory allocation function:

The C dynamic memory allocation functions are defined in stdlib.h


header

malloc( ) allocates the specified number of bytes


realloc( ) increases the size of the specified block of memory.
Reallocates it if needed
calloc( ) allocates the specified number of bytes and initializes them
to zero
free( ) releases the specified block of memory back to the system

Allocating Memory with malloc()

A problem with many simple programs, including in particular little


teaching programs such as we've been writing so far, is that they tend to
use fixed-size arrays which may or may not be big enough. We have an
array of 100 ints for the numbers which the user enters and wishes to
find the average of--what if the user enters 101 numbers? We have an
array of 100 chars which we pass to getline to receive the user's input--
what if the user types a line of 200 characters? If we're lucky, the
relevant parts of the program check how much of an array they've used,
and print an error message or otherwise gracefully abort before
overflowing the array. If we're not so lucky, a program may sail off the
end of an array, overwriting other data and behaving quite badly. In
either case, the user doesn't get his job done. How can we avoid the
restrictions of fixed-size arrays?

The answers all involve the standard library function malloc. Very
simply, malloc returns a pointer to n bytes of memory which we can do
anything we want to with. If we didn't want to read a line of input into a
fixed-size array, we could use malloc, instead. Here's the first step:

Shree R. K. Patel BCA College, Nanikadi[8]


ADVANCED PROGRAMMING LANGUAGE ‘C’- 201 (SEM -II)
UNIT-4
#include <stdlib.h>

char *line;
int linelen = 100;
line = malloc(linelen);
/* incomplete -- malloc's return value not checked */
getline(line, linelen);

malloc is declared in <stdlib.h>, so we #include that header in any


program that calls malloc. A ``byte'' in C is, by definition, an amount of
storage suitable for storing one character, so the above invocation of
malloc gives us exactly as many chars as we ask for. We could illustrate the
resulting pointer like this:

The 100 bytes of memory (not all of which are shown) pointed to by line
are those allocated by malloc. (They are brand-new memory, conceptually
a bit different from the memory which the compiler arranges to have
allocated automatically for our conventional variables. The 100 boxes in
the figure don't have a name next to them, because they're not storage
for a variable we've declared.)

malloc () function:

Shree R. K. Patel BCA College, Nanikadi[9]


ADVANCED PROGRAMMING LANGUAGE ‘C’- 201 (SEM -II)
UNIT-4

 Following example illustrate the use of 10 integer items memory allocation.

Int * p
P = (int * p) malloc (sizeof(int) * 10))

Syntax of Malloc is
(void * ) malloc (Total No. of bytes required )

Here we require 10 int items so total 20 bytes


i.e 10 * 2
i.e 10 * sizeod (int)
we require pointer increment of two bytes so we have written (int * )
as return type.

calloc () Function

The calloc() function also allocates memory. Rather than allocating a


group of bytes as malloc() does, calloc() allocates a group of objects. The
function prototype is
void *calloc(size_t num, size_t size);
Remember that size_t is a synonym for unsigned on most compilers. The
argument num is the number of objects to allocate, and size is the size
(in bytes) of each object. If allocation is successful, all the allocated
memory is cleared (set to 0), and the function returns a pointer to the
first byte. If allocation fails or if either num or size is 0, the function
returns NULL.
Listing below illustrates the use of calloc().

 Following example illustrate the use of 10 integer items memory allocation.


int * p
p = (int * p) calloc (10 , sizeof(int))
Sysntax of Calloc is

Shree R. K. Patel BCA College, Nanikadi[10]


ADVANCED PROGRAMMING LANGUAGE ‘C’- 201 (SEM -II)
UNIT-4

(void * ) calloc (No. of items , Size of data type)


We require pointer increment of two bytes so we have as return type.

Using the calloc() function to allocate memory storage space dynamically.

/* Demonstrates calloc(). */

#include <stdlib.h>
#include <stdio.h>

main()
{
unsigned num;
int *ptr;

printf("Enter the number of type int to allocate: ");


scanf("%d", &num);

ptr = (int*)calloc(num, sizeof(int));

if (ptr != NULL)
puts("Memory allocation was successful.");
else
puts("Memory allocation failed.");
return(0);
}
Enter the number of type int to allocate: 100
Memory allocation was successful.
Enter the number of type int to allocate: 99999999
Memory allocation failed.

This program prompts for a value on lines 11 and 12. This number
determines how much space the program will attempt to allocate. The
program attempts to allocate enough memory (line 14) to hold the
specified number of int variables. If the allocation fails, the return value
from calloc() is NULL; otherwise, it's a pointer to the allocated memory. In
the case of this program, the return value from calloc() is placed in the

Shree R. K. Patel BCA College, Nanikadi[11]


ADVANCED PROGRAMMING LANGUAGE ‘C’- 201 (SEM -II)
UNIT-4
int pointer, ptr. An if statement on lines 16 through 19 checks the status
of the allocation based on ptr's value and prints an appropriate message.

free ( ) function

following example demonstrate of free function.


Int * p
P = (int * ) malloc (10 * sizeof(int))
Free (p)
Which is release all bytes pointed by pointer p

Preprocessor

Introduction

 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 to 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 # and do not require any semicolon at the end.

The C preprocessor is a program that is executed that is executed in the


first phase of a C source program’s compilation. Instructions to the
preprocessor (which may be placed anywhere within—and not
necessarily at the beginning of – a C program), have a simple line-
oriented syntax in which each command begins with the has sign #.

Shree R. K. Patel BCA College, Nanikadi[12]


ADVANCED PROGRAMMING LANGUAGE ‘C’- 201 (SEM -II)
UNIT-4
Example:

# include <stdio.h>
#define PI 3.14159

In ANSI C the # sign need not be placed in the first column on a line, and
(unlike as in Classic C) spaces are allowed between the # sign and
include or define.

The preprocessor aids the programmer in constructing programs that are


easy to read, maintain and port to other installations .The #include
Directive This directive has the alternate forms:

#include <stddef.h>
#include ―mydefs.h‖

Preprocessor directives:

Directive Meaning
# include include a source file

# define define a macro


# undef undefine a macro
# if conditional compilation
# ifdef conditional compilation
# ifndef conditional compilation
# elif conditional compilation
# else conditional compilation
# endif conditional compilation
# line control error reporting
# error force an error message
# pragma used for implementation-dependent control
# null directive; no effect

Shree R. K. Patel BCA College, Nanikadi[13]


ADVANCED PROGRAMMING LANGUAGE ‘C’- 201 (SEM -II)
UNIT-4
The preprocessor directives can be divided into three categories

 Macro substitution: replacing instances of one piece of text with


another.
 File inclusion: inserting the contents of another file into your source
file, as if you had typed it all in there.
 Conditional compilation: Arranging that, depending on various
circumstances, certain parts of your source code are seen or not seen
by the compiler at all.

Macro substitution:

The other major use of the preprocessor is to define macros. The


advantage of a macro is that it can be type-neutral A macro definition is
usually of the following form:

#define MACRO_NAME(arg1, arg2, ...) [code to expand to]

For instance, a simple increment macro might look like this:

#define INCREMENT(x) x++

They look a lot like function calls, but they're not so simple. There are
actually a couple of tricky points when it comes to working with macros.
First, remember that the exact text of the macro argument is "pasted in"
to the macro. For instance, if you wrote something like this:

#define MULT(x, y) x * y

and then wrote


int z = MULT(3 + 2, 4 + 2);

what value do you expect z to end up with? The obvious answer, 30, is
wrong! That's because what happens when the macro MULT expands is
that it looks like this:
int z = 3 + 2 * 4 + 2; // 2 * 4 will be evaluated first!

So z would end up with the value 13! This is almost certainly not what
you want to happen. The way to avoid it is to force the arguments
themselves to be evaluated before the rest of the macro body. You can do
this by surrounding them by parentheses in the macro definition:

Shree R. K. Patel BCA College, Nanikadi[14]


ADVANCED PROGRAMMING LANGUAGE ‘C’- 201 (SEM -II)
UNIT-4
#define MULT(x, y) (x) * (y)
// now MULT(3 + 2, 4 + 2) will expand to (3 + 2) * (4 + 2)

But this isn't the only gotcha! It is also generally a good idea to surround
the macro's code in parentheses if you expect it to return a value.
Otherwise, you can get similar problems as when you define a constant.
For instance, the following macro, which adds 5 to a given argument, has
problems when embedded within a larger statement:

#define ADD_FIVE(a) (a) + 5


int x = ADD_FIVE(3) * 3;
// this expands to (3) + 5 * 3, so 5 * 3 is evaluated first
// Now x is 18, not 24!

To fix this, you generally want to surround the whole macro body with
parentheses to prevent the surrounding context from affecting the macro
body.

#define ADD_FIVE(a) ((a) + 5)


int x = ADD_FIVE(3) * 3;

On the other hand, if you have a multilane macro that you are using for
its side effects, rather than to compute a value, you probably want to
wrap it within curly braces so you don't have problems when using it
following an if statement.

// We use a trick involving exclusive-or to swap two variables


#define SWAP(a, b) a ^= b; b ^= a; a ^= b;
int x = 10;
int y = 5;
// works OK
SWAP(x, y);
// What happens now?
if(x < 0)
SWAP(x, y);

When SWAP is expanded in the second example, only the first statement,
a ^= b, is governed by the conditional; the other two statements will
always execute. What we really meant was that all of the statements
should be grouped together, which we can enforce using curly braces:

#define SWAP(a, b) {a ^= b; b ^= a; a ^= b;}


Now, there is still a bit more to our story! What if you write code like so:

Shree R. K. Patel BCA College, Nanikadi[15]


ADVANCED PROGRAMMING LANGUAGE ‘C’- 201 (SEM -II)
UNIT-4
#define SWAP(a, b) { a ^= b; b ^= a; a ^= b; }
int x = 10;
int y = 5;
int z = 4;
// What happens now?
if(x < 0)
SWAP(x, y);
else
SWAP(x, z);
Then it will not compile because semicolon after the closing curly brace
will break the flow between if and else. The solution? Use a do-while loop:

#define SWAP(a, b) do { a ^= b; b ^= a; a ^= b; } while ( 0 )


int x = 10;
int y = 5;
int z = 4;
// What happens now?
if(x < 0)
SWAP(x, y);
else
SWAP(x, z);

Now the semi-colon doesn't break anything because it is part of the


expression. (By the way, note that we didn't surround the arguments in
parentheses because we don't expect anyone to pass an expression into
swap!)

File inclusion:
A line of the form
#include <filename.h>
or
#include "filename.h"
causes the contents of the file filename.h to be read, parsed, and
compiled at that point. (After filename.h is processed, compilation
continues on the line following the #include line.) For example, suppose
you got tired of retyping external function prototypes such as
extern int getline(char [], int);
at the top of each source file. You could instead place the prototype in a
header file, perhaps getline.h, and then simply place
#include "getline.h"

Shree R. K. Patel BCA College, Nanikadi[16]


ADVANCED PROGRAMMING LANGUAGE ‘C’- 201 (SEM -II)
UNIT-4
at the top of each source file where you called getline. (You might not find
it worthwhile to create an entire header file for a single function, but if
you had a package of several related function, it might be very useful to
place all of their declarations in one header file.) As we may have
mentioned, that's exactly what the Standard header files such as stdio.h
are--collections of declarations (including external function prototype
declarations) having to do with various sets of Standard library
functions. When you use #include to read in a header file, you
automatically get the prototypes and other declarations it contains, and
you should use header files, precisely so that you will get the prototypes
and other declarations they contain.
The difference between the <> and "" forms is where the preprocessor
searches for filename.h. As a general rule, it searches for files enclosed in
<> in central, standard directories, and it searches for files enclosed in ""
in the ``current directory,'' or the directory containing the source file
that's doing the including. Therefore, "" is usually used for header files
you've written, and <> is usually used for headers which are provided for
you (which someone else has written).
The extension ``.h'', by the way, simply stands for ``header,'' and reflects
the fact that #include directives usually sit at the top (head) of your
source files, and contain global declarations and definitions which you
would otherwise put there. (That extension is not mandatory--you can
theoretically name your own header files anything you wish--but .h is
traditional, and recommended.)
As we've already begun to see, the reason for putting something in a
header file, and then using #include to pull that header file into several
different source files, is when the something (whatever it is) must be
declared or defined consistently in all of the source files. If, instead of
using a header file, you typed the something in to each of the source files
directly, and the something ever changed, you'd have to edit all those
source files, and if you missed one, your program could fail in subtle (or
serious) ways due to the mismatched declarations (i.e. due to the
incompatibility between the new declaration in one source file and the
old one in a source file you forgot to change). Placing common
declarations and definitions into header files means that if they ever
change, they only have to be changed in one place, which is a much
more workable system.

What should you put in header files?

 External declarations of global variables and functions. We said that a


global variable must have exactly one defining instance, but that it
can have external declarations in many places. We said that it was a
grave error to issue an external declaration in one place saying that a

Shree R. K. Patel BCA College, Nanikadi[17]


ADVANCED PROGRAMMING LANGUAGE ‘C’- 201 (SEM -II)
UNIT-4
variable or function has one type, when the defining instance in some
other place actually defines it with another type. (If the two placs are
two source files, separately compiled, the compiler will probably not
even catch the discrepancy.) If you put the external declarations in a
header file, however, and include the header wherever it's needed, the
declarations are virtually guaranteed to be consistent. It's a good idea
to include the header in the source file where the defining instance
appears, too, so that the compiler can check that the declaration and
definition match. (That is, if you ever change the type, you do still
have to change it in two places: in the source file where the defining
instance occurs, and in the header file where the external declaration
appears. But at least you don't have to change it in an arbitrary
number of places, and, if you've set things up correctly, the compiler
can catch any remaining mistakes.)
 Preprocessor macro definitions (which we'll meet in the next section).
 Structure definitions (which we haven't seen yet).
 Typedef declarations (which we haven't seen yet).

However, there are a few things not to put in header files:

 Defining instances of global variables. If you put these in a header file,


and include the header file in more than one source file, the variable
will end up multiply defined.
 Function bodies (which are also defining instances). You don't want to
put these in headers for the same reason--it's likely that you'll end up
with multiple copies of the function and hence ``multiply defined''
errors. People sometimes put commonly-used functions in header files
and then use #include to bring them (once) into each program where
they use that function, or use #include to bring together the several
source files making up a program, but both of these are poor ideas.
It's much better to learn how to use your compiler or linker to
combine together separately-compiled object files.

Conditional compilation:
There are a whole set of options that can be used to determine whether
the preprocessor will remove lines of code before handing the file to the
compiler. They include #if, #elif, #else, #ifdef, and #ifndef.
An #if or #if/#elif/#else block or a #ifdef or #ifndef block must be
terminated with A closing #endif.
The #if directive takes a numerical argument that evaluates to true if it's
non-zero. If its argument is false, then code until the closing #else, #elif,
of #endif will be excluded.

Shree R. K. Patel BCA College, Nanikadi[18]


ADVANCED PROGRAMMING LANGUAGE ‘C’- 201 (SEM -II)
UNIT-4
Commenting out Code

Conditional compilation is a particularly useful way to comment out a


block of code that contains multi-line comments (which cannot be
nested).
#if 0
// code
#endif

Include Guards

Another common problem is that a header file is required in multiple


other header files that are later included into a source code file, with the
result often being that variables, structs, classes or functions appear to
be defined multiple times (once for each time the header file is included).
This can result in a lot of compile-time headaches. Fortunately, the
preprocessor provides an easy technique for ensuring that any given file
is included once and only once.

By using the #ifndef directive, you can include a block of text only if a
particular expression is undefined; then, within the header file, you can
define the expression. This ensures that the code in the #ifndef is
included only the first time the file is loaded.
#ifndef _FILE_NAME_H_
#define _FILE_NAME_H_
/* code */
#endif // #ifndef _FILE_NAME_

Shree R. K. Patel BCA College, Nanikadi[19]

You might also like