|
|
Summary
• Character Arrays
• Initialization Of Character Arrays
• Arrays Comparison
• Sorting Arrays
• Searching arrays
• Functions And arrays
• Example 1
• Multidimensional Arrays
• Example 2
• Tips
Page 117
Character Arrays
While dealing with words and sentences, we actually make use of character arrays.
Up to
now, we were dealing with integer arrays and storing integer values. Here we have
to see
what needs to be done for storing a name. A simple variable can't be used to store
a name
(which is a string of characters) as a variable stores only a single character.
We need a
character array to grab a name. A character array is not different from an integer
array.
To declare a character array, we will write as under:
char name [100] ;
In this way, we declare a string or character array. There are some special properties
of
character arrays. Suppose that we declare an array of 100 characters. We enter a
name
with 15-20 characters. These characters in the array occupy 15-20 character spaces.
Now
we have to see what has happened to the remaining character spaces in the array.
Similarly, a question arises, will an array displayed on the screen, show 100 characters
with a name in 15-20 spaces and blanks for the remaining. Here C has a character
handling capability i.e. the notion of strings. When we place a string in a character
array,
the computer keeps a mark to identify that the array was of this size while the
string
stored in it is of the other size. That marker is a special character, called
null character.
The ASCII code of null character is all zeros. In C language,
we represent the null
character as “\0”. C uses this character to terminate a string.
All strings are terminated
with the null character.
Now, we will see how the character arrays are stored in memory. While declaring
a
character array, we normally declare its size larger than the required one. By using
a
character array, it becomes easy to store a string. We declare a character array
as under.
char name [100] ;
Now we can store a string in this array simply by using the
cin statement in the following
way.
cin >> name ;
In the above statement, there is an array on right hand side of
cin instead of a simple
variable. The cin
stream has a built-in intelligence that allows the compiler (program) to
read whole string at a time rather than a single character as in case of simple
variable of
type char. The compiler
determines that the name
is not a simple variable. Rather it is a
string or character array. Thus
cin reads a character array
until the user presses the enter
key. When enter key is pressed,
cin takes the whole input
(i.e. string) and stores it into the
array name. The
C language, by itself, attaches a
null character at the end
of the string. In
this way, the total number of spaces occupied in the array by the string is the
number of
characters entered by the user plus 1 (this one character is the null
character inserted at
the end of the string by C automatically). The null character
is used to determine where
the populated area of the array has ended. If we put a string larger than the size
of the
array in absence of a null
character in it, then it is not possible to determine where a
string is terminated in the memory. This can cause severe logical error. So, one
should be
careful while declaring a character array. The size of array should be one more
than the
number of characters you want to store.
Page 118
Initialization Of Character Arrays
Now we will look into integer array initialization process that can provide a list
of integer
values separated by commas and enclosed in curly braces. Following is the statement
through which we initialize an integer array.
int age [5] = {12, 13, 16, 13, 14};
If we don’t mention the size of the array and assign a list of values to the array,
the
compiler itself generates an array of the size according the number of values in
the list.
Thus, the statement int age [] = {14, 15, 13}; will allocate a memory to the array
of size
3 integers. These things also apply to character arrays as well. We can initialize
an array
by giving a list of characters of the string, the way we assign integer values in
integer
array. We write the characters of this string one by one in single quotes (as we
write a
single character in single quotes), separated by commas and enclosed in curly braces.
So
the initialization line will be as under
char name [100] = {‘i’, ‘m’, ‘r’, ‘a’, ‘n’};
we can also write the string on right hand side in double quotes as
char name [100] = “imran” ;
The easy way to initialize a character array is to assign it a string in double
quotes. We
can skip the size of the array in the square brackets. We know that the compiler
allocates
the memory at the declaration time, which is used during the execution of the program.
In
this case, the compiler will allocate the memory to the array of size equal to the
number
of characters in the provided string plus 1 (1 is for the
null character that is
inserted at the
end of string). Thus it is a better to initialize an array in the following way.
char name [] = “Hello World” ;
In the above statement, a memory of 12 characters will be allocated to the array
name as
there are 11 characters in double quotes (space character after Hello is also considered
and counted) while the twelfth is the null character inserted automatically at the
end of
the string.
We can do many interesting things with arrays. Let’s start with reading a string
(for
example your name) from keyboard and displaying it on the screen. For this purpose,
we
can write the following code segment
char name [100] ;
cout << “Please enter your name : “ ;
cin >> name ;
In the cin statement,
when the user presses the enter key the previous characters entered,
that is a string will be stored in the array
name. Now we have a string
in the array name.
We can display it with cout
statement. To display the string, we have stored in
name. We
can write as under
cout << name ;
This will display the string. Alternatively, we can use a loop to display the string.
As the
string is an array of characters, we can display these characters one by one in
a 'for loop'.
We can write a loop as under
for ( i = 0 ; i < 100 ; i ++ )
cout << name [ i ] ;
Page 119
Thus this loop will display the characters in the array one by one in each iteration.
First, it
will display the character at name [0], followed by that at name [1] and so on.
Here we
know that the string in the array is terminated by a null character
and after this null
character, there are random values that may not be characters (some garbage data)
in the
array. We don’t want to display the garbage data that is in the array after this
null
character. While using the statement
cout << name; the
cout stream takes
the characters
of the array name
up to the null character and the remaining part of the
array is ignored.
When we are displaying the characters one by one, it is necessary to stop the displaying
process at the end of a string (which means when null character is reached). For
this
purpose, we may put a condition in the loop to terminate the loop when the null
character
is reached. So we can use if
statement in the loop to check the null character.
We can
modify the above for
loop so that it could terminate when null character
reaches in the
array.
for ( i = 0 ; i < 100 ; i ++ )
{ if (name [ i ] == ‘\0’)
break ;
cout << name [ i ] ;
}
Here a while loop can also be used instead of a 'for loop'.
Arrays Comparison
We can use this character-by-character manipulation of the array to compare the
characters of two arrays of the same size. Two arrays can be equal only when first
of all
their sizes are equal. Afterwards, we compare the values of the two arrays with
one to one
correspondence. If all the values in the first array are equal to the corresponding
values of
the second array, then both the arrays will be equal. Suppose, we have two integer
arrays
num1 and num2 of size 100 each and want to find
whether both arrays are equal. For this
purpose, we will declare a flag and set it to zero, that means that arrays are not
equal this
time. For this flag, we write
int equals = 0 ;
To compare the values of the arrays one by one, we write a for loop i.e.
for ( i = 0 ; i <
100 ; i ++ ). In the body of the
for loop, we use an
if statement to
check the values. In the
if statement, we use the not equal operator ( != ). The advantage of
using not-equal
operator is that in case if the values at some position are not equal to each other,
then we
need not to compare the remaining values. We terminate the loop here and say that
the
arrays are not equal. If the values at a position are equal, we continue to compare
the next
values. If all the values are found same, we set the flag
equal to 1 and display
the results
that both the arrays are identical. The same criterion applies to character arrays.
The
comparison of character arrays is very common. While finding a name in a database,
we
will compare two character arrays (strings). The comparison of two strings is so
common
in programming that C has a function in its to manipulate it. We will discuss
it
later in the lecture on string handling. For the time being, we will write our own
function
to find the equality of two strings.
Page 120
Following is the code of a program, which takes two arrays of 5 numbers from the
user
and compares them for equality.
// This program takes two arrays of 5 integers from user
//displays them and after comparing them displays the result
# include <iostream.h>
main ( )
{
int num1 [5], num2 [5], i, equals = 0 ;
// input of 5 integers of first array
cout << “Please enter five integers for the first array” << endl ;
for ( i = 0 ; i < 5 ; i ++)
cin >> num1 [ i ] ;
// input of 5 integers of 2nd array
cout << “Please enter five integers for the second array” << endl ;
for ( i = 0 ; i < 5 ; i ++)
cin >> num2 [ i ] ;
//display the elements of two arrays
cout << “\n The values in the first array are : “ ;
for ( i = 0 ; i < 5 ; i ++)
cout << “\t” << num1 [ i ] ;
cout << “\n The values in the second array are : “ ;
for ( i = 0 ; i < 5 ; i ++)
cout << “\t” << num2 [ i ];
// compare the two arrays
for ( i = 0 ; i < 5 ; i ++ )
{ if ( num1 [ i ] != num2 [ i ] )
{
cout << “\n The arrays are not equal “ ;
equals = 0 ; //set the flag to false
break ;
}
equals = 1; //set flag to true
}
if (equals)
cout << “\n Both arrays are equal” ;
}
Page 121
Similarly, we can write a program that compares two strings (character arrays) of
the
same size. While comparing strings, a point to remember is that C language is casesensitive.
In C-language ‘A’ is not equal to ‘a’. Similarly, the string “AZMAT” is not
equal to the string “azmat” or “Azmat”.
A sample out-put of the program is given below.
Please enter five integers for the first array
1
3
5
7
9
Please enter five integers for the second array
1
3
4
5
6
The values in the first array are : 1 3 5 7 9
The values in the first array are : 1 3 4 5 6
The arrays are not equal
Sorting
We want to sort an array in ascending order. There may be many ways to sort an array.
Suppose we have an array of 100 numbers. To sort it in ascending order, we start
from
the first number (number at zero index ) and find the smallest number in the array.
Suppose, we find it at sixteenth position (index 15). If we assign this number directly
to
the first position, the number already placed at first position will be over written.
But we
want that number should exist in the array. For this purpose, we use a technique
called
swapping. In this technique, we swap two values with each other. For
this purpose, we
declare a variable and assign the value of first variable to this variable before
assigning
the second number (i.e. to be swapped) to the first variable. Then we assign the
value of
second variable to the first variable. Afterwards, the number, which we have stored
in a
separate third variable (that is actually the value of first variable) is assigned
to the
second variable. In arrays, the single element of an array is treated as a single
variable so
we can swap two numbers of an array with each other with this technique.
In our sorting process, we declare a variable
x and assign it the number
at the first
position. Then assign the number at sixteenth position to the first position. After
this, we
Page 122
assign the number in x
(that is actually the number that was at first position in the array)
to the sixteenth position. In programming, this can be done in the following fashion.
x = num [0] ; // assign number at first position to x
num [0] = num [15] ; // assign number at sixteenth position to first
position
num [15] = x ; // assign number in x to sixteenth position
We have the smallest number at the first position. Now we start reading the array
from
second position (index 1) and find the smallest number. We swap this number with
the
second position before starting from index 2. The same process can be repeated later.
We
continue this process of finding smallest number and swapping it till we reach the
last
number of the array. The sorting of array in this way is a brute force and a very
tedious
work. The computer will do fine with small arrays. The large arrays may slow it
down.
Searching
The same applies to the search algorithms. For finding out a particular number in
an
array, we can use technique of linear search. In this technique, there may be as
many
comparisons as numbers in the array. We make comparison of the number to be found
with each number in the array and find it out if it matches any number in the array.
However, we can perform even better by using a binary search algorithm.
Binary Search Algorithm
In binary search algorithm, the ‘divide and conquer’ strategy is applied. This algorithm
applies only to sorted arrays in ascending or descending order. Suppose that we
want to
search a number in an ascending array. For this purpose, we divide the array into
two
parts (say left and right). We compare the target value with the value at middle
location
of the array. If it does not match, we see whether it is greater or less than the
middle
value. If it is greater than the middle value, we discard the left part of the array.
Being an
ascending array, the left part contains the smaller numbers than the middle. Our
target
number is greater than the middle number. Therefore, it will be in the right part
of the
array. Now we have a sub-array, which is the half of the actual array (right side
portion of
main array). Now we divide this array into two parts and check the target value.
If target
value is not found, we discard a portion of the array according to the result whether
target
value is greater or less than the middle value. In each iteration of testing the
target value,
we get an array that is half of the previous array. Thus, we find the target value.
The binary search is more efficient than the linear search. In binary search, each
iteration
reduces the search by a factor of two (as we reduce to half array in each iteration).
For
example, if we have an array of 1000 elements, the linear search could require 1000
iterations. The binary search would not require more than 10. If an array has elements
2n,
Page 123
then the maximum number of iterations required by binary search will be
n. If there are
1000 elements (i.e. 210, actually it will 1024), the number of iterations
would not be more
than 10.
Functions and Arrays
In C language, the default mechanism of calling a function is ‘call by value’. When
we
call a function, say fn,
and pass it a parameter x
(argument value) by writing statement
fn(x), the calling mechanism puts the value of
x at some other place.
Then calls the
function and gives this value to it. This means a copy of the value is sent to the
program.
The original x remains
untouched and unchanged at its place. The function uses the
passed value (that has placed at some other place) and manipulates it in its own
way.
When the control goes back to the calling program, the value of original
x is found intact.
This is the call by value mechanism.
Now let’s see what happens when we pass an array to a function. To pass an array
to a
function, we will tell the function two things about the array i.e. the name of
the array and
the size. The size of the array is necessary to pass to the function. As the array
is declared
in the calling function, it is visible there. The calling function knows its size
but the
function being called does not know the size of the array. So it is necessary to
pass the
size of the array along with its name. Suppose we have declared a character array
in the
program by the following statement:
char name[50] ;
We have a function (say reverse,
you should write it as an exercise) that reverses the
array elements and displays them.
Firstly, we need to write the prototype of the function reverse. We say that this
function
returns nothing so we use the keyword
void in its return type.
Secondly, we have to write
the parameters this function will get. We write these parameters with their type.
Now the prototype of this function will be written as
void reverse ( char [], int ) ;
In the above statement, the brackets [] are necessary. These brackets indicate that
an array
of type char will be passed to the function. If we skip these brackets and simply
write
char, it will mean that a single character will be passed to the function.
In addition, the
second parameter i.e. of type
int, is of array's size. Note that in the prototype of the
function we have not written the names of the parameters. It is not necessary to
write the
names of the parameters in function prototype. However, if we write the names, it
is not
an error. The compiler will simply ignore these names.
Now we will define the function reverse. In the function's definition, we will use
the
array and variable names. These names are local to this function so we can give
these
variables a name other than the one used in declaration in the calling program.
We write
this as below.
void reverse ( char characters [], int arraySize )
{
// The body of the function.
}
Page 124
Here, the body of the function is left over for an exercise.
Let’s say we have a character array
name and a name ‘adnan’
is stored in it. We call the
reverse function by passing the array
name to it. For this we
write reverse ( name, 100 );
In this function call, we are sending the name of the array to the function i.e.
name and
the size of the array that is 100. When this call of the function is executed the
control
goes to the function reverse.
The statements in this function are executed which reverses
the array and displays it. After this, the control comes back to the main function
to the
statement next to the function call statement. The return type of the function is
void so it
does not return any thing. Now in the main, we write the statement
cout << name; What
will be displayed by this statement? Whether it will be the original name ‘adnan’
or
something else. It will display the reversed array. In this instance, we see that
whatever
the function reverse
did to the array ( that was passed to it) is appearing in the calling
function. It means that the original array in the calling program has been changed.
Here
we change (reverse) the order of the characters of array in the function and find
that the
characters of the array in the calling function are reversed. This means that the
called
function has not a copy of the array but has the original array itself. Whereas
in case of
simple variables, a called function uses a copy of variables passed to it in a 'call
by value'
mechanism, which is by default in case of simple variables. In arrays, the by default
mechanism is ‘call by reference’.
While passing arrays to a function, we don’t need to
use & and * operators, as we use for variables in
call by reference mechanism.
Thus if we pass an array to a function, the array itself is passed to the function.
This is
due to the fact that when we declare an array, the name of the array has the address
of the
memory location from where the array starts. In other words, it is the address of
the first
element of the array. Thus the name of the array actually represents the address
of the
first location of the array. Passing the name of array to a function means the passing
of
the address of the array which is exactly the same as we do in
call by reference. So
whatever the function does to the array, it is happening in the same memory locations
where the array originally resides. In this way, any modifications that the function
does to
the contents of the array are taking place in the contents of the original array
too. This
means that any change to the array made by the function will be reflected in the
calling
program. Thus an important point to remember is that whenever we pass simple variables
to a function, the default mechanism is
call by value and whenever
we pass an array to a
function, the default mechanism is
call by reference. We know
that when we talk about a
single element of an array like x [3] (which means the fourth element of the array
x), it is
treated as simple variable. So if we pass a single element of an array to a function
(let’s
say like fn ( x [3] ); ), it is just like a simple variable whose copy is passed
to the function
(as it is a call by value). The original value of the element in the array remains
the same.
So be careful while passing arrays and a single element of array to functions. This
can be
well understood from the following examples.
Example 1
Suppose we declare an array in the main program and pass this array to a function,
which
populates it with values. After the function call, we display the elements of the
array and
Page 125
see that it contains the values that were given in the function call. This demonstrates
that
the called function changes the original array passed to it.
Following is the code of the program.
//This program demonstrates that when an array is passed to a function then it is
a call by
//reference and the changes made by the function effects the original array
# include <iostream.h>
void getvalues( int [], int) ;
main ( )
{
int num [10], i ;
getvalues ( num, 10) ; //function call, passing array num
//display the values of the array
cout << “\n The array is populated with values \n” ;
for ( i = 0 ; i < 10 ; i ++)
cout << " num[" << i << "] = " << num[i]<< endl ;
}
void getvalues ( int num[], int arraysize)
{
int i ;
for ( i = 0 ; i < arraysize ; i ++)
num[i] = i ;
}
Here in the function getvalues,
we can get the values of the array from user by using the
cin statement.
Following is the output of the execution of the program.
The array is populated with values
num[0] = 0
num[1] = 1
num[2] = 2
num[3] = 3
num[4] = 4
num[5] = 5
num[6] = 6
num[7] = 7
num[8] = 8
num[9] = 9
Page 126
Multidimensional Arrays
There may be many applications of arrays in daily life. In mathematics, there are
many
applications of arrays. Let’s talk about vectors. A vector is a set of values which
have
independent coordinates. There may be two-dimensional vector or three-dimensional
vector. There are dot and cross products of vectors besides many other manipulations.
We do all the manipulations using arrays. We manipulate the arrays with loops. Then
there is a mathematical structure matrix, which is in rows and columns. These rows
and
columns are manipulated in two-dimensional arrays. To work with rows and columns,
C
provides a structure i.e. a two-dimensional array. A two dimensional array can be
declared by putting two sets of brackets [] with the name of array. The first bracket
represents the number of rows while the second one depicts the number of columns.
So
we can declare an array numbers
of two rows and three columns as follows.
int numbers [2] [3] ;
Using two-dimensional arrays, we can do the addition, multiplication and other
manipulations of matrices. A value in a two-dimensional array is accessed by using
the
row number and column number. To put values in a two-dimensional array is different
from the one-dimensional array. In one-dimensional array, we use a single 'for
loop' to
populate the array while nested loops are used to populate the two-dimensional array.
We can do addition, multiplication and other manipulations of two-dimensional arrays.
In
C language, we can declare arrays of any number of dimensions (i.e. 1, 2, 3 … n
). We
declare a n-dimensional array by putting n pair of brackets [] after the name of
the array.
So a three-dimensional array with values of dimensions 3, 5 and 7 respectively,
will be
declared as int num [3] [5] [7] ;
Example 2
Let’s have a matrix (two-dimensional array) of two rows and three columns. We want
to
fill it with values from the user and to display them in two rows and three columns.
Solution
To solve this problem, we use a two-dimensional array of two rows and three columns.
First, we will declare the array by writing
int matrix [2] [3] ;
We declare different variables in our program. To put the values in the array, we
use two
nested for loops,
which can be written as under.
for ( row = 0 ; row < maxrows ; row ++ )
{
for ( col = 0 ; col < maxcols ; col ++)
{
cout << “Please enter a value for position [“ << row << “, ” << col << ”]” ;
cin >> matrix [row] [col] ;
}
Page 127
}
The inner for loop
totals the elements of the array one row at a time. It fills all the
columns of a row. The outer for loop increments the row after each iteration. In
the above
code segment, the inner loop executes for each iteration of the outer loop. Thus,
when the
outer loop starts with the value of
row 0, the inner loop is
executed for a number of
iterations equal to the number of columns i.e. 3 in our program. Thus the first
row is
completed for the three columns with positions [0,0], [0,1] and [0,2]. Then the
outer loop
increments the row
variable to 1 and the inner loop is again executed which completes
the second row (i.e. the positions [1,0], [1,1] and [1,2] ). All the values of matrix
having
two rows and three columns are found.
Similarly, to display these values one by one, we again use nested loops.
Following is the code of the program.
//This program takes values from user to fill a two-dimensional array (matrix) having
two
//rows and three columns. And then displays these values in row column format.
# include <iostream.h>
main ( )
{
int matrix [2] [3], row, col, maxrows = 2, maxcols = 3 ;
// get values for the matrix
for ( row = 0 ; row < maxrows ; row ++)
{
for (col = 0 ; col < maxcols ; col ++)
{
cout << “Please enter a value for position [“ << row << “, ” << col << ”] ” ;
cin >> matrix [row] [col] ;
}
}
// Display the values of matrix
cout << “The values entered for the matrix are “ << endl ;
for ( row = 0 ; row < maxrows ; row ++)
{
for (col = 0 ; col < maxcols ; col ++)
{
cout << “\t” << matrix [row] [col] ;
}
cout << endl ; //to start a new line for the next row
}
}
A sample output of the program is given below.
Page 128
Please enter a value for position [0,0] 1
Please enter a value for position [0,1] 2
Please enter a value for position [0,2] 3
Please enter a value for position [1,0] 4
Please enter a value for position [1,1] 5
Please enter a value for position [1,2] 6
The values entered for the matrix are
1 2 3
4 5 6
Tips
• A character array can be initialized using a string literal
• Individual characters in a string stored in an array can be accessed directly
using array subscript
• Arrays are passed to functions by reference
• To pass an array to a function, the name of the array(without any brackets)
is passed along with its size
• To receive an array, the function’s parameter list must specify that an
array will be received
• Including variable names in function prototype is unnecessary. The
compiler ignores these names. |
|
|
|