⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chapter5.html

📁 Kernighan and Ritchie - The C Programming Language c程序设计语言(第二版)称作是C语言学习的圣经
💻 HTML
📖 第 1 页 / 共 5 页
字号:
       *pday = yearday;   }</pre>Recall that the arithmetic value of a logical expression, such as the one for<tt>leap</tt>, is either zero (false) or one (true), so it can be used as asubscript of the array <tt>daytab</tt>.<p>The array <tt>daytab</tt> has to be external to both <tt>day_of_year</tt> and<tt>month_day</tt>, so they can both use it. We made it <tt>char</tt> to illustratea legitimate use of <tt>char</tt> for storing small non-character integers.<p><tt>daytab</tt> is the first two-dimensional array we have dealt with. In C,a two-dimensional array is really a one-dimensional array, each of whoseelements is an array. Hence subscripts are written as<pre>   daytab[i][j]    /* [row][col] */</pre>rather than<pre>   daytab[i,j]    /* WRONG */</pre>Other than this notational distinction, a two-dimensional array can betreated in much the same way as in other languages. Elements are stored byrows, so the rightmost subscript, or column, varies fastest as elements areaccessed in storage order.<p>An array is initialized by a list of initializers in braces; each row of atwo-dimensional array is initialized by a corresponding sub-list. We startedthe array <tt>daytab</tt> with a column of zero so that month numbers can runfrom the natural 1 to 12 instead of 0 to 11. Since space is not at a premiumhere, this is clearer than adjusting the indices.<p>If a two-dimensional array is to be passed to a function, the parameterdeclaration in the function must include the number of columns; the number ofrows is irrelevant, since what is passed is, as before, a pointer to an arrayof rows, where each row is an array of 13 <tt>int</tt>s. In this particularcase, it is a pointer to objects that are arrays of 13 <tt>int</tt>s. Thus ifthe array <tt>daytab</tt> is to be passed to a function <tt>f</tt>, thedeclaration of <tt>f</tt> would be:<pre>   f(int daytab[2][13]) { ... }</pre>It could also be<pre>   f(int daytab[][13]) { ... }</pre>since the number of rows is irrelevant, or it could be<pre>   f(int (*daytab)[13]) { ... }</pre>which says that the parameter is a pointer to an array of 13 integers. Theparentheses are necessary since brackets <tt>[]</tt> have higher precedence than<tt>*</tt>. Without parentheses, the declaration<pre>   int *daytab[13]</pre>is an array of 13 pointers to integers. More generally, only the firstdimension (subscript) of an array is free; all the others have to be specified.<p><a href="chapter5.html#s5.12">Section 5.12</a> has a further discussion ofcomplicated declarations.<p><strong>Exercise 5-8.</strong> There is no error checking in <tt>day_of_year</tt>or <tt>month_day</tt>. Remedy this defect.<h2><a name="s5.8">5.8 Initialization of Pointer Arrays</a></h2>Consider the problem of writing a function <tt>month_name(n)</tt>, whichreturns a pointer to a character string containing the name of the<tt>n</tt>-th month. This is an ideal application for an internal<tt>static</tt> array. <tt>month_name</tt> contains a private array ofcharacter strings, and returns a pointer to the proper one when called. Thissection shows how that array of names is initialized.<p>The syntax is similar to previous initializations:<pre>   /* month_name:  return name of n-th month */   char *month_name(int n)   {       static char *name[] = {           "Illegal month",           "January", "February", "March",           "April", "May", "June",           "July", "August", "September",           "October", "November", "December"       };       return (n &lt; 1 || n &gt; 12) ? name[0] : name[n];   }</pre>The declaration of <tt>name</tt>, which is an array of character pointers, is thesame as <tt>lineptr</tt> in the sorting example. The initializer is a list ofcharacter strings; each is assigned to the corresponding position in the array.The characters of the <tt>i</tt>-th string are placed somewhere, and a pointer tothem is stored in <tt>name[i]</tt>. Since the size of the array <tt>name</tt> is notspecified, the compiler counts the initializers and fills in the correctnumber.<h2><a name="s5.9">5.9 Pointers vs. Multi-dimensional Arrays</a></h2>Newcomers to C are sometimes confused about the difference between atwo-dimensional array and an array of pointers, such as <tt>name</tt> in theexample above. Given the definitions<pre>   int a[10][20];   int *b[10];</pre>then <tt>a[3][4]</tt> and <tt>b[3][4]</tt> are both syntactically legal referencesto a single <tt>int</tt>. But <tt>a</tt> is a true two-dimensional array: 200<tt>int</tt>-sized locations have been set aside, and the conventional rectangularsubscript calculation 20 * <em>row</em> +<em>col</em> is used to findthe element <tt>a[row,col]</tt>. For <tt>b</tt>, however, the definition onlyallocates 10 pointers and does not initialize them; initialization must be doneexplicitly, either statically or with code. Assuming that each element of<tt>b</tt> does point to a twenty-element array, then there will be 200<tt>int</tt>s set aside, plus ten cells for the pointers. The importantadvantage of the pointer array is that the rows of the array may be of differentlengths. That is, each element of <tt>b</tt> need not point to a twenty-elementvector; some may point to two elements, some to fifty, and some to none at all.<p>Although we have phrased this discussion in terms of integers, by far the mostfrequent use of arrays of pointers is to store character strings of diverselengths, as in the function <tt>month_name</tt>. Compare the declaration andpicture for  an array of pointers:<pre>   char *name[] = { "Illegal month", "Jan", "Feb", "Mar" };</pre><p align="center"><img src="pic59.gif"><p>with those for a two-dimensional array:<pre>   char aname[][15] = { "Illegal month", "Jan", "Feb", "Mar" };</pre><p align="center"><img src="pic510.gif"><p><strong>Exercise 5-9.</strong> Rewrite the routines <tt>day_of_year</tt> and<tt>month_day</tt> with pointers instead of indexing.<h2><a name="s5.10">5.10 Command-line Arguments</a></h2>In environments that support C, there is a way to  pass command-line argumentsor parameters to a program when it begins executing. When <tt>main</tt> is called,it is called with two arguments. The first (conventionally called <tt>argc</tt>,for argument count) is the number of command-line arguments the program wasinvoked with; the second (<tt>argv</tt>, for argument vector) is a pointer to anarray of character strings that contain the arguments, one per string. Wecustomarily use multiple levels of pointers to manipulate these characterstrings.<p>The simplest illustration is the program <tt>echo</tt>, which echoes itscommand-line arguments on a single line, separated by blanks. That is, thecommand<pre>   echo hello, world</pre>prints the output<pre>   hello, world</pre>By convention, <tt>argv[0]</tt> is the name by which the program was invoked, so<tt>argc</tt> is at least 1. If <tt>argc</tt> is 1, there are no command-linearguments after the program name. In the example above, <tt>argc</tt> is 3, and<tt>argv[0]</tt>, <tt>argv[1]</tt>, and <tt>argv[2]</tt> are <tt>"echo"</tt>,<tt>"hello,"</tt>, and <tt>"world"</tt> respectively. The first optional argument is<tt>argv[1]</tt> and the last is <tt>argv[argc-1]</tt>; additionally, the standardrequires that <tt>argv[argc]</tt> be a null pointer.<p align="center"><img src="pic511.gif"><p>The first version of <tt>echo</tt> treats <tt>argv</tt> as an array of characterpointers:<pre>   #include &lt;stdio.h&gt;   /* echo command-line arguments; 1st version */   main(int argc, char *argv[])   {       int i;       for (i = 1; i &lt; argc; i++)           printf("%s%s", argv[i], (i &lt; argc-1) ? " " : "");       printf("\n");       return 0;   }</pre>Since <tt>argv</tt> is a pointer to an array of pointers, we can manipulatethe pointer rather than index the array. This next variant is based onincrementing <tt>argv</tt>, which is a pointer to pointer to <tt>char</tt>,while <tt>argc</tt> is counted down:<pre>   #include &lt;stdio.h&gt;   /* echo command-line arguments; 2nd version */   main(int argc, char *argv[])   {       while (--argc &gt; 0)           printf("%s%s", *++argv, (argc &gt; 1) ? " " : "");       printf("\n");       return 0;   }</pre>Since <tt>argv</tt> is a pointer to the beginning of the array of argumentstrings, incrementing it by 1 (<tt>++argv</tt>) makes it point at theoriginal <tt>argv[1]</tt> instead of <tt>argv[0]</tt>. Each successiveincrement moves it along to the next argument; <tt>*argv</tt> is then thepointer to that argument. At the same time, <tt>argc</tt> is decremented;when it becomes zero, there are no arguments left to print.<p>Alternatively,  we could write the <tt>printf</tt> statement as<pre>   printf((argc &gt; 1) ? "%s " : "%s", *++argv);</pre>This shows that the format argument of <tt>printf</tt> can be an expression too.<p>As a second example, let us make some enhancements to the pattern-findingprogram from <a href="chapter4.html#s4.1">Section 4.1</a>. If you recall, wewired the search pattern deep into the program, an obviously unsatisfactoryarrangement. Following the lead of the UNIX program <tt>grep</tt>, let usenhance the program so the pattern to be matched is specified by the firstargument on the command line.<pre>   #include &lt;stdio.h&gt;   #include &lt;string.h&gt;   #define MAXLINE 1000   int getline(char *line, int max);   /* find:  print lines that match pattern from 1st arg */   main(int argc, char *argv[])   {       char line[MAXLINE];       int found = 0;       if (argc != 2)           printf("Usage: find pattern\n");       else           while (getline(line, MAXLINE) &gt; 0)               if (strstr(line, argv[1]) != NULL) {                   printf("%s", line);                   found++;               }       return found;   }</pre>The standard library function <tt>strstr(s,t)</tt> returns a pointer to thefirst occurrence of the string <tt>t</tt> in the string <tt>s</tt>, or<tt>NULL</tt> if there is none. It is declared in <tt>&lt;string.h&gt;</tt>.<p>The model can now be elaborated to illustrate further pointer constructions.Suppose we want to allow two optional arguments. One says ``print all the lines<em>except</em> those that match the pattern;'' the second says ``precede eachprinted line by its line number.''<p>A common convention for C programs on UNIX systems is that an argument thatbegins with a minus sign introduces an optional flag or parameter. If wechoose <tt>-x</tt> (for ``except'') to signal the inversion, and <tt>-n</tt>(``number'') to request line numbering, then the command<pre>   find -x -n<em>pattern</em></pre>will print each line that doesn't match the pattern, preceded by its linenumber.<p>Optional arguments should be permitted in any order, and the rest of theprogram should be independent of the number of arguments that we present.Furthermore, it is convenient for users if option arguments can be combined,as in<pre>   find -nx <em>pattern</em></pre>Here is the program:<pre>   #include &lt;stdio.h&gt;   #include &lt;string.h&gt;   #define MAXLINE 1000   int getline(char *line, int max);   /* find: print lines that match pattern from 1st arg */   main(int argc, char *argv[])   {       char line[MAXLINE];       long lineno = 0;       int c, except = 0, number = 0, found = 0;       while (--argc &gt; 0 && (*++argv)[0] == '-')           while (c = *++argv[0])               switch (c) {               case 'x':                   except = 1;                   break;               case 'n':                   number = 1;                   break;               default:                   printf("find: illegal option %c\n", c);                   argc = 0;                   found = -1;                   break;               }       if (argc != 1)           printf("Usage: find -x -n pattern\n");       else           while (getline(line, MAXLINE) &gt; 0) {               lineno++;               if ((strstr(line, *argv) != NULL) != except) {                   if (number)                       printf("%ld:", lineno);                   printf("%s", line);                   found++;               }           }       return found;   }</pre><tt>argc</tt> is decremented and <tt>argv</tt> is incremented before eachoptional argument. At the end of the loop, if there are no errors,<tt>argc</tt> tells how many arguments remain unprocessed and <tt>argv</tt>points to the first of these. Thus <tt>argc</tt> should be 1 and<tt>*argv</tt> should point at the pattern. Notice that <tt>*++argv</tt> is apointer to an argument string, so <tt>(*++argv)[0]</tt> is its firstcharacter. (An alternate valid form would be <tt>**++argv</tt>.) Because<tt>[]</tt> binds tighter than <tt>*</tt> and <tt>++</tt>, the parenthesesare necessary; without them the expression would be taken as<tt>*++(argv[0])</tt>. In fact, that is what we have used in the inner loop,where the task is to walk along a specific argument string. In the innerloop, the expression <tt>*++argv[0]</tt> increments the pointer<tt>argv[0]</tt>!<p>It is rare that one uses pointer expressions more complicated than these; in

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -