This lab will show you how to read data from a file and also develop your ability to use strings in C.
This page will be available as
http://www.tricity.wsu.edu/~bobl/cpts121/lab10_file_io/writeup.html
Calling it up in a browser will allow you to download the template and dictionary files by clicking on the links below (or you can use the schedule on the course web page).
Plug your thumbdrive into your workstation. Give it a few seconds to be recognized by Windows and then create a MinGW terminal emulator. In that emulator, create a new directory for this lab and cd to it:
$ cd /e/cpts121 $ mkdir lab10 $ cd lab10
As always, keep all your work for this lab in this directory.
So far, much of our code has been computing numerical results. Because of its compiled nature, C is a very popular language for this when speed is important, which is often.
But C can also be used for text information. In C, text is represented in the form of strings: arrays of char variables.
This project will require you to call the standard C function strchr() that is in your book in Appendix B. Here is its prototype:
char *strchr(const char *s, int c);
(Don't worry about the const for now.) s is a string and c is, for our purposes, a char. (Yes, it says int, but chars work here, too, and are usually what we want.)
If c occurs in s, strchr() returns a pointer to it. If there is more than one occurrance, the returned pointer points at the first one. If c does not occur, strchr() returns 0 (i.e., NULL). strchr() is handy both for finding if a character occurs in a string and replacing it:
char word[] = "coffee"; char *ch_p; ch_p = strchr(word, 't'); if (!ch_p) { printf("There's no 't' in coffee!\n", word); }
will print out:
There's no 't' in coffee!
and:
char word[] = "foo"; char *ch_p; ch_p = strchr(word, 'o'); if (ch_p) { (*ch_p) = 'r'; } printf("%s\n", word);
will print out:
fro
In this lab, we'll build an C program to manipulate text: a program to help players of crossword-like word-spelling games like "Scrabble(TM)" or "Words With Friends(TM)" -- let's call them "crossword games" -- find words. (Yes, this could be viewed as cheating.)
Crossword games have one thing in common: You're given a set of one or more letters and need to arrange some or all of them to form a word, which you then play. Letters have different values and you can get different points depending on where you play your word, but we'll ignore all that.
The program we will build is called scrabl. It will prompt the user for a string of letters and then search a file containing a list of words for words that can be made with those letters (and meet other criteria).
Here's the pseudocode:
#include <stdio.h> #include <string.h> /* * scrabl -- prompt the user for letters and find all words containing * them */ /* * All buffers and words should be this size. */ #define BUFFER_SIZE 1024 int wordIsLegal(char word[BUFFER_SIZE], char letters[BUFFER_SIZE]) { /* * declare any needed variables * initialize a string `vowels` to "aeiouwy" * copy `letters` to a temporary `buffer` (hint: strcpy()) (see why?) * set a `foundVowel` flag to 0 * for each character `ch` in "word", * if `ch` is not in `buffer`, (hint: strchr()) * break out of the "for" loop * if `ch` is in `vowels`, (hint: strchr()) * set the `foundVowel` flag to 1 * set the character at `ch`'s position in `buffer` to ' ' (so * it won't be found again) * if all characters of "word" have been tested * *and* `foundVowel` is 1 * *and* the length of the string is at least 2 (hint: strlen()), * return 1 (true) * otherwise * return 0 (false) */ } int main(void) { /* * declare any needed variables * prompt for the letters on the user's tray (hint: printf()) * input the `letters` string (hint: scanf()) * open the file "words.txt" for reading (hint: fopen()) * set `countWords` to 0 * for each `word` (line) in that file (hint: fscanf()) * if `word` is a legal word (hint: wordIsLegal()), * print out `word` (hint: printf()) * increment `countWords` * report `countWords` words found (hint: printf()) * close the file (hint: fclose()) */ return 0; }
You can download it as:
http://www.tricity.wsu.edu/~bobl/cpts121/lab10_file_io/scrabl_tplt.c
You will also need to download the file "words.txt":
http://www.tricity.wsu.edu/~bobl/cpts121/lab10_file_io/words.txt
This will be the first time in this course where you need to read input data from a file as well as the user. There are three things you need in order to read data from a file:
First, you must open the file and assign it to a declared "FILE * pointer:
FILE *f_p; ... f_p = fopen("words.txt", "r");
The first argument of fopen() is the name of the file (a string) you're opening. The "r" means you're opening the file for reading. The return value is sometimes called a "file handle" because you will use it to access the file later in the code. Note that files are always dealt with using "FILE *" pointers, and it is rare (and probably a bug) if you see one dereferenced.
Second, you read from the file with fscanf(), which is just like scanf(), except that you pass it the handle as its first argument. Also like scanf(), fscanf() does not include the newline at the end of the line, so you don't need to remove it.
In our case, you'll read one word at a time in a loop with an fscanf() call at the top:
while (fscanf(f_p, "%s", word) != EOF) { /* do what we want to with `word` */ }
fscanf() will fill in word with a new word on every line. Recall that you don't need to put a & before the argument word in the fscanf() call because word is an array. (If it helps, you could pass &word[0] instead of word: They mean the same thing.)
When the loop exits, you relinquish control of the file by calling:
fclose(f_p);
This is not necessary here, but it is couth. Once a file is closed, you can no longer access it.