(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]); }
(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); } }