Friday, 31 March 2017

Arrays & Strings


An array is a collection of variables of the same type that are referenced by a common name. Specific elements or variables in the array are accessed by means of an index into the array.

In C all arrays consist of contiguous memory locations. The lowest address corresponds to the first element in the array while the largest address corresponds to the last element in the array.

C supports both single and multi-dimensional arrays.

Single Dimension Arrays


Syntax :           type  var_name[ size ] ;

where type is the type of each element in the array, var_name is any valid C identifier, and size is the number of elements in the array which has to be a constant value.

NB : In C all arrays use zero as the index to the first element in the array.

For Example :-
           int array[ 5 ] ;

which we might illustrate as follows for a 32-bit system where each int requires 4 bytes.

   array[0]
12
locn 1000
   array[1]
-345
locn 1004
   array[2]
342
locn 1008
   array[3]
-30000
locn 1012
   array[4]
23455
locn 1016

NB : The valid indices for array above are 0 .. 4, i.e. 0 .. number of elements - 1

For Example :- To load an array with values 0 .. 99

           int x[100] ;
           int i ;

           for ( i = 0; i < 100; i++ )
                x[i] = i ;

Arrays should be viewed as just collections of variables so we can treat the individual elements in the same way as any other variables. For example we can obtain the address of each one as follows to read values into the array

     for ( i = 0; i < 100; i++ ) {
                printf( "Enter element %d", i + 1 ) ;
                scanf( "%d\n", &x[i] ) ;
                }
NB : Note the use of the printf statement here. As arrays are normally viewed as starting with index 1 the user will feel happier using this so it is good policy to use it in “public”.

To determine to size of an array at run time the sizeof operator is used. This returns the size in bytes of its argument. The name of the array is given as the operand

           size_of_array = sizeof ( array_name )  ;

NB :  C carries out no boundary checking on array access so the programmer has to ensure he/she is within the bounds of the array when accessing it. If the program tries to access an array element outside of the bounds of the array C will try and accommodate the operation. For example if a program tries to access element array[5] above which does not exist the system will give access to the location where element array[5] should be i.e. 5 x 4 bytes from the beginning of the array.

   array[0]
12
locn 1000
   array[1]
-345
locn 1004
   array[2]
342
locn 1008
   array[3]
-30000
locn 1012
   array[4]
23455
locn 1016
   array[5]
123
locn 1020

This piece of memory does not belong to the array and is likely to be in use by some other variable in the program. If we are just reading a value from this location the situation isn’t so drastic our logic just goes haywire. However if we are writing to this memory location we will be changing values belonging to another section of the program which can be catastrophic.


Initialising Arrays


Arrays can be initialised at time of declaration in the following manner.

     type array[ size ] = { value list };

For Example :-
           int i[5] = {1, 2, 3, 4, 5 } ;

i[0] = 1, i[1] = 2, etc.

The size specification in the declaration may be omitted which causes the compiler to count the number of elements in the value list and allocate appropriate storage.

For Example :-             int i[ ]  =  { 1, 2, 3, 4, 5 } ;

Strings


In C a string is defined as a character array which is terminated by a special character, the null character '\0', as there is no string type as such in C.

Thus the string or character array must always be defined to be one character longer than is needed in order to cater for the '\0'.


For Example :- string to hold 5 characters
           
            char s[6] ;





'\0'

A string constant is simply a list of characters within double quotes e.g. "Hello" with the '\0' character being automatically appended at the end by the compiler.

A string may be initialised as simply as follows

            char s[6] = "Hello" ;

'H'
'e'
'l'
'l'
'o'
'\0'

as opposed to
                        char s[6] = { 'H', 'e', 'l', 'l', 'o', '\0' } ;

Again the size specification may be omitted allowing the compiler to determine the size required.

 

Manipulating Strings


We can print out the contents of a string using printf() as we have seen already or by using puts().

           printf( "%s", s ) ;
           puts( s ) ;

Strings can be read in using  scanf()

           scanf( "%s", s ) ;

where we do not require the familiar & as the name of an array without any index or square braces is also the address of the array.

A string can also be read in using gets()

           gets ( s ) ;

There is also a wide range of string manipulation functions included in the C Standard Library which are prototyped in  <string.h> which you should familiarise yourself with.

For Example :-
char s1[20] = “String1”,  s2[20] = “String2” ;
int i ;

strcpy( s1, s2 )  ;  /*   copies s2 into s1. */

i = strcmp( s1,s2 ) ; /*  compares s1 and s2. It returns zero if
             s1 same as s2,-1 if s1 < s2, and +1 if s1 > s2     */

