Computer Science 3 - 2000 - Test on Prac 20

(This should take no longer than 15 minutes and is simply intended to probe whether you have understood the material in the prac questions. Answer on the questions sheet.)

1. The vacation caused me to lose my records, and I have forgotten. What is your name?

2. Write a simple C++ program (SHOW.CPP) that simply displays its command line parameters in reverse order - for example the command

Show ABC def third last

should output

last third def ABC

     #include "misc.h"

     void main (int argc, char *argv[]) {
     // Display command line arguments in reverse order
     // P.D. Terry, Rhodes University, 2000
       for (int i = argc - 1; i >= 1; i--) puts(argv[i]);
     }

3. The following program purports (claims) to copy one file to another, one complete line at a time. Much to the dismay of Mr Wossname, who wrote it, it does not always work properly. Suggest how it should be improved.

     #include "misc.h"

     void main (int argc, char *argv[]) {
     // copy input file to input.NEW, one line at a time
     // Usage: linecopy input
     // P.D. Wossname, Rhodes University, 2000
       const int MAXLINE = 100;
       char * str;
       char * outName;
     // open input file
       FILE *infile = fopen(argv[1], "r");
     // open output file - first derive name
       appendextension(argv[1], ".NEW", outName);
       FILE *outfile = fopen(outName, "w");
     // copy file line by line
       while (fgets(str, MAXLINE, infile) != NULL) {
         fputs(str, outfile);
       }
     }

The program does not allocate space for the strings, nor does it check that the files open correctly, nor does it close the output file. Here's a better version. The MAXLINE constant has also been made considerably larger, for increased confidence.

     #include "misc.h"

     void main (int argc, char *argv[]) {
     // copy input file to input.NEW, one line at a time
     // Usage: linecopy input
     // P.D. Terry, Rhodes University, 2000
       const int MAXLINE = 10000;
       char str[MAXLINE+1];
       char outName[256];
     // open input file
       FILE *infile = fopen(argv[1], "r");
       if (infile == NULL) {
         fprintf(stderr, "could not open %s", argv[1]); exit(EXIT_FAILURE);
       }
     // open output file - first derive name
       appendextension(argv[1], ".NEW", outName);
       FILE *outfile = fopen(outName, "w");
       if (outfile == NULL) {
         fprintf(stderr, "could not open %s", outName); exit(EXIT_FAILURE);
       }
     // copy file line by line
       while (fgets(str, MAXLINE, infile) != NULL) {
         fputs(str, outfile);
       }
     // attempt to close output file safely
       if (fclose(outfile) == EOF) {
         fprintf(stderr, "could not close %s", outName); exit(EXIT_FAILURE);
       }
     }

4. Here is another over optimistic program. This one claims to be able to read from standard input and build up a list of the unique words in the input for eventual display on standard output. Whoever P.D. Wossname was, he has not been having much success lately, although he has certainly been generous with his comments, and it easy to follow his thinking. Correct this program too.

     #include "misc.h"

     void main () {
     // read stdin file and build up table of unique words
     // Usage: words <input >output
     // P.D. Wossname, Rhodes University, 2000
       const int MAXWORD = 50;                     // Limit on length of words
       const int MAX = 500;                        // Limit on size of table
       static int last = 0;                        // Dynamic size of table
       char Table[MAX][MAXWORD];
       char * str;
       while (scanf("%s", str) == 1) {             // read file word by word
         Table[last] = str;                        // copy the name as a sentinel.
         int I = 0;                                // start at the bottom
         while (Table[I] != str) I++;              // - and we must find it somewhere!
         if (I == last) {                          // it was not in the original table
           last++;                                 // so attempt to add it
         }
       }
       for (int j = 0; j < last; j++) printf("%d\n", Table[j]);
     }

This program does all the silly things people do - assume that arrays in C++ are first class entities and not (as they are) merely pointers to things! It also makes a very silly error in the final printf function call.

     #include "misc.h"

     void main () {
     // read stdin file and build up table of unique words
     // Usage: words <input >output
     // P.D. Terry, Rhodes University, 2000
       const int MAXWORD = 50;                     // Limit on length of words
       const int MAX = 500;                        // Limit on size of table
       static int last = 0;                        // Dynamic size of table
       char Table[MAX][MAXWORD];
       char str[MAXWORD];
       while (scanf("%s", str) == 1) {             // read file word by word
         strcpy(Table[last], str);                 // copy the name properly as a sentinel.
         int I = 0;                                // start at the bottom
         while (stricmp(Table[I], str) != 0) I++;  // - and we must find it somewhere!
         if (I == last) {                          // it was not in the original table
           last++;                                 // so attempt to add it
           if (last == MAX) {                      // table overflow?
             fprintf(stderr, "Table overflow"); exit(EXIT_FAILURE);
           }
         }
       }
       for (int j = 0; j < last; j++) printf("%s\n", Table[j]);
     }

Computer Science 3 - 2000 - Test on Prac 20

(This should take no longer than 15 minutes and is simply intended to probe whether you have understood the material in the prac questions. Answer on the questions sheet.)

1. The vacation caused me to lose my records, and I have forgotten. What is your name?

2. Write a simple C++ program (FIND.CPP) that looks at the command line arguments and tells you the length of the longest one, and which it was. For example, given the command

find the longest polysyllabic word in this list

it should report

Longest argument had 12 characters and was polysyllabic

In writing this program one has to take care to perform the string copy operation correctly:

     #include "misc.h"

     void main (int argc, char *argv[]) {
     // Display longest command line arguments
     // P.D. Terry, Rhodes University, 2000
       int longest = 0;
       char longstr[1000];
       longstr[0] = '\0';         // make it a properly formed empty string
       for (int i = argc - 1; i >= 1; i--) {
         int l = strlen(argv[i]);
         if (l > longest) { longest = l; strcpy(longstr, argv[i]); }
       }
       printf("Longest argument had %d characters and was %s", longest, longstr);
     }

3. Here is the sort of program I expect I shall be asked to look at this weekend. It tries to copy one file to another, giving the user the option of using either the "redirection" features provided by the operating system, or of picking up a file name from the command line.

Why write two loops when one would do? (No, that's not the question; the answer to that one is that it is just too easy to cut and paste and hack code!)

Rewrite the program so that it uses only one loop (this loop cannot contain any if statements either).

     #include "misc.h"

     void main (int argc, char *argv[]) {
     // copy stdin or file specifed as first parameter to stdout
     // Normal usage:  mycopy <infile    or   mycopy infile
     // P.D. Terry, Rhodes University, 2000
       if (argc == 1) {
         char ch = getchar();
         while (ch != EOF) {
           putchar(ch);
           ch = getchar();
         }
       }
       else {
         FILE * infile = fopen(argv[1], "r");
         char ch = getc(infile);
         while (ch != EOF) {
           putchar(ch);
           ch = getc(infile);
         }
       }
     }

The trick here is simply to assign the stdin file pointer to infile by default:

     #include "misc.h"

     void main (int argc, char *argv[]) {
     // copy stdin or file specifed as first parameter to stdout
     // Normal usage:  mycopy <infile    or   mycopy infile
     // P.D. Terry, Rhodes University, 2000
       FILE * infile = stdin;  // default assumption
       if (argc > 1) {
         if ((infile = fopen(argv[1], "r")) == NULL)
           {fprintf(stderr, "Could not open %s", argv[1]); exit(EXIT_FAILURE); }
       }
       char ch = getc(infile);
       while (ch != EOF) {
         putchar(ch);
         ch = getc(infile);
       }
     }

4. One of my colleagues has asked me to write a program that will perform the following task - read a program written in the language Funny (which he is teaching to CSC 1L) and strip out all the comments to produce the sort of program that he can give to his students in prac tests and ask them what his Funny program does. In Funny programs, comments are written between { braces } and cannot be nested. Being a Lazy Lad I realise that one should be able to hack at one's brilliant answer to question 3 and produce such a utility in less time than it takes to boot up a PC in the Braae Lab.

What would the modified program look like?

All we have to do is add an inner loop to the copying loop to detect the start of a comment and to skip the writing operation until the comment is closed again - but being careful not to get stuck if a comment is left unclosed by mistake!

     #include "misc.h"

     void main (int argc, char *argv[]) {
     // copy stdin or file specifed as first parameter to stdout
     // treating as Funny source file and strip out { comments }
     // Normal usage:  strip <infile    or   strip infile
     // P.D. Terry, Rhodes University, 2000
       FILE * infile = stdin;  // default assumption
       if (argc > 1) {
         if ((infile = fopen(argv[1], "r")) == NULL)
           {fprintf(stderr, "Could not open %s", argv[1]); exit(EXIT_FAILURE); }
       }
       char ch = getc(infile);
       while (ch != EOF) {
         if (ch == '{')
           while (ch != '}' && ch != EOF) ch = getc(infile); // skip comments
           else putchar(ch);
         ch = getc(infile);
       }
     }