C Tutorial - Chapter 13

CHARACTER AND BIT MANIPULATION

UPPER AND LOWER CASE

uplow.c

#include 
#include        /* Note - your compiler may not need this */

void mix_up_the_chars(char line[]);


int main()
{
FILE *fp;
char line[80], filename[24];
char *c;

   printf("Enter filename -> ");
   scanf("%s", filename);
   fp = fopen(filename, "r");

   do 
   {
      c = fgets(line, 80, fp);   /* get a line of text */
      if (c != NULL) 
      {
         mix_up_the_chars(line);
      }
   } while (c != NULL);

   fclose(fp);
   
   return 0;
}


/* This function turns all upper case characters into lower case,  */
/*  and all lower case to upper case. It ignores all other         */
/*  characters.                                                    */
void mix_up_the_chars(char line[])
{
int index;

   for (index = 0 ; line[index] != 0 ; index++) 
   {
      if (isupper(line[index]))     /* 1 if upper case */
         line[index] = tolower(line[index]);
      else 
      {
         if (islower(line[index]))  /* 1 if lower case */
            line[index] = toupper(line[index]);
      }
   }
   printf("%s", line);
}



/* Result of execution

  (The selected file is displayed on the monitor with all of
  the upper case characters converted to lower case, and all
  of the lower case characters converted to upper case.)

*/

Examine the program named UPLOW.C for an example of a program that does lots of character manipulation. More specifically, it changes the case of alphabetic characters. It illustrates the use of four functions that have to do with case. It should be no problem for you to study this program on your own and understand how it works. The four functions on display in this program are all within the user written function, mix_up_the_chars(). Compile and run the program with the file of your choice. The four functions are;

     isupper(c);    Is the character upper case?
     islower(c);    Is the character lower case?
     toupper(c);    Make the character upper case.
     tolower(c);    Make the character lower case. 

Many more classification and conversion routines are listed in the reference material for your compiler. You should spend time studying these at this time to get an idea of what functions are available.

CLASSIFICATION OF CHARACTERS

charclas.c

#include 
#include        /* Note - your compiler may not need this */

void count_the_data(char line[]);


int main()
{
FILE *fp;
char line[80], filename[24];
char *c;

   printf("Enter filename -> ");
   scanf("%s", filename);
   fp = fopen(filename, "r");

   do 
   {
      c = fgets(line, 80, fp);   /* get a line of text */
      if (c != NULL) 
      {
         count_the_data(line);
      }
   } while (c != NULL);

   fclose(fp);

   return 0;
}


void count_the_data(char line[])
{
int whites, chars, digits;
int index;

   whites = chars = digits = 0;

   for (index = 0 ; line[index] != 0 ; index++) 
   {
      if (isalpha(line[index]))   /* 1 if line[] is alphabetic  */
          chars++;
      if (isdigit(line[index]))   /* 1 if line[] is a digit     */
          digits++;
      if (isspace(line[index]))   /* 1 if line[] is blank, tab, */
          whites++;               /*           or newline       */
   }   /* end of counting loop */

   printf("%3d%3d%3d %s", whites, chars, digits, line);
}



/* Result of execution (This is a portion of the output, but the
          comments have been removed to allow this section to be
          included as one large comment.  This output assumes that
          CHARCLAS.C is selected as the input file.)

 37 23  3 
  2 13  0 #include 
 18 43  0 #include 
  1  0  0 
  3 24  0 void count_the_data(char line[]);
  1  0  0
  2  7  0 int main()
  1  0  0 {
  2  6  0 FILE *fp;
  3 16  4 char line[80], filename[24];
  2  5  0 char *c;
     (This pattern continues for the rest of the file)
*/

Load and display the next program, CHARCLAS.C for an example of character counting. We have repeatedly used the backslash n character representing a new line. These are called escape sequences, and some of the more commonly used are defined in the following table;

     \n    Newline 
     \t    Tab 
     \"    Double quote 
     \\    Backslash
     \0    NULL (zero) 

Consult your compiler documentation for a complete list of escape sequences available with your compiler.

By preceding each of the above characters with the backslash character, the character can be included in a line of text for display, or printing. In the same way that it is perfectly all right to use the letter n in a line of text as a part of someone's name, and as an end-of-line, the other characters can be used as parts of text or for their particular functions.

This example program uses three of the functions that can determine the class of a character, and counts the characters in each class. The number of each class is displayed along with the line itself. The three functions are as follows;

    isalpha(c); Is the character alphabetic?
    isdigit(c); Is the character a numeral?
    isspace(c); Is the character any of, \n, \t, or blank? 

As noted above, many more classification routines are available with your compiler.

This program should be simple for you to find your way through, so no explanation will be given. It was necessary to give an example with these functions used. Compile and run this program with any file you choose.

THE LOGICAL FUNCTIONS

bitops.c

#include 

