This guide is intended to provide the student with examples of  the C programming style expected in my classes.  All labs will follow this style guide with a single exception.  If a

student provides me with a copy of the style guide adopted by that student's place of employment, the student may use their employer's style guide.

 

Style in contemporary programming is very important.  You should look on your programs in a Computer Science class as fulfilling two functions:

 

1) A working program written to solve a particular problem or set of problems.

 

2) A communication of your ideas and thoughts to your instructor and fellow students.  If your instructor can't read your work, that will be reflected in your grade.

 

The guide will include sections for capitalization, indentation, and each of the program control structures allowed in C.  There will also be sections for user defined data types, including structured data types.

 

 

Capitalization

 

Programs should employ the capitalization style illustrated in Kernighan and Ritchie.  Programs typed in all capital letters are totally unacceptable.

 

A sample program illustrating the "normal" C capitalization style:

 

                 /*

           programmer: D.R. Heckman

                 date: 3/9/91

               fileid: INTRO13B.C

              purpose: Example from Chapter 4 of Getting

                       Started modified slightly.

        */

 

        #include <conio.h>

        #include <stdio.h>

        #include <ctype.h>

 

        #define QUIT 'Q'

 

        typedef char Commands;

 

        int main()

        {

           Commands command;

 

           printf( "Chart desired: Pie  Bar  Scatter  Line  Three-D" );

           printf( "\nPress enter first letter of the chart you want or "

                  " Q to quit!\n" );

 

           do {

              command = toupper( getchar() );

              if( command == 'P' )

                 printf( "Doing pie chart\n" );

              else if (command == 'B')

                 printf( "Doing bar chart\n" );

              else if (command == 'S')

                 printf( "Doing scatter chart\n" );

              else if (command == 'L')

                 printf( "Doing line chart\n" );

              else if (command == 'T')

                 printf( "Doing 3-D chart\n" );

              else

                 printf( "Invalid choice.\n" );

           } while( command != QUIT );

 

           return( 0 );

        }

 

Indentation of data structures and program structures is very important in communicating your design.  Proper use of indentation should be observed in writing C code and pseudo code.

 

Select the indentation option in your IDE to be three or four spaces.  Do not use tab characters to perform this indentation.  If your editor inserts tabs into your source code files, remove the tabs before saving the files.

 

See the remaining sections for examples of indentation with data structures and program structures. 

 

 

Identifiers:

 

All user defined identifiers should be composed of one, two, or three whole words and/or standard abbreviations.  Examine the code segments in this guide for examples.

 

            Variables and function names should start with a lower case alphabetic character.

 

            Type names should start with an upper case alphabetic character.

 

Named constants and symbolic constants should be composed of all upper case
alphabetic characters and the under_score.

 


Parentheses:

 

Parentheses should be used liberally to aid in the "readability" of your programs and pseudo code.  Examine the code segments in this guide for examples in the use of parentheses.

 

 

One-Tailed Alternation … Specification … IF  THEN

 

The if then structure, also called the one-tailed alternation or specification structure, allows a sequence of operations to be performed if a condition is true.

 

Example with one resulting operation:

 

    if( result == 0.0 ) then

       puts( "\nResult is zero!" );

 

Example with multiple operations:

 

    printf( "Result is %lf \n", result );

    if( count > 0 ) {

       average = result / count;

       printf( "Average is %lf \n", average );

    }  /* endif */

 

Another acceptable style of placing the { and } is:

 

       printf( "Result is %lf \n", result );

       if( count > 0 )

          {

             average = result / count;

             printf( "Average is %lf \n", average );

          }  /* endif */

 

Note use of semi-colons ( ; ) to TERMINATE statements.

Note use of indentation and placement of /* endif */

 

 


Two-Tailed Alternation … Selection … IF THEN ELSE

 

The if then else structure, also called the two-tailed alternation or selection structure, allows a sequence of operations to be performed when a condition is true and another sequence when the condition is false.

 

Example with one resulting operation:

 

    if( result == 0.0 )

       puts( "Result is zero!" );

    else

       puts( "Result is non-zero!" );

 

Example with multiple operations:

 

    if( count > 0 ) {

       printf( "Result is %lf \n", result );

       average = result / count;

       printf( "Average is %lf \n", average );

       flag = OK;

    }

    else {

       puts( "There are no valid entries!" );

       flag = ERROR;

    }  /* endif */

 

Another acceptable style of placing the { and } is:

 

    if( count > 0 )

    {

       printf( "Result is %lf \n", result );

       average = result / count;

       printf( "Average is %lf \n", average );

       flag = OK;

    }

    else

    {

       puts( "Result is bad!" );

       flag = ERROR;

    }  /* endif */

 

Note use of semi-colons ( ; ) to terminate statements.

Note use of indentation and placement of /* endif */.

 

 


Multi-Tailed Alternation … Multi-Way Decision … CASE

 

The case structure, also called the multi-tailed alternation or multi-way decision making, allows different sequences of operations to be performed when various possible outcomes of a condition are true.

 

Example with one resulting operation:

 

    switch( selector ) {

       case 0 : puts( " 0 is the case!" ); break;

       case 1 : puts( " 1 is the case!" ); break;

       case 2 : puts( " 2 is the case!" ); break;

       case 3 :

       case 4 :

       case 5 : puts( "between 3 and 5 is the case!" );

                break;

    }  /* end cases */

 

       or, another acceptable style is

 

    switch( selector )

    {

       case 0 : puts( " 0 is the case!" ); break;

       case 1 : puts( " 1 is the case!" ); break;

       case 2 : puts( " 2 is the case!" ); break;

       case 3 :

       case 4 :

       case 5 : puts(" between 3 and 5 is the case!" );

                break;

    } /* end cases */

 

Multiple statements may also be invoked for specific outcomes:

 

    switch( selector ) {

       case 0 : puts( " 0 is the case!" ); value = ‘A’;

                break;

       case 1 : puts( " 1 is the case!" ); value = ‘E’;

                break;

       case 2 : puts( " 2 is the case!" ); value = ‘I’;

                break;

       case 3 : puts( “ 3 is the case!” ); value = ‘O’;

                break

       case 4 : puts( " 4 is the case!” ); value = ‘U’;

                break;

    }  /* end cases */

 

 


CASE  continued

 

An "otherwise clause" may also be used to ensure the outcomes are exhaustive:

 

    switch( selector ) {

       case 0 : puts( " 0 is the case!" ); break;

       case 1 : puts( " 1 is the case!" ); break;

       case 2 : puts( " 2 is the case!" ); break;

      default : puts( " more than 2 is the case!" ); break;

    }  /* end cases */

 

When the "Selector Variable" is not ordinal, the IF THEN ELSE must be used in a "Block If" construction.

 

    if( selector == 0.0 ) {

       puts( " 0 is the case!" );

       value = 0;

    }

    else if( selector == 1.0 ) {

       puts( " 1 is the case!" );

       value = 1;

    }

    else if( selector == 2.0 ) {

       puts( " 2 is the case!" );

       value = 2;

    }

    else {

       puts( " more than 2 is the case!" );

       value = -1;

    }  /* endif */

 

Notice that the Block If construction may be terminated with an else to ensure the conditions tested are exhaustive.

 

 


CASE  continued

 

The Block If construction should not be confused with nested alternation ( nested ifs ).  Nested alternation is used when there are several different conditions to be tested.  Look carefully at the following example of selecting the largest of three values.  Note that the conditions used in the if statements employ different conditions, and the conditions are dependent upon one another.

 

    if( first > second )

       if( first > third ) {

          puts( " First was larger!" );

          big = first;

       }

       else {

          puts( " Third was larger!" );

          big = third;

       }  /* endif */

    else

       if( second > third ) {

          puts( " Second was larger!" );

          big = second;

       }

       else {

          puts( " Third was larger!" );

          big = third;

       }  /* endif */

 /* endif */

 

 


CASE  continued

 

The "block style" placement of { and } is also acceptable:

 

    if( first > second )

       if( first > third )

       {

          puts( " First was larger!" );

          big = first;

       }

       else

       {

          puts( " Third was larger!" );

          big = third;

       }  /* endif */

    else

       if( second > third )

       {

          puts( " Second was larger!" );

          big = second;

       }

       else

       {

          puts( " Third was larger!" );

          big = third;

       }  /* endif */

    /* endif */

 

 


FOR Loop … Counter Controlled Loop … Repetition a Known Number of Times

 

The For Loop structure is also called repetition a known number of times, because, that is exactly what it allows.  Repetition of a sequence of operations a specific numbers of times.

 

Example with one repeated operation:

 

    sum = 0.0;

    for( i = 0; i < 100; i++ )

       sum += x[i];

 

Example with multiple repeated operations:

 

    sum = 0.0;

    for( index = 0; index < 100; index++ ) {

       printf( "  adding element %d \n", index );

       sum += data[index];

    }  /* endfor */

 

or with the block style, which is also acceptable:

 

    sum = 0.0;

    for( index = 0; index < 100; index++ )

    {

       printf( " adding element %d \n", index );

       sum += data[index];

    }  /* endfor */

 

Note use of indentation and placement of /* endfor */

 

Rules for use of the index or counter variable and variables used for the upper and lower bounds of a for do loop.

 

1)  The for loop index or counter variable may not be altered within the body of the for loop.  The for loop will increment the index or counter as required.

 

2)  Variables used for the upper and lower bounds of a for loop may not be altered within the body of the loop.

 

 


WHILE  Loop … Pre-Test Loop … Repetition an Unknown Number of  Times

 

The While structure is also called repetition an unknown number of times, perhaps not at all.  The While structure is also called a pre-test loop.  Since the while test is performed before the body of the loop is executed.  The steps within the body of the loop may never be executed.  There are three fundamental rules for use of the While Loop.

 

1)..The While Loop is used when it is not known initially how many repetitions of the loop will be necessary.

 

2)  During execution of the statements in the body of the while loop, an action will eventually take place that causes the While Loop to stop repetition.

 

3)  The condition used by the While Loop must be initialized to some meaningful value before the While Loop is executed.  Or, in other words, the While Loop must be "primed".

 

Example with one repeated operation:

 

   FILE * filePointer;

   char ch;

 

   filePointer = fopen( "TRIALS.DAT", "rt" ));

   if( filePointer == NULL ) {

       fprintf( stderr, "Cannot open input file. \n" );

       return( 1 );

   }

 

   while( !feof( filePointer ))

       ch = fgetc( filePointer );

 

   fclose( file_pointer );

 

Example with multiple repeated operations:

 

   count = 0;

   while( !feof( filePointer )) {

       fgets( line, 127, filePointer );

       printf( "%s \n", line );

       count++;

   }  /* endwhile */

   fclose( filePointer );

 


WHILE  continued

 

The block style of placing the { and } is also acceptable:

 

   count = 0;

   while( !feof( filePointer ))

   {

      fgets( line, 127, filePointer );

      printf( "%s \n", line );

      count++;

   }  /* endwhile */

       fclose( filePointer );

 

Note use of indentation and placement of /* endwhile */.

 

 

DO WHILE … Post-Test Loop … Repetition an Unknown Number of Times

 

The Do While structure is also called repetition an unknown number of times, at least once.  The Do While structure is also called a post-test loop.  Since the Do While test is

 performed after the body of the loop is executed, the steps within the body of the loop are executed at least one time.  There are two fundamental rules for use of the Do While Loop.

 

1)  The Do While Loop is used when it is not known initially how many repetitions of the loop will be necessary.

 

2)  During execution of the statements in the body of the Do While Loop, an action will eventually take place that causes the loop to stop repetition.

 

Example with one repeated operation:

 

   do

      printf( " INFINITE LOOP " );

   while( -1 );

 


DO WHILE continued

 

Example with multiple repeated operations:

 

   do {

      printf( "Please enter a value between 1 and 5: " );

      scanf( "%d", &entry );

      if( entry < 1 || entry > 5 )

         puts( "Invalid entry, please try again!" )

   } while( entry < 1 || entry > 5 );

 

   or the “block style” is also acceptable:

 

   do

   {

      printf( "Please enter a value between 1 and 5: " );

      scanf( "%d", &entry );

      if( entry < 1 || entry > 5 )

         puts( "Invalid entry, please try again!" )

   }

   while( entry < 1 || entry > 5 );

 

 

USER DEFINED DATA TYPES

 

User-defined data types fall into two groups, 1) scalar data and 2) structured data.

 

ENUMERATED DATA

 

The user defined scalar data type allowed in ANSI C is the enumerated type.  Rules for using enumerated types are as follows:

 

1) The limitation on enumerated type use is the focus of this rule -- variables of enumerated types display unsigned integers when written to text oriented devices (i.e. read from the keyboard or written to the display ).

 

2) If enumerated types are to be used, input from the external world must be encoded into an enumerated type variable and output in the form of an enumerated type variable must be decoded before it can be written.

 

3) The "data objects" used within the definition of an enumerated type should be treated like the identifiers of named constants.

 


ENUMERATED DATA continued

 

Example:

 

   typedef enum { SAMSTAG, SAMSTAGABEND } PartyDays;

 

   typedef enum { SUNDAY, MONDAY, TUESDAY, WEDNESDAY,

                  THURSDAY, FRIDAY, SATURDAY } Days;

   

   int main()

   {

      PartyDays myDayOff;

      Days      singleDay;

      int       entry;

 

      /* prompt for and read entry, encode into enumerated type */

 

      printf( " When do you want to party? " );

      scanf( "%d", & entry );

      if( entry == 1 ) {

         myDayOff = SAMSTAG;

         puts( "SAMSTAG selected!" );

      }

      else {

         myDayOff = SAMSTAGABEND;

         puts( "SAMSTAGABEND selected!" );

      }  /* endif */

 

   /* prompt for and read entry, encode into enumerated type */

 

      do {

         printf( "Enter day number ( 0..6 ):" );

         scanf( "%d", & entry );

         switch( entry ) {

            case 0 : theDay = SUNDAY;    break;

            case 1 : theDay = MONDAY;    break;

            case 2 : theDay = TUESDAY;   break;

            case 3 : theDay = WEDNESDAY; break;

            case 4 : theDay = THURSDAY;  break;

            case 5 : theDay = FRIDAY;    break;

            case 6 : theDay = SATURDAY;  break;

           default : puts( “Invalid entry, try again!” ); break;

         } /* end cases */

      } while( entry < 0 || entry > 6 );

 

   /* code continued on next page */

 


USER DEFINED DATA TYPES continued

 

   /* code from the previous page continued */

 

   /* evaluate encoded enumerated type */

 

      switch( theDay ) {

         case SUNDAY :

         case SATURDAY :

                 puts( "That is not a work day\\\1" );

                 break;

         case MONDAY :

         case TUESDAY :

         case WEDNESDAY :

         case THURSDAY :

         case FRIDAY :

                 puts( "Yes, that is a work day!" );

                 break;

         default :

                 puts( "Error condition, invalid day entry!" );

                 break;

      } /* endcases */

 

      return( 0 );

   }

 

 


ARRAYS

 

Arrays and their subscript variables should always be implemented with type declarations.  Identifiers for the array type declarations and actual array variables should be chosen carefully.

 

Rules about types:

 

1)  You can't put data in a type, so chose the type identifier carefully so there is no conflict with the variable identifier.  I usually recommend that beginning students include the word "type" in all type identifiers.

 

2)  You are going to use the array variable identifier many times in your program, so chose a concise representative name.

 

Examples:

 

    #define MAX_ITEMS 100

    #define MAX_CELLS 200

    #define STRING_LEN 256

    #define PATH_LEN 127

   

    typedef int Frequency[MAX_CELLS];

    typedef float ArrayType[MAX_ITEMS];

    typedef char String[STRING_LEN +1];

    typedef char DosPath[PATH_LEN];

 

    Frequency frequency;

    ArrayType array;

    String string;

    DosPath fileName;

 

 


STRUCTS

 

structs allow the encapsulation of several data fields of different data types.  structs should always be implemented with type declarations.  Identifiers for struct types and actual struct variables should be chosen carefully.

 

Rules for using structs:

 

1)  You can't put data in a type, so chose the type identifier carefully so there is no conflict with the variable identifier.  I usually recommend that beginning students include the word "type" in all type identifiers.

 

2)  Choose the identifiers for fields within a struct just as carefully as you choose the type identifier itself.

 

3)  structs can not be defined within structs but they may be used within structs.

 

Example:

 

   #define KEY_LEN 8

   #define MAX_ITEMS 100

   #define FIRST_LEN 20

   #define LAST_LEN 25

 

   typedef char KeyType[KEY_LEN +1];

   typedef char FirstName[FIRST_LEN +1];

   typedef char LastName[LAST_LEN +1];

 

   typedef struct {

      KeyType key;

      LastName lastName;

      char middleInitial;

      FirstName firstName;

      int age;

   } PersonnelRecord;

 

   /* code continued on next page */

 


STRUCTS continued

 

   /* code continued from previous page */

 

   int readPersonnelRecord( FILE * fp,

                            PersonnelRecord * pPR )

   {

      char initial;

      int  age;

 

      fscanf( fp, “%8s”, pPR->key );

      if( feof( fp ))

         return( EOF );

      if( strlen( pPR->key ) == 0 )

         return( IO_FAIL );

 

      fscanf( fp, “%25[^\n]%20[^\n]%c%d%*c”,

         pPR->lastName, pPR->firstName, & initial, & age );

      pPR->middleInitial = initial;

      pPR->age = age;

      return( 0 );

   }

 

 

UNIONS

 

Unions may be used to "redefine" an area in memory to be used with two different types of data.  More commonly, unions are used together with struct to create a "Variant Record".  Records are classed as variant records when they have a common beginning part but different endings.  This is a common requirement in the real world.

 

