Chapter 4

attr.c

/*   File: attr.c
     This program reads characters until end of file. It prints the
     attributes of each character including the ASCII value.
*/
#include  <stdio.h>

int print_reps( char ch );

main()
{    char ch;
     int flag;

     printf("***Character Attributes***\n\n");
     printf("Type text, terminate with EOF \n");
     flag = scanf("%c", &ch);         /* read the first char */
     while (flag != EOF) {
          if (ch >= 'a' && ch <= 'z') {      /* lower case letter? */
               print_reps(ch);
               printf("lower case letter\n");
          }
          else if (ch >= 'A' && ch <= 'Z') {      /* upper case letter? */
               print_reps(ch);
               printf("an upper case letter\n");
          }
          else if (ch >= '0' && ch <= '9') { /* digit character? */
               print_reps(ch);
               printf("a digit symbol\n");
          }
          else if (ch == '.' || ch == ',' || ch == ';' || ch == ':' ||
                    ch == '?' || ch == '!') {     /* punctuation? */
               print_reps(ch);
               printf("a punctuation symbol\n");
          }
          else if (ch == ' ') {                   /* space? */
               print_reps(ch);
               printf("a space character\n");
          }
          else if (ch < 32 || ch == 127) {        /* control character? */
               print_reps(ch);
               printf("a control character\n");
          }
          else {                             /* must be a special symbol */
               print_reps(ch);
               printf("a special symbol\n");
          }
          flag = scanf("%c", &ch);         /* read the next char */
     }    /* end of while loop */
}         /* end of program */


int print_reps( char ch)
{
     printf("%c, ASCII value decimal %d, octal %o, hexadecimal %x: ",
                    ch,ch,ch,ch);
}

attr2.c

/*   File: attr2.c
     This program reads characters until end of file. It prints the
     attributes of each character including the ASCII value.
*/
#include <stdio.h>
#include "category.h"

main()
{    char ch;
     int flag;

     printf("***Character Attributes***\n\n");
     printf("Type text, terminate with EOF \n");
     flag = scanf("%c", &ch);         /* read the first char */

     while (flag != EOF) {
          if( IS_LOWER(ch) ) print_category(LOWER, ch);
          else if( IS_UPPER(ch) ) print_category(UPPER, ch);
          else if( IS_DIGIT(ch) ) print_category(DIGIT, ch);
          else if( IS_PUNCT(ch) ) print_category(PUNCT, ch);
          else if( IS_SPACE(ch) ) print_category(SPACE, ch);
          else if( IS_CONTROL(ch) ) print_category(CONTROL, ch);
          else print_category(SPECIAL, ch);

          flag = scanf("%c", &ch);         /* read the next char */
     }    /* end of while loop */
}         /* end of program */

int print_category( int cat, char ch)
{
     printf("%c, ASCII value decimal %d, octal %o, hexadecimal %x: ",
                    ch,ch,ch,ch);
     if(      cat == LOWER )   printf("lower case letter\n");
     else if( cat == UPPER )   printf("an upper case letter\n");
     else if( cat == DIGIT )   printf("a digit symbol\n");
     else if( cat == PUNCT )   printf("a punctuation symbol\n");
     else if( cat == SPACE )   printf("a space character\n");
     else if( cat == CONTROL ) printf("a control character\n");
     else printf("a special symbol\n");
}

category.h

/*   File:  category.h
     This file contains macros defining  character categories and
        character comparison macros.
*/

int print_category( int cat, char ch);



/*  THIS HEADER FILE IS LEFT AS AN EXERCISE   */

chrutil.c

/* File: chrutil.c */
/*   This file contains various utility functions for processing characters  */

#include <stdio.h>
#include "tfdef.h"
#include "chrutil.h"

/*   Function converts ch to an integer if it is a digit. Otherwise, it
     prints an error message.
*/
int dig_to_int(char ch)
{
     if (IS_DIGIT(ch))
          return ch - '0';
     printf("ERROR:dig_to_int:  %c is not a digit\n", ch);
     return ERROR;
}

/*   Function converts a positive integer less than 10 to a corresponding
     digit character.
*/
char int_to_dig(int n)
{
     if (n >= 0 && n < 10)
          return n + '0';
     printf("ERROR:int_to_dig:  %d is not in the range 0 to 9\n", n);
     return NULL;
}



/*  Function reads the next integer from the input  */
int getint()
{    int n = 0;
     int got_dig = FALSE;
     signed char ch;


     ch = getchar();                     /* read next char                  */
     while (IS_WHITE_SPACE(ch))          /* skip white space                */
              ch = getchar(); 
     while (IS_DIGIT(ch)) {              /* repeat as long as ch is a digit */
          n = n * 10 + dig_to_int(ch);   /* accumulate value in n           */
          got_dig = TRUE;
#ifdef DEBUG
printf("debug:getint: ch = %c\n", ch);   /* debug statement */
printf("debug:getint: n = %d\n", n);     /* debug statement */
#endif
          ch = getchar();                /* read next char                  */
     }
     if(ch == EOF) return EOF;           /* test for end of file            */
     if(!got_dig)  return ERROR;         /* test for no digits read         */
     return n;                           /* otherwise return the result     */

}

/* Function tests if c is an alphabetic letter. */
int letterp(char c)
{
     if (IS_LOWER(c) || IS_UPPER(c))
          return TRUE;
     return FALSE;
}


/*   Function returns TRUE if c is a delimiter, i.e., it is a white space
     or a punctuation. Otherwise, it returns FALSE.
*/
int delimitp(char c)
{
     if (whitep(c) || punctp(c))
          return TRUE;
     return FALSE;
}

/* Function returns TRUE if c is white space; returns FALSE otherwise. */
int whitep(char c)
{
     if (c == '\n' || c == '\t' || c == ' ')
          return TRUE;
     return FALSE;
}

/* Function returns TRUE if c is a punctuation; returns FALSE otherwise. */
int punctp(char c)
{
     if (c == '.' || c == ',' || c == ';' || c == ':'
               || c == '?' || c == '!')
          return TRUE;
     return FALSE;
}


/*   Function checks if c is a vowel. */
int vowelp(char c)
{
     switch(c) {
          case 'a':
          case 'A':
          case 'e':
          case 'E':
          case 'i':
          case 'I':
          case 'o':
          case 'O':
          case 'u':
          case 'U':  return TRUE;
          default:   return FALSE;
     }
}


/* Function tests if c is printable. */
int illegal(char c)
{
   if (IS_PRINT(c) || IS_WHITE_SPACE(c))
     return FALSE;
   return TRUE;
}

chrutil.h

/* File: chrutil.h */
/*   This file contains various  macros and prototypes for character processing */

#define   ERROR     -2

#define   IS_DIGIT(c)   ((c) >= '0' && (c) <= '9')
#define   IS_LOWER(c)   ((c) >= 'a' && (c) <= 'z')
#define   IS_UPPER(c)   ((c) >= 'A' && (c) <= 'Z')
#define   IS_WHITE_SPACE(c)   ((c) == ' ' || (c) == '\t' || (c) == '\n')
#define   IS_PRINT(c)   ((c) >= 32 && (c) < 127)

#define  LOWER     0
#define  UPPER     1
#define  DIGIT     2
#define  PUNCT     3
#define  SPACE     4
#define  CONTROL   5
#define  SPECIAL   6


int dig_to_int(char ch);
char int_to_dig(int n);
char uppercase(char ch);
int getint();

int delimitp(char c);
int whitep(char c);
int punctp(char c);
int vowelp(char c);
int letterp(char c);
int illegal(char c);      /* Tests if c is legal. */

cnt.c

/*   Program File: cnt.c
     Other Source Files: chrutil.c
     Header Files: tfdef.h, chrutil.h
     This program reads standard input characters and counts the number
     of lines, words, and characters. All characters are counted including
     the newline and other control characters, if any.
*/

#include <stdio.h>
#include "tfdef.h"
#include "chrutil.h"

main()
{    signed char ch;
     int inword,         /* flag for in a word */
     lns, wds, chrs;     /* Counters for lines, words, chars. */

     printf("***Line, Word, Character Count Program***\n\n");
     printf("Type characters, EOF to quit\n");
     lns = wds = chrs = 0;    /* initialize counters to 0 */
     inword = FALSE;          /* set inword flag to False */

     while ((ch = getchar()) != EOF) {    /* repeat while not EOF */
          chrs = chrs + 1;               /* increment chrs */
          if (ch == '\n')                /* if newline char */
               lns = lns + 1;            /* increment lns */

          /* if not inword and not a delimiter  */
          if (!inword && !delimitp(ch)) { /* if not in word and not delim., */
               inword = TRUE;           /* set inword to True */
               wds = wds + 1;           /* increment wds */
          }

          else if (inword && delimitp(ch))   /* if in word and a delimiter*/
               inword = FALSE;               /* set inword to False */

     } /* end of while loop */
     printf("Lines = %d, Words = %d, Characters = %d\n",
               lns, wds, chrs);
} /* end of program */

copy0.c

/*   File: copy0.c
     Programmer:
     Date:
     This program reads a stream of characters, one character at
     a time, and echoes each to the output until EOF.
*/

#include <stdio.h>
main()
{    char ch;       /* declaration for a character object ch */
     int flag;         /* flag stores the number of items read by scanf() */

     printf("***Copy Program***\n\n");
     printf("Type text, terminate with EOF\n");
     flag = scanf("%c", &ch);         /* read the first char */
     while (flag != EOF) {            /* repeat while not EOF */
          printf("%c", ch);           /* print the last char read */
          flag = scanf("%c", &ch);    /* read the next char, update flag */
     }                                /* flag is EOF, ch may be unchanged */
}

copy1.c

/*   File: copy1.c
     Programmer:
     Date:
     This program reads a stream of characters until end of file. Each
     character read is converted to its upper case version and printed
     out.
*/
#include <stdio.h>

#define IS_LOWER(c)    ((c) >= 'a' && (c) <= 'z')
#define TO_UPPER(c)    ((c) - 'a' + 'A')
char uppercase(char ch);

main()
{    signed char ch;

     printf("***Copy Program - Upper Case***\n\n");
     printf("Type text, terminate with EOF\n");

     while ((ch = getchar()) != EOF) 
          putchar (uppercase(ch));  /* print value of uppercase(ch) */
    
}

/*   Function returns a lower case letter to an upper case. It returns
     all other characters unchanged.
*/
char uppercase(char c)
{
   if ( IS_LOWER(c) )       /* if c is a lower case letter */
     return TO_UPPER(c);           /* convert to upper case and return */
                                   /* otherwise, */
     return c;                     /* return c unchanged */
}

copychr.c

/* File: copychr.c
     Program copies standard input to standard output.
*/
#include <stdio.h>

main()
{    signed char c;


     printf("***File Copy Program***\n\n");
     printf("Type text, EOF to quit\n");
     c = getchar();

     while (c != EOF) {
          putchar(c);
          c = getchar();
     }
}

encrypt.c

/*   File: encrypt.c
     Other Source Files: chrutil.c
     Header Files: chrutil.h
     This program encrypts text by converting each letter to the next letter
     in the alphabet. The last letter of the alphabet is changed to the first
     letter.
*/

#include <stdio.h>
#include "chrutil.h"
void print_next(char c);

main()
{    signed char c;

     printf("***Text Encryption***\n\n");
     printf("Type text, EOF to quit\n");

     while ((c = getchar()) != EOF) {
          if (letterp(c))
               print_next(c);

          else
               putchar(c);
     }
}


/*   Prints the next higher letter to c. Alphabet is assumed circular. */
void print_next(char c)
{
     switch(c) {
          case 'z': printf("%c", 'a');
                    break;
          case 'Z': printf("%c", 'A');
                    break;
          default:  printf("%c", c + 1);
     }
}

encrypt2.c

/*   File: encrypt2.c
     Other Source Files: chrutil.c
     Header Files: chrutil.h
     This program encrypts text by converting each letter to the next letter
     in the alphabet. Illegal characters are ignored.
*/

#include <stdio.h>
#include "chrutil.h"
void print_next(char c);

main()
{    signed char c;

     printf("***Text Encryption Ignoring Illegal Characters***\n\n");
     printf("Type text, EOF to quit\n");

     while ((c = getchar()) != EOF) {    /* while there are chars to process */

          if (illegal(c)) continue;           /* ignore illegal characters   */

          if (letterp(c))                     /* encrypt letters             */
               print_next(c);

          else
               putchar(c);                    /* print all others as is      */
     }
}



/*   Prints the next higher letter to c. Alphabet is assumed circular. */
void print_next(char c)
{
     switch(c) {
          case 'z': printf("%c", 'a');
                    break;
          case 'Z': printf("%c", 'A');
                    break;
          default:  printf("%c", c + 1);
     }
}

menu.c

/*   File: menu.c
     An example of a menu driven program. The main() driver prints the menu,
     reads the selected item, and performs an appropriate task.  */
#include <stdio.h>
#include "payroll.h"

main()
{    signed char c;
     int id;
     float hours_worked, rate_of_pay, pay;

     printf("***Pay Calculation: Menu Driven***\n\n"); /* print title */
     print_menu();        /* Display the menu to the user             */
     while ((c = getchar()) != EOF) {        /* get user selection    */
          switch(c) {                 /* select an appropriate path   */
               case 'g':       /* should be a function get_data()     */
               case 'G': printf("Id number: ");
                         scanf("%d", &id);
                         printf("Type Hours worked and rate of pay\n");
                         scanf("%f %f", &hours_worked, &rate_of_pay);
                         break;
               case 'd':
               case 'D': display_data(id, hours_worked, rate_of_pay);
                         break;
               case 'm':
               case 'M': modify_data();
                         break;
               case 'c':
               case 'C': pay = calc_pay(hours_worked, rate_of_pay);
                         break;
               case 'p':
               case 'P': display_data(id, hours_worked, rate_of_pay);
                         print_pay(pay);
                         break;
               case 'h':
               case 'H': print_menu();
                         break;
               case 'q':
               case 'Q': exit(0);
               default:  printf("Invalid selection\n");
                         print_menu();
          } /* end of switch */
          while ((c = getchar()) != '\n');    /* flush the buffer */
     } /* end of while loop */
} /* end of program */

mix0.c

/*   File: mix0.c
     This program shows problems reading character data when it follows
     numeric data.
*/
#include <stdio.h>

#define  DEBUG

main()
{    char ch;
     int flag, n;

     printf("***Numeric and Character Data***\n\n");
     printf("Type an integer\n");

     while ((flag = scanf("%d", &n)) != EOF) {       /* continue until EOF */
          printf("n = %d\n", n);                     /* print n */

          printf("Do you wish to continue? (Y/N): ");  /* prompt */
          scanf("%c", &ch);                            /* read a character, */
#ifdef DEBUG
printf("debug:%c in input stream\n", ch);              /* type its value */
#endif

          if (ch == 'y')                               /* if char is 'y' */
               printf("Type an integer\n");            /* prompt */
          else                                         /* otherwise, */
               break;                                  /* terminate loop */
     }
}

mix1.c

/*   File: mix1.c
     This program shows how character data might be read correctly when it
     follows numeric data. It assumes only one white space character
     terminates numeric data. This character is suppressed.
*/
#include <stdio.h>

#define  DEBUG

main()
{    char ch;
     int flag, n;

     printf("***Numeric and Character Data***\n\n");
     printf("Type an integer\n");

     while ((flag = scanf("%d", &n)) != EOF) {
          printf("n = %d\n", n);

          printf("Do you wish to continue? (Y/N): ");
          scanf("%*c%c", &ch);     /* suppress a character, read another */
#ifdef DEBUG
printf("debug:%c in input stream\n", ch);
#endif

          if (ch == 'y')
               printf("Type an integer\n");
          else
               break;
     }
}

mix2.c

/*   File: mix2.c
     This program shows how character data can be read correctly when it
     follows numeric data even if several white space characters follow
     numeric data.
*/
#include <stdio.h>

#define DEBUG

main()
{    char ch;
     int flag, n;

     printf("***Numeric and Character Data***\n\n");
     printf("Type an integer\n");

     while ((flag = scanf("%d", &n)) != EOF) {
          printf("n = %d\n", n);

          /* flush white space characters in a line; stop when newline read */
          while (getchar() != '\n');

          printf("Do you wish to continue? (Y/N): ");
          scanf("%c", &ch);
#ifdef DEBUG
printf("debug:%c in input stream\n", ch);
#endif

          if (ch == 'y')
               printf("Type an integer\n");
          else
               break;
     }
}

payroll.c

/* File: payroll.c  */
/* Prints the menu. */
void print_menu(void)
{    /* print the menu */
     printf("Select:\n");
     printf("\tG(et Data\n");
     printf("\tD(isplay Data\n");
     printf("\tM(odify Data\n");
     printf("\tC(alculate Pay\n");
     printf("\tP(rint Pay\n");
     printf("\tH(elp\n");
     printf("\tQ(uit\n");
}

/* Displays input data, Id number, hours worked, and rate of pay. */
void display_data(int id, float hrs, float rate)
{
     printf("Id Number %d\n", id);
     printf("Hours worked %f\n", hrs);
     printf("Rate of pay %f\n", rate);
}

/* Calculates pay as hrs * rate */
/*  a very simple version of calc_pay.  Out previous implementation
    could be used here instead.
*/
float calc_pay(float hrs, float rate)
{
     return hrs * rate;
}

/* Modifies input data. */
void modify_data(void)
{
     printf("Modify Data not implemented yet\n");
}

/* Prints pay */
void print_pay(float pay)
{
     printf("Total pay = %f\n", pay);
}

payroll.h

/* File: payroll.h  */
/*   prototypes for functions in payroll.c   */

/* Prints the menu. */
void print_menu(void);

/* Displays input data, Id number, hours worked, and rate of pay. */
void display_data(int id, float hrs, float rate);

/* Calculates pay as hrs * rate */
float calc_pay(float hrs, float rate);

/* Modifies input data. */
void modify_data(void);

/* Prints pay */
void print_pay(float pay);

scan0.c

/*   File: scan0.c
     This program shows problems with scanf() when wrong data is entered.
*/
#include <stdio.h>

main()
{    int cnt, n;

     printf("***Numeric and Character Data***\n\n");
     printf("Type integers, EOF to quit: ");

     cnt = 0;
     while ((scanf("%d", &n) != EOF) && (cnt < 4)) {
          printf("n = %d\n", n);

          cnt = cnt + 1;
          printf("Type an integer, EOF to quit: ");
     }
}

scan1.c

/*   File: scan1.c
     This program shows how to handle mistyped numeric data by flushing
     erroneous characters.
*/
#include <stdio.h>

#define DEBUG

main()
{    char ch;
     int flag, n;

     printf("***Mistyped Numeric Data: Flush characters***\n\n");
     printf("Type integers, EOF to quit\n");

     while ((flag = scanf("%d", &n)) != EOF) {

          if (flag != 1) {
               ch = getchar();              /* flush one character */
#ifdef DEBUG
printf("debug:%c in input stream, discarding\n", ch);
#endif
          }

          else   printf("n = %d\n", n);

          printf("Type an integer, EOF to quit\n");
     }
}

tfdef.c

/* File: tfdef.h */
#define TRUE 1
#define FALSE 0

wds.c

/*   Program File: wds.c
     Other Source Files: chrutil.c
     Header Files: tfdef.h, chrutil.h
     This program reads standard input characters and prints each word on a
     separate line. It also counts the number of lines, words, and characters.
     All characters are counted including the newline and other control
     characters, if any.
*/

#include <stdio.h>
#include "tfdef.h"
#include "chrutil.h"

main()
{    signed char ch;
     int inword,         /* flag for in a word                */
     lns, wds, chrs;     /* Counters for lines, words, chars. */

     printf("***Line, Word, Character Count Program***\n\n");
     printf("Type characters, EOF to quit\n");
     lns = wds = chrs = 0;    /* initialize counters to 0 */
     inword = FALSE;          /* set inword flag to False */

     while ((ch = getchar()) != EOF) {   /* repeat while not EOF */
          chrs = chrs + 1;               /* increment chrs       */
          if (ch == '\n')                /* if newline char      */
               lns = lns + 1;            /* increment lns        */

          /* if not inword and not a delimiter  */
          if (!inword && !delimitp(ch)) {   /* if not in word and not delim. */
               inword = TRUE;               /* set inword to True            */
               wds = wds + 1;               /* increment wds                 */
          }

          else if (inword && delimitp(ch)) {  /* if in word and a delimiter*/
               inword = FALSE;                /* set inword to False       */
               putchar('\n');                 /* end word with a newline   */
          }

          if (inword)                    /*  if in a word         */
               putchar(ch);              /*  print the character  */

     } /* end of while loop */
     printf("Lines = %d, Words = %d, Characters = %d\n",
               lns, wds, chrs);
} /* end of program */

words.c

/*   File: words.c
     Other Source Files: chrutil.c
     Header Files: tfdef.h, chrutil.h
     This program reads text and extracts words until end of file. Only
     printable characters are allowed in a word. Upon encountering a control
     character, a message is printed and the program is aborted.
*/
#include <stdio.h>
#include "tfdef.h"
#include "chrutil.h"  /* includes prototypes for delimitp(), printp() */

main()
{    signed char ch;

     printf("***Words: Non-Printable Character Aborts***\n\n");
     printf("Type text, EOF to quit\n");

     while ((ch = getchar()) != EOF) {  /* while characters remain to be read */

          while (delimitp(ch))          /* skip over leading delimiters       */
               ch = getchar();

          while (!delimitp(ch) && printp(ch)) {   /* process  a word    */
               putchar(ch);                       /* print ch           */
               ch = getchar();                    /* read the next char */
          }

          if (ch == EOF)                /* if end of file, terminate          */
               break;

          if (illegal(ch)) {/* if a control char, print msg and abort */
               printf("\nAborting - Control character present: ASCII %d\n",ch);
               break;
          }

          printf("\n");                  /* terminate word with newline       */
     }
}