int main()
{
char mask;
char number[6];
char and, or, xor, inv, index;

   number[0] = 0X00;
   number[1] = 0X11;
   number[2] = 0X22;
   number[3] = 0X44;
   number[4] = 0X88;
   number[5] = 0XFF;

   printf(" nmbr  mask   and    or   xor   inv\n");
   mask = 0X0F;
   for (index = 0 ; index <= 5 ; index++) 
   {
      and = mask & number[index];
      or = mask | number[index];
      xor = mask ^ number[index];
      inv = ~number[index];
      printf("%5x %5x %5x %5x %5x %5x\n", 
                             number[index], mask, and, or, xor, inv);
   }

   printf("\n");
   mask = 0X22;
   for (index = 0 ; index <= 5 ; index++) 
   {
      and = mask & number[index];
      or = mask | number[index];
      xor = mask ^ number[index];
      inv = ~number[index];
      printf("%5x %5x %5x %5x %5x %5x\n",
                             number[index], mask, and, or, xor, inv);
   }

   return 0;
}



/* Result of execution

  nmbr  mask   and    or   xor   inv
     0     f     0     f     f  ffff
    11     f     1    1f    1e  ffee
    22     f     2    2f    2d  ffdd
    44     f     4    4f    4b  ffbb
  ff88     f     8  ff8f  ff87    77
  ffff     f     f  ffff  fff0     0

     0    22     0    22    22  ffff
    11    22     0    33    33  ffee
    22    22    22    22     0  ffdd
    44    22     0    66    66  ffbb
  ff88    22     0  ffaa  ffaa    77
  ffff    22    22  ffff  ffdd     0

*/

Load and display the program BITOPS.C. The functions in this group of functions are used to do bitwise operations, meaning that the operations are performed on the bits as though they were individual bits. No carry from bit to bit is performed as would be done with a binary addition. Even though the operations are performed on a single bit basis, an entire byte or integer variable can be operated on in one instruction. The operators and the operations they perform are given in the following table;

   &   Logical AND, if both bits are 1, the result is 1. 
   |   Logical OR, if either bit is one, the result is 1. 
   ^   Logical XOR, (exclusive OR), if one and only one 
                             bit is 1, the result is 1. 
   ~   Logical invert, if bit is 1, the result is 0, and 
                            if bit is 0, the result is 1.
 

The example program uses several fields that are combined in each of the ways given above. The data is in hexadecimal format. It will be assumed that you already know hexadecimal format if you need to use these operations. If you don't, you will need to study it on your own. Teaching the hexadecimal format of numbers is beyond the scope of this tutorial. Be sure to compile and execute this program and observe the output.

THE SHIFT INSTRUCTIONS

shifter.c

#include 

int main()
{
int small, big, index, count;

   printf("       shift left      shift right\n\n");
   small = 1;
   big = 0x4000;
   for(index = 0;index < 17;index++) 
   {
      printf("%8d %8x %8d %8x\n",small,small,big,big);
      small = small << 1;
      big = big >> 1;
   }

   printf("\n");
   count = 2;
   small = 1;
   big = 0x4000;
   for(index = 0;index < 9;index++) 
   {
      printf("%8d %8x %8d %8x\n",small,small,big,big);
      small = small << count;
      big = big >> count;
   }

   return 0;
}



/* Result of execution

       1       1   16384    4000
       2       2    8192    2000
       4       4    4096    1000
       8       8    2048     800
      16      10    1024     400
      32      20     512     200
      64      40     256     100
     128      80     128      80
     256     100      64      40
     512     200      32      20
    1024     400      16      10
    2048     800       8       8
    4096    1000       4       4
    8192    2000       2       2
   16384    4000       1       1
  -32768    8000       0       0
       0       0       0       0

       1       1   16384    4000
       4       4    4096    1000
      16      10    1024     400
      64      40     256     100
     256     100      64      40
    1024     400      16      10
    4096    1000       4       4
   16384    4000       1       1
       0       0       0       0

*/

The last two operations to be covered in this chapter are the left shift and the right shift instructions. Load the example program SHIFTER.C for an example using these two instructions. The two operations use the following operators;

    <<    n Left shift n places.
    >>    n Right shift n places. 

Once again the operations are carried out and displayed using the hexadecimal format. The program should be simple for you to understand on your own, there is no tricky code.

WHERE DO I GO FROM HERE?

Now that you have completed this tutorial, you are filled with knowledge of the C programming language, but you have relatively little experience with using it. I can make three recommendations to improve your knowledge of C and to give you additional exposure to it.

First, obtain a copy of the second edition of "The C Programming Language" written by Brian Kernighan and Dennis Ritchie, Prentice Hall, 1988. A careful reading of this book will provide you with a wealth of knowledge of the C programming language including many details which I felt were beyond the scope of this beginning tutorial. The book does not cover prototyping, since it was added later by the ANSI-C standardization committee, but that is the only major deficiency in the book and is easily compensated for. Simply use prototypes and the modern method of function definition when studying any of the example programs.

Secondly, and probably the most important recommendation, is to write programs in C. Writing C code, finding and fixing the errors that you will inadvertently introduce into the code, and finally seeing your program execute just the way you intended it to, provides a great feeling of accomplishment.

The third recommendation is to read current information on the language. Good sources for information are programming magazines, possibly a new book on C, or time spent reading Usenet newsgroups such as comp.lang.c or comp.lang.c.moderated. There are other newsgroups devoted to various operating systems, or to specific compilers which you may find interesting and informative.

The more you expose yourself to the C programming language, the more you will learn about it, and the more you will enjoy using it.

Good luck!