Rules for using unions:

 

1)  All the rules cited for structs apply

 

2)  That field identifiers in the variations of a variant record must be unique.

 

3)  A Variant Record commonly employs a "tag field" to tell the program which ending is being used.

 


UNIONS continued

 

Example

 

   #define NAME_SIZE 20

   #define NUMBER_SIZE 9

   #define REASON_SIZE 80

   #define MAX_EMPLOYEES 10

 

   typedef struct { char month[3]; char day[3]; char year[3];

   } Date;

 

   typedef struct { Date fired; char reason[REASON_SIZE +1];

   } Fired;

 

   typedef struct { Date left;  char reason[REASON_SIZE +1];

   } Left;

 

   typedef struct { Date employed; int max_hours;

   } Temp;

 

   typedef struct { Date hired; float pay_rate; int position_level;

   } Full;

 

   typedef union {

      Fired fired;

      Left left;

      Temp temp;

      Full full;

   } VariantPart;

 

   typedef struct {

      char name[NAME_SIZE +1];

      char number[NUMBER_SIZE +1];

      char status;                  /* tag field */

      VariantPart varies;

   } EmployeeRecord;

 

 


TEXT FILES

 

There are actually two implementations of files in C:  Text Files and Binary Files.

 

Text Files are universal streams of ASCII characters which may be interpreted by fscanf() and fgetc(), and produced ( output ) by fprintf() and fputc().

 

Text Files require some external linkage with the operating system.  This is done with the functions fopen(), feof(), and fclose(), all of which work with a "File Pointer".

 

Example:

 

   #define KEY_LEN 8

   #define MAX_ITEMS 100

   #define FIRST_LEN 20

   #define LAST_LEN 25

 

   typedef char KeyType[KEY_LEN +1];

   typedef char FirstName[FIRST_LEN +1];

   typedef char LastName[LAST_LEN +1];

/*                                    code compressed to fit on this page */

   typedef struct {

      KeyType key; LastName lastName; char middleInitial;

      FirstName firstName; int age;

   } PersonnelRecord;

 

   int listRecords( char fileName[] )

   {

      FILE * fp;

      PersonnelRecord pR;

      char initial;

      int age;

      fp = fopen( fileName );

      if( fp == NULL ) return( 1 );

 

      while( !feof( fp )) {

         fscanf( fp, “%8s”, pPR->key );

         if( feof( fp )) continue;

         if( strlen( pPR->key ) == 0 ) continue;

 

         fscanf( fp, “%25[^\n]%20[^\n]%c%d%*c”,

            pR.lastName, pR.firstName, & initial, & age );

 

         pR.middleInitial = initial; pR.age = age;

         printf( "%25s %20s %c %3d \n",

            pR.lastName, pR.firstName, pR.middleInitial, pR.age );

      }

      fclose( fp );

      return( 0 );

   }


BINARY FILES

 

Binary Files are only readable on the system on which they were written.  You may find that some implementations of C do not support Binary Files.

 

Both Text Files and Binary Files require some external linkage with the operating system and positioning of the file pointer.  External linkage is accomplished with the fopen() for Text Files and open() for Binary Files.  The Binary File handling functions open(), close(), and eof() all work with "File Handles".

 

Example:

 

   #define KEY_LEN 8

   #define MAX_ITEMS 100

   #define FIRST_LEN 20

   #define LAST_LEN 25

/*                                    code compressed to fit on this page */

   typedef char KeyType[KEY_LEN +1];

   typedef char FirstName[FIRST_LEN +1];

   typedef char LastName[LAST_LEN +1];

 

   typedef struct {

      KeyType key; LastName lastName; char middleInitial;

      FirstName firstName; int age;

   } PersonnelRecord;

 

   int main()

   {

      PersonnelRecord pR;

      FILE* fp;

      int fileHandle;

 

      fp = fopen( "pers.dat", "r" );

      fileHandle = open( "pers.bin", O_WRONLY | O_CREAT | O_APPEND | O_BINARY );

      while( readPersonnelRecord( fp, & pR ) == 0 )

        writePersonnelRecord( fileHandle, & pR );

 

      fclose( fp );

      close( fileHandle );

      return( 0 );

   }

 

   void writePersonnelRecord( int fh, PersonnelRecord * pPR )

   {

      int length;

      length = write( fh, pPR, sizeof( PersonnelRecord ));

      if( length != sizeof( PersonnelRecord )) {

         fprintf( stderr, “pers: binary file output failed! \n” );

         exit( 1 );

      }

   }