📄 chapter7.html
字号:
<h2><a name="s7.6">7.6 Error Handling - Stderr and Exit</a></h2>The treatment of errors in <tt>cat</tt> is not ideal. The trouble is that ifone of the files can't be accessed for some reason, the diagnostic is printedat the end of the concatenated output. That might be acceptable if the outputis going to a screen, but not if it's going into a file or into anotherprogram via a pipeline.<p>To handle this situation better, a second output stream, called<tt>stderr</tt>, is assigned to a program in the same way that <tt>stdin</tt>and <tt>stdout</tt> are. Output written on <tt>stderr</tt> normally appearson the screen even if the standard output is redirected.<p>Let us revise <tt>cat</tt> to write its error messages on the standard error.<pre> #include <stdio.h> /* cat: concatenate files, version 2 */ main(int argc, char *argv[]) { FILE *fp; void filecopy(FILE *, FILE *); char *prog = argv[0]; /* program name for errors */ if (argc == 1 ) /* no args; copy standard input */ filecopy(stdin, stdout); else while (--argc > 0) if ((fp = fopen(*++argv, "r")) == NULL) { fprintf(stderr, "%s: can't open %s\n", prog, *argv); exit(1); } else { filecopy(fp, stdout); fclose(fp); } if (ferror(stdout)) { fprintf(stderr, "%s: error writing stdout\n", prog); exit(2); } exit(0); }</pre>The program signals errors in two ways. First, the diagnostic output producedby <tt>fprintf</tt> goes to <tt>stderr</tt>, so it finds its way to the screeninstead of disappearing down a pipeline or into an output file. We includedthe program name, from <tt>argv[0]</tt>, in the message, so if this programis used with others, the source of an error is identified.<p>Second, the program uses the standard library function <tt>exit</tt>, whichterminates program execution when it is called. The argument of <tt>exit</tt>is available to whatever process called this one, so the success or failureof the program can be tested by another program that uses this one as asub-process. Conventionally, a return value of 0 signals that all is well;non-zero values usually signal abnormal situations. <tt>exit</tt> calls<tt>fclose</tt> for each open output file, to flush out any buffered output.<p>Within <tt>main</tt>, <tt>return</tt> <em>expr</em> is equivalent to<tt>exit</tt>(<em>expr</em>). <tt>exit</tt> has the advantage that itcan be called from other functions, and that calls to it can be found with apattern-searching program like those in <a href="chapter5.html">Chapter 5</a>.<p>The function <tt>ferror</tt> returns non-zero if an error occurred on thestream <tt>fp</tt>.<pre> int ferror(FILE *fp)</pre>Although output errors are rare, they do occur (for example, if a disk fillsup), so a production program should check this as well.<p>The function <tt>feof(FILE *)</tt> is analogous to <tt>ferror</tt>; it returnsnon-zero if end of file has occurred on the specified file.<pre> int feof(FILE *fp)</pre>We have generally not worried about exit status in our small illustrativeprograms, but any serious program should take care to return sensible,useful status values.<h2><a name="s7.7">7.7 Line Input and Output</a></h2>The standard library provides an input and output routine <tt>fgets</tt> thatis similar to the <tt>getline</tt> function that we have used in earlierchapters:<pre> char *fgets(char *line, int maxline, FILE *fp)</pre><tt>fgets</tt> reads the next input line (including the newline) from file<tt>fp</tt> into the character array <tt>line</tt>; at most<tt>maxline-1</tt> characters will be read. The resulting line is terminatedwith <tt>'\0'</tt>. Normally <tt>fgets</tt> returns <tt>line</tt>; on end offile or error it returns <tt>NULL</tt>. (Our <tt>getline</tt> returns theline length, which is a more useful value; zero means end of file.)<p>For output, the function <tt>fputs</tt> writes a string (which need notcontain a newline) to a file:<pre> int fputs(char *line, FILE *fp)</pre>It returns <tt>EOF</tt> if an error occurs, and non-negative otherwise.<p>The library functions <tt>gets</tt> and <tt>puts</tt> are similar to<tt>fgets</tt> and <tt>fputs</tt>, but operate on <tt>stdin</tt> and<tt>stdout</tt>. Confusingly, <tt>gets</tt> deletes the terminating<tt>'\n'</tt>, and <tt>puts</tt> adds it.<p>To show that there is nothing special about functions like <tt>fgets</tt> and<tt>fputs</tt>, here they are, copied from the standard library on our system:<pre> /* fgets: get at most n chars from iop */ char *fgets(char *s, int n, FILE *iop) { register int c; register char *cs; cs = s; while (--n > 0 && (c = getc(iop)) != EOF) if ((*cs++ = c) == '\n') break; *cs = '\0'; return (c == EOF && cs == s) ? NULL : s; } /* fputs: put string s on file iop */ int fputs(char *s, FILE *iop) { int c; while (c = *s++) putc(c, iop); return ferror(iop) ? EOF : 0; }</pre>For no obvious reason, the standard specifies different return values for<tt>ferror</tt> and <tt>fputs</tt>.<p>It is easy to implement our <tt>getline</tt> from <tt>fgets</tt>:<pre> /* getline: read a line, return length */ int getline(char *line, int max) { if (fgets(line, max, stdin) == NULL) return 0; else return strlen(line); }</pre><strong>Exercise 7-6.</strong> Write a program to compare two files, printingthe first line where they differ.<p><strong>Exercise 7-7.</strong> Modify the pattern finding program of<a href="chapter5.html">Chapter 5</a> to take its input from a set of namedfiles or, if no files are named as arguments, from the standard input. Shouldthe file name be printed when a matching line is found?<p><strong>Exercise 7-8.</strong> Write a program to print a set of files,starting each new one on a new page, with a title and a running page countfor each file.<h2><a name="s7.8">7.8 Miscellaneous Functions</a></h2>The standard library provides a wide variety of functions. This section is abrief synopsis of the most useful. More details and many other functions canbe found in <a href="appb.html">Appendix B</a>.<h3><a name="s7.8.1">7.8.1 String Operations</a></h3>We have already mentioned the string functions <tt>strlen</tt>,<tt>strcpy</tt>, <tt>strcat</tt>, and <tt>strcmp</tt>, found in<tt><string.h></tt>. In the following, <tt>s</tt> and <tt>t</tt> are<tt>char *</tt>'s, and <tt>c</tt> and <tt>n</tt> are <tt>int</tt>s.<p><table align="center"><td><tt>strcat(s,t)</tt> </td><td>concatenate <tt>t</tt> to end of <tt>s</tt></td><tr><td><tt>strncat(s,t,n)</tt></td><td>concatenate <tt>n</tt> characters of <tt>t</tt> to end of <tt>s</tt></td><tr><td><tt>strcmp(s,t)</tt> </td><td>return negative, zero, or positive for <tt>s < t</tt>, <tt>s == t</tt>, <tt>s > t</tt></td><tr><td><tt>strncmp(s,t,n)</tt></td><td>same as <tt>strcmp</tt> but only in first <tt>n</tt> characters</td><tr><td><tt>strcpy(s,t)</tt> </td><td>copy <tt>t</tt> to <tt>s</tt></td><tr><td><tt>strncpy(s,t,n)</tt></td><td>copy at most <tt>n</tt> characters of <tt>t</tt> to <tt>s</tt></td><tr><td><tt>strlen(s)</tt> </td><td>return length of <tt>s</tt></td><tr><td><tt>strchr(s,c)</tt> </td><td>return pointer to first <tt>c</tt> in <tt>s</tt>, or <tt>NULL</tt> if not present</td><tr><td><tt>strrchr(s,c)</tt> </td><td>return pointer to last <tt>c</tt> in <tt>s</tt>, or <tt>NULL</tt> if not present</td></table><h3><a name="s7.8.2">7.8.2 Character Class Testing and Conversion</a></h3>Several functions from <tt><ctype.h></tt> perform character tests andconversions. In the following, <tt>c</tt> is an <tt>int</tt> that can berepresented as an <tt>unsigned char</tt> or <tt>EOF</tt>. The functionreturns <tt>int</tt>.<p><table align="center"><td><tt>isalpha(c)</tt></td><td>non-zero if <tt>c</tt> is alphabetic, 0 if not</td><tr><td><tt>isupper(c)</tt></td><td>non-zero if <tt>c</tt> is upper case, 0 if not</td><tr><td><tt>islower(c)</tt></td><td>non-zero if <tt>c</tt> is lower case, 0 if not</td><tr><td><tt>isdigit(c)</tt></td><td>non-zero if <tt>c</tt> is digit, 0 if not</td><tr><td><tt>isalnum(c)</tt></td><td>non-zero if <tt>isalpha(c)</tt> or <tt>isdigit(c)</tt>, 0 if not</td><tr><td><tt>isspace(c)</tt></td><td>non-zero if <tt>c</tt> is blank, tab, newline, return, formfeed, vertical tab</td><tr><td><tt>toupper(c)</tt></td><td>return <tt>c</tt> converted to upper case</td><tr><td><tt>tolower(c)</tt></td><td>return <tt>c</tt> converted to lower case</td></table><h3><a name="s7.8.3">7.8.3 Ungetc</a></h3>The standard library provides a rather restricted version of the function<tt>ungetch</tt> that we wrote in <a href="chapter4.html">Chapter 4</a>; itis called <tt>ungetc</tt>.<pre> int ungetc(int c, FILE *fp)</pre>pushes the character <tt>c</tt> back onto file <tt>fp</tt>, and returnseither <tt>c</tt>, or <tt>EOF</tt> for an error. Only one character ofpushback is guaranteed per file. <tt>ungetc</tt> may be used with any of theinput functions like <tt>scanf</tt>, <tt>getc</tt>, or <tt>getchar</tt>.<h3><a name="s7.8.4">7.8.4 Command Execution</a></h3>The function <tt>system(char *s)</tt> executes the command contained in thecharacter string <tt>s</tt>, then resumes execution of the current program.The contents of <tt>s</tt> depend strongly on the local operating system. Asa trivial example, on UNIX systems, the statement<pre> system("date");</pre>causes the program <tt>date</tt> to be run; it prints the date and time ofday on the standard output. <tt>system</tt> returns a system-dependentinteger status from the command executed. In the UNIX system, the statusreturn is the value returned by <tt>exit</tt>.<h3><a name="s7.8.5">7.8.5 Storage Management</a></h3>The functions <tt>malloc</tt> and <tt>calloc</tt> obtain blocks of memorydynamically.<pre> void *malloc(size_t n)</pre>returns a pointer to <tt>n</tt> bytes of uninitialized storage, or<tt>NULL</tt> if the request cannot be satisfied.<pre> void *calloc(size_t n, size_t size)</pre>returns a pointer to enough free space for an array of <tt>n</tt> objects ofthe specified size, or <tt>NULL</tt> if the request cannot be satisfied. Thestorage is initialized to zero.<p>The pointer returned by <tt>malloc</tt> or <tt>calloc</tt> has the properalignment for the object in question, but it must be cast into theappropriate type, as in<pre> int *ip; ip = (int *) calloc(n, sizeof(int));</pre><tt>free(p)</tt> frees the space pointed to by <tt>p</tt>, where <tt>p</tt>was originally obtained by a call to <tt>malloc</tt> or <tt>calloc</tt>.There are no restrictions on the order in which space is freed, but it is aghastly error to free something not obtained by calling <tt>malloc</tt> or<tt>calloc</tt>.<p>It is also an error to use something after it has been freed. A typical butincorrect piece of code is this loop that frees items from a list:<pre> for (p = head; p != NULL; p = p->next) /* WRONG */ free(p);</pre>The right way is to save whatever is needed before freeing:<pre> for (p = head; p != NULL; p = q) { q = p->next; free(p); }</pre><a href="chapter8.html#s8.7">Section 8.7</a> shows the implementation of astorage allocator like <tt>malloc</tt>, in which allocated blocks may befreed in any order.<h3><a name="s7.8.6">7.8.6 Mathematical Functions</a></h3>There are more than twenty mathematical functions declared in<tt><math.h></tt>; here are some of the more frequently used. Eachtakes one or two <tt>double</tt> arguments and returns a <tt>double</tt>.<p><table align="center"><td><tt>sin(x)</tt> </td><td>sine of <em>x</em>, <em>x</em> in radians</td><tr><td><tt>cos(x)</tt> </td><td>cosine of <em>x</em>, <em>x</em> in radians</td><tr><td><tt>atan2(y,x)</tt></td><td>arctangent of <em>y/x</em>, in radians</td><tr><td><tt>exp(x)</tt> </td><td>exponential function <em>e<sup>x</sup></em></td><tr><td><tt>log(x)</tt> </td><td>natural (base <em>e</em>) logarithm of <em>x (x>0)</em></td><tr><td><tt>log10(x)</tt> </td><td>common (base 10) logarithm of <em>x (x>0)</em></td><tr><td><tt>pow(x,y)</tt> </td><td><em>x<sup>y<sup></em></td><tr><td><tt>sqrt(x)</tt> </td><td>square root of <em>x (x>0)</em></td><tr><td><tt>fabs(x)</tt> </td><td>absolute value of <em>x</em></td></table><h3><a name="s7.8.7">7.8.7 Random Number generation</a></h3>The function <tt>rand()</tt> computes a sequence of pseudo-random integers inthe range zero to <tt>RAND_MAX</tt>, which is defined in<tt><stdlib.h></tt>. One way to produce random floating-point numbersgreater than or equal to zero but less than one is<pre> #define frand() ((double) rand() / (RAND_MAX+1.0))</pre>(If your library already provides a function for floating-point randomnumbers, it is likely to have better statistical properties than this one.)<p>The function <tt>srand(unsigned)</tt> sets the seed for <tt>rand</tt>. Theportable implementation of <tt>rand</tt> and <tt>srand</tt> suggested by thestandard appears in <a href="chapter2.html#s2.7">Section 2.7</a>.<p><strong>Exercise 7-9.</strong> Functions like <tt>isupper</tt> can beimplemented to save space or to save time. Explore both possibilities.<p><hr><p align="center"><a href="chapter6.html">Back to Chapter 6</a> -- <a href="kandr.html">Index</a> -- <a href="chapter8.html">Chapter 8</a><p><hr></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -