"The C Programming Language", 2nd edition, Kernighan and Ritchie

来源:互联网 发布:java gbk中文乱码 编辑:程序博客网 时间:2024/04/28 17:45

目      录
译者序

第1版序
前言
第1章   基本概念 
1.1   入门 
1.2   变量与算术表达式 
1.3   for语句 
1.4   符号常量 
1.5   字符输入输出 
1.5.1   文件复制 
1.5.2   字符计数 
1.5.3   行计数 
1.5.4   单词计数 
1.6   数组 
1.7   函数 
1.8   变元—按值调用 
1.9   字符数组 
1.10   外部变量与作用域 
第2章   类型、运算符与表达式 
2.1   变量名 
2.2   数据类型与大小 
2.3   常量 
2.4   说明 
2.5   算术运算符 
2.6   关系运算符与逻辑运算符  
2.7   类型转换 
2.8   加一与减一运算符 
2.9   按位运算符 
2.10   赋值运算符与赋值表达式 
2.11   条件表达式 
2.12   运算符优先级与表达式求值次序 
第3章   控制流 
3.1   语句与分程序 
3.2    if-else语句 
3.3   else-if语句 
3.4   switch语句 
3.5   while与for循环语句 
3.6   do-while循环语句 
3.7   break语句与continue语句 
3.8   goto语句与标号 
第4章   函数与程序结构 
4.1   函数的基本知识 
4.2   返回非整数值的函数 
4.3   外部变量 
4.4   作用域规则 
4.5   头文件 
4.6   静态变量 
4.7   寄存器变量 
4.8   分程序结构 
4.9   初始化 
4.10   递归 
4.11   C预处理程序 
4.11.1   文件包含 
4.11.2   宏替换 
4.11.3   条件包含 
第5章   指针与数组 
5.1   指针与地址 
5.2   指针与函数变元 
5.3   指针与数组 
5.4   地址算术运算 
5.5   字符指针与函数 
5.6   指针数组与指向指针的指针 
5.7   多维数组 
5.8   指针数组的初始化 
5.9   指针与多维数组 
5.10   命令行变元 
5.11   指向函数的指针 
5.12   复杂说明 
第6章   结构 
6.1   结构的基本知识 
6.2   结构与函数 
6.3   结构数组 
6.4   结构指针 
6.5   自引用结构 
6.6   查找表 
6.7   类型定义 
6.8   联合 
6.9   位字段 
第7章   输入与输出 
7.1   标准输入输出 
7.2   格式输出—printf函数 
7.3   变长变元表 
7.4   格式输入—scanf函数 
7.5   文件访问 
7.6   错误处理—stderr和exit函数 
7.7   行输入输出 
7.8   其他函数 
7.8.1   字符串处理函数 
7.8.2   字符类测试和转换函数 
7.8.3   ungetc函数 
7.8.4   命令执行函数 
7.8.5   存储管理函数 
7.8.6   数学函数 
7.8.7   随机数发生器函数 
第8章   UNIX系统界面 
8.1   文件描述符 
8.2   低级I/O—read和write系统调用 
8.3   open、creat、close和unlink系统调用 
8.4   随机访问—lseek系统调用 
8.5   实例—fopen和getc函数的一种实现
方法 
8.6   实例—目录显示 
8.7   实例—存储分配程序 
附录A   参考手册 
A.1   引言 
A.2   词法规则 
A.3   语法符号 
A.4   标识符的含义 
A.5   对象和左值 
A.6   转换 
A.7   表达式 
A.8   说明 
A.9   语句 
A.10   外部说明 
A.11   作用域与连接 
A.12      预处理 
A.13   语法 
附录B   标准库 
B.1   输入与输出:<stdio.h> 
B.2   字符类测试:<ctype.h> 
B.3   字符串函数:<string.h> 
B.4   数学函数:<math.h> 
B.5   实用函数:<stdlib.h> 
B.6   诊断:<assert.h> 
B.7   变量变元表:<stdarg.h> 
B.8   非局部跳转:<setjmp.h> 
B.9   信号处理:<signal.h> 
B.10   日期与时间函数:<time.h> 
B.11   由实现定义的限制:<limits.h>和
<float.h> 
附录C   变更小结 

  1. getchar() and putchar()
  2. #include <stdio.h>
  3. /* 用于将输入复制到输出的程序;第2个版本*/
  4. main ( )
  5. {
  6. int c;
  7. while ( (c = getchar ( ) ) != EOF )//End Of File,文件结束< stdio.h>库定义的整数
  8. putchar ( c );
  9. }
  10. 在这一程序中,w h i l e循环语句先读一个字符并将其赋给c,然后测试该字符是否为文件结束标记。如果该字符不是文件结束标记,那么就执行w h i l e语句体,把该字符打印出来。再重复执行该w h i l e语句。当最后到达输入结束位置时, w h i l e循环语句终止执行,从而整个m a i n程序执行结束。之所以不把c说明成c h a r类型,是因为c必须大到除了能存储任何可能的字符外还要能存储文件结束符E O F。因此,把c说明成i n t类型的。

1.5.1 文件复制

Verify that the expression getchar() != EOF is 0 or 1.

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4.   printf("Press a key. ENTER would be nice :-)/n/n");
  5.   printf("The expression getchar() != EOF evaluates to %d/n", getchar() != EOF);
  6.   return 0;
  7. }

Write a program to print the value of EOF .

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4.   printf("The value of EOF is %d/n/n", EOF);
  5.   
  6.   return 0;
  7. }
1.5.2 字符计数
  1. #include <stdio.h>
  2. /* 统计输入的字符数; 第2个版本*/
  3. main ( )
  4. {
  5. double nc;
  6. for ( nc = 0; getchar ( ) != EOF; ++nc )
  7. ;
  8. printf("%.0f/n", nc);
  9. }
  1. #include <stdio.h>
  2. /* 统计输入的行数*/
  3. main ( )
  4. {
  5. long c, nl;
  6. nl = 0;
  7. while ( (c = getchar ( ) ) != EOF )
  8. if ( c =='/n' )
  9. ++nl;
  10. printf("%d/n", nl);
  11. }

编写一个用于统计空格、制表符与换行符个数的程序

Write a program to count blanks, tabs, and newlines

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4.   int blanks, tabs, newlines;
  5.   int c;
  6.   int done = 0;
  7.   int lastchar = 0;
  8.   blanks = 0;
  9.   tabs = 0;
  10.   newlines = 0;
  11.   while(done == 0)
  12.   {
  13.     c = getchar();
  14.     if(c == ' ')
  15.       ++blanks;
  16.     if(c == '/t')
  17.       ++tabs;
  18.     if(c == '/n')
  19.       ++newlines;
  20.     if(c == EOF)
  21.     {
  22.       if(lastchar != '/n')
  23.       {
  24.         ++newlines; /* this is a bit of a semantic stretch, but it copes
  25.                      * with implementations where a text file might not
  26.                      * end with a newline. Thanks to Jim Stad for pointing
  27.                      * this out.
  28.                      */
  29.       }
  30.       done = 1;
  31.     }
  32.     lastchar = c;
  33.   }
  34.   printf("Blanks: %d/nTabs: %d/nLines: %d/n", blanks, tabs, newlines);
  35.   return 0;
  36. }

编写一个程序,把它的输入复制到输出,并在此过程中将相连的多个空格用一个
空格代替。

Write a program to copy its input to its output, replacing each string of one or more blanks by a single blan

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4.   int c;
  5.   int inspace;
  6.   inspace = 0;
  7.   while((c = getchar()) != EOF)
  8.   {
  9.     if(c == ' ')
  10.     {
  11.       if(inspace == 0)
  12.       {
  13.         inspace = 1;
  14.         putchar(c);
  15.       }
  16.     }
  17.     /* We haven't met 'else' yet, so we have to be a little clumsy */
  18.     if(c != ' ')
  19.     {
  20.       inspace = 0;
  21.       putchar(c);
  22.     }
  23.   }
  24.   return 0;
  25. }
  26. Chris Sidi writes: "instead of having an "inspace" boolean, you can keep track of the previous character and see if both the current character and previous character are spaces:" 
  27. #include <stdio.h>
  28. /* count lines in input */
  29. int
  30. main()
  31. {
  32.         int c, pc; /* c = character, pc = previous character */
  33.         /* set pc to a value that wouldn't match any character, in case
  34.         this program is ever modified to get rid of multiples of other
  35.         characters */
  36.         pc = EOF;
  37.         while ((c = getchar()) != EOF) {
  38.                 if (c == ' ')
  39.                         if (pc != ' ')   /* or if (pc != c) */ 
  40.                                 putchar(c);
  41.                 /* We haven't met 'else' yet, so we have to be a little clumsy */
  42.                 if (c != ' ')
  43.                         putchar(c);
  44.                 pc = c;
  45.         }
  46.         return 0;
  47. }
  48. Stig writes: "I am hiding behind the fact that break is mentioned in the introduction"
  49. #include <stdio.h>
  50. int main(void)
  51. {
  52.         int c;
  53.         while ((c = getchar()) != EOF) {
  54.                 if (c == ' ') {
  55.                        putchar(c);
  56.                        while((c = getchar()) == ' ' && c != EOF)
  57.                                ;
  58.                }
  59.                if (c == EOF)
  60.                        break/* the break keyword is mentioned
  61.                                * in the introduction... 
  62.                                * */
  63.                putchar(c);
  64.         }
  65.         return 0;

编写一个程序,把它的输入复制到输出,并在此过程中把制表符换成/ t、把回退
符换成/ b、把反斜杠换成/ /。这样可以使得制表符与回退符能以无歧义的方式可见。

Write a program to copy its input to its output, replacing each tab by /t , each backspace by /b , and each backslash by // . This makes tabs and backspaces visible in an unambiguous way. 

 

  1. Category 0 
  2. Gregory Pietsch pointed out that my solution was actually Category 1. He was quite right. Better still, he was kind enough to submit a Category 0 solution himself. Here it is
  3. /* Gregory Pietsch <gkp1@flash.net> */
  4. /*
  5.  * Here's my attempt at a Category 0 version of 1-10.
  6.  *
  7.  * Gregory Pietsch
  8.  */
  9. #include <stdio.h>
  10. int main()
  11. {
  12.     int c, d;
  13.     while ( (c=getchar()) != EOF) {
  14.         d = 0;
  15.         if (c == '//') {
  16.             putchar('//');
  17.             putchar('//');
  18.             d = 1;
  19.         }
  20.         if (c == '/t') {
  21.             putchar('//');
  22.             putchar('t');
  23.             d = 1;
  24.         }
  25.         if (c == '/b') {
  26.             putchar('//');
  27.             putchar('b');
  28.             d = 1;
  29.         }
  30.         if (d == 0)
  31.             putchar(c);        
  32.     }
  33.     return 0;
  34. }
  35. Category 1 
  36. This solution, which I wrote myself, is the sadly discredited Cat 0 answer which has found a new lease of life in Category 1. 
  37. #include <stdio.h>
  38. #define ESC_CHAR '//'
  39. int main(void)
  40. {
  41.   int c;
  42.   while((c = getchar()) != EOF)
  43.   {
  44.     switch(c)
  45.     {
  46.       case '/b':
  47.         /* The OS on which I tested this (NT) intercepts /b characters. */
  48.         putchar(ESC_CHAR);
  49.         putchar('b');
  50.         break;
  51.       case '/t':
  52.         putchar(ESC_CHAR);
  53.         putchar('t');
  54.         break;
  55.       case ESC_CHAR:
  56.         putchar(ESC_CHAR);
  57.         putchar(ESC_CHAR);
  58.         break;
  59.       default:
  60.         putchar(c);
  61.         break;
  62.     }
  63.   }
  64.   return 0;

 1.5.4 单词计数

 

  1. #include <stdio.h>
  2. #define IN 1 /* 在单词内*/
  3. #define OUT 0 /* 在单词外*/
  4. /* 统计输入的行数、单词数与字符数*/
  5. main ( )
  6. {
  7. int c, nl, nw, nc, state;
  8. state = OUT;
  9. nl = nw = nc = 0;
  10. while ( (c = getchar ( ) ) != EOF ) {
  11. ++nc;
  12. if ( c =='/n' )
  13. ++nl;
  14. if ( c == ' ' ||c == '/n' || c == '/t' )
  15. state = OUT;
  16. else if ( state == OUT ) {
  17. state = IN;
  18. ++nw;
  19. }
  20. }
  21. printf("%d %d %d/n", nl, nw, nc);
  22. }

你准备怎样测试单词计数程序?如果程序中出现任何错误,那么什么样的输入最
有利于发现这些错误?

How would you test the word count program? What kinds of input are most likely to uncover bugs if there are any?

  1. It sounds like they are really trying to get the programmers to learn how to do a unit test. I would submit the following: 
  2. 0. input file contains zero words 
  3. 1. input file contains 1 enormous word without any newlines 
  4. 2. input file contains all white space without newlines 
  5. 3. input file contains 66000 newlines 
  6. 4. input file contains word/{huge sequence of whitespace of different kinds}/word 
  7. 5. input file contains 66000 single letter words, 66 to the line 
  8. 6. input file contains 66000 words without any newlines 
  9. 7. input file is /usr/dict contents (or equivalent) 
  10. 8. input file is full collection of moby words 
  11. 9. input file is binary (e.g. its own executable) 
  12. 10. input file is /dev/nul (or equivalent) 
  13. 66000 is chosen to check for integral overflow on small integer machines. 
  14. Dann suggests a followup exercise 1-11a: write a program to generate inputs (0,1,2,3,4,5,6) 
  15. I guess it was inevitable that I'd receive a solution for this followup exercise! Here is Gregory Pietsch's program to generate Dann's suggested inputs: 
  16. #include <assert.h>
  17. #include <stdio.h>
  18. int main(void)
  19. {
  20.     FILE *f;
  21.     unsigned long i;
  22.     static char *ws = " /f/t/v";
  23.     static char *al = "abcdefghijklmnopqrstuvwxyz";
  24.     static char *i5 = "a b c d e f g h i j k l m "
  25.                       "n o p q r s t u v w x y z "
  26.                       "a b c d e f g h i j k l m "
  27.                       "n o p q r s t u v w x y z "
  28.                       "a b c d e f g h i j k l m "
  29.                       "n/n";
  30.     /* Generate the following: */
  31.     /* 0. input file contains zero words */
  32.     f = fopen("test0""w");
  33.     assert(f != NULL);
  34.     fclose(f);
  35.     /* 1. input file contains 1 enormous word without any newlines */
  36.     f = fopen("test1""w");
  37.     assert(f != NULL);
  38.     for (i = 0; i < ((66000ul / 26) + 1); i++)
  39.         fputs(al, f);
  40.     fclose(f);
  41.     /* 2. input file contains all white space without newlines */
  42.     f = fopen("test2""w");
  43.     assert(f != NULL);
  44.     for (i = 0; i < ((66000ul / 4) + 1); i++)
  45.         fputs(ws, f);
  46.     fclose(f);
  47.     /* 3. input file contains 66000 newlines */
  48.     f = fopen("test3""w");
  49.     assert(f != NULL);
  50.     for (i = 0; i < 66000; i++)
  51.         fputc('/n', f);
  52.     fclose(f);
  53.     /* 4. input file contains word/ 
  54.      *    {huge sequence of whitespace of different kinds}
  55.      *    /word 
  56.      */
  57.     f = fopen("test4""w");
  58.     assert(f != NULL);
  59.     fputs("word", f);
  60.     for (i = 0; i < ((66000ul / 26) + 1); i++)
  61.         fputs(ws, f);
  62.     fputs("word", f);
  63.     fclose(f);
  64.     /* 5. input file contains 66000 single letter words,
  65.      *    66 to the line 
  66.      */
  67.     f = fopen("test5""w");
  68.     assert(f != NULL);
  69.     for (i = 0; i < 1000; i++)
  70.         fputs(i5, f);
  71.     fclose(f);
  72.     /* 6. input file contains 66000 words without any newlines */
  73.     f = fopen("test6""w");
  74.     assert(f != NULL);
  75.     for (i = 0; i < 66000; i++)
  76.         fputs("word ", f);
  77.     fclose(f);
  78.     return 0;
  79. }

编写一个程序,以每行一个单词的形式打印输入。

Write a program that prints its input one word per line.

 

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4.   int c;
  5.   int inspace;
  6.   inspace = 0;
  7.   while((c = getchar()) != EOF)
  8.   {
  9.     if(c == ' ' || c == '/t' || c == '/n')
  10.     {
  11.       if(inspace == 0)
  12.       {
  13.         inspace = 1;
  14.         putchar('/n');
  15.       }
  16.       /* else, don't print anything */
  17.     }
  18.     else
  19.     {
  20.       inspace = 0;
  21.       putchar(c);
  22.     }
  23.   }
  24.   return 0;
  25. }

1.6 数组

  1. #include <stdio.h>
  2. /* 统计各个数字、空白字符及其他字符分别出现的次数*/
  3. main ( )
  4. {
  5. int c, i, nwhite, nother;
  6. int ndigit[10];
  7. nwhite = nother = 0;
  8. for ( i =0; i < 10; ++i )
  9. ndigit[i] = 0;
  10. while ( ( c = getchar() ) != EOF )
  11. if ( c >= '0' && c <= '9' )
  12. ++ndigit[c - '0'];
  13. else if ( c == ' ' ||c == '/n' || c == '/t' )
  14. ++nwhite;
  15. else
  16. ++nother;
  17. printf( "digits =" );
  18. for ( i =0; i < 10; ++i )
  19. printf( " %d", ndigit[i] );
  20. printf( ", white space = %d, other = %d", nwhite, nother);
  21. }
  22. 当把程序自身作为输入时,输出为:
    digits = 9 3 0 0 0 0 0 0 0 1, white space = 123, other = 345

练习1-13 编写一个程序,打印其输入的文件中单词长度的直方图。横条的直方图比较容易
绘制,竖条直方图则要困难些。

Write a program to print a histogram of the lengths of words in its input. It is easy to draw the histogram with the bars horizontal; a vertical orientation is more challenging.

 

  1. #include <stdio.h>
  2. #define MAXWORDLEN 10
  3. int main(void)
  4. {
  5.   int c;
  6.   int inspace = 0;
  7.   long lengtharr[MAXWORDLEN + 1];
  8.   int wordlen = 0;
  9.   int firstletter = 1;
  10.   long thisval = 0;
  11.   long maxval = 0;
  12.   int thisidx = 0;
  13.   int done = 0;
  14.   for(thisidx = 0; thisidx <= MAXWORDLEN; thisidx++)
  15.   {
  16.     lengtharr[thisidx] = 0;
  17.   }
  18.   while(done == 0)
  19.   {
  20.     c = getchar();
  21.     if(c == ' ' || c == '/t' || c == '/n' || c == EOF)
  22.     {
  23.       if(inspace == 0)
  24.       {
  25.         firstletter = 0;
  26.         inspace = 1;
  27.         if(wordlen <= MAXWORDLEN)
  28.         {
  29.           if(wordlen > 0)
  30.           {
  31.             thisval = ++lengtharr[wordlen - 1];
  32.             if(thisval > maxval)
  33.             {
  34.               maxval = thisval;
  35.             }
  36.           }
  37.         }
  38.         else
  39.         {
  40.           thisval = ++lengtharr[MAXWORDLEN];
  41.           if(thisval > maxval)
  42.           {
  43.             maxval = thisval;
  44.           }
  45.         }
  46.       }
  47.       if(c == EOF)
  48.       {
  49.         done = 1;
  50.       }
  51.     }
  52.     else
  53.     {
  54.       if(inspace == 1 || firstletter == 1)
  55.       {
  56.         wordlen = 0;
  57.         firstletter = 0;
  58.         inspace = 0;
  59.       }
  60.       ++wordlen;
  61.     }
  62.   }
  63.   for(thisval = maxval; thisval > 0; thisval--)
  64.   {
  65.     printf("%4d  | ", thisval);
  66.     for(thisidx = 0; thisidx <= MAXWORDLEN; thisidx++)
  67.     {
  68.       if(lengtharr[thisidx] >= thisval)
  69.       {
  70.         printf("*  ");
  71.       }
  72.       else
  73.       {
  74.         printf("   ");
  75.       }
  76.     }
  77.     printf("/n");
  78.   }
  79.   printf("      +");
  80.   for(thisidx = 0; thisidx <= MAXWORDLEN; thisidx++)
  81.   {
  82.     printf("---");
  83.   }
  84.   printf("/n       ");
  85.   for(thisidx = 0; thisidx < MAXWORDLEN; thisidx++)
  86.   {
  87.     printf("%2d ", thisidx + 1);
  88.   }
  89.   printf(">%d/n", MAXWORDLEN);
  90.   return 0;
  91. }
  92. Here's the output of the program when given its own source as input: 
  93.  113  | *                                
  94.  112  | *                                
  95.  111  | *                                
  96.  110  | *                                
  97.  109  | *                                
  98.  108  | *                                
  99.  107  | *                                
  100.  106  | *                                
  101.  105  | *                                
  102.  104  | *                                
  103.  103  | *                                
  104.  102  | *                                
  105.  101  | *                                
  106.  100  | *                                
  107.   99  | *                                
  108.   98  | *                                
  109.   97  | *                                
  110.   96  | *                                
  111.   95  | *                                
  112.   94  | *  *                             
  113.   93  | *  *                             
  114.   92  | *  *                             
  115.   91  | *  *                             
  116.   90  | *  *                             
  117.   89  | *  *                             
  118.   88  | *  *                             
  119.   87  | *  *                             
  120.   86  | *  *                             
  121.   85  | *  *                             
  122.   84  | *  *                             
  123.   83  | *  *                             
  124.   82  | *  *                             
  125.   81  | *  *                             
  126.   80  | *  *                             
  127.   79  | *  *                             
  128.   78  | *  *                             
  129.   77  | *  *                             
  130.   76  | *  *                             
  131.   75  | *  *                             
  132.   74  | *  *                             
  133.   73  | *  *                             
  134.   72  | *  *                             
  135.   71  | *  *                             
  136.   70  | *  *                             
  137.   69  | *  *                             
  138.   68  | *  *                             
  139.   67  | *  *                             
  140.   66  | *  *                             
  141.   65  | *  *                             
  142.   64  | *  *                             
  143.   63  | *  *  *                          
  144.   62  | *  *  *                          
  145.   61  | *  *  *                          
  146.   60  | *  *  *                          
  147.   59  | *  *  *                          
  148.   58  | *  *  *                          
  149.   57  | *  *  *                          
  150.   56  | *  *  *                          
  151.   55  | *  *  *                          
  152.   54  | *  *  *                          
  153.   53  | *  *  *                          
  154.   52  | *  *  *  *                       
  155.   51  | *  *  *  *                       
  156.   50  | *  *  *  *                       
  157.   49  | *  *  *  *                       
  158.   48  | *  *  *  *                       
  159.   47  | *  *  *  *                       
  160.   46  | *  *  *  *                       
  161.   45  | *  *  *  *                       
  162.   44  | *  *  *  *                       
  163.   43  | *  *  *  *        *              
  164.   42  | *  *  *  *        *              
  165.   41  | *  *  *  *        *              
  166.   40  | *  *  *  *        *              
  167.   39  | *  *  *  *        *              
  168.   38  | *  *  *  *        *              
  169.   37  | *  *  *  *        *              
  170.   36  | *  *  *  *        *              
  171.   35  | *  *  *  *        *              
  172.   34  | *  *  *  *        *              
  173.   33  | *  *  *  *        *              
  174.   32  | *  *  *  *        *              
  175.   31  | *  *  *  *        *              
  176.   30  | *  *  *  *        *           *  
  177.   29  | *  *  *  *        *           *  
  178.   28  | *  *  *  *  *     *           *  
  179.   27  | *  *  *  *  *     *           *  
  180.   26  | *  *  *  *  *     *           *  
  181.   25  | *  *  *  *  *  *  *           *  
  182.   24  | *  *  *  *  *  *  *           *  
  183.   23  | *  *  *  *  *  *  *           *  
  184.   22  | *  *  *  *  *  *  *        *  *  
  185.   21  | *  *  *  *  *  *  *        *  *  
  186.   20  | *  *  *  *  *  *  *        *  *  
  187.   19  | *  *  *  *  *  *  *        *  *  
  188.   18  | *  *  *  *  *  *  *        *  *  
  189.   17  | *  *  *  *  *  *  *        *  *  
  190.   16  | *  *  *  *  *  *  *        *  *  
  191.   15  | *  *  *  *  *  *  *        *  *  
  192.   14  | *  *  *  *  *  *  *  *     *  *  
  193.   13  | *  *  *  *  *  *  *  *     *  *  
  194.   12  | *  *  *  *  *  *  *  *     *  *  
  195.   11  | *  *  *  *  *  *  *  *     *  *  
  196.   10  | *  *  *  *  *  *  *  *     *  *  
  197.    9  | *  *  *  *  *  *  *  *  *  *  *  
  198.    8  | *  *  *  *  *  *  *  *  *  *  *  
  199.    7  | *  *  *  *  *  *  *  *  *  *  *  
  200.    6  | *  *  *  *  *  *  *  *  *  *  *  
  201.    5  | *  *  *  *  *  *  *  *  *  *  *  
  202.    4  | *  *  *  *  *  *  *  *  *  *  *  
  203.    3  | *  *  *  *  *  *  *  *  *  *  *  
  204.    2  | *  *  *  *  *  *  *  *  *  *  *  
  205.    1  | *  *  *  *  *  *  *  *  *  *  *  
  206.       +---------------------------------
  207.         1  2  3  4  5  6  7  8  9 10 >10

 

练习1-14 编写一个程序,打印其输入的文件中各个字符出现频率的直方图。

Write a program to print a histogram of the frequencies of different characters in its input.

  1. #include <stdio.h>
  2. /* NUM_CHARS should really be CHAR_MAX but K&R haven't covered that at this stage in the book */
  3. #define NUM_CHARS 256
  4. int main(void)
  5. {
  6.   int c;
  7.   long freqarr[NUM_CHARS + 1];
  8.   long thisval = 0;
  9.   long maxval = 0;
  10.   int thisidx = 0;
  11.   for(thisidx = 0; thisidx <= NUM_CHARS; thisidx++)
  12.   {
  13.     freqarr[thisidx] = 0;
  14.   }
  15.   while((c = getchar()) != EOF)
  16.   {
  17.     if(c < NUM_CHARS)
  18.     {
  19.       thisval = ++freqarr[c];
  20.       if(thisval > maxval)
  21.       {
  22.         maxval = thisval;
  23.       }
  24.     }
  25.     else
  26.     {
  27.       thisval = ++freqarr[NUM_CHARS];
  28.       if(thisval > maxval)
  29.       {
  30.         maxval = thisval;
  31.       }
  32.     }
  33.   }
  34.   for(thisval = maxval; thisval > 0; thisval--)
  35.   {
  36.     printf("%4d  |", thisval);
  37.     for(thisidx = 0; thisidx <= NUM_CHARS; thisidx++)
  38.     {
  39.       if(freqarr[thisidx] >= thisval)
  40.       {
  41.         printf("*");
  42.       }
  43.       else if(freqarr[thisidx] > 0)
  44.       {
  45.         printf(" ");
  46.       }
  47.     }
  48.     printf("/n");
  49.   }
  50.   printf("      +");
  51.   for(thisidx = 0; thisidx <= NUM_CHARS; thisidx++)
  52.   {
  53.     if(freqarr[thisidx] > 0)
  54.     {
  55.       printf("-");
  56.     }
  57.   }
  58.   printf("/n       ");
  59.   for(thisidx = 0; thisidx < NUM_CHARS; thisidx++)
  60.   {
  61.     if(freqarr[thisidx] > 0)
  62.     {
  63.       printf("%d", thisidx / 100);
  64.     }
  65.   }
  66.   printf("/n       ");
  67.   for(thisidx = 0; thisidx < NUM_CHARS; thisidx++)
  68.   {
  69.     if(freqarr[thisidx] > 0)
  70.     {
  71.       printf("%d", (thisidx - (100 * (thisidx / 100))) / 10 );
  72.     }
  73.   }
  74.   printf("/n       ");
  75.   for(thisidx = 0; thisidx < NUM_CHARS; thisidx++)
  76.   {
  77.     if(freqarr[thisidx] > 0)
  78.     {
  79.       printf("%d", thisidx - (10 * (thisidx / 10)));
  80.     }
  81.   }
  82.   if(freqarr[NUM_CHARS] > 0)
  83.   {
  84.     printf(">%d/n", NUM_CHARS);
  85.   }
  86.   printf("/n");
  87.   return 0;
  88. }
  89. Here's the output of the program when given its own source as input: 
  90.  474  | *                                                                    
  91.  473  | *                                                                    
  92.  472  | *                                                                    
  93.  471  | *                                                                    
  94.  470  | *                                                                    
  95.  469  | *                                                                    
  96.  468  | *                                                                    
  97.  467  | *                                                                    
  98.  466  | *                                                                    
  99.  465  | *                                                                    
  100.  464  | *                                                                    
  101.  463  | *                                                                    
  102.  462  | *                                                                    
  103.  461  | *                                                                    
  104.  460  | *                                                                    
  105.  459  | *                                                                    
  106.  458  | *                                                                    
  107.  457  | *                                                                    
  108.  456  | *                                                                    
  109.  455  | *                                                                    
  110.  454  | *                                                                    
  111.  453  | *                                                                    
  112.  452  | *                                                                    
  113.  451  | *                                                                    
  114.  450  | *                                                                    
  115.  449  | *                                                                    
  116.  448  | *                                                                    
  117.  447  | *                                                                    
  118.  446  | *                                                                    
  119.  445  | *                                                                    
  120.  444  | *                                                                    
  121.  443  | *                                                                    
  122.  442  | *                                                                    
  123.  441  | *                                                                    
  124.  440  | *                                                                    
  125.  439  | *                                                                    
  126.  438  | *                                                                    
  127.  437  | *                                                                    
  128.  436  | *                                                                    
  129.  435  | *                                                                    
  130.  434  | *                                                                    
  131.  433  | *                                                                    
  132.  432  | *                                                                    
  133.  431  | *                                                                    
  134.  430  | *                                                                    
  135.  429  | *                                                                    
  136.  428  | *                                                                    
  137.  427  | *                                                                    
  138.  426  | *                                                                    
  139.  425  | *                                                                    
  140.  424  | *                                                                    
  141.  423  | *                                                                    
  142.  422  | *                                                                    
  143.  421  | *                                                                    
  144.  420  | *                                                                    
  145.  419  | *                                                                    
  146.  418  | *                                                                    
  147.  417  | *                                                                    
  148.  416  | *                                                                    
  149.  415  | *                                                                    
  150.  414  | *                                                                    
  151.  413  | *                                                                    
  152.  412  | *                                                                    
  153.  411  | *                                                                    
  154.  410  | *                                                                    
  155.  409  | *                                                                    
  156.  408  | *                                                                    
  157.  407  | *                                                                    
  158.  406  | *                                                                    
  159.  405  | *                                                                    
  160.  404  | *                                                                    
  161.  403  | *                                                                    
  162.  402  | *                                                                    
  163.  401  | *                                                                    
  164.  400  | *                                                                    
  165.  399  | *                                                                    
  166.  398  | *                                                                    
  167.  397  | *                                                                    
  168.  396  | *                                                                    
  169.  395  | *                                                                    
  170.  394  | *                                                                    
  171.  393  | *                                                                    
  172.  392  | *                                                                    
  173.  391  | *                                                                    
  174.  390  | *                                                                    
  175.  389  | *                                                                    
  176.  388  | *                                                                    
  177.  387  | *                                                                    
  178.  386  | *                                                                    
  179.  385  | *                                                                    
  180.  384  | *                                                                    
  181.  383  | *                                                                    
  182.  382  | *                                                                    
  183.  381  | *                                                                    
  184.  380  | *                                                                    
  185.  379  | *                                                                    
  186.  378  | *                                                                    
  187.  377  | *                                                                    
  188.  376  | *                                                                    
  189.  375  | *                                                                    
  190.  374  | *                                                                    
  191.  373  | *                                                                    
  192.  372  | *                                                                    
  193.  371  | *                                                                    
  194.  370  | *                                                                    
  195.  369  | *                                                                    
  196.  368  | *                                                                    
  197.  367  | *                                                                    
  198.  366  | *                                                                    
  199.  365  | *                                                                    
  200.  364  | *                                                                    
  201.  363  | *                                                                    
  202.  362  | *                                                                    
  203.  361  | *                                                                    
  204.  360  | *                                                                    
  205.  359  | *                                                                    
  206.  358  | *                                                                    
  207.  357  | *                                                                    
  208.  356  | *                                                                    
  209.  355  | *                                                                    
  210.  354  | *                                                                    
  211.  353  | *                                                                    
  212.  352  | *                                                                    
  213.  351  | *                                                                    
  214.  350  | *                                                                    
  215.  349  | *                                                                    
  216.  348  | *                                                                    
  217.  347  | *                                                                    
  218.  346  | *                                                                    
  219.  345  | *                                                                    
  220.  344  | *                                                                    
  221.  343  | *                                                                    
  222.  342  | *                                                                    
  223.  341  | *                                                                    
  224.  340  | *                                                                    
  225.  339  | *                                                                    
  226.  338  | *                                                                    
  227.  337  | *                                                                    
  228.  336  | *                                                                    
  229.  335  | *                                                                    
  230.  334  | *                                                                    
  231.  333  | *                                                                    
  232.  332  | *                                                                    
  233.  331  | *                                                                    
  234.  330  | *                                                                    
  235.  329  | *                                                                    
  236.  328  | *                                                                    
  237.  327  | *                                                                    
  238.  326  | *                                                                    
  239.  325  | *                                                                    
  240.  324  | *                                                                    
  241.  323  | *                                                                    
  242.  322  | *                                                                    
  243.  321  | *                                                                    
  244.  320  | *                                                                    
  245.  319  | *                                                                    
  246.  318  | *                                                                    
  247.  317  | *                                                                    
  248.  316  | *                                                                    
  249.  315  | *                                                                    
  250.  314  | *                                                                    
  251.  313  | *                                                                    
  252.  312  | *                                                                    
  253.  311  | *                                                                    
  254.  310  | *                                                                    
  255.  309  | *                                                                    
  256.  308  | *                                                                    
  257.  307  | *                                                                    
  258.  306  | *                                                                    
  259.  305  | *                                                                    
  260.  304  | *                                                                    
  261.  303  | *                                                                    
  262.  302  | *                                                                    
  263.  301  | *                                                                    
  264.  300  | *                                                                    
  265.  299  | *                                                                    
  266.  298  | *                                                                    
  267.  297  | *                                                                    
  268.  296  | *                                                                    
  269.  295  | *                                                                    
  270.  294  | *                                                                    
  271.  293  | *                                                                    
  272.  292  | *                                                                    
  273.  291  | *                                                                    
  274.  290  | *                                                                    
  275.  289  | *                                                                    
  276.  288  | *                                                                    
  277.  287  | *                                                                    
  278.  286  | *                                                                    
  279.  285  | *                                                                    
  280.  284  | *                                                                    
  281.  283  | *                                                                    
  282.  282  | *                                                                    
  283.  281  | *                                                                    
  284.  280  | *                                                                    
  285.  279  | *                                                                    
  286.  278  | *                                                                    
  287.  277  | *                                                                    
  288.  276  | *                                                                    
  289.  275  | *                                                                    
  290.  274  | *                                                                    
  291.  273  | *                                                                    
  292.  272  | *                                                                    
  293.  271  | *                                                                    
  294.  270  | *                                                                    
  295.  269  | *                                                                    
  296.  268  | *                                                                    
  297.  267  | *                                                                    
  298.  266  | *                                                                    
  299.  265  | *                                                                    
  300.  264  | *                                                                    
  301.  263  | *                                                                    
  302.  262  | *                                                                    
  303.  261  | *                                                                    
  304.  260  | *                                                                    
  305.  259  | *                                                                    
  306.  258  | *                                                                    
  307.  257  | *                                                                    
  308.  256  | *                                                                    
  309.  255  | *                                                                    
  310.  254  | *                                                                    
  311.  253  | *                                                                    
  312.  252  | *                                                                    
  313.  251  | *                                                                    
  314.  250  | *                                                                    
  315.  249  | *                                                                    
  316.  248  | *                                                                    
  317.  247  | *                                                                    
  318.  246  | *                                                                    
  319.  245  | *                                                                    
  320.  244  | *                                                                    
  321.  243  | *                                                                    
  322.  242  | *                                                                    
  323.  241  | *                                                                    
  324.  240  | *                                                                    
  325.  239  | *                                                                    
  326.  238  | *                                                                    
  327.  237  | *                                                                    
  328.  236  | *                                                                    
  329.  235  | *                                                                    
  330.  234  | *                                                                    
  331.  233  | *                                                                    
  332.  232  | *                                                                    
  333.  231  | *                                                                    
  334.  230  | *                                                                    
  335.  229  | *                                                                    
  336.  228  | *                                                                    
  337.  227  | *                                                                    
  338.  226  | *                                                                    
  339.  225  | *                                                                    
  340.  224  | *                                                                    
  341.  223  | *                                                                    
  342.  222  | *                                                                    
  343.  221  | *                                                                    
  344.  220  | *                                                                    
  345.  219  | *                                                                    
  346.  218  | *                                                                    
  347.  217  | *                                                                    
  348.  216  | *                                                                    
  349.  215  | *                                                                    
  350.  214  | *                                                                    
  351.  213  | *                                                                    
  352.  212  | *                                                                    
  353.  211  | *                                                                    
  354.  210  | *                                                                    
  355.  209  | *                                                                    
  356.  208  | *                                                                    
  357.  207  | *                                                                    
  358.  206  | *                                                                    
  359.  205  | *                                                                    
  360.  204  | *                                                                    
  361.  203  | *                                                                    
  362.  202  | *                                                                    
  363.  201  | *                                                                    
  364.  200  | *                                                                    
  365.  199  | *                                                                    
  366.  198  | *                                                                    
  367.  197  | *                                                                    
  368.  196  | *                                                                    
  369.  195  | *                                                                    
  370.  194  | *                                                                    
  371.  193  | *                                                                    
  372.  192  | *                                                                    
  373.  191  | *                                                                    
  374.  190  | *                                                                    
  375.  189  | *                                                                    
  376.  188  | *                                                                    
  377.  187  | *                                                                    
  378.  186  | *                                                                    
  379.  185  | *                                                                    
  380.  184  | *                                                                    
  381.  183  | *                                                                    
  382.  182  | *                                                                    
  383.  181  | *                                                                    
  384.  180  | *                                                                    
  385.  179  | *                                                                    
  386.  178  | *                                                                    
  387.  177  | *                                                                    
  388.  176  | *                                                                    
  389.  175  | *                                                                    
  390.  174  | *                                                                    
  391.  173  | *                                                                    
  392.  172  | *                                                                    
  393.  171  | *                                                                    
  394.  170  | *                                                                    
  395.  169  | *                                                                    
  396.  168  | *                                                                    
  397.  167  | *                                                                    
  398.  166  | *                                                                    
  399.  165  | *                                                                    
  400.  164  | *                                                                    
  401.  163  | *                                                                    
  402.  162  | *                                                                    
  403.  161  | *                                                                    
  404.  160  | *                                                                    
  405.  159  | *                                                                    
  406.  158  | *                                                                    
  407.  157  | *                                                                    
  408.  156  | *                                                                    
  409.  155  | *                                                                    
  410.  154  | *                                                                    
  411.  153  | *                                                                    
  412.  152  | *                                                                    
  413.  151  | *                                                                    
  414.  150  | *                                                                    
  415.  149  | *                                                                    
  416.  148  | *                                                                    
  417.  147  | *                                                                    
  418.  146  | *                                                                    
  419.  145  | *                                                                    
  420.  144  | *                                                                    
  421.  143  | *                                                                    
  422.  142  | *                                                                    
  423.  141  | *                                                                    
  424.  140  | *                                                                    
  425.  139  | *                                                                    
  426.  138  | *                                                                    
  427.  137  | *                                                                    
  428.  136  | *                                                                    
  429.  135  | *                                                                    
  430.  134  | *                                                                    
  431.  133  | *                                                                    
  432.  132  | *                                                                    
  433.  131  | *                                                                    
  434.  130  | *                                                                    
  435.  129  | *                                                                    
  436.  128  | *                                                                    
  437.  127  | *                                                                    
  438.  126  | *                                                                    
  439.  125  | *                                                                    
  440.  124  | *                                                                    
  441.  123  | *                                                                    
  442.  122  | *                                                                    
  443.  121  | *                                                                    
  444.  120  | *                                                                    
  445.  119  | *                                                                    
  446.  118  | *                                                                    
  447.  117  | *                                                                    
  448.  116  | *                                                                    
  449.  115  | *                                                                    
  450.  114  | *                                                                    
  451.  113  | *                                                                    
  452.  112  | *                                                                    
  453.  111  | *                                                                    
  454.  110  | *                                                                    
  455.  109  | *                                                 *                  
  456.  108  | *                                                 *                  
  457.  107  | *                                                 *                  
  458.  106  | *                                                 *                  
  459.  105  | *                                                 *                  
  460.  104  | *                                                 *                  
  461.  103  | *                                                 *                  
  462.  102  | *                                                 *                  
  463.  101  | *                                                 *                  
  464.  100  | *                                                 *                  
  465.   99  | *                                                 *                  
  466.   98  | *                                                 *                  
  467.   97  |**                                                 *                  
  468.   96  |**                                                 *                  
  469.   95  |**                                                 *                  
  470.   94  |**                                                 *                  
  471.   93  |**                                                 *                  
  472.   92  |**                                                 *                  
  473.   91  |**                                                 *                  
  474.   90  |**                                                 *                  
  475.   89  |**                                                 *                  
  476.   88  |**                                                 *                  
  477.   87  |**                                                 *                  
  478.   86  |**                                                 *                  
  479.   85  |**                                                 *                  
  480.   84  |**                                                 *                  
  481.   83  |**                                                 *                  
  482.   82  |**                                                 *                  
  483.   81  |**                                                 *                  
  484.   80  |**                                                 *                  
  485.   79  |**                                                 *                  
  486.   78  |**                                                 *                  
  487.   77  |**                                                 *                  
  488.   76  |**                                                 *                  
  489.   75  |**                                                 *                  
  490.   74  |**                                                 *                  
  491.   73  |**                                                 *                  
  492.   72  |**                                                 *                  
  493.   71  |**                                                 *         *        
  494.   70  |**                                                 *         *        
  495.   69  |**                                                 *         *        
  496.   68  |**                                                 *         *        
  497.   67  |**                                                 *         *        
  498.   66  |**                                                 *         *        
  499.   65  |**                                                 *         *        
  500.   64  |**                                                 *         *        
  501.   63  |**                                                 *         *        
  502.   62  |**                                                 *         *        
  503.   61  |**                                                 *         *        
  504.   60  |**                                                 *         *        
  505.   59  |**                                                 *       * *        
  506.   58  |**                                                 *       * *        
  507.   57  |**                                                 *       * *        
  508.   56  |**                                                 *       * *        
  509.   55  |**                                                 *       * *        
  510.   54  |**                                                 *       * *        
  511.   53  |**                                                 *       * *        
  512.   52  |**                                                 *       * *        
  513.   51  |**                                                **       * *        
  514.   50  |**                                                **       * *        
  515.   49  |**                                                **       ***        
  516.   48  |**                                                **       ***        
  517.   47  |**                                                **       ***        
  518.   46  |**                                                **       ***        
  519.   45  |**                                                **       ***        
  520.   44  |**                                                **       ***        
  521.   43  |**                                              * **       ***        
  522.   42  |**                                         *  * * **       ***        
  523.   41  |**                                         *  * * **       ***        
  524.   40  |**      **                                 *  * * **       ***        
  525.   39  |**      **            *                    *  * * **       ***        
  526.   38  |**      **            *                    *  * * **       ***        
  527.   37  |**      **            *                    *  * * **       ***   *    
  528.   36  |**      **            *                    *  * * **       ***   *    
  529.   35  |**      **            *                    *  * * **       ***   *    
  530.   34  |**      **            *                    *  * * **       ***   *    
  531.   33  |**      **            *                    *  * * **       ***   *    
  532.   32  |**      **            *                    *  * * **   *   ***   *    
  533.   31  |**      **            *                    *  * * **   *   ***   *    
  534.   30  |**      **            *                    *  * * **   *   ***   *    
  535.   29  |**      **            *                    *  * * **   *   ***   *    
  536.   28  |** *    **            *                    *  *** ** * *   ***   *    
  537.   27  |** *    **      *     *                    *  *** ** * *   ***   *    
  538.   26  |** *    **      *     *                    *  *** ** * *   ***   *    
  539.   25  |** *    **      *     *                    *  *** ** * *   ***   *    
  540.   24  |** *    **      *     *                    *  *** ** * *   ***   *    
  541.   23  |** *    **      *     *                    *  *** ** * *   ***   *    
  542.   22  |** *    **      *     *                    *  *** ** * *   ***   *    
  543.   21  |** *    **      *     * *                  *  *** ** * *   *** * *    
  544.   20  |** *    **      *     * *                  *  *** ** * *   *** * * * *
  545.   19  |** *    **      *     * *                  *  *** ** * *   *** * * * *
  546.   18  |** *    ** *    *     * *                  *  *** ** * *   *** * * * *
  547.   17  |** *    ** *    *     * *                  *  *** ** * *   *** * * * *
  548.   16  |** *    ** *    *     * *                  *  *** ** * **  *** * * * *
  549.   15  |** *    ** *    *     * * *        *       *  *** ** * **  *** * * * *
  550.   14  |** *    ** *    *     * * **  * *  *      **  *** ** * *** *** * * * *
  551.   13  |** *    ** *    *     * * **  * ** ***    **  *** ** * *** *** * * * *
  552.   12  |** *    ** *    *     * ****  * ** ***    **  *** ** * *** *** * * * *
  553.   11  |** *    ** *    *     * ****  * ** *** * ***  *** ** * ******* * * * *
  554.   10  |** *    ** *    *     * ****  * ** *** * ***  *** ** * ******* * * * *
  555.    9  |** *    ** *    *     * ****  * ** *** * ***  *** ** * ******* * * * *
  556.    8  |** *    ** *    *     ******  * ** *** * ***  *** ** * ******* * * * *
  557.    7  |** *    ** *    **    ******  * ** *** * *** **** ** ********* * * * *
  558.    6  |** *    ** *   ***    ******  * ** *** ***** **** ** ********* * * * *
  559.    5  |** * *  ****** ***    ******  * ** *** ***** ******* ********* * * * *
  560.    4  |** * *  ****** ***    ******  * ** *** ***** ******* *********** * * *
  561.    3  |** * *  ****** ***    ******  * ** *** ************* *********** * * *
  562.    2  |** ***  ****** ***    ******  * ** *** ************* *********** * * *
  563.    1  |**********************************************************************
  564.       +----------------------------------------------------------------------
  565.        0000000000000000000000000000000000000000000000111111111111111111111111
  566.        1333333344444444445555566666677777788889999999000000000111111111122222
  567.        0234578901234567890234901257902578923581235789012345789012345678901345 

1.7 函数

 

  1. 下面给出函数power(m, n)的定义及调用它的主程序,由此可以看到整个结构。
  2. #include <stdio.h>
  3. int power(int m, int n);
  4. /* 测试power函数*/
  5. main ( )
  6. {
  7. int i;
  8. for ( i =0; i < 10; ++i )
  9. printf("%d %d %d/n", i, power(2, i), power(-3, i));
  10. return 0;
  11. }
  12. /* power: 求底的n次幂; n >=0 */
  13. int power(int baseint n)
  14. {
  15. int i, p;
  16. p = 1;
  17. for ( i = 1; i <= n; ++i )
  18. p = p * base;
  19. return p;
  20. }
  21. 函数定义的一般形式为:
  22. 返回值类型函数名(可能有的参数说明)
  23. {
  24. 说明序列
  25. 语句序列
  26. }

练习1-15 重写1 . 2节的温度转换程序,使用函数来实现温度转换。

  1. #include <stdio.h>
  2. float FtoC(float f)
  3. {
  4.   float c;
  5.   c = (5.0 / 9.0) * (f - 32.0);
  6.   return c;
  7. }
  8. int main(void)
  9. {
  10.   float fahr, celsius;
  11.   int lower, upper, step;
  12.   lower = 0;
  13.   upper = 300;
  14.   step = 20;
  15.   printf("F     C/n/n");
  16.   fahr = lower;
  17.   while(fahr <= upper)
  18.   {
  19.     celsius = FtoC(fahr);
  20.     printf("%3.0f %6.1f/n", fahr, celsius);
  21.     fahr = fahr + step;
  22.   }
  23.   return 0;
  24. }

 

1.8 变元—按值调用
  1. /* power: 求底的n次幂; n >=0;第2个版本*/
  2. int power(int baseint n)
  3. {
  4. int p;
  5. for ( n = 1; n > 0; --n )
  6. p = p * base;
  7. return p;
  8. }
1.9 字符数组
while (还有没有处理的行)
if (该行比已处理的最长的行还要长)
保存该行

保存该行的长度
打印最长的行
这一算法描述很清楚,很自然地把所要编写的程序分成了若干部分,分别用于读入新行、测试
读入的行、保存该行及控制这一过程。
由于分割得比较好,故可以像这样来编写程序。首先编写一个独立的函数g e t l i n e来读取输入
的下一行。我们想使这个函数在其他地方也能使用。g e t l i n e函数至少在读到文件末尾时要返回一
个信号,而更有用的设计是它能在读入文本行时返回该行的长度,而在遇到文件结束符时返回0。
由于0不是有效的行长度,因此是一个可以接受的标记文件结束的返回值。每一行至少要有一个
字符,只包含换行符的行的长度为1。
当发现某一个新读入的行比以前读入的最长的行还要长时,就要把该新行保存起来。这意
味着需要用第二个函数c o p y来把新行复制到一个安全的位置。
最后,需要用主函数m a i n来控制对g e t l i n e和c o p y这两个函数的调用。整个程序如下:
  1. #include <stdio.h>
  2. #define MAXLINE 1000 /* 最大输入行的大小*/
  3. int getline (char line[ ], int maxline );
  4. void copy ( char to[ ], char from [] );
  5. /* 打印最长的输入行*/
  6. main ( )
  7. {
  8. int len; /* 当前行长度*/
  9. int max; /* 至目前为止所发现的最长行的长度*/
  10. char line[MAXLINE]; /* 当前输入的行*/
  11. char longest[MAXLINE]; /* 用于保存最长的行*/
  12. max = 0;
  13. while ( ( len = getline (line, MAXLINE) ) > 0 )
  14. if (len > max) {
  15. max = len;
  16. copy ( longest, line );
  17. }
  18. if (max > 0) /* 有一行*/
  19. printf ("%s" , longest ) ;
  20. return 0 ;
  21. }
  22. /* getline:将一行读入s中并返回其长度*/
  23. int getline (char s [ ], int lim)
  24. {
  25. int c, i;
  26. for (i = 0; i < lim -1 && (c = getchar ( ) ) != EOF && c != '/n'; ++i )
  27. s[i] = c;
  28. if (c == '/n' ) {
  29. s[i] = c;
  30. ++i;
  31. }
  32. s[i] = '/0';
  33. return i;
  34. }
  35. /* copy:从from拷贝到to; 假定to足够大*/
  36. void copy ( char to [ ], char from [ ])
  37. {
  38. int i;
  39. i = 0;
  40. while ( ( to[ i ] = from [ i ]) != '/0')
  41. ++i;
  42. }
练习1 - 1 6 对用于打印最长行的程序的主程序m a i n进行修改,使之可以打印任意长度的输入
行的长度以及文本行中尽可能多的字符

Revise the main routine of the longest-line program so it will correctly print the length of arbitrarily long input lines, and as much as possible of the text.

  1. #include <stdio.h>
  2. #define MAXLINE 1000 /* maximum input line size */
  3. int getline(char line[], int maxline);
  4. void copy(char to[], char from[]);
  5. /* print longest input line */
  6. int main(void)
  7. {
  8.   int len;               /* current line length */
  9.   int max;               /* maximum length seen so far */
  10.   char line[MAXLINE];    /* current input line */
  11.   char longest[MAXLINE]; /* longest line saved here */
  12.   max = 0;
  13.   while((len = getline(line, MAXLINE)) > 0)
  14.   {
  15.     printf("%d: %s", len, line);
  16.     if(len > max)
  17.     {
  18.       max = len;
  19.       copy(longest, line);
  20.     }
  21.   }
  22.   if(max > 0)
  23.   {
  24.     printf("Longest is %d characters:/n%s", max, longest);
  25.   }
  26.   printf("/n");
  27.   return 0;
  28. }
  29. /* getline: read a line into s, return length */
  30. int getline(char s[], int lim)
  31. {
  32.   int c, i, j;
  33.   for(i = 0, j = 0; (c = getchar())!=EOF && c != '/n'; ++i)
  34.   {
  35.     if(i < lim - 1)
  36.     {
  37.       s[j++] = c;
  38.     }
  39.   }
  40.   if(c == '/n')
  41.   {
  42.     if(i <= lim - 1)
  43.     {
  44.       s[j++] = c;
  45.     }
  46.     ++i;
  47.   }
  48.   s[j] = '/0';
  49.   return i;
  50. }
  51. /* copy: copy 'from' into 'to'; assume 'to' is big enough */
  52. void copy(char to[], char from[])
  53. {
  54.   int i;
  55.   i = 0;
  56.   while((to[i] = from[i]) != '/0')
  57.   {
  58.     ++i;
  59.   }
  60. }
  61. Chris Sidi, however, was not convinced - he thought this answer was "too easy", so he checked with bwk, who agreed. Chris writes: "Looks like Mr. Kernighan meant for "main routine" in Exercise 1-16 to refer to function main(), saying your solution of modifying getline() is "too easy." :) (Though I think your solution shouldn't be removed from the Answers web site, just complimented with another one that only modifies main())" 
  62. Cue Mr "386sx", riding to the rescue on a white horse... 
  63. /* Exercise 1-16 */
  64. #include <stdio.h>
  65. #define MAXLINE 20
  66. int getline(char s[], int lim);
  67. void copy(char to[], char from[]);
  68. int main(void)
  69. {
  70.     char line[MAXLINE];
  71.     char longest[MAXLINE];
  72.     char temp[MAXLINE];
  73.     int len, max, prevmax, getmore;
  74.     
  75.     max = prevmax = getmore = 0;
  76.     while((len = getline(line, MAXLINE)) > 0)
  77.     {
  78.         if(line[len - 1] != '/n')
  79.         {
  80.             if(getmore == 0)
  81.                 copy(temp, line);
  82.             prevmax += len;
  83.             if(max < prevmax)
  84.                 max = prevmax;
  85.             getmore = 1;
  86.         }
  87.         else
  88.         {
  89.             if(getmore == 1)
  90.             {
  91.                 if(max < prevmax + len)
  92.                 {
  93.                     max = prevmax + len;
  94.                     copy(longest, temp);
  95.                     longest[MAXLINE - 2] = '/n';
  96.                 }
  97.                 getmore = 0;
  98.             }
  99.             
  100.             else if(max < len)
  101.             {
  102.                 max = len;
  103.                 copy(longest, line);
  104.             }
  105.             prevmax = 0;
  106.         }
  107.     }
  108.     if(max > 0)
  109.     {
  110.         printf("%s", longest);
  111.         printf("len = %d/n", max);
  112.     }
  113.     return 0;
  114. }
  115. int getline(char s[], int lim)
  116. {
  117.     int c, i;
  118.     for(i = 0;
  119.         i < lim - 1 && ((c = getchar()) != EOF && c != '/n');
  120.         ++i)
  121.         s[i] = c;
  122.     if(c == '/n')
  123.     {
  124.         s[i] = c;
  125.         ++i;
  126.     }
  127.     else if(c == EOF && i > 0)
  128.     {
  129.         /* gotta do something about no newline preceding EOF */
  130.         s[i] = '/n'
  131.         ++i;
  132.     }
  133.     s[i] = '/0';
  134.     return i;
  135. }
  136. void copy(char to[], char from[])
  137. {
  138.     int i;
  139.     i = 0;
  140.     while((to[i] = from[i]) != '/0')
  141.         ++i;
练习1 - 1 7 编写一个程序,把所有长度大于8 0个字符的输入行都打印出来。

Write a program to print all input lines that are longer than 80 characters.

  1. #include <stdio.h>
  2. #define MINLENGTH 81
  3. int readbuff(char *buffer) {
  4.     size_t i=0;
  5.     int c;
  6.     while (i < MINLENGTH) {
  7.         c = getchar();
  8.         if (c == EOF) return -1;
  9.         if (c == '/n'return 0;
  10.         buffer[i++] = c;
  11.     }
  12.     return 1;
  13. }
  14. int copyline(char *buffer) {
  15.     size_t i;
  16.     int c;
  17.     int status = 1;
  18.     for(i=0; i<MINLENGTH; i++)
  19.         putchar(buffer[i]);
  20.     while(status == 1) {
  21.         c = getchar();
  22.         if (c == EOF)
  23.             status = -1;
  24.         else if (c == '/n')
  25.             status = 0;
  26.         else
  27.             putchar(c);
  28.     }
  29.     putchar('/n');
  30.     return status;
  31. }
  32. int main(void) {
  33.     char buffer[MINLENGTH];
  34.     int status = 0;
  35.     while (status != -1) {
  36.         status = readbuff(buffer);
  37.         if (status == 1)
  38.             status = copyline(buffer);
  39.     }
  40.     return 0;
练习1-18 编写一个程序,把每个输入行中的尾部空格及制表符都删除掉,并删除空格行。

Write a program to remove all trailing blanks and tabs from each line of input, and to delete entirely blank lines.

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define MAXQUEUE 1001
  4. int advance(int pointer)
  5. {
  6.   if (pointer < MAXQUEUE - 1)
  7.     return pointer + 1;
  8.   else
  9.     return 0;
  10. }
  11. int main(void)
  12. {
  13.   char blank[MAXQUEUE];
  14.   int head, tail;
  15.   int nonspace;
  16.   int retval;
  17.   int c;
  18.   retval = nonspace = head = tail = 0;
  19.   while ((c = getchar()) != EOF) {
  20.     if (c == '/n') {
  21.       head = tail = 0;
  22.       if (nonspace)
  23.         putchar('/n');
  24.       nonspace = 0;
  25.     }
  26.     else if (c == ' ' || c == '/t') {
  27.       if (advance(head) == tail) {
  28.         putchar(blank[tail]);
  29.         tail = advance(tail);
  30.         nonspace = 1;
  31.         retval = EXIT_FAILURE;
  32.       }
  33.       blank[head] = c;
  34.       head = advance(head);
  35.     }
  36.     else {
  37.       while (head != tail) {
  38.         putchar(blank[tail]);
  39.         tail = advance(tail);
  40.       }
  41.       putchar(c);
  42.       nonspace = 1;
  43.     }
  44.   }
  45.   return retval;
  46. }
  47. #include <stdio.h>
  48. #include <stdlib.h>
  49. #define MAXQUEUE 1001
  50. int advance(int pointer)
  51. {
  52.   if (pointer < MAXQUEUE - 1)
  53.     return pointer + 1;
  54.   else
  55.     return 0;
  56. }
  57. int main(void)
  58. {
  59.   char blank[MAXQUEUE];
  60.   int head, tail;
  61.   int nonspace;
  62.   int retval;
  63.   int c;
  64.   int spaceJustPrinted; /*boolean: was the last character printed whitespace?*/
  65.   retval = spaceJustPrinted = nonspace = head = tail = 0;
  66.   while ((c = getchar()) != EOF) {
  67.     if (c == '/n') {
  68.       head = tail = 0;
  69.       if (spaceJustPrinted == 1) /*if some trailing whitespace was printed...*/
  70.         retval = EXIT_FAILURE;
  71.       if (nonspace) {
  72.         putchar('/n');
  73.         spaceJustPrinted = 0; /* this instruction isn't really necessary since
  74.                               spaceJustPrinted is only used to determine the
  75.                               return value, but we'll keep this boolean
  76.                               truthful */
  77.         nonspace = 0;  /* moved inside conditional just to save a needless
  78.                        assignment */
  79.       }
  80.     }
  81.     else if (c == ' ' || c == '/t') {
  82.       if (advance(head) == tail) {
  83.         putchar(blank[tail]); /* these whitespace chars being printed early
  84.                               are only a problem if they are trailing,
  85.                               which we'll check when we hit a /n or EOF */
  86.         spaceJustPrinted = 1;
  87.         tail = advance(tail);
  88.         nonspace = 1;
  89.       }
  90.       blank[head] = c;
  91.       head = advance(head);
  92.     }
  93.     else {
  94.       while (head != tail) {
  95.         putchar(blank[tail]);
  96.         tail = advance(tail);
  97.       }
  98.       putchar(c);
  99.       spaceJustPrinted = 0;
  100.       nonspace = 1;
  101.     }
  102.   }
  103.   /* if the last line wasn't ended with a newline before the EOF,
  104.   we'll need to figure out if trailing space was printed here */
  105.   if (spaceJustPrinted == 1) /*if some trailing whitespace was printed...*/ 
  106.     retval = EXIT_FAILURE;
  107.   return retval;

 

练习1-19 编写函数reverse ( s ),把字符串s颠倒过来。用它编写一个程序,一次把一个输
入行字符串颠倒过来。

Write a function reverse(s) that reverses the character string s . Use it to write a program that reverses its input a line at a time

 

  1. #include <stdio.h>
  2. #define MAX_LINE 1024
  3. void discardnewline(char s[])
  4. {
  5.   int i;
  6.   for(i = 0; s[i] != '/0'; i++)
  7.   {
  8.     if(s[i] == '/n')
  9.       s[i] = '/0';
  10.   }
  11. }
  12. int reverse(char s[])
  13. {
  14.   char ch;
  15.   int i, j;
  16.   for(j = 0; s[j] != '/0'; j++)
  17.   {
  18.   }
  19.   --j;
  20.   for(i = 0; i < j; i++)
  21.   {
  22.     ch   = s[i];
  23.     s[i] = s[j];
  24.     s[j] = ch;
  25.     --j;
  26.   }
  27.   return 0;
  28. }
  29. int getline(char s[], int lim)
  30. {
  31.   int c, i;
  32.   for(i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '/n'; ++i)
  33.   {
  34.     s[i] = c;
  35.   }
  36.   if(c == '/n')
  37.   {
  38.     s[i++] = c;
  39.   }
  40.   s[i] = '/0';
  41.   return i;
  42. }
  43. int main(void)
  44. {
  45.   char line[MAX_LINE];
  46.   while(getline(line, sizeof line) > 0)
  47.   {
  48.     discardnewline(line);
  49.     reverse(line);
  50.     printf("%s/n", line);
  51.   }
  52.   return 0;
  53. }

 

1.10 外部变量与作用域

  1. #include <stdio.h>
  2. #define MAXLINE 1000 /* 最大输入行的大小*/
  3. int max; /* 至目前为止所发现的最长行的长度*/
  4. char line[MAXLINE]; /* 当前输入的行*/
  5. char longest[MAXLINE]; /* 用于保存最长的行*/
  6. int getline (void );
  7. void copy ( void );
  8. /* 打印最长的输入行; 特别版本*/
  9. main ( )
  10. {
  11. int len;
  12. extern int max;
  13. extern char longest[ ];
  14. max = 0;
  15. while ( ( len = getline ( ) ) > 0 )
  16. if (len > max) {
  17. max = len;
  18. copy ( );
  19. }
  20. if (max > 0) /* 有一行*/
  21. printf ("%s" , longest ) ;
  22. return 0 ;
  23. }
  24. /* getline:特别版本*/
  25. int getline (void )
  26. {
  27. int c, i;
  28. extern char line[ ];
  29. for (i = 0; i < MAXLINE -1 && (c = getchar ( ) ) != EOF && c != '/n'; ++i )
  30. line[i] = c;
  31. if (c == '/n' ) {
  32. line[i] = c;
  33. ++i;
  34. }
  35. line[i] = '/0';
  36. return i;
  37. }
  38. /* copy:特别版本*/
  39. void copy ( void )
  40. {
  41. int i;
  42. extern char line[ ], longest[ ];
  43. i = 0;
  44. while ( ( longest[ i ] = line [ i ]) != '/0')
  45. ++i;
  46. }

 

练习1-20 编写程序d e t a b,将输入中的制表符替换成适当数目的空白符(使空白充满到下
一制表符停止位)。假定制表符停止位的位置是固定的,比如在每个n列的位置上。n应作成变量
或符号参数吗?
Write a program detab that replaces tabs in the input with the proper number of blanks to space to the next tab stop. Assume a fixed set of tab stops, say every n columns. Should n be a variable or a symbolic parameter?

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #define MAX_BUFFER   1024
  5. #define SPACE        ' '
  6. #define TAB          '/t'
  7. int CalculateNumberOfSpaces(int Offset, int TabSize)
  8. {
  9.    return TabSize - (Offset % TabSize);
  10. }
  11. /* K&R's getline() function from p29 */
  12. int getline(char s[], int lim)
  13. {
  14.   int c, i;
  15.   for(i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '/n'; ++i)
  16.     s[i] = c;
  17.   if(c == '/n')
  18.   {
  19.     s[i] = c;
  20.     ++i;
  21.   }
  22.   s[i] = '/0';
  23.   return i;
  24. }
  25. int main(void)
  26. {
  27.   char  Buffer[MAX_BUFFER];
  28.   int TabSize = 5; /* A good test value */
  29.   int i, j, k, l;
  30.   while(getline(Buffer, MAX_BUFFER) > 0)
  31.   {
  32.     for(i = 0, l = 0; Buffer[i] != '/0'; i++)
  33.     {
  34.       if(Buffer[i] == TAB)
  35.       {
  36.         j = CalculateNumberOfSpaces(l, TabSize);
  37.         for(k = 0; k < j; k++)
  38.         {
  39.           putchar(SPACE);
  40.           l++;
  41.         }
  42.       }
  43.       else
  44.       {
  45.         putchar(Buffer[i]);
  46.         l++;
  47.       }
  48.     }
  49.   }
  50.   return 0;
  51. }
  52. In answer to the question about whether n should be variable or symbolic, I'm tempted to offer the answer 'yes'. :-) Of course, it should be variable, to allow for modification of the value at runtime, for example via a command line argument, without requiring recompilation. 

 

练习1-21 编写程序e n t a b,将空白符串用可达到相同空白的最小数目的制表符和空白符来
替换。使用与d e t a b程序相同的制表停止位。请问,当一个制表符与一个空白符都可以到达制表
符停止位时,选用哪一个比较好?

Write a program entab that replaces strings of blanks with the minimum number of tabs and blanks to achieve the same spacing. Use the same stops as for detab . When either a tab or a single blank would suffice to reach a tab stop, which should be given preference?

  1. #include <stdio.h>
  2. #define MAXLINE 1000 /* max input line size */
  3. #define TAB2SPACE 4 /* 4 spaces to a tab */
  4. char line[MAXLINE]; /*current input line*/
  5. int getline(void);  /* taken from the KnR book. */
  6. int
  7. main()
  8. {
  9.   int i,t;
  10.   int spacecount,len;
  11.   while (( len = getline()) > 0 )
  12.     {
  13.       spacecount = 0;
  14.       for( i=0; i < len; i++)
  15.         {
  16.           if(line[i] == ' ')
  17.             spacecount++; /* increment counter for each space */
  18.           if(line[i] != ' ')
  19.             spacecount = 0; /* reset counter */
  20.           if(spacecount == TAB2SPACE) /* Now we have enough spaces
  21.                                      ** to replace them with a tab
  22.                                      */
  23.             {
  24.               /* Because we are removing 4 spaces and
  25.               ** replacing them with 1 tab we move back 
  26.               ** three chars and replace the ' ' with a /t
  27.               */
  28.               i -= 3; /* same as "i = i - 3" */
  29.               len -= 3;
  30.               line[i] = '/t';
  31.               /* Now move all the char's to the right into the
  32.               ** places we have removed.
  33.               */
  34.               for(t=i+1;t<len;t++)
  35.                line[t]=line[t+3];
  36.               /* Now set the counter back to zero and move the 
  37.               ** end of line back 3 spaces
  38.               */
  39.               spacecount = 0;
  40.               line[len] = '/0'
  41.             }
  42.         }
  43.       printf("%s", line);
  44.     }
  45.   return 0;
  46. }
  47. /* getline: specialized version */
  48. int getline(void)
  49. {
  50.   int c, i;
  51.   extern char line[];
  52.   
  53.   for ( i=0;i<MAXLINE-1 && ( c=getchar()) != EOF && c != '/n'; ++i)
  54.     line[i] = c;
  55.   if(c == '/n'
  56.     {
  57.       line[i] = c;
  58.       ++i;
  59.     }
  60.   line[i] = '/0';
  61.   return i;
  62. }
  63. Stefan Farfeleder's Cat 1 solution: 
  64. /* 1-21.c */
  65. #include <stdio.h>
  66. #define TABSTOP 4
  67. int main(void)
  68. {
  69.     size_t spaces = 0;
  70.     int ch;
  71.     size_t x = 0;               /* position in the line */
  72.     size_t tabstop = TABSTOP;   /* get this from the command-line 
  73.                                  * if you want to */
  74.     while ((ch = getchar()) != EOF)
  75.     {
  76.         if (ch == ' ')
  77.         {
  78.             spaces++;
  79.         }
  80.         else if (spaces == 0) /* no space, just printing */
  81.         {
  82.             putchar(ch);
  83.             x++;
  84.         }
  85.         else if (spaces == 1) /* just one space, never print a tab */
  86.         {
  87.             putchar(' ');
  88.             putchar(ch);
  89.             x += 2;
  90.             spaces = 0;
  91.         }
  92.         else
  93.         {
  94.             while (x / tabstop != (x + spaces) / tabstop) 
  95.                 /* are the spaces reaching behind the next tabstop ? */
  96.             {
  97.                 putchar('/t');
  98.                 x++;
  99.                 spaces--;
  100.                 while (x % tabstop != 0)
  101.                 {
  102.                     x++;
  103.                     spaces--;
  104.                 }
  105.             }
  106.             while (spaces > 0) /* the remaining ones are real space */
  107.             {
  108.                 putchar(' ');
  109.                 x++;
  110.                 spaces--;
  111.             }
  112.             putchar(ch); /* now print the non-space char */
  113.             x++;
  114.         }
  115.         if (ch == '/n')
  116.         {
  117.             x = 0; /* reset line position */
  118.         }
  119.     }
  120.     return 0;

练习1-22 编写一个程序,用于把较长的输入行“折”成短一些的两行或多行,折行的位
置在输入的第n列之前的最后一个非空白字符之后。要保证程序具备一定的智能,能应付输入行
很长以及在指定的列前没有空白符或制表符时的情况。

Write a program to "fold" long input lines into two or more shorter lines after the last non-blank character that occurs before the n -th column of input. Make sure your program does something intelligent with very long lines, and if there are no blanks or tabs before the specified column.

 

  1. #include <stdio.h>
  2. #define MAXLINE 1000 /* max input line size */
  3.     
  4. char line[MAXLINE]; /*current input line*/
  5. int getline(void);  /* taken from the KnR book. */
  6. int
  7. main()
  8. {
  9.   int t,len;
  10.   int location,spaceholder;
  11.   const int FOLDLENGTH=70; /* The max length of a line */
  12.   while (( len = getline()) > 0 )
  13.     {
  14.       if( len < FOLDLENGTH )
  15.         {
  16.         }
  17.       else
  18.         {
  19.         /* if this is an extra long line then we 
  20.         ** loop through it replacing a space nearest
  21.         ** to the foldarea with a newline.
  22.         */
  23.           t = 0;
  24.           location = 0;
  25.           while(t<len)
  26.             {
  27.               if(line[t] == ' ')
  28.                spaceholder = t;
  29.               if(location==FOLDLENGTH)
  30.                {
  31.                  line[spaceholder] = '/n';
  32.                  location = 0;
  33.                }
  34.               location++;
  35.               t++;
  36.             }
  37.         }
  38.       printf ( "%s", line);
  39.     }
  40.   return 0;
  41. }
  42. /* getline: specialized version */
  43. int getline(void)
  44. {
  45.   int c, i;
  46.   extern char line[];
  47.   
  48.   for ( i=0;i<MAXLINE-1 && ( c=getchar()) != EOF && c != '/n'; ++i)
  49.     line[i] = c;
  50.   if(c == '/n'
  51.     {
  52.       line[i] = c;
  53.       ++i;
  54.     }
  55.   line[i] = '/0';
  56.   return i;

 

练习1-23 编写一个用于把C程序中所有注解都删除掉的程序。不要忘记处理好带引号的字
符串与字符常量。在C程序中注解不允许嵌套。

Write a program to remove all comments from a C program. Don't forget to handle quoted strings and character constants properly. C comments do not nest.

 

  1. This was the first exercise to be posted as a fun "competition" on comp.lang.c, on 1 June 2000. As a result, there was a small flurry of submissions. Not all of them are completely working solutions. See the very end of this page for a test program which breaks most of them. :-) 
  2. Category 0 Solutions 
  3. From Rick Dearman 
  4. Now handles "/* comment in string */" correctly, but does not remove the comment from 
  5.   return /* comment inside return statement */ 0;
  6. /******************************************************
  7. "Write a program to remove all comments from a C program. 
  8. Don't forget to handle quoted strings and character 
  9. constants properly. C comments do not nest."
  10. Author: Rick Dearman (rick@ricken.demon.co.uk) 
  11. ******************************************************/
  12. #include <stdio.h>
  13. #define MAXLINE 1000 /* max input line size */
  14. char line[MAXLINE]; /*current input line*/
  15. int getline(void);  /* taken from the KnR book. */
  16. int
  17. main()
  18. {
  19.   int in_comment,len;
  20.   int in_quote;
  21.   int t;
  22.   
  23.   in_comment = in_quote = t = 0;
  24.   while ((len = getline()) > 0 )
  25.     {
  26.       t=0;
  27.       while(t < len)
  28.         {
  29.           if( line[t] == '"')
  30.                in_quote = 1;
  31.           if( ! in_quote )
  32.           {
  33.                if( line[t] == '/' && line[t+1] == '*')
  34.                {
  35.                        t=t+2;
  36.                        in_comment = 1;
  37.                }
  38.                if( line[t] == '*' && line[t+1] == '/')
  39.                {
  40.                        t=t+2;
  41.                        in_comment = 0;
  42.                }
  43.                if(in_comment == 1)
  44.                 {
  45.                        t++;
  46.                }
  47.                else
  48.                {
  49.                        printf ("%c", line[t]);
  50.                        t++;
  51.                }
  52.           } 
  53.           else
  54.           {
  55.               printf ("%c", line[t]);
  56.               t++;
  57.           }
  58.         }
  59.     }
  60.   return 0;
  61. }
  62. /* getline: specialized version */
  63. int getline(void)
  64. {
  65.   int c, i;
  66.   extern char line[];
  67.   
  68.   for ( i=0;i<MAXLINE-1 && ( c=getchar()) != EOF && c != '/n'; ++i)
  69.     line[i] = c;
  70.   if(c == '/n'
  71.     {
  72.       line[i] = c;
  73.       ++i;
  74.     }
  75.   line[i] = '/0';
  76.   return i;
  77. }
  78. From Ben Pfaff 
  79. This version is a bugfix for the code var/'/2' 
  80. /* K&R2 1-23: Write a program to remove all comments from a C program.
  81.    Don't forget to handle quoted strings and character constants
  82.    properly.  C comments do not nest.
  83.    This solution does not deal with other special cases, such as
  84.    trigraphs, line continuation with /, or <> quoting on #include,
  85.    since these aren't mentioned up 'til then in K&R2.  Perhaps this is
  86.    cheating.
  87.    Note that this program contains both comments and quoted strings of
  88.    text that looks like comments, so running it on itself is a
  89.    reasonable test.  It also contains examples of a comment that ends
  90.    in a star and a comment preceded by a slash.  Note that the latter
  91.    will break C99 compilers and C89 compilers with // comment
  92.    extensions.
  93.    Interface: The C source file is read from stdin and the
  94.    comment-less output is written to stdout. **/
  95. #include <stdio.h>
  96. int
  97. main(void)
  98. {
  99. #define PROGRAM 0
  100. #define SLASH 1
  101. #define COMMENT 2
  102. #define STAR 3
  103. #define QUOTE 4
  104. #define LITERAL 5
  105.     /* State machine's current state, one of the above values. */
  106.     int state;
  107.     /* If state == QUOTE, then ' or ".  Otherwise, undefined. */
  108.     int quote;
  109.     /* Input character. */
  110.     int c;
  111.     state = PROGRAM;
  112.     while ((c = getchar()) != EOF) {
  113.         /* The following cases are in guesstimated order from most common
  114.            to least common. */
  115.         if (state == PROGRAM || state == SLASH) {
  116.             if (state == SLASH) {
  117.                 /* Program text following a slash. */
  118.                 if (c == '*')
  119.                     state = COMMENT;
  120.                 else {
  121.                     putchar('/');
  122.                     state = PROGRAM;
  123.                 }
  124.             }
  125.             if (state == PROGRAM) {
  126.                 /* Program text. */
  127.                 if (c == '/'' || c == '"') {
  128.                     quote = c;
  129.                     state = QUOTE;
  130.                     putchar(c);
  131.                 }
  132.                 else if (c == "/*"[0])
  133.                     state = SLASH;
  134.                 else
  135.                     putchar(c);
  136.             }
  137.         }
  138.         else if (state == COMMENT) {
  139.             /* Comment. */
  140.             if (c == "/*"[1])
  141.                 state = STAR;
  142.         }
  143.         else if (state == QUOTE) {
  144.             /* Within quoted string or character constant. */
  145.             putchar(c);
  146.             if (c == '//')
  147.                 state = LITERAL;
  148.             else if (c == quote)
  149.                 state = PROGRAM;
  150.         }
  151.         else if (state == SLASH) {
  152.         }
  153.         else if (state == STAR) {
  154.             /* Comment following a star. */
  155.             if (c == '/')
  156.                 state = PROGRAM;
  157.             else if (c != '*')
  158.                 state = COMMENT;
  159.         }
  160.         else /* state == LITERAL */ {
  161.             /* Within quoted string or character constant, following /. */
  162.             putchar(c);
  163.             state = QUOTE;
  164.         }
  165.     }
  166.     if (state == SLASH)
  167.         putchar('/' //**/
  168.                 1);
  169.     return 0;
  170. }
  171. /* 
  172.    Local variables:
  173.    compile-command: "checkergcc -W -Wall -ansi -pedantic knr123-0.c -o knr123-0"
  174.    End: 
  175. */
  176. From Lew Pitcher 
  177. /* Lew Pitcher <lpitcher@yesic.com> */
  178. /*/
  179. ** derem - remove C comments
  180. **
  181. ** (attempt to solve K&R Exercise 1-22)
  182. **
  183. ** As I only have v1 copy of K&R, I cannot
  184. ** be sure what is covered in K&R ANSI chapter 1.
  185. ** So, I restrict myself to the components covered
  186. ** in K&R v1 chapter 1, but modified for requisite ANSI
  187. ** features (int main() and return value).
  188. **
  189. ** Components covered in v1 K&R chapter 1 include:
  190. **  while (), for (), if () else
  191. **  getchar(), putchar(), EOF
  192. **  character constants, character escapes
  193. **  strings
  194. **  array subscripting
  195. **
  196. ** Not directly covered are
  197. **  string subscripting ( "/*"[0] )
  198. **  initializers ( int state = PROGRAM; )
  199. **/
  200. /*/*/
  201. #include <stdio.h>
  202. #define PROGRAM        0
  203. #define BEGIN_COMMENT  1
  204. #define COMMENT        2
  205. #define END_COMMENT    3
  206. #define QUOTE          4
  207. int main(void)
  208. {
  209.         int this_char, quote_char;
  210.         int state;
  211.         state = PROGRAM;
  212.         while ((this_char = getchar()) != EOF)
  213.         {
  214.                if (state == PROGRAM)
  215.                {
  216.                        if (this_char == '/')
  217.                                state = BEGIN_COMMENT;
  218.                        else if ((this_char == '"') || (this_char == '/''))
  219.                        {
  220.                                state = QUOTE;
  221.                                putchar(quote_char = this_char);
  222.                        }
  223.                        else    putchar(this_char);
  224.                }
  225.                else if (state == BEGIN_COMMENT)
  226.                {
  227.                        if (this_char == '*')
  228.                                state = COMMENT;
  229.                        else
  230.                        {
  231.                                putchar('/'); /* for the '/' of the comment */
  232.                                if (this_char != '/')
  233.                                {
  234.                                       state = PROGRAM;
  235.                                       putchar(this_char);
  236.                                }
  237.                                else    state = COMMENT;       /* stuttered */
  238.                        }
  239.                }
  240.                else if (state == QUOTE)
  241.                {
  242.                        putchar(this_char);
  243.                        if (this_char == '//')
  244.                                putchar(getchar());    /* escaped character */
  245.                        else if (this_char == quote_char)
  246.                                state = PROGRAM;
  247.                }
  248.                else if (state == COMMENT)
  249.                {
  250.                        if (this_char == '*')
  251.                                state = END_COMMENT;
  252.                }
  253.                else if (state == END_COMMENT)
  254.                {
  255.                        if (this_char == '/')
  256.                                state = PROGRAM;
  257.                        else if (this_char != '*')     /* stuttered */
  258.                                state = COMMENT;
  259.                }
  260.         }
  261.         return 0;
  262. }
  263. From Gregory Pietsch 
  264. /* Gregory Pietsch <gkp1@flash.net> */
  265. #include <stdio.h>
  266. char p[] =
  267. "0/!10/"040/'050.001/011*!21/"/41/'/51./02*!32.!23/ "
  268. "03*!33.!24/"004//064.045/'005//075.056.047.05";
  269. int main(){int c,i,d;char s,n;s='0';while((c=getchar())
  270. !=EOF){d=0;for(i=0;p[i]!='/0'&&d==0;i=i+4){if(p[i]==s&
  271. (p[i+1]==c||p[i+1]=='.')){if(p[i+2]=='0')putchar(c);else
  272. if(p[i+2]=='/'){putchar('/');putchar(c);}else if(p[i+2]
  273. ==' ')putchar(' ');n=p[i+3];d=1;}}s=n;}return 0;}
  274. Category 1 Solutions 
  275. From Ben Pfaff (again) 
  276. This version has the var/'/2' bug fix. 
  277. /* K&R2 1-23: Write a program to remove all comments from a C program.
  278.    Don't forget to handle quoted strings and character constants
  279.    properly.  C comments do not nest.
  280.    This solution does not deal with other special cases, such as
  281.    trigraphs, line continuation with /, or <> quoting on #include,
  282.    since these aren't mentioned up 'til then in K&R2.  Perhaps this is
  283.    cheating.
  284.    Note that this program contains both comments and quoted strings of
  285.    text that looks like comments, so running it on itself is a
  286.    reasonable test.  It also contains examples of a comment that ends
  287.    in a star and a comment preceded by a slash.  Note that the latter
  288.    will break C99 compilers and C89 compilers with // comment
  289.    extensions.
  290.    Interface: The C source file is read from stdin and the
  291.    comment-less output is written to stdout. **/
  292. #include <stdio.h>
  293. int
  294. main(void)
  295. {
  296.     /* State machine's current state. */
  297.     enum {
  298.         PROGRAM,
  299.         SLASH,
  300.         COMMENT,
  301.         STAR,
  302.         QUOTE,
  303.         LITERAL
  304.     } state;
  305.     /* If state == QUOTE, then ' or ".  Otherwise, undefined. */
  306.     int quote;
  307.     state = PROGRAM;
  308.     for (;;) {
  309.         int c = getchar();
  310.         if (c == EOF) {
  311.             if (state == SLASH)
  312.                 putchar('/' //**/
  313.                         1 / 1 /'/1');
  314.             break;
  315.         }
  316.         switch (state) {
  317.         case SLASH:
  318.             /* Program text following a slash. */
  319.             if (c == "/*"[1]) {
  320.                 state = COMMENT;
  321.                 break;
  322.             }
  323.             putchar('/');
  324.             state = PROGRAM;
  325.             /* Fall through. */
  326.         case PROGRAM:
  327.             /* Program text. */
  328.             if (c == '/'' || c == '"') {
  329.                 quote = c;
  330.                 state = QUOTE;
  331.                 putchar(c);
  332.             }
  333.             else if (c == "/*"[0])
  334.                 state = SLASH;
  335.             else
  336.                 putchar(c);
  337.             break;
  338.         case COMMENT:
  339.             /* Comment. */
  340.             if (c == '*')
  341.                 state = STAR;
  342.             break;
  343.         case STAR:
  344.             /* Comment following a star. */
  345.             if (c == '/')
  346.                 state = PROGRAM;
  347.             else if (c != '*') {
  348.                 state = COMMENT;
  349.                 putchar (' ');
  350.             }
  351.             break;
  352.         case QUOTE:
  353.             /* Within quoted string or character constant. */
  354.             putchar(c);
  355.             if (c == '//')
  356.                 state = LITERAL;
  357.             else if (c == quote)
  358.                 state = PROGRAM;
  359.             break;
  360.         case LITERAL:
  361.             /* Within quoted string or character constant, following /. */
  362.             putchar(c);
  363.             state = QUOTE;
  364.             break;
  365.         default:
  366.             abort();
  367.         }
  368.     }
  369.     return 0;
  370. }
  371. /* 
  372.    Local variables:
  373.    compile-command: "checkergcc -W -Wall -ansi -pedantic knr123.c -o knr123"
  374.    End: 
  375. */
  376. From Chris Torek 
  377. /* torek@elf.bsdi.com (Chris Torek) */
  378. /*
  379. "Write a program to remove all comments from a C program. Don't forget
  380. to handle quoted strings and character constants properly. C comments do
  381. not nest."
  382. Well, what the heck.  I mailed this a day or two ago, but here is
  383. the posted version.  I modified the problem a bit: it removes
  384. comments from full ANSI C89 or C99 programs, handling trigraphs
  385. and /-newline sequences.  It attempts to preserve any trigraphs in
  386. the output, even while examining them in the "C code" as their
  387. translated characters.  (I am not sure why I bothered doing all of
  388. them, when only ??/ matters here.)  It keeps output line numbers in
  389. sync with input line numbers, so that if the output is compiled,
  390. any error messages will refer back to the proper input source line.
  391. Lightly tested.
  392. */
  393. #include <assert.h>
  394. #include <stdio.h>
  395. #include <stdlib.h>
  396. #include <string.h>
  397. /*
  398.  * This flag controls whether we do trigraph processing.
  399.  */
  400. int     trigraphs = 1;
  401. /*
  402.  * This flag controls whether a comment becomes "whitespace" (ANSI C)
  403.  * or "nothing at all" (some pre-ANSI K&R C compilers).
  404.  */
  405. int     whitespace = 1;
  406. /*
  407.  * This flag controls whether we do C89 or C99.  (C99 also handles C++.)
  408.  */
  409. int     c99;
  410. /*
  411.  * These are global so that options() can get at them, and for later
  412.  * error messages if needed.
  413.  */
  414. const char *inname, *outname;
  415. int options(const char *, char **);
  416. void usage(void);
  417. void    process(FILE *, FILE *);
  418. #ifdef __GNUC__
  419. void    panic(const char *) __attribute__((noreturn));
  420. #else
  421. void    panic(const char *);
  422. #endif
  423. int main(int argc, char **argv) {
  424.         int i;
  425.         FILE *in, *out;
  426.         for (i = 1; i < argc; i++) {
  427.                if (argv[i][0] == '-')
  428.                        i += options(argv[i] + 1, argv + i + 1);
  429.                else if (inname == NULL)
  430.                        inname = argv[i];
  431.                else
  432.                        usage();
  433.         }
  434.         if (inname != NULL) {
  435.                if ((in = fopen(inname, "r")) == NULL) {
  436.                        fprintf(stderr, "cannot open %s for reading/n", inname);
  437.                        exit(EXIT_FAILURE);
  438.                }
  439.         } else {
  440.                inname = "stdin";
  441.                in = stdin;
  442.         }
  443.         if (outname != NULL) {
  444.                if ((out = fopen(outname, "w")) == NULL) {
  445.                        fprintf(stderr, "cannot open %s for writing/n",
  446.                            outname);
  447.                        exit(EXIT_FAILURE);
  448.                }
  449.         } else {
  450.                outname = "stdout";
  451.                out = stdout;
  452.         }
  453.         process(inout);
  454.         fclose(in);
  455.         fclose(out);
  456.         exit(EXIT_SUCCESS);
  457. }
  458. /*
  459.  * This scans for -o type options.  Options that have an argument
  460.  * can either take it immediately or as a subsequent argument (e.g.,
  461.  * -ofoo means the same thing as -o foo).  We return 0 for "handled
  462.  * them normally", 1 for "handled them normally but needed more
  463.  * arguments".
  464.  *
  465.  * Currently this function is more powerful than really needed, but
  466.  * if we ever decide to have more arguments...
  467.  */
  468. int options(const char *afterdash, char **moreargs) {
  469.         int nmore = 0, c;
  470.         while ((c = *afterdash++) != '/0') {
  471.                if (c == 'o') {
  472.                        if (*afterdash) {
  473.                                outname = afterdash;
  474.                                afterdash = "";
  475.                        } else if (moreargs[nmore] != NULL)
  476.                                outname = moreargs[nmore++];
  477.                        else
  478.                                usage();
  479.                } else if (c == 't')
  480.                        trigraphs = 0;
  481.                else if (c == 'w')
  482.                        whitespace = 0;
  483.                else if (c == '9')
  484.                        c99 = 1;
  485.                else
  486.                        usage();
  487.         }
  488.         return nmore;
  489. }
  490. void usage(void) {
  491.         fprintf(stderr, "usage: uncomment [-9tw] [-o outfile] [infile]/n");
  492.         exit(EXIT_FAILURE);    /* ??? */
  493. }
  494. /*
  495.  * States, level 0:
  496.  *      normal
  497.  *      trigraph processing: Q1 Q2 (for ??x)
  498.  *
  499.  * States, level 1:
  500.  *      backslash-newline processing: BACK (seen /, may consume NL)
  501.  *
  502.  * States, level 2:
  503.  *      normal
  504.  *      character constant: CC (seen '), CCBACK (seen / inside CC)
  505.  *      string constant: SC, SCBACK
  506.  *      comment: SLASH, COMM, COMMSTAR (for /, in-comment, & seen-star)
  507.  *      C99: SLASHSLASH
  508.  */
  509. enum l0state {
  510.         L0_NORMAL,
  511.         L0_Q1, L0_Q2
  512. };
  513. enum l1state {
  514.         L1_NORMAL,
  515.         L1_BACK
  516. };
  517. enum l2state {
  518.         L2_NORMAL,
  519.         L2_CC, L2_CCBACK,
  520.         L2_SC, L2_SCBACK,
  521.         L2_SLASH, L2_COMM, L2_COMMSTAR,
  522.         L2_SLASHSLASH
  523. };
  524. struct state {
  525.         FILE *in;
  526.         enum l0state l0state;
  527.         int npushback;
  528.         char pushback[4];
  529.         char pushorig[4];      /* nonzero => trigraph pushback */
  530.         int lastgetc;
  531.         int lineno;
  532. };
  533. /*
  534.  * Set up "initial" state.
  535.  */
  536. static void state0(struct state *sp, FILE *in) {
  537.         sp->in = in;
  538.         sp->l0state = L0_NORMAL;
  539.         sp->npushback = 0;
  540.         sp->lastgetc = 0;
  541.         sp->lineno = 1;
  542. }
  543. static void pushback(struct state *sp, int c, char origc) {
  544.         assert(sp->npushback < sizeof sp->pushback);
  545.         sp->pushback[sp->npushback] = c;
  546.         sp->pushorig[sp->npushback++] = origc;
  547. }
  548. /*
  549.  * Get a character, doing trigraph processing.  Set *origc to 0 for normal
  550.  * characters, or the actual input character pre-trigraph-mapping
  551.  * for trigraph input.
  552.  *
  553.  * As a side effect, this can wind up getting up to 3 characters, maybe
  554.  * stuffing two of them into the pushback buffer sp->buf[].  It also bumps
  555.  * sp->lineno when a previously-read newline has been passed over.
  556.  */
  557. static int getl0char(struct state *sp, char *origc) {
  558.         int c, newc;
  559.         enum l0state state;
  560.         state = sp->l0state;
  561.         *origc = 0;
  562.         while ((c = getc(sp->in)) != EOF) {
  563.                if (sp->lastgetc == '/n')
  564.                        sp->lineno++;
  565.                sp->lastgetc = c;
  566.                switch (state) {
  567.                case L0_NORMAL:
  568.                        /* ? => get another character; otherwise we are ok */
  569.                        if (c == '?') {
  570.                                state = L0_Q1;
  571.                                continue;
  572.                        }
  573.                        assert(sp->l0state == L0_NORMAL);
  574.                        return c;
  575.                case L0_Q1:
  576.                        /* ?? => get another character */
  577.                        if (c == '?') {
  578.                                state = L0_Q2;
  579.                                continue;
  580.                        }
  581.                        /* ?X => return ?, look at X later */
  582.                        pushback(sp, c, 0);
  583.                        sp->l0state = L0_NORMAL;
  584.                        return '?';
  585.                case L0_Q2:
  586.                        /*
  587.                         * ??X, where X is trigraph => map
  588.                         * ??X, where X is non-trigraph => tricky
  589.                         * ??? => also tricky
  590.                         */
  591.                        switch (c) {
  592.                        case '=':
  593.                                newc = '#';
  594.                                break;
  595.                        case '(':
  596.                                newc = '[';
  597.                                break;
  598.                        case '/':
  599.                                newc = '//';
  600.                                break;
  601.                        case ')':
  602.                                newc = ']';
  603.                                break;
  604.                        case '/'':
  605.                                newc = '^';
  606.                                break;
  607.                        case '<':
  608.                                newc = '{';
  609.                                break;
  610.                        case '!':
  611.                                newc = '|';
  612.                                break;
  613.                        case '>':
  614.                                newc = '}';
  615.                                break;
  616.                        case '?':
  617.                                /*
  618.                                 * This one is slightly tricky.  Three '?'s
  619.                                 * mean that the '?' we read two characters
  620.                                 * ago gets returned, and the two remaining
  621.                                 * '?'s leave us in Q2 state.
  622.                                 */
  623.                                sp->l0state = L0_Q2;
  624.                                return '?';
  625.                        default:
  626.                                /*
  627.                                 * This one returns the first ?, leaves
  628.                                 * the second ? to be re-examined, and
  629.                                 * leaves the last character to be re-examined.
  630.                                 * In any case we are back in "normal" state.
  631.                                 */
  632.                                pushback(sp, c, 0);
  633.                                pushback(sp, '?', 0);
  634.                                sp->l0state = L0_NORMAL;
  635.                                return '?';
  636.                        }
  637.                        /* mapped a trigraph char -- return new char */
  638.                        *origc = c;
  639.                        sp->l0state = L0_NORMAL;
  640.                        return newc;
  641.                default:
  642.                        panic("getl0char state");
  643.                }
  644.         }
  645.         sp->lastgetc = EOF;
  646.         return EOF;
  647. }
  648. void warn(struct state *, const char *);
  649. void process(FILE *in, FILE *out) {
  650.         enum l1state l1state = L1_NORMAL;
  651.         enum l2state l2state = L2_NORMAL;
  652.         int c, pendnls;
  653.         char origc, backc;
  654.         struct state state;
  655.         state0(&state, in);
  656.         pendnls = 0;
  657.         backc = 0;             /* defeat gcc warning */
  658.         /*
  659.          * Slight sort-of-bug: files ending in / cause two "final" getc()s.
  660.          */
  661.         do {
  662.                if (state.npushback) {
  663.                        c = state.pushback[--state.npushback];
  664.                        origc = state.pushorig[state.npushback];
  665.                } else if (trigraphs) {
  666.                        c = getl0char(&state, &origc);
  667.                } else {
  668.                        c = getc(in);
  669.                        origc = 0;
  670.                        if (state.lastgetc == '/n')
  671.                                state.lineno++;
  672.                        state.lastgetc = c;
  673.                }
  674.                /*
  675.                 * Do backslash-newline processing.
  676.                 */
  677.                switch (l1state) {
  678.                case L1_NORMAL:
  679.                        if (c == '//') {
  680.                                l1state = L1_BACK;
  681.                                backc = origc;
  682.                                continue;
  683.                        }
  684.                        break;
  685.                case L1_BACK:
  686.                        /*
  687.                         * If backc is nonzero here, the backslash that
  688.                         * got us into this state was spelled ??/ --
  689.                         * if we eat a newline (and hence the backslash),
  690.                         * we forget that the eaten newline was spelled
  691.                         * this way.  This is sort of a bug, but so it goes.
  692.                         */
  693.                        l1state = L1_NORMAL;
  694.                        if (c == '/n') {
  695.                                pendnls++;
  696.                                continue;
  697.                        }
  698.                        if (c != EOF)
  699.                                pushback(&state, c, origc);
  700.                        c = '//';
  701.                        origc = backc;
  702.                        break;
  703.                default:
  704.                        panic("bad l1state");
  705.                }
  706.                /*
  707.                 * Now ready to do "C proper" processing.
  708.                 */
  709. #define SYNCLINES()    while (pendnls) putc('/n', out), pendnls--
  710. #define OUTPUT(ch, tri) ((tri) ? fprintf(out, "??%c", tri) : putc(ch, out))
  711. #define COPY()         OUTPUT(c, origc)
  712.                switch (l2state) {
  713.                case L2_NORMAL:
  714.                        switch (c) {
  715.                        case '/'':
  716.                                l2state = L2_CC;
  717.                                break;
  718.                        case '"':
  719.                                l2state = L2_SC;
  720.                                break;
  721.                        case '/':
  722.                                l2state = L2_SLASH;
  723.                                continue;
  724.                        default:
  725.                                break;
  726.                        }
  727.                        SYNCLINES();
  728.                        if (c != EOF)
  729.                                COPY();
  730.                        break;
  731.                case L2_CC:
  732.                        switch (c) {
  733.                        case EOF:
  734.                                warn(&state, "EOF in character constant");
  735.                                break;
  736.                        case '/n':
  737.                                warn(&state, "newline in character constant");
  738.                                break;
  739.                        case '//':
  740.                                l2state = L2_CCBACK;
  741.                                break;
  742.                        case '/'':
  743.                                l2state = L2_NORMAL;
  744.                                break;
  745.                        default:
  746.                                break;
  747.                        }
  748.                        if (c != EOF)
  749.                                COPY();
  750.                        break;
  751.                case L2_CCBACK:
  752.                        switch (c) {
  753.                        case EOF:
  754.                                warn(&state, "EOF in character constant");
  755.                                break;
  756.                        case '/n':
  757.                                warn(&state, "newline in character constant");
  758.                                break;
  759.                        default:
  760.                                break;
  761.                        }
  762.                        l2state = L2_CC;
  763.                        if (c != EOF)
  764.                                COPY();
  765.                        break;
  766.                case L2_SC:    /* much like CC */
  767.                        switch (c) {
  768.                        case EOF:
  769.                                warn(&state, "EOF in string constant");
  770.                                break;
  771.                        case '/n':
  772.                                warn(&state, "newline in string constant");
  773.                                break;
  774.                        case '//':
  775.                                l2state = L2_SCBACK;
  776.                                break;
  777.                        case '"':
  778.                                l2state = L2_NORMAL;
  779.                                break;
  780.                        default:
  781.                                break;
  782.                        }
  783.                        if (c != EOF)
  784.                                COPY();
  785.                        break;
  786.                case L2_SCBACK:
  787.                        switch (c) {
  788.                        case EOF:
  789.                                warn(&state, "EOF in string constant");
  790.                                break;
  791.                        case '/n':
  792.                                warn(&state, "newline in string constant");
  793.                                break;
  794.                        default:
  795.                                break;
  796.                        }
  797.                        l2state = L2_SC;
  798.                        if (c != EOF)
  799.                                COPY();
  800.                        break;
  801.                case L2_SLASH:
  802.                        if (c == '*')
  803.                                l2state = L2_COMM;
  804.                        else if (c99 && c == '/')
  805.                                l2state = L2_SLASHSLASH;
  806.                        else {
  807.                                SYNCLINES();
  808.                                OUTPUT('/', 0);
  809.                                if (c != '/') {
  810.                                       if (c != EOF)
  811.                                               COPY();
  812.                                       l2state = L2_NORMAL;
  813.                                }
  814.                        }
  815.                        break;
  816.                case L2_COMM:
  817.                        switch (c) {
  818.                        case '*':
  819.                                l2state = L2_COMMSTAR;
  820.                                break;
  821.                        case '/n':
  822.                                pendnls++;
  823.                                break;
  824.                        case EOF:
  825.                                warn(&state, "EOF inside comment");
  826.                                break;
  827.                        }
  828.                        break;
  829.                case L2_COMMSTAR:
  830.                        switch (c) {
  831.                        case '/':
  832.                                l2state = L2_NORMAL;
  833.                                /*
  834.                                 * If comments become whitespace,
  835.                                 * and we have no pending newlines,
  836.                                 * must emit a blank here.
  837.                                 *
  838.                                 * The comment text is now all eaten.
  839.                                 */
  840.                                if (whitespace && pendnls == 0)
  841.                                       putc(' 'out);
  842.                                SYNCLINES();
  843.                                break;
  844.                        case '*':
  845.                                /* stay in L2_COMMSTAR state */
  846.                                break;
  847.                        case EOF:
  848.                                warn(&state, "EOF inside comment");
  849.                                break;
  850.                        case '/n':
  851.                                pendnls++;
  852.                                /* FALLTHROUGH */
  853.                        default:
  854.                                l2state = L2_COMM;
  855.                        }
  856.                        break;
  857.                case L2_SLASHSLASH:
  858.                        switch (c) {
  859.                        case EOF:
  860.                                /* ??? do we really care? */
  861.                                warn(&state, "EOF inside //-comment");
  862.                                break;
  863.                        case '/n':
  864.                                l2state = L2_NORMAL;
  865.                                pendnls++;     /* cheesy, but... */
  866.                                SYNCLINES();
  867.                        default:
  868.                                break;
  869.                        }
  870.                        break;
  871.                default:
  872.                        panic("bad l2state");
  873.                }
  874.         } while (c != EOF);
  875.         SYNCLINES();
  876. }
  877. void warn(struct state *sp, const char *msg) {
  878.         fprintf(stderr, "uncomment: %s(%d): %s/n", inname, sp->lineno, msg);
  879. }
  880. void panic(const char *msg) {
  881.         fprintf(stderr, "panic: %s/n", msg);
  882.         abort();
  883.         exit(EXIT_FAILURE);
  884. }
  885. From Chris Mears 
  886. Here's Chris's updated version, without the bugs (says he). :-) 
  887. /*
  888.  * C comment stripper.
  889.  *
  890.  * Strips comments from C or C++ code.
  891.  */
  892. #include <stdio.h>
  893. enum state_t { normal, string, character, block_comment, line_comment};
  894. enum token_t { none, backslash, slash, star, tri1, tri2, tri_backslash};
  895. static int print_mode(enum state_t s)
  896. {
  897.         return (s == normal || s == string || s == character);
  898. }
  899. void cstrip(FILE *infile, FILE *outfile)
  900. {
  901.         int ch;
  902.         int comment_newline = 0;
  903.         enum state_t state = normal;
  904.         enum token_t token = none;
  905.         enum token_t last_token = none;
  906.         
  907.         if (!infile || !outfile || (infile == outfile)) {
  908.                 return;
  909.         }
  910.         while ((ch = fgetc(infile)) != EOF) {
  911.                 switch (ch) {
  912.                 case '/':
  913.                         if (token == tri2) {
  914.                                 token = tri_backslash;
  915.                                 if (print_mode(state))
  916.                                         fputc(ch, outfile);
  917.                         } else if (state == string || state == character) {
  918.                                 fputc(ch, outfile);
  919.                                 token = slash;
  920.                         } else if (state == block_comment && token == star) {
  921.                                 state = normal;
  922.                                 token = none;
  923.                                 /* Replace block comments with whitespace. */
  924.                                 if (comment_newline) {
  925.                                         fputc('/n', outfile);
  926.                                 } else {
  927.                                         fputc(' ', outfile);
  928.                                 }
  929.                         } else if (state == normal && token == slash) {
  930.                                 state = line_comment;
  931.                                 token = slash;
  932.                         } else {
  933.                                 token = slash;
  934.                         }
  935.                         
  936.                         break;
  937.                 case '//':
  938.                         if (state == normal && token == slash)
  939.                                 fputc('/', outfile);
  940.                         if (print_mode(state))
  941.                                 fputc(ch, outfile);
  942.                         if (token == backslash || token == tri_backslash) {
  943.                                 token = none;
  944.                         } else {
  945.                                 last_token = token;
  946.                                 token = backslash;
  947.                         }
  948.                                 
  949.                         break;
  950.                 case '"':
  951.                         if (state == normal && token == slash)
  952.                                 fputc('/', outfile);
  953.                         if (state == string && token != backslash)
  954.                                 state = normal;
  955.                         else if (state == normal && token != backslash)
  956.                                 state = string;
  957.                         if (print_mode(state))
  958.                                 fputc(ch, outfile);
  959.                         token = none;
  960.                         
  961.                         break;
  962.                 case '/'':
  963.                         if (state == normal && token == slash)
  964.                                 fputc('/', outfile);
  965.                         if (state == character && token != backslash)
  966.                                 state = normal;
  967.                         else if (state == normal && token != backslash)
  968.                                 state = character;
  969.                         if (print_mode(state))
  970.                                 fputc(ch, outfile);
  971.                         token = none;
  972.                         
  973.                         break;
  974.                 case '/n':
  975.                         /* This test is independent of the others. */
  976.                         if (state == block_comment)
  977.                                 comment_newline = 1;
  978.                         
  979.                         if (state == normal && token == slash)
  980.                                 fputc('/', outfile);
  981.                         
  982.                         if (token == backslash || token == tri_backslash)
  983.                                 token = last_token;
  984.                         else if (state == line_comment &
  985.                                         token != backslash) {
  986.                                 state = normal;
  987.                                 token = none;
  988.                         } else {
  989.                                 token = none;
  990.                         }
  991.                         if (print_mode(state))
  992.                                 fputc(ch, outfile);
  993.                         break;
  994.                 case '*':
  995.                         if (state == normal && token == slash) {
  996.                                 state = block_comment;
  997.                                 token = none;
  998.                                 comment_newline = 0;
  999.                         } else {
  1000.                                 token = star;
  1001.                         }
  1002.                         
  1003.                         if (print_mode(state))
  1004.                                 fputc(ch, outfile);
  1005.                         break;
  1006.                 case '?':
  1007.                         if (state == normal && token == slash)
  1008.                                 fputc('/', outfile);
  1009.                         
  1010.                         if (token == tri1) {
  1011.                                 token = tri2;
  1012.                         } else if (token == tri2) {
  1013.                                 token = tri2;   /* retain state */
  1014.                         } else {
  1015.                                 /* We might need the last token if this
  1016.                                  * trigraph turns out to be a backslash.
  1017.                                  */
  1018.                                 last_token = token;
  1019.                                 token = tri1;
  1020.                         }
  1021.                         if (print_mode(state))
  1022.                                 fputc(ch, outfile);
  1023.                         break;
  1024.                 default:
  1025.                         if (state == normal && token == slash)
  1026.                                 fputc('/', outfile);
  1027.                         if (print_mode(state))
  1028.                                 fputc(ch, outfile);
  1029.                         token = none;
  1030.                         break;
  1031.                 } /* switch */
  1032.         } /* while */
  1033.         return;
  1034. }
  1035. /* Small driver program. */
  1036. int main(void)
  1037. {
  1038.         cstrip(stdin, stdout);
  1039.         return 0;
  1040. }
  1041. Here's a critique of the above, sent in by Rick Litherland. (Please note: when Rick posted this, I hadn't yet posted Chris Mears's updated version of the code.) 
  1042. (Since I find it hard to pick the solution number out of KRX12300.C at a glance, I'll refer to the solutions as uncomment00, uncomment01, and so on.) 
  1043. [Rick - KR means K&R. X means eXercise. 1 means Chapter 1. 23 means exercise 23. The next digit is the category number - 0 == Cat 0 (ANSI C89, with code restricted to what K&R have discussed at this point in the book). The final digit is the solution number. 0 is the first I received in that category, 1 is the second, and so on. (RJH)] 
  1044. uncomment03 (Gregory Pietsch) 
  1045. =========== 
  1046. I can find only one possible flaw in this, namely that it does not allow for a slash in program text being immediately followed by a quotation mark. One could reasonably argue that this is not a flaw at all, because that would never happen in sensible code. On the other hand, it can happen in legal code, as demonstrated by the following complete (if useless) program. 
  1047. #include <stdio.h>
  1048. int main(void)
  1049. {
  1050.     /* print the number three */
  1051.     printf("%d/n", 6/'/2');
  1052.     /* remember to return a value from main */
  1053.     return 0;
  1054. }
  1055. When this is fed to uncomment03, the output is 
  1056. #include <stdio.h>
  1057. int main(void)
  1058. {
  1059.      
  1060.     printf("%d/n", 6/'/2');
  1061.     /* remember to return a value from main */
  1062.     return 0;
  1063. }
  1064. Clearly, uncomment03 realises that the second comment is too important to remove. Um, sorry, that was a feeble excuse for a joke. What's happening is that uncomment03 doesn't recognise the beginning of the character constant '/2', so it takes the closing quote as the start of a "character constant" that is never terminated. The peculiar idiom 6/'/2' for 3 can be replaced by the even more brain-damaged 6/"/2"[0] with the same effect. Since uncomment03 is table-driven, it's easy to make it recognise these situations by adding two new rules to the table. 
  1065. /* modified krx12303.c */
  1066. #include <stdio.h>
  1067. char p[] =
  1068. "0/!10/"@40/'@50.@01/@11*!2"
  1069. "1/"/41/'/5"            /* added by RAL */
  1070. "1./02*!32.!23/ 03*!33.!24/"@04//@64.@45/'@05//@75.@56.@47.@5";
  1071. int main(){int c,i,d;char s,n;s='0';while((c=getchar())
  1072. !=EOF){d=0;for(i=0;p[i]!='/0'&&d==0;i=i+4){if(p[i]==s&
  1073. (p[i+1]==c||p[i+1]=='.')){if(p[i+2]=='@')putchar(c);else
  1074. if(p[i+2]=='/'){putchar('/');putchar(c);}else if(p[i+2]
  1075. ==' ')putchar(' ');n=p[i+3];d=1;}}s=n;}return 0;}
  1076. /* end of modified krx12303.c */
  1077. uncomment02 (Lew Pitcher) 
  1078. =========== 
  1079. uncomment11 (Chris Torek) 
  1080. =========== 
  1081. These have the same problem (or non-problem, according to your point of view) as uncomment03. If it were regarded as a problem, it could probably be fixed quite easily, though not (I think) as neatly as with uncomment03; I haven't looked at these carefully enough to be sure. 
  1082. uncomment01, uncomment10 (Ben Pfaff) 
  1083. =========== =========== 
  1084. An oversight has the effect that if a slash in program text is followed by anything other than a star or another slash, the following character is dropped. For example, with input 
  1085. int a = 4/2;
  1086. the output is 
  1087. int a = 4/;
  1088. The correction is the same in both cases; replace 
  1089.     /* Program text following a slash. */
  1090.     if (c == '*')
  1091.         state = COMMENT;
  1092.     else {
  1093.         putchar('/');
  1094.         if (c != '/')
  1095.             state = PROGRAM;
  1096.     }
  1097. by 
  1098.     /* Program text following a slash. */
  1099.     if (c == '*')
  1100.         state = COMMENT;
  1101.     else {
  1102.         putchar('/');
  1103.         if (c != '/') {
  1104.             putchar(c);
  1105.             state = PROGRAM;
  1106.         }
  1107.     }
  1108. After this, these programs will have the same problem (or not) as the previous three. 
  1109. uncomment12 (Chris Mears) 
  1110. =========== 
  1111. This is a completely different kettle of fish. If you run this with Ben Pfaff's solution as input, the output is quite bizarre; some comments have just their initial and final slashes removed, for instance. I've managed to find two things contributing to this. The first is illustrated by the input 
  1112. int c = '/';
  1113. with output 
  1114. int c = '';
  1115. This can be fixed by changing the lines 
  1116.     case '/':
  1117.         if (state == string) {
  1118. to 
  1119.     case '/':
  1120.         if (state == string || state == character) {
  1121. However, with or without this change, the input 
  1122. char *p = "//"/* This is not a comment. */ 
  1123. is left unchanged. What happens is that the closing quote of the string literal isn't recognised as such because of the preceding backlash, despite the backslash before that. The handling of backslashes is split between three cases (at least), and is complicated enough that I don't feel competent to propose a remedy. 
  1124. This program breaks most of the above submissions: 
  1125. /* krx123tp.c - a test program to serve as input to krx123*.c
  1126.  *
  1127.  * This is a shameless copy of Ben Pfaff's solution, to which I have
  1128.  * added a few extra statements to further test the candidate programs
  1129.  * for this exercise. As Ben says, this program already contains lots
  1130.  * of examples of comments and not-quite-comments. I've just made it
  1131.  * a little tougher.
  1132.  *
  1133.  */
  1134. /* K&R2 1-23: Write a program to remove all comments from a C program.
  1135.    Don't forget to handle quoted strings and character constants
  1136.    properly.  C comments do not nest.
  1137.    This solution does not deal with other special cases, such as
  1138.    trigraphs, line continuation with /, or <> quoting on #include,
  1139.    since these aren't mentioned up 'til then in K&R2.  Perhaps this is
  1140.    cheating.
  1141.    Note that this program contains both comments and quoted strings of
  1142.    text that looks like comments, so running it on itself is a
  1143.    reasonable test.  It also contains examples of a comment that ends
  1144.    in a star and a comment preceded by a slash.  Note that the latter
  1145.    will break C99 compilers and C89 compilers with // comment
  1146.    extensions.
  1147.    Interface: The C source file is read from stdin and the
  1148.    comment-less output is written to stdout. **/
  1149. #include <stdio.h>
  1150. int
  1151. main(void)
  1152. {
  1153.     /* State machine's current state. */
  1154.     enum {
  1155.         PROGRAM,
  1156.         SLASH,
  1157.         COMMENT,
  1158.         STAR,
  1159.         QUOTE,
  1160.         LITERAL
  1161.     } state;
  1162.     /* If state == QUOTE, then ' or ".  Otherwise, undefined. */
  1163.     int quote;
  1164.     state = PROGRAM;
  1165.     for (;;) {
  1166.         int c = getchar();
  1167.         if (c == EOF) {
  1168.             if (state == SLASH)
  1169.                 putchar('/' //**/
  1170.                         1 / 1 /'/1');
  1171.             break;
  1172.         }
  1173.         if(0)
  1174.           printf("%d/n", 6/'/2'); 
  1175.         /* line of code, and comment, added by RJH 10 July 2000 */
  1176.         switch (state) {
  1177.         case SLASH:
  1178.             /* Program text following a slash. */
  1179.             if (c == "/*"[1]) {
  1180.                 state = COMMENT;
  1181.                 break;
  1182.             }
  1183.             putchar('/');
  1184.             state = PROGRAM;
  1185.             /* Fall through. */
  1186.         case PROGRAM:
  1187.             /* Program text. */
  1188.             if (c == '/'' || c == '"') {
  1189.                 quote = c;
  1190.                 state = QUOTE;
  1191.                 putchar(c);
  1192.             }
  1193.             else if (c == "/*"[0])
  1194.                 state = SLASH;
  1195.             else
  1196.                 putchar(c);
  1197.             break;
  1198.         case COMMENT:
  1199.             /* Comment. */
  1200.             if (c == '*')
  1201.                 state = STAR;
  1202.             break;
  1203.         case STAR:
  1204.             /* Comment following a star. */
  1205.             if (c == '/')
  1206.                 state = PROGRAM;
  1207.             else if (c != '*') {
  1208.                 state = COMMENT;
  1209.                 putchar (' ');
  1210.             }
  1211.             break;
  1212.         case QUOTE:
  1213.             /* Within quoted string or character constant. */
  1214.             putchar(c);
  1215.             if (c == '//')
  1216.                 state = LITERAL;
  1217.             else if (c == quote)
  1218.                 state = PROGRAM;
  1219.             break;
  1220.         case LITERAL:
  1221.             /* Within quoted string or character constant, following /. */
  1222.             putchar(c);
  1223.             state = QUOTE;
  1224.             break;
  1225.         default:
  1226.             abort();
  1227.         }
  1228.     }
  1229.     return /* this comment added by RJH 10 July 2000 */ 0;
  1230. }
  1231. /* 
  1232.    Local variables:
  1233.    compile-command: "checkergcc -W -Wall -ansi -pedantic knr123.c -o knr123"
  1234.    End: 
  1235. */ 

练习1-24 编写一个程序,查找C程序中的基本语法错误,如圆括号、方括号、花括号不配
对等。不要忘记引号(包括单引号和双引号)、换码序列与注解。(如果读者想把该程序编写成
完全通用性的,那么难度比较大。)

 

Write a program to check a C program for rudimentary syntax errors like unbalanced parentheses, brackets and braces. Don't forget about quotes, both single and double, escape sequences, and comments. (This program is hard if you do it in full generality.)

  1. Rick Dearman's Category 0 solution:
  2. /******************************************************
  3.    KnR 1-24
  4.    --------
  5.    Write a program to check the syntax of a C program
  6.    for matching {} () "" '' [] 
  7.    Author: Rick Dearman
  8.    email: rick@ricken.demon.co.uk
  9. ******************************************************/
  10. #include <stdio.h>
  11. #define MAXLINE 1000 /* max input line size */
  12. char line[MAXLINE]; /*current input line*/
  13. int getline(void);  /* taken from the KnR book. */
  14. int
  15. main()
  16. {
  17.   int len=0;
  18.   int t=0;
  19.   int brace=0, bracket=0, parenthesis=0;
  20.   int s_quote=1, d_quote=1;
  21.   while ((len = getline()) > 0 )
  22.     {
  23.       t=0;
  24.       while(t < len)
  25.         {
  26.           if( line[t] == '[')
  27.             {
  28.               brace++;
  29.             }
  30.           if( line[t] == ']')
  31.             {
  32.               brace--;
  33.             }
  34.           if( line[t] == '(')
  35.             {
  36.               parenthesis++;
  37.             }
  38.           if( line[t] == ')')
  39.             {
  40.               parenthesis--;
  41.             }
  42.           if( line[t] == '/'')
  43.             {
  44.               s_quote *= -1;
  45.             }
  46.           if( line[t] == '"')
  47.             {
  48.               d_quote *= -1;
  49.             }
  50.           t++;
  51.         }
  52.     }
  53.   if(d_quote !=1)
  54.     printf ("Mismatching double quote mark/n");
  55.   if(s_quote !=1)
  56.     printf ("Mismatching single quote mark/n");
  57.   if(parenthesis != 0)
  58.     printf ("Mismatching parenthesis/n");
  59.   if(brace != 0)
  60.     printf ("Mismatching brace mark/n");
  61.   if(bracket != 0)
  62.     printf ("Mismatching bracket mark/n");
  63.   if( bracket==0 && brace==0 && parenthesis==0 && s_quote == 1 && d_quote == 1)
  64.         printf ("Syntax appears to be correct./n");
  65.   return 0;
  66. }
  67. /* getline: specialized version */
  68. int getline(void)
  69. {
  70.   int c, i;
  71.   extern char line[];
  72.   
  73.   for ( i=0;i<MAXLINE-1 && ( c=getchar()) != EOF && c != '/n'; ++i)
  74.     line[i] = c;
  75.   if(c == '/n'
  76.     {
  77.       line[i] = c;
  78.       ++i;
  79.     }
  80.   line[i] = '/0';
  81.   return i;
  82. }
  83. Stefan Farfeleder's Category 1 solution: 
  84. /* 1-24.c */
  85. #include <stdio.h>
  86. #include <stdlib.h>
  87. #define MAX_STACK 1024
  88. enum
  89. {
  90.     CODE,       /* nothing of the following */
  91.     COMMENT,    /* inside a comment */
  92.     QUOTE1,     /* inside '' */
  93.     QUOTE2      /* inside "" */
  94. };
  95. int main(void)
  96. {
  97.     int ch;
  98.     int state = CODE;
  99.     char stack[MAX_STACK];
  100.     size_t top = 0; /* points to the top of the stack :-) */
  101.     size_t line = 1;
  102.     int error = 0;  /* for ok-message */
  103.     while ((ch = getchar()) != EOF)
  104.     {
  105.         if (ch == '/n')
  106.         {
  107.             line++;
  108.         }
  109.         switch (state)
  110.         {
  111.         case CODE:
  112.             if (ch == '/'')
  113.             {
  114.                 state = QUOTE1;
  115.             }
  116.             else if (ch == '"')
  117.             {
  118.                 state = QUOTE2;
  119.             }
  120.             else if (ch == '/')
  121.             {
  122.                 int second = getchar();
  123.                 if (second == '*')
  124.                 {
  125.                     state = COMMENT;
  126.                 }
  127.                 else
  128.                 {
  129.                     ungetc(second, stdin);
  130.                 }
  131.             }
  132.             else if (ch == '(' || ch == '[' || ch == '{')
  133.             {
  134.                 if (top < MAX_STACK)
  135.                 {
  136.                     stack[top++] = ch;
  137.                 }
  138.                 else
  139.                 {
  140.                     printf("Stack too small!/n");
  141.                     return EXIT_FAILURE; /* exit gracefully :-) */
  142.                 }
  143.             }
  144.             else if (ch == ')' || ch == ']' || ch == '}')
  145.             {
  146.                 if (top == 0) /* found closing brace but stack is empty */
  147.                 {
  148.                     printf("Line %lu: Closing '%c' found without "
  149.                            "counterpart./n", (unsigned long)line, ch);
  150.                     error = 1;
  151.                 }
  152.                 else
  153.                 {
  154.                     char open = stack[--top];
  155.                     if ((ch == ')' && open != '(') ||
  156.                         (ch == ']' && open != '[') ||
  157.                         (ch == '}' && open != '{'))
  158.                     {
  159.                         printf("Line %lu: Closing '%c' does not match "
  160.                              "opening '%c'./n", (unsigned long)line, ch, open);
  161.                         error = 1;
  162.                     }
  163.                 }
  164.             }
  165.             break;
  166.         case COMMENT:
  167.             if (ch == '*')
  168.             {
  169.                 int second = getchar();
  170.                 if (second == '/')
  171.                 {
  172.                     state = CODE;
  173.                 }
  174.                 else
  175.                 {
  176.                     ungetc(second, stdin);
  177.                 }
  178.             }
  179.             break;
  180.         case QUOTE1:
  181.             if (ch == '//')
  182.             {
  183.                 (void)getchar(); /* an escaped char inside '' throw it away */
  184.             }
  185.             else if (ch == '/'')
  186.             {
  187.                 state = CODE;
  188.             }
  189.             break;
  190.         case QUOTE2:
  191.             if (ch == '//')
  192.             {
  193.                 (void)getchar(); /* an escaped char inside "" throw it away */
  194.             }
  195.             else if (ch == '"')
  196.             {
  197.                 state = CODE;
  198.             }
  199.             break;
  200.         }
  201.     }
  202.     if (state == COMMENT)
  203.     {
  204.         printf("Code ends inside comment!/n");
  205.     }
  206.     else if (state == QUOTE1)
  207.     {
  208.         printf("Code ends inside single quotes!/n");
  209.     }
  210.     else if (state == QUOTE2)
  211.     {
  212.         printf("Code ends inside double quotes!/n");
  213.     }
  214.     else if (top == 0 && error == 0)
  215.     {
  216.         printf("Code seems to be ok./n");
  217.     }
  218.     if (top > 0) /* still something in the stack */
  219.     {
  220.         size_t i;
  221.         for (i = 0; i < top; i++)
  222.         {
  223.             printf("Opening '%c' found without counterpart./n", stack[i]);
  224.         }
  225.     }
  226.     return 0;
  227. }
  228. Stig Brautaset's Cat 1 solution: 
  229. /* This is my first rudimentary C syntax checker. It checks for syntax errors, 
  230.  * like closing a set of brackets using the wrong type. It is not *very* good
  231.  * at it, but it does not bother about comments, and it does know something
  232.  * about escape sequences and character strings/constants.
  233.  *
  234.  * It uses a simple static stack to keep track of the braces, and it also uses
  235.  * a stack to keep track of the errors on each line. Someday I might change 
  236.  * that to use a queue for the error-tracking, because as it is now, it outputs
  237.  * the rightmost error on the line first, and then it steps leftwards (if there
  238.  * is more than one error on each line). 
  239.  *
  240.  * I might also implement my dynamically allocated stack and queue implementa-
  241.  * tions, so that running out of space in the stack is not an issue. I might
  242.  * also skip it, since it has little to do with the exercise in question.
  243.  *
  244.  * The program is especially bad at error-recovery. If it finds an error, (or
  245.  * something it believes to be an error) subsequent errors reported might be a 
  246.  * bit dubious.
  247.  */
  248. #include <stdio.h>
  249. #define MAXVAL 1000
  250. #define MAXLINE 1000
  251. typedef struct {
  252.         int top;
  253.         int val[MAXVAL];
  254.         int pos[MAXVAL];
  255. } stackstr;
  256. /* very simple stack push function */
  257. int push(stackstr *stk, int foo, int bar)
  258.         if (stk->top == MAXVAL) {
  259.                printf("stack overflow. NOT putting more values on the stack./n");
  260.                return 1;
  261.         }
  262.         stk->val[stk->top] = foo;
  263.         stk->pos[stk->top] = bar;
  264.         stk->top++;
  265.         
  266.         return 0;
  267. }
  268. /* very simple function to pop values off a stack */
  269. int pop(stackstr *stk, int *foo, int *bar)
  270. {
  271.         if (stk->top == 0) {
  272.                return 1;
  273.         }
  274.         stk->top--;
  275.         *foo = stk->val[stk->top];
  276.         *bar = stk->pos[stk->top];
  277.         
  278.         return 0;
  279. }
  280. /* we go through the input one line at a time, and this function 
  281.  * gets the line to test 
  282.  */
  283. int getline(char *s, int lim)
  284. {
  285.         int i, c;
  286.         for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '/n'; i++)
  287.                *(s + i) = c;
  288.         if (c == '/n')
  289.                *(s + i++) = c;
  290.         *(s + i) = '/0';
  291.         return i;
  292. }
  293. void scanline(stackstr *stk, stackstr *errstk, char *s, int len)
  294. {
  295.         int i, c, d, foo;
  296.         static int string = 0, comment = 0, isconst = 0, escape = 0;
  297.         
  298.         for (i = 0; i < len; i++) {
  299.                c = *(s + i);
  300.                
  301.                 if (!comment) {
  302.                        if (c == '//') { /* we have an escape */
  303.                                /* test for a valid escape sequence */
  304.                                if ((d = *(s + ++i)) == '//' || d == 'n' || d == '0' || d == 'r' || d == '?'
  305.                                       || d == 't' || d == '/'' || d == '/"' || d == 'b' || d == 'x') {
  306.                                       continue/* ok, valid escape sequence -- don't bother about it */
  307.                                } else {
  308.                                       push(errstk, 5, i); /* illigal escape sequence */
  309.                                }
  310.                        } else if (c == '/"') { /* is it a text string then? */
  311.                                if (!string)
  312.                                       string = 1;
  313.                                else
  314.                                       string = 0;
  315.                        } else if (c == '/'') { /* is it a constant? */
  316.                                if (!isconst)
  317.                                       isconst = 1;
  318.                                else
  319.                                       isconst = 0;
  320.                        }
  321.                }
  322.                
  323.                 if (!isconst && !string && !comment && c == '/') {
  324.                         if ((d = *(s + ++i)) == '*')
  325.                                 comment = 1;
  326.                } else if (comment && c == '*') {
  327.                         if ((d = *(s + ++i)) == '/') {
  328.                                 comment = 0;
  329.                                continue/* done with the comment stuff -- start over */
  330.                        }
  331.                }                                      
  332.                /* only bother about ({[ ]})'s that's not in
  333.                 * a string, constant or comment
  334.                 */
  335.                if (!isconst && !string && !comment) {
  336.                        if (c == '(' || c == '{' || c == '[') {
  337.                                push(stk, c, 0);
  338.                        } else if (c == ']' || c == '}' || c == ')') {
  339.                                if (pop(stk, &d, &foo)) {
  340.                                       push(errstk, 4, i);
  341.                                }
  342.                                if (c == ')' && d != '(') {
  343.                                       push(stk, d, 0);
  344.                                       push(errstk, 1, i);
  345.                                } else if (c == ']' && d != '[') {
  346.                                       push(stk, d, 0);
  347.                                       push(errstk, 2, i);
  348.                                } else if (c == '}' && d != '{') {
  349.                                       push(stk, d, 0);
  350.                                       push(errstk, 3, i);
  351.                                }
  352.                        }
  353.                }
  354.         }
  355. }
  356. /* print errors on the line (if there were any) */
  357. void print_err(stackstr *errstk, int lineno)
  358. {
  359.         int errno, pos;
  360.         
  361.         /* yes I know... this way the errors come "backwards" :) */
  362.         while (!pop(errstk, &errno, &pos)) {
  363.                printf("on line number %d: ", lineno);
  364.                switch(errno) {
  365.                case 1:
  366.                        printf("closing unopened parantheses, column %d/n", pos+1);
  367.                        break;
  368.                case 2:
  369.                        printf("closing unopened square bracket, column %d/n", pos+1);
  370.                        break;
  371.                case 3:
  372.                        printf("closing unopened curly braces, column %d/n", pos+1);
  373.                        break;
  374.                case 4:
  375.                       printf("trying to close unopened block/control structure, column %d/n", pos+1);
  376.                        break;
  377.                case 5:
  378.                        printf("illigal escape sequence, column %d/n", pos+1);
  379.                        break;
  380.                default:
  381.                        printf("undeterminable error/n");
  382.                 break;
  383.                }
  384.         }
  385. }
  386. int main(void)
  387. {
  388.         stackstr errstk = {0}, stk = {0};
  389.         int c, linenbr = 0, errcount = 0, linelen;
  390.         char line[MAXLINE];
  391.         while ((linelen = getline(line, MAXLINE)) > 0) {
  392.                linenbr++;
  393.                scanline(&stk, &errstk, line, linelen);
  394.                if (errstk.top) {
  395.                        print_err(&errstk, linenbr);
  396.                        errcount++;
  397.                }
  398.         }
  399.         if (errcount) 
  400.                printf("%d lines contained error(s)/n", errcount);
  401.         else
  402.                printf("Well, *I* didn't find any syntax errors, but don't take my word for it...:)/n");
  403.                        
  404.         return 0;