i = strlen( s1 ) ;         /* returns the length of s1 */

strcat ( s1, s2 ) ;        /* Concatenates s2 onto end of s1  */


Multidimensional Arrays


Multidimensional arrays of any dimension are possible in C but in practice only two or three dimensional arrays are workable. The most common multidimensional array is a two dimensional array for example the computer display, board games, a mathematical matrix etc.

Syntax :           type   name [ rows ] [ columns ]  ;

For Example :- 2D array of dimension 2 X 3.

                        int d[ 2 ] [ 3 ] ;

d[0][0]
d[0][1]
d[0][2]
d[1][0]
d[1][1]
d[1][2]

A two dimensional array is actually an array of arrays, in the above case an array of two integer arrays (the rows) each with three elements, and is stored row-wise in memory.

For Example :- Program to fill in a 2D array with numbers 1 to 6 and to print it out row-wise.

           #include <stdio.h>
           void main( )
           {
           int i, j, num[2][3] ;

           for ( i = 0; i < 2; i++ )
                for ( j = 0; j < 3; j ++ )
                     num[i][j] =  i * 3 + j + 1 ;

           for ( i = 0; i < 2; i++ )
                {
                for ( j = 0; j < 3; j ++ )
                     printf("%d ",num[i][j]  ) ;
                printf("\n" );
                }
           }

For Example :- Program to tabulate sin(x) from x = 0 to 10 radians in steps of 0.1 radians.

     #include <stdio.h>
     #include <math.h>
void main()
{
int i  ;
double x ;
double table[100][2] ;// we will need 100 data points for
                      // the above range and step size and
// will store both x and f(x)
for ( x = 0.0, i = 0; x < 10.0; x += 0.1, i++ ) {
  table[i][0] = x ;
  table[i][1] = sin( x ) ;
  printf(“\n Sin( %lf ) = %lf”, table[i][0], table[i][1] );
}
}
To initialise a multidimensional array all but the leftmost index must be specified so that the compiler can index the array properly.

For Example :-
           int d[ ] [ 3 ] = { 1, 2, 3, 4, 5, 6 } ;

However it is more useful to enclose the individual row values in curly braces for clarity as follows.

                        int d[ ] [ 3 ] = { {1, 2, 3}, {4, 5, 6} } ;

Arrays of Strings

An array of strings is in fact a two dimensional array of characters but it is more useful to view this as an array of individual single dimension character arrays or strings.

For Example :-            
                        char str_array[ 10 ] [ 30 ] ;

where the row index is used to access the individual row strings and where the column index is the size of each string, thus str_array is an array of 10 strings each with a maximum size of  29 characters leaving one extra for the terminating null character.

For Example :- Program to read strings into str_array and print them out character by character.

#include <stdio.h>

char str_array[10][30] ;

void main()
{
int i, j ;

puts("Enter ten strings\n") ;

for ( i = 0 ; i < 10; i++ ) // read in as strings so a single for
 // loop suffices
{
printf( " %d : ", i + 1) ;
gets( str_array[i] ) ;         
}

for ( i = 0; i < 10; i++ )//printed out as individual chars so a
{                        // nested for loop structure is required
  for ( j=0; str_array[i][j] != '\0' ; j++ )
     putchar ( str_array[i][j] ) ;
  putchar( '\n' ) ;
}
}

 


Arrays as arguments to functions ( 1D )


In C it is impossible to pass an entire array as an argument to a function -- instead the address of the array is passed as a parameter to the function. (In time we will regard this as a pointer).

The name of an array without any index is the address of the first element of the array and hence of the whole array as it is stored contiguously. However we need to know the size of the array in the function - either by passing an extra parameter or by using the sizeof operator..

For Example :-
     void main()
     {
       int array[20] ;

       func1( array ) ;/* passes pointer to array to func1 */
     }

Since we are passing the address of the array the function will be able to manipulate the actual data of the array in main(). This is call by reference as we are not making a copy of the data but are instead passing its address to the function. Thus the called function is manipulating the same data space as the calling function.

In the function receiving the array the formal parameters can be declared in one of three almost equivalent ways as follows :-

·      As a sized array :
           func1 ( int x[10] ) {
           ...       
           }
·      As an unsized array :
           func1 ( int x[ ] ) {
           ...
           }
·      As an  actual pointer
           func1 ( int *x ) {
           ...
           }

All three methods are identical because each tells us that in this case the address of an array of integers is to be expected.

