📄 chapter1.html
字号:
<pre> /* power: raise base to n-th power; n >= 0; version 2 */ int power(int base, int n) { int p; for (p = 1; n > 0; --n) p = p * base; return p; }</pre>The parameter <tt>n</tt> is used as a temporary variable, and is counted down (a<tt>for</tt> loop that runs backwards) until it becomes zero; there is no longera need for the variable <tt>i</tt>. Whatever is done to <tt>n</tt> inside <tt>power</tt> has no effect on the argument that <tt>power</tt> was originally calledwith.<p>When necessary, it is possible to arrange for a function to modify a variablein a calling routine. The caller must provide the <em>address</em> of the variableto be set (technically a <em>pointer</em> to the variable), and the calledfunction must declare the parameter to be a pointer and access the variableindirectly through it. We will cover pointers in<a href="chapter5.html">Chapter 5</a>.<p>The story is different for arrays. When the name of an array is used as anargument, the value passed to the function is the location or address of thebeginning of the array - there is no copying of array elements. Bysubscripting this value, the function can access and alter any argument ofthe array. This is the topic of the next section.<h2><a name="s1.9">1.9 Character Arrays</a></h2>The most common type of array in C is the array of characters. To illustratethe use of character arrays and functions to manipulate them, let's write aprogram that reads a set of text lines and prints the longest. The outline issimple enough:<pre> while (<em>there's another line</em>) if (<em>it's longer than the previous longest</em>) (<em>save it</em>) (<em>save its length</em>) <em>print longest line</em></pre>This outline makes it clear that the program divides naturally into pieces.One piece gets a new line, another saves it, and the rest controls theprocess.<p>Since things divide so nicely, it would be well to write them that way too.Accordingly, let us first write a separate function <tt>getline</tt> to fetchthe next line of input. We will try to make the function useful in othercontexts. At the minimum, <tt>getline</tt> has to return a signal about possibleend of file; a more useful design would be to return the length of the line,or zero if end of file is encountered. Zero is an acceptable end-of-filereturn because it is never a valid line length. Every text line has at leastone character; even a line containing only a newline has length 1.<p>When we find a line that is longer than the previous longest line, it must besaved somewhere. This suggests a second function, <tt>copy</tt>, to copy the newline to a safe place.<p>Finally, we need a main program to control <tt>getline</tt> and <tt>copy</tt>.Here is the result.<pre> #include <stdio.h> #define MAXLINE 1000 /* maximum input line length */ int getline(char line[], int maxline); void copy(char to[], char from[]); /* print the longest input line */ main() { int len; /* current line length */ int max; /* maximum length seen so far */ char line[MAXLINE]; /* current input line */ char longest[MAXLINE]; /* longest line saved here */ max = 0; while ((len = getline(line, MAXLINE)) > 0) if (len > max) { max = len; copy(longest, line); } if (max > 0) /* there was a line */ printf("%s", longest); return 0; } /* getline: read a line into s, return length */ int getline(char s[],int lim) { int c, i; for (i=0; i < lim-1 && (c=getchar())!=EOF && c!='\n'; ++i) s[i] = c; if (c == '\n') { s[i] = c; ++i; } s[i] = '\0'; return i; } /* copy: copy 'from' into 'to'; assume to is big enough */ void copy(char to[], char from[]) { int i; i = 0; while ((to[i] = from[i]) != '\0') ++i; }</pre>The functions <tt>getline</tt> and <tt>copy</tt> are declared at thebeginning of the program, which we assume is contained in one file.<p><tt>main</tt> and <tt>getline</tt> communicate through a pair of arguments and areturned value. In <tt>getline</tt>, the arguments are declared by the line<pre> int getline(char s[], int lim);</pre>which specifies that the first argument, <tt>s</tt>, is an array, and thesecond, <tt>lim</tt>, is an integer. The purpose of supplying the size of anarray in a declaration is to set aside storage. The length of an array <tt>s</tt>is not necessary in <tt>getline</tt> since its size is set in <tt>main</tt>.<tt>getline</tt> uses <tt>return</tt> to send a value back to the caller, justas the function <tt>power</tt> did. This line also declares that <tt>getline</tt>returns an <tt>int</tt>; since <tt>int</tt> is the default return type, itcould be omitted.<p>Some functions return a useful value; others, like <tt>copy</tt>, are used onlyfor their effect and return no value. The return type of <tt>copy</tt> is<tt>void</tt>, which states explicitly that no value is returned.<p><tt>getline</tt> puts the character <tt>'\0'</tt> (the <em>null character</em>,whose value is zero) at the end of the array it is creating, to mark the endof the string of characters. This conversion is also used by the C language:when a string constant like<pre> "hello\n"</pre>appears in a C program, it is stored as an array of characters containing thecharacters in the string and terminated with a <tt>'\0'</tt> to mark the end.<p align="center"><img src="pic11.gif"><p>The <tt>%s</tt> format specification in <tt>printf</tt> expects thecorresponding argument to be a string represented in this form. <tt>copy</tt>also relies on the fact that its input argument is terminated with a<tt>'\0'</tt>, and copies this character into the output.<p>It is worth mentioning in passing that even a program as small as this onepresents some sticky design problems. For example, what should <tt>main</tt> doif it encounters a line which is bigger than its limit? <tt>getline</tt> workssafely, in that it stops collecting when the array is full, even if nonewline has been seen. By testing the length and the last character returned,<tt>main</tt> can determine whether the line was too long, and then cope as itwishes. In the interests of brevity, we have ignored this issue.<p>There is no way for a user of <tt>getline</tt> to know in advance how long aninput line might be, so <tt>getline</tt> checks for overflow. On the other hand,the user of <tt>copy</tt> already knows (or can find out) how big the stringsare, so we have chosen not to add error checking to it.<p><strong>Exercise 1-16.</strong> Revise the main routine of the longest-lineprogram so it will correctly print the length of arbitrary long input lines,and as much as possible of the text.<p><strong> Exercise 1-17.</strong> Write a program to print all input linesthat are longer than 80 characters.<p><strong> Exercise 1-18.</strong> Write a program to remove trailing blanksand tabs from each line of input, and to delete entirely blank lines.<p><strong> Exercise 1-19.</strong> Write a function <tt>reverse(s)</tt> thatreverses the character string <tt>s</tt>. Use it to write a program thatreverses its input a line at a time.<h2><a name="s1.10">1.10 External Variables and Scope</a></h2>The variables in <tt>main</tt>, such as <tt>line</tt>, <tt>longest</tt>, etc.,are private or local to <tt>main</tt>. Because they are declared within <tt>main</tt>,no other function can have direct access to them. The same is true of thevariables in other functions; for example, the variable <tt>i</tt> in <tt>getline</tt> is unrelated to the <tt>i</tt> in copy. Each local variable in afunction comes into existence only when the function is called, anddisappears when the function is exited. This is why such variables areusually known as <em>automatic</em> variables, following terminology in otherlanguages. We will use the term automatic henceforth to refer to these localvariables. (<a href="chapter4.html">Chapter 4</a> discusses the <tt>static</tt> storageclass, in which local variables do retain their values between calls.)<p>Because automatic variables come and go with function invocation, they do notretain their values from one call to the next, and must be explicitly setupon each entry. If they are not set, they will contain garbage.<p>As an alternative to automatic variables, it is possible to define variablesthat are <em>external</em> to all functions, that is, variables that can beaccessed by name by any function. (This mechanism is rather like FortranCOMMON or Pascal variables declared in the outermost block.) Because externalvariables are globally accessible, they can be used instead of argument liststo communicate data between functions. Furthermore, because externalvariables remain in existence permanently, rather than appearing anddisappearing as functions are called and exited, they retain their valueseven after the functions that set them have returned.<p>An external variable must be <em>defined</em>, exactly once, outside of anyfunction; this sets aside storage for it. The variable must also be<em>declared</em> in each function that wants to access it; this states thetype of the variable. The declaration may be an explicit <tt>extern</tt>statement or may be implicit from context. To make the discussion concrete,let us rewrite the longest-line program with <tt>line</tt>, <tt>longest</tt>,and <tt>max</tt> as external variables. This requires changing the calls,declarations, and bodies of all three functions.<pre> #include <stdio.h> #define MAXLINE 1000 /* maximum input line size */ int max; /* maximum length seen so far */ char line[MAXLINE]; /* current input line */ char longest[MAXLINE]; /* longest line saved here */ int getline(void); void copy(void); /* print longest input line; specialized version */ main() { int len; extern int max; extern char longest[]; max = 0; while ((len = getline()) > 0) if (len > max) { max = len; copy(); } if (max > 0) /* there was a line */ printf("%s", longest); return 0; } /* getline: specialized version */ int getline(void) { int c, i; extern char line[]; for (i = 0; i < MAXLINE - 1 && (c=getchar)) != EOF && c != '\n'; ++i) line[i] = c; if (c == '\n') { line[i] = c; ++i; } line[i] = '\0'; return i; } /* copy: specialized version */ void copy(void) { int i; extern char line[], longest[]; i = 0; while ((longest[i] = line[i]) != '\0') ++i; }</pre>The external variables in <tt>main</tt>, <tt>getline</tt> and <tt>copy</tt> aredefined by the first lines of the example above, which state their type andcause storage to be allocated for them. Syntactically, external definitionsare just like definitions of local variables, but since they occur outside offunctions, the variables are external. Before a function can use an externalvariable, the name of the variable must be made known to the function; thedeclaration is the same as before except for the added keyword <tt>extern</tt>.<p>In certain circumstances, the <tt>extern</tt> declaration can be omitted. If thedefinition of the external variable occurs in the source file before its usein a particular function, then there is no need for an <tt>extern</tt>declaration in the function. The <tt>extern</tt> declarations in <tt>main</tt>,<tt>getline</tt> and <tt>copy</tt> are thus redundant. In fact, common practice isto place definitions of all external variables at the beginning of the sourcefile, and then omit all extern declarations.<p>If the program is in several source files, and a variable is defined in <em>file1</em> and used in <em>file2</em> and <em>file3</em>, then <tt>extern</tt>declarations are needed in <em>file2</em> and <em>file3</em> to connect theoccurrences of the variable. The usual practice is to collect <tt>extern</tt>declarations of variables and functions in a separate file, historicallycalled a <em>header</em>, that is included by <tt>#include</tt> at the front ofeach source file. The suffix <tt>.h</tt> is conventional for header names. Thefunctions of the standard library, for example, are declared in headers like<tt><stdio.h></tt>. This topic is discussed at length in<a href="chapter4.html">Chapter 4</a>, and the library itself in<a href="chapter7.html">Chapter 7</a> and<a href="appb.html">Appendix B</a>.<p>Since the specialized versions of <tt>getline</tt> and <tt>copy</tt> have noarguments, logic would suggest that their prototypes at the beginning of thefile should be <tt>getline()</tt> and <tt>copy()</tt>. But for compatibilitywith older C programs the standard takes an empty list as an old-styledeclaration, and turns off all argument list checking; t
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -