Listing 10.2:An outline of the filerandom-pbm.c.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include "array.h"
4 static inline int random(int n) ...
5 static int write_pbm(char **M, int m, int n, char *outfile) ...
6 static char **make_random_matrix(int m, int n, double f) ...
7 static void show_usage(char *progname) ...
8 int main(int argc, char **argv) ...
file) torand-10.pbm. If the program is invoked with insufficient or illegal command-line arguments, it prints a help message to thestderrand exits, as in
$ ./random-pbm
Usage: ./random-pbm m n s f outfile
writes an mxn random bitmap to a file named ‘outfile’
f: fill ratio 0.0 <= f <= 1.0
s: integer >= 1: seeds the random number generator
We use Chapter 7’sXmalloc module and Chapter 8’sarray.hheader file to allocate memory for the bitmap’s matrix. Therefore, following the suggestions of Chapters 2 and 6, the program’s directory will look like this:
$ cd random
$ ls -F
Makefile array.h@ random-pbm.c xmalloc.c@ xmalloc.h@
I will describe the contents of the filerandom-pbm.cin the next section.
10.4 The file random-pbm.c
Listing 10.2 gives an outline of the filerandom-pbm.c. The functionrandom()that ap- pears on line 4 is the same as that shown in Listing 10.1. The functionshow_usage() that appears on line 7 is responsible for printing the help message shown in Section 10.3.
I will let you write it. The remaining three functions are described in the following sub- sections.
10.4.1 The functionmain()
The functionmain()that appears on line 8 of Listing 10.2 is responsible for parsing the command-line arguments and then directing the rest of the program’s flow. The initial part of the functionmain()is shown in Listing 10.3. Let me explain some of the details.
Line 5. The matrixMwill hold the bitmap’s data. Since the data consists of zeros and ones, any integer data type will do. We choosecharhere since it is the smallest such data type.
Line 8. The variablestatusholds the program’s exit status. We initialize it to the de- fault ofEXIT_FAILURE. Later on, after obtaining reassurance that the program has succeeded (line 38 in Listing 10.4), we will change it toEXIT_SUCCESS.
Line 9. As we saw in Section 10.3, the program is expected to be invoked with five ar- guments, and thereforeargcshould be 6; see Section 4.7 regarding command-line
76 Chapter 10. Generating random numbers
Listing 10.3: The initial part of the functionmain()in filerandom-pbm.c.
1 int main(int argc, char **argv)
2 {
3 int m, n, s; //image is m×n, seed is s
4 double f; //fill ratio
5 char **M;
6 char *outfile;
7 char *endptr;
8 int status = EXIT_FAILURE;
9 if (argc = 6) {
10 show_usage(argv[0]);
11 return EXIT_FAILURE;
12 }
13 m = strtol(argv[1], &endptr, 10);
14 if (*endptr = ’\0’ || m < 1) {
15 show_usage(argv[0]);
16 return status;
17 }
18 //ããã similarly, extract n, s, f, and outfile
arguments. Ifargcis not 6, we print a usage message and exit. We passargv[0]
toshow_usage()so that it can print the program’s name along with the message.
See the sample message shown in Section 10.3.
Line 13. We call the standard library’sstrtol()function (Chapter 5) to translate the stringargv[1]to an integer. Subsequently, we verify thatargv[1]is a proper representation of an integer and that its numerical value is no less than 1. If not, we print a usage message and exit.
Lines 18–34. Here I have excised several lines frommain()to give you an opportunity to insert your own code. You will need to extract the integersnands, the floating point numberf, and the stringoutfilefrom the command-line arguments. You will use thestrtod()function (Chapter 5) to extract the value off.
The remaining part of the functionmain()is shown in Listing 10.4. Let us examine the details.
Line 35. Now that we have extracted the user-specified value of the seedsfor the random number generator, we callsrand()to set the seed tos.
Line 36. We call the functionmake_random_matrix()(to be described later) to pro- duce anm×nmatrix of random zeros and ones with a fill ratio off.
Line 37. We call the functionwrite_pbm()(to be described later) to write the matrix’s data as a PBM file. The function returns 1 on success and 0 on failure. (The most likely cause of failure is the lack of permission to open the file for writing.) If the call returns 1, then it has succeeded; therefore we change the value ofstatusto EXIT_SUCCESS.
10.4. The filerandom-pbm.c 77
Listing 10.4:The end of the functionmain()in filerandom-pbm.c.
35 srand(s);
36 M = make_random_matrix(m, n, f);
37 if (write_pbm(M, m, n, outfile) == 1)
38 status = EXIT_SUCCESS;
39 free_matrix(M);
40 return status;
41 }
Listing 10.5:The functionmake_random_matrix()in filerandom-pbm.c.
1 static char **make_random_matrix(int m, int n, double f)
2 {
3 char **M;
4 int i, j, k;
5 make_matrix(M, m, n);
6 for (i = 0; i < m; i++)
7 for (j = 0; j < n; j++)
8 M[i][j] = 0;
9 k = 0;
10 while (k < f*m*n) {
11 i = random(m);
12 j = random(n);
13 if (M[i][j] == 0) {
14 M[i][j] = 1;
15 k++;
16 }
17 }
18 return M;
19 }
10.4.2 The functionmake_random_matrix()
The functionmake_random_matrix()that appears on line 6 of Listing 10.2 allocates memory for anm×nmatrix, fills it with random zeros and ones (with a fill ratio off), and returns a pointer to that matrix. Listing 10.5 shows the function in its entirety. The implementation is mostly self-explanatory; therefore I will highlight the interesting as- pects only. First, we callmake_matrix()(defined inarray.h) to allocate memory for the matrix, and then we zero all its entries. Recall that zero in the PBM specification means white.
In thewhile-loop that follows, we callrandom()to generate random row and col- umn indicesiandjin the ranges0 ≤ i < mand0 ≤ j < n. IfM[i][j]is zero, we change it to one and then increment the counterk, which keeps a count of the black dots. The test is necessary since ifM[i][j]is already black, making it black again has no effect.
10.4.3 The functionwrite_pbm()
The functionwrite_pbm()that appears on line 5 of Listing 10.2 receives the bitmap matrix created bymake_random_matrix()and writes it in the PBM format to a file whose name it receives as an argument. It returns 1 on success and 0 on failure.
78 Chapter 10. Generating random numbers I will describe the function’s overall plan in words and let you fill in the details. First, call the standard library’sfopen()to open the output file for writing. If unsuccessful, print an appropriate message to thestderr, and then return 0. Next, write the image’s header as described in Section 10.2. See Figure 10.2 for a sample. Then write the data part according to the contents of the matrixM. Finally, close the output stream and return 1.
You may use theprint_matrix()macro from Part 8.3 ofProject array.h(page 60) to print the matrixM.