full
Shared by: ashrafp
-
Stats
- views:
- 4
- posted:
- 8/23/2011
- language:
- English
- pages:
- 58
Document Sample


Simple Input and Output
When you take time to consider it, a computer would be pretty useless without some way
to talk to the people who use it. Just like we need information in order to accomplish
tasks, so do computers. And just as we supply information to others so that they can do
tasks, so do computers.
These supplies and returns of information to a computer are called input and output.
'Input' is information supplied to a computer or program. 'Output' is information provided
by a computer or program. Frequently, computer programmers will lump the discussion
in the more general term input/output or simply, I/O.
In C, there are many different ways for a program to communicate with the user.
Amazingly, the simplest methods usually taught to beginning programmers may also be
the most powerful. In the "Hello, World" example at the beginning of this text, we were
introduced to a Standard Library file stdio.h, and one of its functions, printf(). Here we
discuss more of the functions that stdio.h gives us.
Output using printf()
Recall from the beginning of this text the demonstration program duplicated below:
#include <stdio.h>
int main(void)
{
printf("Hello, world!\n");
return 0;
}
If you compile and run this program, you will see the sentence below show up on your
screen:
Hello, world!
This amazing accomplishment was achieved by using the function printf(). A function
is like a "black box" that does something for you without exposing the internals inside.
We can write functions ourselves in C, but we will cover that later.
You have seen that to use printf() one puts text, surrounded by quotes, in between the
brackets. We call the text surrounded by quotes a literal string (or just a string), and we
call that string an argument to printf.
As a note of explanation, it is sometimes convenient to include the open and closing
parentheses after a function name to remind us that it is, indeed, a function. However
usually when the name of the function we are talking about is understood, it is not
necessary.
As you can see in the example above, using printf() can be as simple as typing in some
text, surrounded by double quotes (note that these are double quotes and not two single
quotes). So, for example, you can print any string by placing it as an argument to the
printf() function:
printf("This sentence will print out exactly as you see it...");
And once it is contained in a proper main() function, it will show:
This sentence will print out exactly as you see it...
Printing numbers and escape sequences
Placeholder codes
The printf function is a powerful function, and is probably the most-used function in C
programs.
For example, let us look at a problem. Say we don't know what 1905 + 31214 is. Let's use
C to get the answer.
We start writing
#include <stdio.h> /* this is important, since printf
* can not be used without this line */
(For more information about the line above, see The Preprocessor).
int main(void)
{
printf("1905+31214 is");
return 0;
}
but here we are stuck! printf only prints strings! Thankfully, printf has methods for
printing numbers. What we do is put a placeholder format code in the string. We write:
printf("1905+31214 is %d", 1905+31214);
The placeholder %d literally "holds the place" for the actual number that is the result of
adding 1905 to 31214.
These placeholders are called format specifiers. Many other format specifiers work with
printf. If we have a floating-point number, we can use %f to print out a floating-point
number, decimal point and all. An incomplete list is:
%i and %d - int
%f - float
%lf - double
%s - string
%x - hexadecimal
Tabs and newlines
What if, we want to achieve some output that will look like:
1905
31214 +
-----
printf will not put line breaks in at the end of each statement: we must do this ourselves.
But how?
What we can do is use the newline escape character. An escape character is a special
character that we can write but will do something special onscreen, such as make a beep,
write a tab, and so on. To write a newline we write \n. All escape characters start with a
backslash.
So to achieve the output above, we write
printf(" 1905\n31214 +\n-----\n%d", 33119);
or to be a bit clearer, we can break this long printf statement over several lines. So our
program will be:
#include <stdio.h>
int main(void)
{
printf(" 1905\n");
printf("31214 +\n");
printf("-----\n");
printf("%d", 33119);
return 0;
}
There are other escape characters we can use. Another common one is to use \t to write a
tab. You can use \a to ring the computer's bell, but you should not use this very much in
your programs, as excessive use of sound is not very friendly to the user.
Other output methods
puts()
The puts() function is a very simple way to send a string to the screen when you have no
placeholders to be concerned about. It works very much like the printf() function we saw
the "Hello, World!" example:
puts("Print this string.");
will print to the screen:
Print this string.
followed by the newline character (as discussed above). (The puts function appends a
newline character to its output.) The fputs function is similar:
fputs("Print this string via fputs", stdout);
will print to the stdout file (usually the screen):
Print this string via fputs
without a newline tacked on to the end.
Since puts() and fputs() do not allow the placeholders and the associated formatting that
printf() allows, for most programmers learning printf() is sufficient for their needs.
Input using scanf()
The scanf() function is the input method equivalent to the printf() output function—
simple yet powerful. In its simplest invocation, the scanf() format string holds a single
placeholder representing the type of value that will be entered by the user. These
placeholders are exactly the same as the printf() function - %d for ints, %f for floats,
and %lf for doubles.
There is, however, one variation to scanf() as compared to printf(). The scanf()
function requires the memory address of the variable to which you want to save the input
value. While pointers are possible here, this is a concept that won't be approached until
later in the text. Instead, the simple technique is to use the address-of operator, &. For
now it may be best to consider this "magic" before we discuss pointers.
A typical application might be like this:
#include <stdio.h>
int main(void)
{
int a;
printf("Please input an integer value: ");
scanf("%d", &a);
return 0;
}
If you are trying to input a string using scanf, you should not include the & operator.
If you were to describe the effect of the scanf function call above, it might read as:
"Read in an integer from the user and store it at the address of variable a ".
Note of caution on inputs: When data is typed at a keyboard, the information does not
go straight to the program that is running. It is first stored in what is known as a buffer—a
small amount of memory reserved for the input source. Sometimes there will be data left
in the buffer when the program wants to read from the input source, and the scanf()
function will read this data instead of waiting for the user to type something. In order to
avoid this, it is possible to write the statement fflush(stdin), which will clear the
buffer, before using scanf.
Examples
An example program asking the user to enter two numbers and then display their sum:
#include <stdio.h>
int main(void)
{
int number1, number2;
printf("Please input an integer value: ");
scanf("%d", &number1);
printf("Please input an integer value: ");
scanf("%d", &number2);
printf("%d + %d = %d\n", number1, number2, number1 + number2);
return 0;
}
If-Then(-Else)
The if-then construct (sometimes called if-then-else) is common across many
programming languages. Although the syntax varies quite a bit from language to
language, the basic structure (in pseudocode form) looks like this: (This example is
actually perfectly valid Visual Basic or QuickBASIC syntax.)
If (condition) Then
(statements)
Else
(statements)
End If
When an interpreter finds an If, it expects a boolean condition - for example, x > 0,
which means "the variable x contains a number that is greater than zero" - and evaluates
that condition. If the condition is true, the statements following the Then are executed.
Otherwise, the execution continues in the following branch - either in the Else block
(which is usually optional), or if there is no Else branch, then after the End If.
After either branch has been executed, control returns to the point after the End If.
In early programming languages - and in particular, in some dialects of BASIC in the
1980s - an if-then statement could only contain GOTO statements. This led to a hard-to-
read style of programming known as spaghetti programming, with programs in this style
called spaghetti code. As a result, structured programming, which allowed (virtually)
arbitrary statements to be put in statement blocks inside an if statement, gained in
popularity, until it became the norm. While it is possible while using only GOTO
statements in if-then statements to write programs that are not spaghetti code and are
just as well structured and readable as programs written in a structured programming
language, structured programming makes this easier and enforces it. Structured if-then-
else statements like the example above are one of the key elements of structured
programming, and they are present in most popular modern high-level programming
languages including VB (all versions including .NET), C and its derivatives (including
C++ and C#), Java and JavaScript.
Else If parts
By using Else If, it is possible to combine several conditions. Only the statements
following the first condition that is found to be true will be executed. All other statements
will be skipped. The statements of the final Else will be executed if none of the
conditions are true. This example is written in the Ada programming language:
if condition then
-- statements;
elseif condition then
-- more statements;
elseif condition then
-- more statements;
...
else condition then
-- other statements;
end if;
elseif, in Ada, is simply syntactic sugar for else followed by if. In Ada, the difference
is that only one end if is needed, if one uses elseif instead of else followed by if.
In some other languages, such as C and Java, else if literally just means else followed
by if - so no syntactic sugar is needed or provided. This works since when an else is
followed by one statement (in this case the if), it doesn't need any braces.
In Python, there is a special keyword elif for this because Python uses indent to indicate
structure, so if you only used else and if, then you would need to keep increasing the
indent at every condition. In Perl, there is a special keyword elsif for this because
braces are required for if and else, so if you only used else and if, then you would
need to keep adding braces.
If expressions
Many languages support if expressions, which are similar to if statements, but return a
value as a result. Thus, they are true expressions (which evaluate to a value), not
statements (which just perform an action).
As a ternary operator
Main article: ?:
In C and C-like languages conditional expressions take the form of a ternary operator
called the conditional expression operator, ?:, which follows this template:
(condition)?(evaluate if condition was true):(evaluate if condition was
false)
This means that conditions can be inlined into expressions, unlike with if statements, as
shown here using C syntax:
//Invalid
my_variable = if(x > 10) { "foo" } else { "bar" };
//Valid
my_variable = (x > 10)?"foo":"bar";
To accomplish the same as the second (correct) line above, using a standard if/else
statement, this would take more than one line of code (under standard layout
conventions):
if (x > 10) {
my_variable = 'foo';
}
else {
my_variable = 'bar';
}
Case and switch statements
Main article: Switch statement
Switch statements (in some languages, case statements) compare a given value with
specified constants and take action according to the first constant to match. The example
on the left is written in Pascal, and the example on the right is written in C.
Pascal: C:
switch (someChar) {
case someChar of case 'a': actionOnA; break;
'a': actionOnA; case 'x': actionOnX; break;
'x': actionOnX; case 'y':
'y','z':actionOnYandZ; case 'z': actionOnYandZ; break;
end; default: actionOnNoMatch;
}
Pattern matching is not strictly speaking always a choice construct, because it is possible
in Haskell to write only one alternative, which is guaranteed to always be matched - in
this situation, it is not being used as a choice construct, but simply as a way to bind
variables. However, it is frequently used as a choice construct in the languages in which
it is available.
Examples
The following are simple examples, written in the various languages, that use switch (or
switch-like) statements to print one of several possible lines, depending on the value of
an integer entered by the user.
C, C++, C#, Java, php, ActionScript
In C and similarly-constructed languages, the lack of break keywords to cause fall
through of program execution from one block to the next is used extensively. For
example, if n=2, the fourth case statement will produce a match to the control variable.
The next line outputs "n is an even number.". As an apparent bug, execution continues
through the next 3 case statements and to the next line, which outputs "n is a prime
number." which is a common error due to a missing break statement. The break line
after a case block causes the switch statement to conclude. If the user types in more than
one digit, the default block is executed, producing an error message by executing the
default code.
switch (n)
{
case 0:
puts("You typed zero.");
break;
case 1:
case 9:
puts("n is a perfect square.");
break;
case 2:
puts("n is an even number.");
case 3:
case 5:
case 7:
puts("n is a prime number.");
break;
case 4:
puts("n is a perfect square.");
case 6:
case 8:
puts("n is an even number.");
break;
default:
puts("Only single-digit numbers are allowed.");
break;
}
Looping program(for,while,do while)
Example of for loop
Object-program to print numbers of a given range
#include<stdio.h>
#include<conio.h>
int main()
{
int M,N;
printf("enter the ranges do you want diaplay\n");
scanf("%d%d",&M,&N);
printf("the numbers between %d to %d \n",M,N);
for(;M<=N;M++)
printf("%d ",M);
getch();
}
Object-Display the leap Years between 1000 and 2000
#include <stdio.h>
#include <conio.h>
int main()
{
int loop;
printf("the leap year or not between 1000 to 2000\n");
for(loop=1000;loop<=2000;loop++)
{
if(loop%4==0)
printf("%d leap year\n",loop);
else
printf("%d not\n",loop);
}
getch();
}
While loop:-
syntax:-
While (condition)
{
Statements;
}
Do while loop:-
syntax:-
do {
statements;
} while (condition);
is not equivalent to
statements;
while (condition) {
statements;
}
Array
One-Dimensional Arrays
A postfix expression followed by an expression in square brackets ([ ]) is a subscripted representation of
an element of an array object. A subscript expression represents the value at the address that is
expression positions beyond postfix-expression when expressed as
postfix-expression [ expression ]
Usually, the value represented by postfix-expression is a pointer value, such as an array identifier, and
expression is an integral value. However, all that is required syntactically is that one of the expressions be
of pointer type and the other be of integral type. Thus the integral value could be in the postfix-expression
position and the pointer value could be in the brackets in the expression, or "subscript," position. For
example, this code is legal:
// one_dimensional_arrays.c
int sum, *ptr, a[10];
int main() {
ptr = a;
sum = 4[ptr];
}
Subscript expressions are generally used to refer to array elements, but you can apply a subscript to any
pointer. Whatever the order of values, expression must be enclosed in brackets ([ ]).
The subscript expression is evaluated by adding the integral value to the pointer value, then applying the
indirection operator (*) to the result. In effect, for a one-dimensional array, the following four expressions
are equivalent, assuming that a is a pointer and b is an integer:
a[b]
*(a + b)
*(b + a)
b[a]
According to the conversion rules for the addition operator the integral value is converted to an address
offset by multiplying it by the length of the type addressed by the pointer.
For example, suppose the identifier line refers to an array of int values. The following procedure is used
to evaluate the subscript expression line[ i ]:
1. The integer value i is multiplied by the number of bytes defined as the length of an int item. The
converted value of i represents i int positions.
2. This converted value is added to the original pointer value (line) to yield an address that is
offset i int positions from line.
3. The indirection operator is applied to the new address. The result is the value of the array
element at that position (intuitively, line [ i ]).
The subscript expression line[0] represents the value of the first element of line, since the offset from
the address represented by line is 0. Similarly, an expression such as line[5] refers to the element
offset
TWO-DIMENSIONAL ARRAYS
Two-dimensional arrays are a little more complicated to use than one-dimensional ones.
This page presents two methods of passing a pointer to a two-dimensional array to a
function for processing.
Subscript Notation
Consider an int array as declared below.
#define NUM_STUDENTS 5
#define NUM_TESTS 4
int grades[NUM_STUDENTS][NUM_TESTS];
By convention, the first subscript is understood to be for rows and the second for
columns.
This array can hold up to 20 integer values, the product of the values used to
declare the array.
As is usual in C, subscripts start with zero, so the subscripts range from 0 to 4 for
the rows and 0 to 3 for the columns.
If the system uses four bytes for an int, this array would use 80 bytes of RAM. All
of the bytes are in consecutive memory locations, the first row occupying the first
20 bytes, the second the next 20, and so on.
The following table illustrates how the subscripts are specified for this array, which has
five (5) rows and four (4) columns.
0 1 2 3
0 [0][0] [0][1] [0][2] [0][3]
1 [1][0] [1][1] [1][2] [1][3]
2 [2][0] [2][1] [2][2] [2][3]
3 [3][0] [3][1] [3][2] [3][3]
4 [4][0] [4][1] [4][2] [4][3]
Array Initialization: Inline
To initialize all elements of the grades array to -1 (a number that is highly improbable for
a grade), you could use a nested loop structure such as the following.
for( i = 0; i < NUM_STUDENTS; i++)
for( j = 0; j < NUM_TESTS; j++)
grades[i][j] = -1;
Array Initialization: At Declaration
It is also possible to initialize elements of an array at the time of its declaration. The
following declaration assigns values for three grades for each of the first two students in
the array. Note that the values for a specific row are enclosed within their own pair of
curly brackets.
int grades[NUM_STUDENTS][NUM_TESTS] = { {55, 60, 65},
{95, 90, 85} };
It may facilitate your programming, if you keep track of how many elements in the array
hold usable values. For this simple example, we can initialize two variables.
int num_students = 2;
int num_tests = 3;
Array Processing: Using Subscripts in a Function
Since, by definition, the name of any array is a pointer, we can call a function which
returns the highest grade in the array as follows.
high_test = get_highest( grades, num_students, num_tests);
The second and third arguments allow the function to search only the elements which
have been initialized.
One of the ways of writing get_highest() uses subscript notation:
int get_highest(int a[][NUM_TESTS], int row, int col)
/* Assumes that there is at least one element */
{
int i, j;
int highest = a[0][0];
for( i = 0; i < row; i++)
for( j = 0; j < col; j++)
if ( a[i][j] > highest)
highest = a[i][j];
return highest;
}
It is necessary in this instance to specify the number of columns in the array (the number
of items in a row) so that the compiler can determine the offsets from the beginning of
the array. Unlike with the one-dimensional array algorithm, where we avoided comparing
the first element with itself, here the extra code required does not outweigh the simplicity
of the above algorithm.
Sample Program 1
This is a complete program which initializes part of an array of integer grades at the time
of its declaration with 6 values and then calls a function to find, return, and print the
highest grade. Note that the dimensions of the array have been changed from those used
in the discussion above by altering the compiler directives.
#include <stdio.h>
#define NUM_STUDENTS 25
#define NUM_TESTS 10
int get_highest(int a[][NUM_TESTS], int row, int col);
int main()
{
int grades[NUM_STUDENTS][NUM_TESTS] = { {55, 60, 65},
{85, 90, 95} };
int num_students = 2;
int num_tests = 3;
int high_test;
high_test = get_highest( grades, num_students, num_tests);
printf("The highest score is %d.\n", high_test);
return 0;
}
int get_highest(int a[][NUM_TESTS], int row, int col)
/* Assumes that there is at least one element */
{
int i, j;
int highest = a[0][0];
for( i = 0; i < row; i++)
for( j = 0; j < col; j++)
if ( a[i][j] > highest)
highest = a[i][j];
return highest;
}
Pointer Notation with Offset
Consider the int array as declared below. It is the same as the one discussed above except
for the slight modification of the identifiers. This change was made so that we can have a
second array which will be declared with different dimensions.
#define NUM_STUDENTS1 5
#define NUM_TESTS1 4
int grades1[NUM_STUDENTS1][NUM_TESTS1];
The following table illustrates the offsets of the elements from the start of this array,
which has five (5) rows and four (4) columns. The italicized numbers are the subscripts
for the rows and columns.
0 1 2 3
0 0 1 2 3
1 4 5 6 7
2 8 9 10 11
3 12 13 14 15
4 16 17 18 19
Array Initialization: Inline
To initialize all elements of the grades1 array to -1 (a number that is highly improbable
for a grade), you could use a nested loop structure as was done above or do a cheat such
as the following.
for( i = 0; i < NUM_STUDENTS1 * NUM_TESTS1; i++)
*((int *)grades1 + i) = -1;
This method takes advantage of the fact that grades1 is a pointer constant for a two-
dimensional array. It uses the loop control variable as the offset from the beginning of the
array. The casting of the pointer constant fools the compiler into thinking that the array is
one-dimensional. Since both our two-dimensional grade1 array and a one-dimensional
array capable of holding 20 ints would be stored using a total of 80 consecutive bytes of
RAM, no harm is done by this trickery.
Array Initialization: Generalized Using a Function
However, since the code above is array specific, we may want to generalize by creating a
function which will initialize any two-dimensional array of ints.
void init_int_array(int *a, int num_rows, int num_cols)
{
int i;
for( i = 0; i < num_rows * num_cols; i++)
*(a + i) = -1;
}
Here we are using the generic variable name a which is a pointer to an int. The loop
control variable i is the offset into the array. The call to this function for grades1 would
be:
init_int_array( (int *)grades1, NUM_STUDENTS1, NUM_TESTS1);
Here we cast the pointer constant into a pointer to an integer, which matches the
declaration in the function. The constants for the dimensions of the array are passed to
init_int_array() to be used for the calculation of the total number of elements in the array.
Array Processing: Generalized Using a Function
If all of the usable data is stored in the upper left corner of the array, it is a relatively
simple matter to access the appropriate elements. The following call to get_highest()
sends a casted pointer to the array, the number of columns in the array, and the bounds of
the upper left corner where the data is.
high_test1 =
get_highest( (int *)grades1, NUM_TESTS1, num_students1,
num_tests1);
The code for the function which follows illustrates the power of pointers and offsets in
the C language. While we may wish to view a list of items as a number of sub-lists, the
items are stored in the computer in consecutive memory locations. We can use pointer
arithmetic to convert our two-dimensional perception of reality to the linear view dictated
by how RAM is utilized. The four arguments passed by the function call above are
sufficient for this purpose.
1. The pointer constant grades1 provides the array's starting point in RAM.
2. NUM_TESTS1 provides the maximum number of possible items in the sub-list.
3. num_students1 provides the number of rows to be checked.
4. num_tests1 provides the number of columns to be checked.
The following expression can be used to access an element of the array.
*(a + i*cols + j)
1. a, which remains constant, points at the zeroth element of the list.
2. cols, which remains constant, is the number of columns in a row.
3. i ranges from 0 to one less than the number of rows to be searched.
4. j ranges from 0 to one less than the number of columns to be searched.
With a remaining constant, it can be seen that i*cols + j provides the offset from the
beginning of the list.
Here is a complete function which can be used to return the largest int in a portion of a
two-dimensional array of any size.
int get_highest(int *a, int cols, int row, int col)
/* Assumes that the elements with usable values are
in the upper left corner of the array as
delimited by row and col;
cols is the number of columns in the array passed */
{
int i, j;
int highest = *a;
for( i = 0; i < row; i++)
for( j = 0; j < col; j++)
if ( *(a + i*cols + j) > highest)
highest = *(a + i*cols + j);
return highest;
}
Sample Program 2
This is a program which initializes parts of two arrays of integer grades at the time of
their declaration, each with 6 values. Then it calls a function to find, return, and print the
highest grade in each of the two arrays.
#include <stdio.h>
#define NUM_STUDENTS1 25
#define NUM_TESTS1 10
#define NUM_STUDENTS2 15
#define NUM_TESTS2 8
int get_highest(int *a, int cols, int row, int col);
int main()
{
int grades1[NUM_STUDENTS1][NUM_TESTS1] = { {55, 60, 65},
{85, 90, 95} };
int num_students1 = 2;
int num_tests1 = 3;
int high_test1;
int grades2[NUM_STUDENTS2][NUM_TESTS2] = { {55, 60},
{85, 90},
{75, 70} };
int num_students2 = 3;
int num_tests2 = 2;
int high_test2;
high_test1 =
get_highest( (int *)grades1, NUM_TESTS1, num_students1,
num_tests1);
printf("The highest score in the first class is %d.\n", high_test1);
high_test2 =
get_highest( (int *)grades2, NUM_TESTS2, num_students2,
num_tests2);
printf("The highest score in the second class is %d.\n",
high_test2);
return 0;
}
int get_highest(int *a, int cols, int row, int col)
/* Assumes that the elements with usable values are
in the upper left corner of the array as
delimited by row and col;
cols is the number of columns in the array passed */
{
int i, j;
int highest = *a;
for( i = 0; i < row; i++)
for( j = 0; j < col; j++)
if ( *(a + i*cols + j) > highest)
highest = *(a + i*cols + j);
return highest;
}
Static and Dynamic Allocation of Multi-Dimensional
Arrays in C
An array in C is a region of memory in which the elements (chars, ints,
etc.) can be accessed using an index (in a 1-dimensional array, e.g.
name[0]) or several indices (in a multi-dimensional array, e.g.
names[3][0][2]). The first element in a 1-dimensional array x[] is
x[0], in a 2-dimensional array x[][] is x[0][0], and so on.
In C you can allocate memory for an array using statements such as:
char name[32];
int nums[100];
double coords[60][60]
char names[10][20][64];
double space[32][32][32][32];
The index of the last element in a 1-dimensional array is one less than the size
of the array (e.g. name[31] if the array is declared using char name[32]). In a
multidimensional array the indices of the last element are one less than the
sizes of each dimension (e.g. names[9][19][63] if the array is declared using
char names[10][20][64]).
When an array is declared as above, memory is allocated for the elements of
the array when the program starts, and this memory remains allocated during
the lifetime of the program. This is known as static array allocation.
It may happen that you don't know (at the time of writing the code) how large
an array you will need (or how many arrays). In this case it is convenient to
allocate an array while the program is running. This is known as dynamic array
allocation.
Dynamic allocation of a 1-dimensional array is easily done using the malloc()
function. For example, if you wish to allocate an array of 1000 ints then the
following code can be used:
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
void main(void)
{
int *a;
int i=1000;
if ( ( a = (int *)malloc(i*sizeof(int)) ) == NULL )
{
printf("\nError, memory not allocated.\n");
exit(1);
}
for ( i=0; i<1000; i++ )
a[i] = i;
// ...
free(a);
}
Dynamic allocation of arrays of more than one dimension is not so easily done, because
dynamic allocation of an n-dimensional array actually requires dynamic allocation of n 1-
dimensional arrays. To allocate a 2-dimensional array you must first allocate memory
sufficient to hold all the elements of the array (the data), then allocate memory for
pointers to each row of the array. For arrays of more than two dimensions it gets more
complicated. To allocate a 3-dimensional array you first allocate memory for the data,
then allocate memory for an array of pointers to rows of data within that memory, then
allocate memory for an array of pointers to a subset of those pointers. And so on for
arrays of higher dimension.
Structures and Unions
In this tutorial you will learn about C Programming - Structures and Unions, Giving
values to members, Initializing structure, Functions and structures, Passing structure to
elements to functions, Passing entire function to functions, Arrays of structure, Structure
within a structure and Union.
Arrays are used to store large set of data and manipulate them but the disadvantage is that
all the elements stored in an array are to be of the same data type. If we need to use a
collection of different data type items it is not possible using an array. When we require
using a collection of different data items of different data types we can use a structure.
Structure is a method of packing data of different types. A structure is a convenient
method of handling a group of related data items of different data types.
structure definition:
general format:
struct tag_name
{
data type member1;
data type member2;
…
…
}
Example:
struct lib_books
{
char title[20];
char author[15];
int pages;
float price;
};
the keyword struct declares a structure to holds the details of four fields namely title,
author pages and price. These are members of the structures. Each member may belong to
different or same data type. The tag name can be used to define objects that have the tag
names structure. The structure we just declared is not a variable by itself but a template
for the structure.
We can declare structure variables using the tag name any where in the program. For
example the statement,
struct lib_books book1,book2,book3;
declares book1,book2,book3 as variables of type struct lib_books each declaration has
four elements of the structure lib_books. The complete structure declaration might look
like this
struct lib_books
{
char title[20];
char author[15];
int pages;
float price;
};
struct lib_books, book1, book2, book3;
structures do not occupy any memory until it is associated with the structure variable
such as book1. the template is terminated with a semicolon. While the entire declaration
is considered as a statement, each member is declared independently for its name and
type in a separate statement inside the template. The tag name such as lib_books can be
used to declare structure variables of its data type later in the program.
We can also combine both template declaration and variables declaration in one
statement, the declaration
struct lib_books
{
char title[20];
char author[15];
int pages;
float price;
} book1,book2,book3;
is valid. The use of tag name is optional for example
struct
{
…
…
…
}
book1, book2, book3 declares book1,book2,book3 as structure variables representing 3
books but does not include a tag name for use in the declaration.
A structure is usually defines before main along with macro definitions. In such cases the
structure assumes global status and all the functions can access the structure.
Giving values to members:
As mentioned earlier the members themselves are not variables they should be linked to
structure variables in order to make them meaningful members. The link between a
member and a variable is established using the member operator ‗.‘ Which is known as
dot operator or period operator.
For example:
Book1.price
Is the variable representing the price of book1 and can be treated like any other ordinary
variable. We can use scanf statement to assign values like
scanf(“%s”,book1.file);
scanf(“%d”,& book1.pages);
Or we can assign variables to the members of book1
strcpy(book1.title,”basic”);
strcpy(book1.author,”Balagurusamy”);
book1.pages=250;
book1.price=28.50;
/* Example program for using a structure*/
#include< stdio.h >
void main()
{
int id_no;
char name[20];
char address[20];
char combination[3];
int age;
}newstudent;
printf(“Enter the student information”);
printf(“Now Enter the student id_no”);
scanf(“%d”,&newstudent.id_no);
printf(“Enter the name of the student”);
scanf(“%s”,&new student.name);
printf(“Enter the address of the student”);
scanf(“%s”,&new student.address);
printf(“Enter the cmbination of the student”);
scanf(“%d”,&new student.combination);
printf(“Enter the age of the student”);
scanf(“%d”,&new student.age);
printf(“Student information\n”);
printf(“student id_number=%d\n”,newstudent.id_no);
printf(“student name=%s\n”,newstudent.name);
printf(“student Address=%s\n”,newstudent.address);
printf(“students combination=%s\n”,newstudent.combination);
printf(“Age of student=%d\n”,newstudent.age);
}
Initializing structure:
Like other data type we can initialize structure when we declare them. As for initalization
goes structure obeys the same set of rules as arrays we initalize the fields of a structure by
the following structure declaration with a list containing values for weach fileds as with
arrays these values must be evaluate at compile time.
Example:
Struct student newstudent
{
12345,
―kapildev‖
―Pes college‖;
―Cse‖;
19;
};
this initializes the id_no field to 12345, the name field to ―kapildev‖, the address field to
―pes college‖ the field combination to ―cse‖ and the age field to 19.
Functions and structures:
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:
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);
}
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].combinatio
n,std[I].age);
}
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:
Unions like structure contain members whose individual data types may differ from one
another. However the members that compose a union all share the same storage area
within the computers memory where as each member within a structure is assigned its
own unique storage area. Thus unions are used to observe memory. They are useful for
application involving multiple members. Where values need not be assigned to all the
members at any one time. Like structures union can be declared using the keyword union
as follows:
union item
{
int m;
float p;
char c;
}
code;
this declares a variable code of type union item. The union contains three members each
with a different data type. However we can use only one of them at a time. This is
because if only one location is allocated for union variable irrespective of size. The
compiler allocates a piece of storage that is large enough to access a union member we
can use the same syntax that we use to access structure members. That is
code.m
code.p
code.c
are all valid member variables. During accessing we should make sure that we are
accessing the member whose value is currently stored.
For example a statement such as
code.m=456;
code.p=456.78;
printf(“%d”,code.m);
Would prodece erroneous result.
In effect a union creates a storage location that can be used by one of its members at a
time. When a different number is assigned a new value the new value supercedes the
previous members value. Unions may be used in all places where a structure is allowed.
The notation for accessing a union member that is nested inside a structure remains the
same as for the nested structure.
Functions
In this tutorial you will learn about C Programming - Functions (Part-I) Functions are
used in c for the following reasons, Function definition, Types of functions, Functions
with no arguments and no return values, Functions with arguments but no return values,
Functions with arguments and return values, Return value data type of function and Void
functions.
The basic philosophy of function is divide and conquer by which a complicated tasks are
successively divided into simpler and more manageable tasks which can be easily
handled. A program can be divided into smaller subprograms that can be developed and
tested successfully.
A function is a complete and independent program which is used (or invoked) by the
main program or other subprograms. A subprogram receives values called arguments
from a calling program, performs calculations and returns the results to the calling
program.
There are many advantages in using functions in a program they are:
1. It facilitates top down modular programming. In this programming style, the high level
logic of the overall problem is solved first while the details of each lower level functions
is addressed later.
2. the length of the source program can be reduced by using functions at appropriate
places. This factor is critical with microcomputers where memory space is limited.
3. It is easy to locate and isolate a faulty function for further investigation.
4. A function may be used by many other programs this means that a c programmer can
build on what others have already done, instead of starting over from scratch.
5. A program can be used to avoid rewriting the same sequence of code at two or more
locations in a program. This is especially useful if the code involved is long or
complicated.
6. Programming teams does a large percentage of programming. If the program is divided
into subprograms, each subprogram can be written by one or two team members of the
team rather than having the whole team to work on the complex program
We already know that C support the use of library functions and use defined functions.
The library functions are used to carry out a number of commonly used operations or
calculations. The user-defined functions are written by theprogrammer to carry out
various individual tasks.
Functions are used in c for the following reasons:
1. Many programs require that a specific function is repeated many times instead of
writing the function code as many timers as it is required we can write it as a single
function and access the same function again and again as many times as it is required.
2. We can avoid writing redundant program code of some instructions again and again.
3. Programs with using functions are compact & easy to understand.
4. Testing and correcting errors is easy because errors are localized and corrected.
5. We can understand the flow of program, and its code easily since the readability is
enhanced while using the functions.
6. A single function written in a program can also be used in other programs also.
Function definition:
[ data type] function name (argument list)
argument declaration;
{
local variable declarations;
statements;
[return expression]
}
Example :
mul(a,b)
int a,b;
{
int y;
y=a+b;
return y;
}
When the value of y which is the addition of the values of a and b. the last two statements
ie,
y=a+b; can be combined as
return(y)
return(a+b);
Types of functions:
A function may belong to any one of the following categories:
1. Functions with no arguments and no return values.
2. Functions with arguments and no return values.
3. Functions with arguments and return values.
Functions with no arguments and no return values:
Let us consider the following program
/* Program to illustrate a function with no argument and no
return values*/
#include
main()
{
staetemtn1();
starline();
statement2();
starline();
}
/*function to print a message*/
statement1()
{
printf(“\n Sample subprogram output”);
}
statement2()
{
printf(“\n Sample subprogram output two”);
}
starline()
{
int a;
for (a=1;a<60;a++)
printf(“%c”,’*’);
printf(“\n”);
}
In the above example there is no data transfer between the calling function and the called
function. When a function has no arguments it does not receive any data from the calling
function. Similarly when it does not return value the calling function does not receive any
data from the called function. A function that does not return any value cannot be used in
an expression it can be used only as independent statement.
Functions with arguments but no return values:
The nature of data communication between the calling function and the arguments to the
called function and the called function does not return any values to the calling function
this shown in example below:
Consider the following:
Function calls containing appropriate arguments. For example the function call
value (500,0.12,5)
Would send the values 500,0.12 and 5 to the function value (p, r, n) and assign values
500 to p, 0.12 to r and 5 to n. the values 500,0.12 and 5 are the actual arguments which
become the values of the formal arguments inside the called function.
Both the arguments actual and formal should match in number type and order. The values
of actual arguments are assigned to formal arguments on a one to one basis starting with
the first argument as shown below:
main()
{
function1(a1,a2,a3……an)
}
function1(f1,f2,f3….fn);
{
function body;
}
here a1,a2,a3 are actual arguments and f1,f2,f3 are formal arguments.
The no of formal arguments and actual arguments must be matching to each other
suppose if actual arguments are more than the formal arguments, the extra actual
arguments are discarded. If the number of actual arguments are less than the formal
arguments then the unmatched formal arguments are initialized to some garbage values.
In both cases no error message will be generated.
The formal arguments may be valid variable names, the actual arguments may be variable
names expressions or constants. The values used in actual arguments must be assigned
values before the function call is made.
When a function call is made only a copy of the values actual arguments is passed to the
called function. What occurs inside the functions will have no effect on the variables used
in the actual argument list.
Let us consider the following program
/*Program to find the largest of two numbers using
function*/
#include
main()
{
int a,b;
printf(“Enter the two numbers”);
scanf(“%d%d”,&a,&b);
largest(a,b)
}
/*Function to find the largest of two numbers*/
largest(int a, int b)
{
if(a>b)
printf(“Largest element=%d”,a);
else
printf(“Largest element=%d”,b);
}
in the above program we could make the calling function to read the data from the
terminal and pass it on to the called function. But function foes not return any value.
Functions with arguments and return values:
The function of the type Arguments with return values will send arguments from the
calling function to the called function and expects the result to be returned back from the
called function back to the calling function.
To assure a high degree of portability between programs a function should generally be
coded without involving any input output operations. For example different programs
may require different output formats for displaying the results. Theses shortcomings can
be overcome by handing over the result ofa function to its calling function where the
returned value can be used as required by the program. In the above type of function the
following steps are carried out:
1. The function call transfers the controls along with copies of the values of the actual
arguments of the particular function where the formal arguments are creates and assigned
memory space and are given the values of the actual arguments.
2. The called function is executed line by line in normal fashion until the return statement
is encountered. The return value is passed back to the function call is called function.
3. The calling statement is executed normally and return value is thus assigned to the
calling function.
Note that the value return by any function when no format is specified is an integer.
Return value data type of function:
A C function returns a value of type int as the default data type when no other type is
specified explicitly. For example if function does all the calculations by using float values
and if the return statement such as return (sum); returns only the integer part of the sum.
This is since we have not specified any return type for the sum. There is the necessity in
some cases it is important to receive float or character or doubledata type. To enable a
calling function to receive a non-integer value from a called function we can do the two
things:
1. The explicit type specifier corresponding to the data type required must be mentioned
in the function header. The general form of the function definition is
Type_specifier function_name(argument list)
Argument declaration;
{
function statement;
}
The type specifier tells the compiler, the type of data the function is to return.
2. The called function must be declared at the start of the body in the calling function,
like any other variable. This is to tell the calling function the type of data the function is
actually returning. The program given below illustrates the transfer of a floating-point
value between functions done in a multiple function program.
main()
{
float x,y,add();
double sub(0;
x=12.345;
y=9.82;
printf(“%f\n” add(x,y));
printf(“%lf\n”sub(x,y);
}
float add(a,b)
float a,b;
{
return(a+b);
}
double sub(p,q)
double p,q;
{
return(p-q);
}
We can notice that the functions too are declared along with the variables. These
declarations clarify to the compiler that the return type of the function add is float and sub
is double.
Pointers
In this tutorial you will learn about C Programming - Pointers, Pointer declaration,
Address operator, Pointer expressions & pointer arithmetic, Pointers and function, Call
by value, Call by Reference, Pointer to arrays, Pointers and structures, Pointers on
pointer.
Introduction:
In c a pointer is a variable that points to or references a memory location in which data is
stored. Each memory cell in the computer has an address that can be used to access that
location so a pointer variable points to a memory location we can access and change the
contents of this memory location via the pointer.
Pointer declaration:
A pointer is a variable that contains the memory location of another variable. The syntax
is as shown below. You start by specifying the type of data stored in the location
identified bythe pointer. The asterisk tells the compiler that you are creating a pointer
variable. Finally you give the name of the variable.
type * variable name
Example:
int *ptr;
float *string;
Address operator:
Once we declare a pointer variable we must point it to something we can do this by
assigning to the pointer the address of the variable you want to point as in the following
example:
ptr=#
This places the address where num is stores into the variable ptr. If num is stored in
memory 21260 address then the variable ptr has the value 21260.
/* A program to illustrate pointer declaration*/
main()
{
int *ptr;
int sum;
sum=45;
ptr=∑
printf (“\n Sum is %d\n”, sum);
printf (“\n The sum pointer is %d”, ptr);
}
we will get the same result by assigning the address of num to a regular(non pointer)
variable. The benefit is that we can also refer to the pointer variable as *ptr the asterisk
tells to the computer that we are not interested in the value 21260 but in the value stored
in that memory location. While the value of pointer is 21260 the value of sum is 45
however we can assign a value tothe pointer * ptr as in *ptr=45.
This means place the value 45 in the memory address pointer by the variable ptr. Since
the pointer contains the address 21260 the value 45 is placed in that memory location.
And since this is the location of the variable num the value also becomes 45. this shows
how we can change the value of pointer directly using a pointer and the indirection
pointer.
/* Program to display the contents of the variable their
address using pointer variable*/
include< stdio.h >
{
int num, *intptr;
float x, *floptr;
char ch, *cptr;
num=123;
x=12.34;
ch=’a’;
intptr=&x;
cptr=&ch;
floptr=&x;
printf(“Num %d stored at address %u\n”,*intptr,intptr);
printf(“Value %f stored at address %u\n”,*floptr,floptr);
printf(“Character %c stored at address %u\n”,*cptr,cptr);
}
Pointer expressions & pointer arithmetic:
Like other variables pointer variables can be used in expressions. For example if p1 and
p2 are properly declared and initializedpointers, then the following statements are valid.
y=*p1**p2;
sum=sum+*p1;
z= 5* - *p2/p1;
*p2= *p2 + 10;
C allows us to add integers to or subtract integers from pointers as well as to subtract one
pointer from the other. We can also use short hand operators with the pointers p1+=;
sum+=*p2; etc.,
we can also compare pointers by using relational operators the expressions such as p1
>p2 , p1==p2 and p1!=p2 are allowed.
/*Program to illustrate the pointer expression and pointer
arithmetic*/
#include< stdio.h >
main()
{
int ptr1,ptr2;
int a,b,x,y,z;
a=30;b=6;
ptr1=&a;
ptr2=&b;
x=*ptr1+ *ptr2 –6;
y=6*- *ptr1/ *ptr2 +30;
printf(“\nAddress of a +%u”,ptr1);
printf(“\nAddress of b %u”,ptr2);
printf(“\na=%d, b=%d”,a,b);
printf(“\nx=%d,y=%d”,x,y);
ptr1=ptr1 + 70;
ptr2= ptr2;
printf(“\na=%d, b=%d”,a,b);
}
Pointers and function:
The pointer are very much used in a function declaration. Sometimes only with a pointer
a complex function can be easily represented and success. The usage of the pointers in a
function definition may be classified into two groups.
1. Call by reference
2. Call by value.
Call by value:
We have seen that a function is invoked there will be a link established between the
formal and actual parameters. A temporary storage is created where the value of actual
parameters is stored. The formal parameters picks up its value from storage area the
mechanism of data transfer between actual and formal parameters allows the actual
parameters mechanism of data transfer is referred as call by value. The corresponding
formal parameter represents a local variable in the called function. The current value of
corresponding actual parameter becomes the initial value of formal parameter. The value
of formal parameter may be changed in the body of the actual parameter. The value of
formal parameter may be changed in the body of the subprogram by assignment or
inputstatements. This will not change the value of actual parameters.
/* Include< stdio.h >
void main()
{
int x,y;
x=20;
y=30;
printf(“\n Value of a and b before function call =%d
%d”,a,b);
fncn(x,y);
printf(“\n Value of a and b after function call =%d
%d”,a,b);
}
fncn(p,q)
int p,q;
{
p=p+p;
q=q+q;
}
Call by Reference:
When we pass address to a function the parameters receiving the address should be
pointers. The process of calling a function by using pointers to pass the address of the
variable is known as call by reference. The function which is called by reference can
change the values of the variable used in the call.
/* example of call by reference*?
/* Include< stdio.h >
void main()
{
int x,y;
x=20;
y=30;
printf(“\n Value of a and b before function call =%d
%d”,a,b);
fncn(&x,&y);
printf(“\n Value of a and b after function call =%d
%d”,a,b);
}
fncn(p,q)
int p,q;
{
*p=*p+*p;
*q=*q+*q;
}
Pointer to arrays:
an array is actually very much like pointer. We can declare the arrays first element as a[0]
or as int *a because a[0] is an address and *a is also an address the form ofdeclaration is
equivalent. The difference is pointer is a variable and can appear on the left of the
assignment operator that is lvalue. The array name is constant and cannot appear as the
left side of assignment operator.
/* A program to display the contents of array using
pointer*/
main()
{
int a[100];
int i,j,n;
printf(“\nEnter the elements of the array\n”);
scanf(“%d”,&n);
printf(“Enter the array elements”);
for(I=0;I< n;I++)
scanf(“%d”,&a[I]);
printf(“Array element are”);
for(ptr=a,ptr< (a+n);ptr++)
printf(“Value of a[%d]=%d stored at address
%u”,j+=,*ptr,ptr);
}
Strings are characters arrays and here last element is \0 arrays and pointers to char arrays
can be used to perform a number of string functions.
Pointers and structures:
We know the name of an array stands for the address of its zeroth element the same
concept applies for names of arrays of structures. Suppose item is an array variable of
struct type. Consider the followingdeclaration:
struct products
{
char name[30];
int manufac;
float net;
item[2],*ptr;
this statement declares item as array of two elements, each
type struct products and ptr as a pointer data objects of
type struct products, the
assignment ptr=item;
would assign the address of zeroth element to product[0].
Its members can be accessed by using the following
notation.
ptr- >name;
ptr- >manufac;
ptr- >net;
The symbol - > is called arrow pointer and is made up of minus sign and greater than
sign. Note that ptr- > is simple another way of writing product[0].
When the pointer is incremented by one it is made to pint to next record ie item[1]. The
following statement will print the values of members of all the elements of the product
array.
for(ptr=item; ptr< item+2;ptr++)
printf(“%s%d%f\n”,ptr- >name,ptr- >manufac,ptr- >net);
We could also use the notation
(*ptr).number
to access the member number. The parenthesis around ptr are necessary because the
member operator ‗.‘ Has a higher precedence than the operator *.
File Handling in C Language
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
characters, 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 it sometimes 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.
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.
1. No special processing of the data occurs and each byte of data is transferred to or
from the disk unprocessed.
2. 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.
Creating a file and output some data
In order to create files we have to learn about File I/O i.e. how to write data into a file and
how to read data from a file. We will start this section with an example of writing data to
a file. We begin as before with the include statement for stdio.h, then define some
variables for use in the example including a rather strange looking new type.
/* Program to create a file and write some data the file */
#include <stdio.h>
#include <stdio.h>
main( )
{
FILE *fp;
char stuff[25];
int index;
fp = fopen("TENLINES.TXT","w"); /* open for writing */
strcpy(stuff,"This is an example line.");
for (index = 1; index <= 10; index++)
fprintf(fp,"%s Line number %d\n", stuff, index);
fclose(fp); /* close the file before ending program */
}
The type FILE is used for a file variable and is defined in the stdio.h file. It is used to
define a file pointer for use in file operations. Before we can write to a file, we must open
it. What this really means is that we must tell the system that we want to write to a file
and what the file name is. We do this with the fopen() function illustrated in the first line
of the program. The file pointer, fp in our case, points to the file and two arguments are
required in the parentheses, the file name first, followed by the file type.
The file name is any valid DOS file name, and can be expressed in upper or lower case
letters, or even mixed if you so desire. It is enclosed in double quotes. For this example
we have chosen the name TENLINES.TXT. This file should not exist on your disk at this
time. If you have a file with this name, you should change its name or move it because
when we execute this program, its contents will be erased. If you don’t have a file by
this name, that is good because we will create one and put some data into it. You are
permitted to include a directory with the file name.The directory must, of course, be a
valid directory otherwise an error will occur. Also, because of the way C handles literal
strings, the directory separation character ‘\’ must be written twice. For example, if
the file is to be stored in the \PROJECTS sub directory then the file name should be
entered as ―\\PROJECTS\\TENLINES.TXT‖. The second parameter is the file attribute
and can be any of three letters, r, w, or a, and must be lower case.
Reading (r)
When an r is used, the file is opened for reading, a w is used to indicate a file to be used
for writing, and an a indicates that you desire to append additional data to the data
already in an existing file. Most C compilers have other file attributes available; check
your Reference Manual for details. Using the r indicates that the file is assumed to be a
text file. Opening a file for reading requires that the file already exist. If it does not exist,
the file pointer will be set to NULL and can be checked by the program.
Here is a small program that reads a file and display its contents on screen.
/* Program to display the contents of a file on screen */
#include <stdio.h>
void main()
{
FILE *fopen(), *fp;
int c;
fp = fopen("prog.c","r");
c = getc(fp) ;
while (c!= EOF)
{
putchar(c);
c = getc(fp);
}
fclose(fp);
}
Writing (w)
When a file is opened for writing, it will be created if it does not already exist and it will
be reset if it does, resulting in the deletion of any data already there. Using the w
indicates that the file is assumed to be a text file.
Here is the program to create a file and write some data into the file.
#include <stdio.h>
int main()
{
FILE *fp;
file = fopen("file.txt","w");
/*Create a file and add text*/
fprintf(fp,"%s","This is just an example :)"); /*writes data to the
file*/
fclose(fp); /*done!*/
return 0;
}
Appending (a)
When a file is opened for appending, it will be created if it does not already exist and it
will be initially empty. If it does exist, the data input point will be positioned at the end of
the present data so that any new data will be added to any data that already exists in the
file. Using the a indicates that the file is assumed to be a text file.
Here is a program that will add text to a file which already exists and there is some text in
the file.
#include <stdio.h>
int main()
{
FILE *fp
file = fopen("file.txt","a");
fprintf(fp,"%s","This is just an example :)"); /*append some text*/
fclose(fp);
return 0;
}
Outputting to the file
The job of actually outputting to the file is nearly identical to the outputting we have
already done to the standard output device. The only real differences are the new function
names and the addition of the file pointer as one of the function arguments. In the
example program, fprintf replaces our familiar printf function name, and the file pointer
defined earlier is the first argument within the parentheses. The remainder of the
statement looks like, and in fact is identical to, the printf statement.
Closing a file
To close a file you simply use the function fclose with the file pointer in the parentheses.
Actually, in this simple program, it is not necessary to close the file because the system
will close all open files before returning to DOS, but it is good programming practice for
you to close all files in spite of the fact that they will be closed automatically, because
that would act as a reminder to you of what files are open at the end of each program.
You can open a file for writing, close it, and reopen it for reading, then close it, and open
it again for appending, etc. Each time you open it, you could use the same file pointer, or
you could use a different one. The file pointer is simply a tool that you use to point to a
file and you decide what file it will point to. Compile and run this program. When you
run it, you will not get any output to the monitor because it doesn’t generate any.
After running it, look at your directory for a file named TENLINES.TXT and type it; that
is where your output will be. Compare the output with that specified in the program; they
should agree! Do not erase the file named TENLINES.TXT yet; we will use it in
some of the other examples in this section.
Reading from a text file
Now for our first program that reads from a file. This program begins with the familiar
include, some data definitions, and the file opening statement which should require no
explanation except for the fact that an r is used here because we want to read it.
#include <stdio.h>
main( )
{
FILE *fp;
char c;
funny = fopen("TENLINES.TXT", "r");
if (fp == NULL)
printf("File doesn't exist\n");
else {
do {
c = getc(fp); /* get one character from the file
*/
putchar(c); /* display it on the monitor
*/
} while (c != EOF); /* repeat until EOF (end of file)
*/
}
fclose(fp);
}
In this program we check to see that the file exists, and if it does, we execute the main
body of the program. If it doesn‘t, we print a message and quit. If the file does not exist,
the system will set the pointer equal to NULL which we can test. The main body of the
program is one do while loop in which a single character is read from the file and output
to the monitor until an EOF (end of file) is detected from the input file. The file is then
closed and the program is terminated. At this point, we have the potential for one of the
most common and most perplexing problems of programming in C. The variable returned
from the getc function is a character, so we can use a char variable for this purpose. There
is a problem that could develop here if we happened to use an unsigned char however,
because C usually returns a minus one for an EOF – which an unsigned char type variable
is not
capable of containing. An unsigned char type variable can only have the values of zero to
255, so it will return a 255 for a minus one in C. This is a very frustrating problem to try
to find. The program can never find the EOF and will therefore never terminate the loop.
This is easy to prevent: always have a char or int type variable for use in returning an
EOF. There is another problem with this program but we will worry about it when we get
to the next program and solve it with the one following that.
After you compile and run this program and are satisfied with the results, it would be a
good exercise to change the name of TENLINES.TXT and run the program again to see
that the NULL test actually works as stated. Be sure to change the name back because we
are still not finished with TENLINES.TXT.
Get documents about "