Note however that in cases 2 and 3 above where we specify the formal parameter as an unsized array or simply as a pointer we cannot determine the size of the array passed in using the sizeof operator as the compiler does not know what dimensions the array has at this point. Instead sizeof returns the size of the pointer itself, two in the case of near pointers in a 16-bit system but four in 32-bit systems.
For Example :- Program to calculate the average value of an array of doubles.

     #include <stdio.h>
     void read_array( double array[ ], int size ) ;
     double mean( double array[ ], int size ) ;

     void main()
     {
     double data[ 100 ] ;
     double average ;

     read_array( data, 100 ) ;
     average = mean( data, 100 ) ;
     }

     void read_array( double array[ ], int size )
     {
     int i ;

     for ( i = 0; i<100; i++ )  {
           printf( “\nEnter data value %d : i + 1 );
           scanf( “%lf”, &array[i] ;
           _flushall() ;
           }
     }

     double mean( double array[ ], int size )
     {
     double total = 0.0 ;
     int count = size ;
     while ( count-- )  // size is a local variable which we can
   // use at will
           total += array[ count ] ;
     return ( total / size ) ;
     }

For Example :- Program to test if a user input string is a palindrome or not.

#include  <stdio.h>
int palin( char array[ ] ) ;    /* Function to determine if array
  is a palindrome returns 1 if it is a palindrome, 0 otherwise */
void main( )
{
char str[100] ;

puts( "Enter test string" ) ;
gets( str ) ;

if ( palin( str ) )
    printf( "%s is a palindrome\n", str ) ;
else
    printf( "%s is not a palindrome\n") ;
}


            int palin ( char array[ ] )
     {
     int i = 0, j = 0 ;

     while ( array[j++] ) ;     /* get length of string  i.e. increment j while array[j] != '\0' */
     j -=  2 ;            /* move back two -- gone one beyond '\0' */

     for (  ; i < j ; i++, j-- )
           if ( array[ i ] != array[ j ]
                return 0 ;           /* return value 0 if not a palindrome */

     return 1 ;           /* otherwise it is a palindrome */
     }

An alternative way of writing the palin() function might be as follows using string manipulation functions ( must add #include <string.h> to top of file in this case).

     int palin( char array[ ] )
     {
     char temp[30] ;

     strcpy( temp, array ) ;/* make a working copy of string */

     strrev( temp ) ;           /* reverse string */

     if ( ! strcmp( temp, array ) )  /* compare strings –
                                    if same strcmp returns 0  */
           return 1 ;
     else
           return 0 ;
     }

Passing Multidimensional Arrays


Function calls with multi-dimensional arrays will be the same as with single dimension arrays as we will still only pass the address of the first element of the array.

However to declare the formal parameters to the function we need to specify all but one of the dimensions of the array so that it may be indexed properly in the function.

For Example :-            

2D array of doubles :-             double x[10][20] ;

Call func1 with x a parameter :-          func1( x ) ;

Declaration in func1 :-             func1( double y[ ][20] ) {
                                                ...
                                                            }

The compiler must at least be informed how many columns the matrix has to index it correctly. For example to access element y[5][3] of the array in memory the compiler might do the following

            element No =  5 * 20 + 3 = 103.

NB : Multi-dimensional arrays are stored row-wise so y[5][3] is the 4th element in the 6th row.

Since we are dealing with an array of doubles this means it must access the memory location
103 X 8 bytes from the beginning of the array.

Thus the compiler needs to know how many elements are in each row of the 2D array above. In general the compiler needs to know all dimensions except the leftmost at the very least.

For Example :- Program to add two 2 x 2 matrices.

#include < stdio.h>

void mat_read( int mat[2][2] ) ;     // Write these two functions for
//yourselves
void mat_print( int mat[2][2] ) ;

void mat_add( int mat1[ ][2], int mat2[ ][2], int mat3[ ][2] ) ;

void main()
{
int mat_a[2][2], mat_b[2][2], mat_res[2][2] ;

puts( “Enter Matrix a row-wise :-\n” );
mat_read( mat_a ) ;
puts( “\nMatrix a is :-\n” ) ;
mat_print( mat_a ) ;
puts( “Enter Matrix b row-wise” );
mat_read( mat_b ) ;
puts( “\nMatrix b is :-\n” ) ;
mat_print( mat_b ) ;

mat_add( mat_a, mat_b, mat_res ) ;

puts( “The resultant matrix is\n” ) ;
mat_print( mat_res ) ;
}

void mat_add( int mat1[ ][2], int mat2[ ][2], int mat3[ ][2] )
{
int j, k ;

for ( j = 0; j < 2; j++ )
     for ( k = 0; k < 2; k++ )
           mat_res[j][k] = mat1[j][k] + mat2[j][k]  ;
}

Exercises



1. Write a program that allows the user to read a user specified number of double precision floating point numbers from the keyboard, storing them in an array of maximum size 100 say. Your program should then calculate the sum and the average of the numbers input.

2. Modify your program in exercise 1 so that the maximum and minimum values in the data are found and are ignored when calculating the average value.

3.  Write a program that allows the elements of a user input array of doubles to be reversed so that first becomes last etc. Use a separate swap function to carry out the switching of elements.

4. Write a program that reads an array of up to 20 integers from the keyboard and produces a histogram of the values as indicated below.






*







*
*







*
*






*
*
*
*



*

*
*
*
*

*

*
*
*
*
*
*

*
*
*
*
*
*
*
*
*
*
1
3
2
4
6
7
4
1
3

A two dimensional array of characters should be used to produce the histogram, filling it with asterisks appropriate to the data values and then just printing out the array. Some scaling will be required if the values are allowed to exceed the number of asterisks that can fit on the screen vertically.

5. Write a program to accept two strings from the keyboard, compare them and then print out whether or not they are the same.

6(a). Write a function to test whether or not a word is a palindrome e.g. MADAM.

  (b). Modify the function in 2(a) so that white space characters are ignored i.e. so that
MADAM IM ADAM for example is deemed a palindrome.

7.  Write and test a function that inserts a character anywhere in a string. The function should take the general form
                          strins(  char *string,  char character,  int position )

Notes :-
              1. Recall Microsoft C supports a broad range of string handling functions such as strlen(), strcpy(), etc.

             2. Your function should provide sufficient error checking to prevent erroneous operation e.g. your function should check that the desired position actually exists.

            3. Your function need not consider memory / space requirements placing the onus on the user to make sure sufficient space is available in the operands.

Modify the strins( ) function written above so that it allows a string of characters rather than an individual character to be inserted at the designated position.


8.  Write a program that multiplies two 2 X 2  matrices and prints out the resultant matrix.  The program should read in the individual matrices and display them in standard format  for the user to check them. The user should be allowed to correct/alter any one element of the matrix at a time and check the revised matrix until satisfied. The results of the operation should be displayed along with the two component matrices.

Recall that
 
9.  A real polynomial p(x) of degree n is given by
    
where the coefficients an are real numbers.

Write a function

           double  eval ( double p[], double x,  int n );

which calculates the value of a polynomial of degree n at a value x using the coefficients in the array p[].  Your program should read in the values of the coefficients an and store them in an array  and present the results of the calculation.

            (a)  Use straightforward  calculations to compute the value.
            (b)  Employ Horner's Rule to calculate the value.       

Recall  Horner's Rule for a three degree polynomial for example is

                        p(x)   =    a0  +   x(  a1  +   x(  a2  +   x( a3 )))

Compare  the efficiency obtained using both methods.


10.  Programming Assignment : Tic-Tac-Toe

Write a C program which allows the user to play the computer in a game of tic--tac--toe (noughts and crosses  ).

The program should use a two dimensional array to represent the 3x3 board matrix and allow the various positions on the board to be referenced as co-ordinates such as (0,0) for the upper--left  corner and (2,2) for the lower--right corner.

Your program might include functions to do the following :-

            1.  Initialise the playing area appropriately.
            2.  Display the current state of the game.
            3.  Get the player's move.
            4.  Get the computer's move.
            5.  Check if there is a winner.

The character 'O' should be used to indicate a computer occupied position and the character 'X' to indicate that of a player. The space character might be used to indicate an unoccupied location. In displaying the current state of the board simple formatted text output  will suffice ( clearing the screen between move updates etc.) as opposed to providing DOS graphics support.

The tic tac toe program should incorporate the following three user specified options in a single package.

Option 1:     The computer will be limited to playing a very simple dull game. When it is the computer's turn to move it simply scans the board matrix and fills the first unoccupied position encountered. If it cannot find an unoccupied location it reports a drawn game.

Option 2:    The computer plays a full game ie. it checks first if it can win the game with its current move. This failing it checks if it can prevent the  player from winning with  his/her next move.  Otherwise it fills the first available unoccupied position.

Option 3:     The program allows two players to play each other (without any help or hints!).

The program should run continuously allowing the player to exit using a special "hot-key" during
a game and  should allow the player to choose who moves first.

No comments:

Post a Comment