{"id":264,"date":"2021-11-16T17:47:27","date_gmt":"2021-11-16T09:47:27","guid":{"rendered":"https:\/\/blog.liuyingjie.com.cn\/?p=264"},"modified":"2023-08-13T07:53:39","modified_gmt":"2023-08-13T07:53:39","slug":"kr2-solutions-chapter-1","status":"publish","type":"post","link":"https:\/\/blog.liuyingjie.com.cn\/?p=264","title":{"rendered":"K&#038;R2 solutions: Chapter 1 &#8211; A Tutorial Introduction"},"content":{"rendered":"\n<p>Exercise 1-1. Run the &#8220;hello world&#8221; program on your system. Experiment with leaving out parts of the program, to see what error messages you get.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n\nmain(){\n    printf(\"Hello, World\\n\");\n}<\/code><\/pre>\n\n\n\n<p>Exercise 1-2. Experiment to find out what happens when printf \\\\&#8217;s argument string contains \\c, where c is some character not listed above.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n\nmain() {\n    \/*\n    newline NL  (LF)        \\n  backslash       \\       \\\n    horizontal  tab HT      \\t  question mark   ?       \\?\n    vertical    tab VT      \\v  single quote    '      \\'\n    backspace   BS          \\b  double quote    \"      \n    carriage    return CR   \\r  octal number    ooo     \\ooo\n    formfeed    FF          \\f  hex number      hh      \\xhh\n    audible     alert BEL   \\a\n    *\/\n    printf(\"newline (0x0A): '\\n'\\n\");\n    printf(\"horizontal tab (0x09): '\\t'\\n\");\n    printf(\"vertical tab (0x0B):'\\v'\\n\");\n    printf(\"backspace (0x08): ' \\b'\\n\");\n    printf(\"carriage return (0x0D): '\\r'\\n\");\n    printf(\"formfeed (0x0C): '\\f'\\n\");\n    printf(\"alert (0x07) - added in C89: '\\a'\\n\");\n    printf(\"backslash (0x5C): '\\'\\n\");\n    printf(\"question mark (0x3F): '\\?'\\n\");\n    printf(\"single quote (0x27): '\\''\\n\");\n    printf(\"double quote: (0x22)''\\n\");\n    printf(\"octal number (ooo): '\\101'\\n\");\n    printf(\"hex number (xhh): '\\x41'\\n\");\n}<\/code><\/pre>\n\n\n\n<p>Exercise 1-3. Modify the temperature conversion program to print a heading above the table.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n\n\/* print Fahrenheit-Celsius table\n    for fahr = 0, 20, ..., 300; floating-point version *\/\nmain() {\n    float fahr, celsius;\n    float lower, upper, step;\n\n    lower = 0;      \/* lower limit of temperatuire scale *\/\n    upper = 300;    \/* upper limit *\/\n    step = 20;      \/* step size *\/\n\n    fahr = lower;\n    printf(\"Fahrenheit\\tCelsius\\n\");\n    while (fahr &lt;= upper){\n        celsius = (5.0 \/ 9.0) * (fahr - 32.0);\n        printf(\"%3.0f\\t\\t%6.1f\\n\", fahr, celsius);\n        fahr = fahr + step;\n    }\n}<\/code><\/pre>\n\n\n\n<p>Exercise 1-4. Write a program to print the corresponding Celsius to Fahrenheit table.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n\nmain() {\n    float fahr, celsius;\n    float lower, upper, step;\n\n    lower = 0;      \/* lower limit of temperatuire scale *\/\n    upper = 300;    \/* upper limit *\/\n    step = 20;      \/* step size *\/\n\n    celsius = lower;\n    printf(\"Fahrenheit\\tCelsius\\n\");\n    while (celsius &lt;= upper){\n        fahr = (9.0 \/ 5.0) * celsius + 32.0;\n        printf(\"%3.0f\\t\\t%6.1f\\n\", celsius, fahr);\n        celsius = celsius + step;\n    }\n}<\/code><\/pre>\n\n\n\n<p>Exercise 1-5. Modify the temperature conversion program to print the table in reverse order, that is, from 300 degrees to 0.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n\nmain() {\n    float fahr, celsius;\n    float lower, upper, step;\n\n    lower = 0;      \/* lower limit of temperatuire scale *\/\n    upper = 300;    \/* upper limit *\/\n    step = 20;      \/* step size *\/\n\n    fahr = upper;\n    printf(\"Fahrenheit\\tCelsius\\n\");\n    while (fahr &gt;= lower){\n        celsius = (5.0 \/ 9.0) * (fahr - 32.0);\n        printf(\"%3.0f\\t\\t%6.1f\\n\", fahr, celsius);\n        fahr = fahr - step;\n    }\n}<\/code><\/pre>\n\n\n\n<p>Exercise 1-6. Verify that the expression <code>getchar() != EOF<\/code> is 0 or 1.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">\/* This program prompts for input, and then captures a character\n * from the keyboard. If EOF is signalled (typically through a\n * control-D or control-Z character, though not necessarily),\n * the program prints 0. Otherwise, it prints 1.\n *\n * If your input stream is buffered (and it probably is), then\n * you will need to press the ENTER key before the program will\n * respond.\n *\/\n#include&lt;stdio.h&gt;\n\nmain() {\n    printf(\"Press any key or type CONTROL-Z, then type ENTER. :-)\\n\\n\");\n    printf(\"The expression getchar() != EOF evaluates to %d\\n\", getchar() != EOF);\n}<\/code><\/pre>\n\n\n\n<p>Exercise 1-7. Write a program to print the value of <code>EOF<\/code> .<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n\nmain() {\n    printf(\"The value of EOF is %d\\n\",EOF);\n}<\/code><\/pre>\n\n\n\n<p>Exercise 1-8. Write a program to count blanks, tabs, and newlines.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n\nmain() {\n    int c, nb, nt, nl;\n    nb = nt = nl = 0;\n    while ((c = getchar()) != EOF) {\n        if (c == ' ') {   \/\/ASCII value for \" \"\n            ++nb;\n        }\n        if (c == '\\t') {  \/\/ASCII value for \"\\t\"\n            ++nt;\n        }\n        if (c == '\\n') {  \/\/ASCII value for \"\\n\"\n            ++nl;\n        }\n    }\n    printf(\"Total spaces:%d \\nTotal tabs:%d \\nTotal lines:%d\\n\", nb, nt, nl);\n}<\/code><\/pre>\n\n\n\n<p>Using ASCII values<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n\n\/\/Using ASCII values\n\nmain() {\n    int c, nb, nt, nl;\n    nb = nt = nl = 0;\n    while ((c = getchar()) != EOF) {\n        if (c == 32) {  \/\/ASCII value for \" \"\n            ++nb;\n        }\n        if (c == 9) {   \/\/ASCII value for \"\\t\"\n            ++nt;\n        }\n        if (c == 10) {  \/\/ASCII value for \"\\n\"\n            ++nl;\n        }\n    }\n    printf(\"Total spaces:%d \\nTotal tabs:%d \\nTotal lines:%d\\n\", nb, nt, nl);\n}<\/code><\/pre>\n\n\n\n<p>Exercise 1-9. Write a program to copy its input to its output, replacing each string of one or more blanks by a single blank.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n\nmain() {\n    char c;\n    char prev_c;  \/* previous character *\/\n\n    prev_c = 0;\n    while ((c = getchar()) != EOF){\n        \/* output c if it's not a blank OR if the previous c is not a blank *\/\n        if (c != ' ' || prev_c != ' ') {\n            putchar(c);\n            prev_c = c;\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<p>Exercise 1-10. 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.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n\nmain() {\n    int c;\n    while ((c = getchar()) != EOF){\n        if (c == '\\\\' || c == '\\t' || c == '\\b'){\n            putchar('\\\\');\n            if (c == '\\\\'){\n                putchar('\\\\');\n            }\n            if (c == '\\t'){\n                putchar('t');\n            }\n            if (c == '\\b'){\n                putchar('b');\n            }\n        }else{\n            putchar(c);\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<p>Exercise 1-11. How would you test the word count program? What kinds of input are most likely to uncover bugs if there are any?<\/p>\n\n\n\n<p>Exercise 1-12. Write a program that prints its input one word per line.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n\n#define IN 1\n#define OUT 0\n\nmain() {\n    int c, state;\n\n    state = OUT;\n    while ((c = getchar()) != EOF){\n        if (c == '\\n' || c == ' ' || c == '\\t'){\n            if (state == IN){\n                state = OUT;\n                putchar('\\n');\n            }\n            continue;\n        }\n        state = IN;\n        putchar(c);\n    }\n}<\/code><\/pre>\n\n\n\n<p>Exercise 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.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n\n#define MAXHIST 15      \/* max length of histogram  *\/\n#define MAXWORD 11      \/* max length of a word     *\/\n#define IN  1           \/* inside a word            *\/\n#define OUT 0           \/* outside a word           *\/\n\n\/* print horizontal histogram *\/\nmain() {\n    int c, i, nc, state;\n    int len;            \/* length of each bar       *\/\n    int maxvalue;       \/* maximum value for wl[]   *\/\n    int ovflow;         \/* number of overflow words *\/\n    int wl[MAXWORD];    \/* word length counters     *\/\n\n    state = OUT;\n    nc = 0;             \/* number of chars in a word*\/\n    ovflow = 0;         \/* number of words &gt;= MAXWORD*\/\n    for (i = 0; i &lt; MAXWORD; ++i){\n        wl[i] = 0;\n    }\n    while ((c = getchar()) != EOF){\n        if (c == ' ' || c == '\\n' || c == '\\t'){\n            state = OUT;\n            if (nc &gt; 0){\n                if (nc &lt; MAXWORD) {\n                    ++wl[nc];\n                } else {\n                    ++ovflow;\n                }\n            }\n            nc = 0;\n        }else if(state == OUT){\n            state = IN;\n            nc = 1;     \/* beginning of a new word  *\/\n        }else{\n            ++nc;       \/* inside a word            *\/\n        }\n    }\n\n    maxvalue = 0;\n    for (i = 1; i &lt; MAXWORD; ++i){\n        if (wl[i] &gt; maxvalue){\n            maxvalue = wl[i];\n        }\n    }\n    for (i = 1; i &lt; MAXWORD; ++i) {\n        printf(\"%5d - %5d : \", i, wl[i]);\n        if (wl[i] &gt; 0) {\n            if ((len = wl[i] * MAXHIST \/ maxvalue) &lt;= 0) {\n                len = 1;\n            }\n        } else {\n            len = 0;\n        }\n        while (len &gt; 0) {\n            putchar('*');\n            --len;\n        }   \n        putchar('\\n');\n        }\n    if (ovflow &gt; 0) {\n        printf(\"There are %d words &gt;= %d\\n\", ovflow, MAXWORD);\n    }\n}<\/code><\/pre>\n\n\n\n<p>Exercise 1-14. Write a program to print a histogram of the frequencies of different characters in its input.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n#include&lt;ctype.h&gt;\n\n#define MAXHISI 15      \/* max length of histagram  *\/\n#define MAXCHAR 128     \/* max different characters *\/\n\n\/* print horizontal histcgram freq. if different characters *\/\nmain() {\n    int c, i;\n    int len;            \/* length of each bar       *\/\n    int maxvalue;       \/* maximum value for cc[]   *\/\n    int cc[MAXCHAR];    \/* character counters       *\/\n\n    for (i = 0; i &lt; MAXCHAR; i++){\n        cc[i] = 0;\n    }\n    while((c =  getchar()) != EOF)\n        if (c &lt; MAXCHAR){\n            ++cc[c];\n        }\n    maxvalue = 0;\n    for (i = 1; i &lt;MAXCHAR; i++){\n        if (cc[i] &gt; maxvalue){\n            maxvalue = cc[i];\n        }\n    }\n    for (i = 1; i &lt; MAXCHAR; i++){\n        if (isprint(i)){    \/* isprint(c) printing character including space    *\/\n            printf(\"%5d - %c - %5d : \", i, i, cc[i]);\n        } else {\n            printf(\"%5d -  - %5d : \", i, cc[i]);\n        }\n        if (cc[i] &gt; 0){\n            if ((len = cc[i] * MAXHISI \/ MAXCHAR &lt;= 0)) {\n                len = 1;\n            }\n        } else {\n            len = 0;\n        }\n        while (len &gt; 0){\n            putchar('*');\n            --len;\n        }\n        putchar('\\n');\n    }\n}<\/code><\/pre>\n\n\n\n<p>Exercise 1-15. Rewrite the temperature conversion program of Section 1.2 to use a function for conversion.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n\nint fahr_celsius(int fahr);\n\nmain() {\n    int i;\n    for (i = 0; i &lt;= 300; i = i + 20){\n        printf(\"%3.1d %6.1d\\n\", i, fahr_celsius(i));\n    }\n}\n\nint fahr_celsius(int fahr) {\n    int celsius;\n    celsius = (5.0 \/ 9.0) * (fahr - 32.0);\n    return celsius;\n}<\/code><\/pre>\n\n\n\n<p>Exercise 1-16. 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.<\/p>\n\n\n\n<p>Original code:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n#define MAXLINE 1000    \/* maximum input line size *\/\n\nint getline(char s[], int lim);\nvoid copy(char to[], char from[]);\n\n\/* print the longest input line *\/\nmain() {\n    int len;        \/* current line length          *\/\n    int max;        \/* maximum length seen so far   *\/\n    char line[MAXLINE];     \/* current input line   *\/\n    char longest[MAXLINE];  \/* longest line saved here *\/\n\n    max = 0;\n    while ((len = getline(line,MAXLINE)) &gt; 0){\n        if (len &gt; max){\n            max = len;\n            copy(longest, line);\n        }\n    }\n    if (max &gt; 0){    \/* there was a line *\/\n        printf(\"Longest line: %s\", longest);\n    }\n    return 0;\n}\n\n\/* getline: read a line into s, return length *\/\nint getline(char s[], int lim) {\n    int c, i;\n    for (i = 0; i &lt; lim - 1 &amp;&amp; (c = getchar()) != EOF &amp;&amp; c != '\\n'; i++){\n        s[i] = c;\n    }\n    if (c == '\\n'){\n        s[i] = c;\n        ++i;\n    }\n    s[i] = '\\0';\n    return i;\n}\n\n\/* copy: copy 'from' into 'to'; assume to is big enough *\/\nvoid copy(char to[], char from[]) {\n    int i;\n\n    i = 0;\n    while ((to[i] = from[i]) != '\\0') {\n        ++i;\n    }\n}<\/code><\/pre>\n\n\n\n<p>Revised code:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n#define MAXLINE 1000    \/* maximum input line size *\/\n\nint getline(char s[], int lim);\nvoid copy(char to[], char from[]);\n\n\/* print the longest input line *\/\nmain() {\n    int len;        \/* current line length          *\/\n    int max;        \/* maximum length seen so far   *\/\n    char line[MAXLINE];     \/* current input line   *\/\n    char longest[MAXLINE];  \/* longest line saved here *\/\n\n    max = 0;\n    while ((len = getline(line, MAXLINE)) &gt; 0) {\n        printf(\"%d %s\\n\", len, line);\n        if (len &gt; max) {\n            max = len;\n            copy(longest, line);\n        }\n    }\n    if (max &gt; 0) {    \/* there was a line *\/\n        printf(\"Longest line: %s\", longest);\n    }\n    return 0;\n}\n\n\/* getline: read a line into s, return length *\/\nint getline(char s[], int lim) {\n    int c, i, j = 0;\n    for (i = 0; (c = getchar()) != EOF &amp;&amp; c != '\\n'; i++) {\n        if (i &lt; lim - 2) {\n            s[j] = c;       \/* line stall in boundariea *\/\n            ++j;\n        }\n        if (c == '\\n') {\n            s[j] = c;\n            ++j;\n            ++i;\n        }   \n    }\n    s[j] = '\\0';\n    return i;\n}\n\n\/* copy: copy 'from' into 'to'; assume to is big enough *\/\nvoid copy(char to[], char from[]) {\n    int i;\n\n    i = 0;\n    while ((to[i] = from[i]) != '\\0') {\n        ++i;\n    }\n}<\/code><\/pre>\n\n\n\n<p>Exercise 1-17. Write a program to print all input lines that are longer than 80 characters.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n\n#define MAXLINE 1000\n#define LONGLINE 80\n\nint getline(char line[], int maxline);\n\nmain() {\n    int len;\n    char line[MAXLINE];\n\n    while ((len = getline(line, MAXLINE)) &gt; 0){\n        if (len &gt; LONGLINE){\n            printf(\"%s\", line);\n        }\n    }\n    return 0;\n}\n\nint getline(char s[], int lim) {\n    int c, i, j = 0;\n    for (i = 0; (c = getchar()) != EOF &amp;&amp; c != '\\n'; i++){\n        if (i &lt; lim - 2) {\n            s[j] = c;\n            ++j;\n        }\n    }\n    if (c == '\\n'){\n        s[j] = c;\n        ++j;\n        ++i;\n    }\n    s[j] = '\\0';\n    return i;\n}<\/code><\/pre>\n\n\n\n<p>Exercise 1-18. Write a program to remove all trailing blanks and tabs from each line of input, and to delete entirely blank lines.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n#define MAXLINE 1000 \/* maximun input line size *\/\n\nmain() {\n    char line[MAXLINE];     \/* current input line   *\/\n\n    while(getline(line, MAXLINE) &gt; 0)\n        if (remove(line) &gt; 0){\n            printf(\"%s\", line);\n        }\n    return 0;\n}\n\n\/* getline: read a line into s, return length *\/\nint getline(char line[], int maxline) {\n    int c, i, j = 0;\n    for (i = 0; (c = getchar()) != EOF &amp;&amp; c != '\\n'; i++){\n        if (i &lt; maxline - 2){\n            line[j] = c;       \/* line stall in boundariea *\/\n            ++j;\n        }\n    }\n    if (c == '\\n'){\n        line[j] = c;\n        ++j;\n        ++i;\n    }\n    line[j] = '\\0';\n    return i;\n}\n\n\/* remove tariling blanks and tabs from character string *\/\nint remove(char s[]) {\n    int i = 0;\n\n    while (s[i] != '\\n') {        \/* find newline character *\/\n        ++i;\n    }\n    --i;                        \/* back off from '\\n' *\/\n    while (i &gt;= 0 &amp;&amp; (s[i] == ' ' || s[i] == '\\t')) {\n        --i;\n    }\n    if (i &gt;= 0){             \/* is it a nonblank line? *\/\n        ++i;\n        s[i] = '\\n';          \/* put newline character back *\/\n        ++i;\n        s[i] = '\\0';          \/* terminate the string *\/\n    }\n    return i;\n}<\/code><\/pre>\n\n\n\n<p>Exercise 1-19. Write a function <code>reverse(s)<\/code> that reverses the character string s . Use it to write a program that reverses its input a line at a time.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n#define MAXLINE 1000    \/* maximum input line size *\/\n\nint getline(char line[], int maxline);\nvoid reverse(char s[]);\n\n\/* reverse input lines, s line at a time *\/\nmain() {\n    char line[MAXLINE];     \/* current input line *\/\n\n    while (getline(line, MAXLINE) &gt; 0){\n        reverse(line);\n        printf(\"%s\", line);\n    }\n}\n\n\/* getline: read a line into s, return length *\/\nint getline(char line[], int maxline) {\n    int c, i, j = 0;\n    for (i = 0; (c = getchar()) != EOF &amp;&amp; c != '\\n'; i++) {\n        if (i &lt; maxline - 2) {\n            line[j] = c;       \/* line stall in boundariea *\/\n            ++j;\n        }\n    }\n    if (c == '\\n') {\n        line[j] = c;\n        ++j;\n        ++i;\n    }\n    line[j] = '\\0';\n    return i;\n}\n\n\/* reverse: reverse string *\/\nvoid reverse(char s[]) {\n    int i, j;\n    char temp;\n\n    i = 0;\n    while (s[i] != '\\0') {        \/* find the end of string *\/\n        ++i;\n    }\n    --i;                        \/* back off from '\\0' *\/  \n    if (s[i] == '\\n'){\n        --i;                    \/* leave nawline in place *\/\n    }\n    j = 0;                      \/* beginning of new string *\/\n    while (j &lt; i){\n        temp = s[j];\n        s[j] = s[i];            \/* swap the characters *\/\n        s[i] = temp;\n        --i;\n        ++j;\n    }\n}<\/code><\/pre>\n\n\n\n<p>Exercise 1-20. Write a program <code>detab<\/code> 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?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n\n#define TABINC 8    \/* tab increment size *\/\n\n\/* replace tabs with the proper number of blanks *\/\nmain() {\n    int c, nb, pos;\n\n    nb = 0;     \/* number of blanks necessary *\/\n    pos = 1;    \/* position of character in line *\/\n    while ((c = getchar()) != EOF){\n        if (c == '\\t'){       \/* tab character *\/\n            nb = TABINC - (pos - 1) % TABINC;\n            while (nb &gt; 0){\n                putchar(' ');\n                ++pos;\n                --nb;\n            }\n        } else if (c == '\\n') {       \/* newline character *\/\n            putchar(c);\n            pos = 1;\n        } else {                    \/* all other characters*\/\n            putchar(c);\n            ++pos;\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<p>Exercise 1-21. Write a program <code>entab<\/code> that replaces strings of blanks with the minimum number of tabs and blanks to achieve the same spacing. Use the same stops as for <code>detab<\/code> . When either a tab or a single blank would suffice to reach a tab stop, which should be given preference?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n\n#define TABINC 8    \/* tab increment size *\/\n\n\/* replace strings of blanks with tabs and blanks *\/\nmain() {\n    int c, nb, nt, pos;\n\n    nb = 0;     \/* # of blanks necessary *\/\n    nt = 0;     \/* # of tabs necessary *\/\n    for (pos = 1; (c = getchar()) != EOF; ++pos) {\n        if (c == ' '){\n            if (pos % TABINC != 0){\n                ++nb;       \/* increment # of blanks *\/\n            } else {\n                nb = 0;     \/* reset # of blanks *\/\n                ++nt;       \/* one more tab *\/\n            }\n        } else {\n            for ( ; nt &gt; 0; --nt){\n                putchar('\\t');    \/* output tab(s) *\/\n            }\n            if (c == '\\t'){\n                nb = 0;\n            } else {\n                for ( ; nb &gt; 0; --nb){\n                    putchar(' ');\n                }\n            }\n            putchar(c);\n            if (c == '\\n'){\n                pos = 0;\n            } else if(c == '\\t') {\n                pos = pos + (TABINC - (pos - 1) % TABINC) - 1;\n            }\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<p>Exercise 1-22. Write a program to &#8220;fold&#8221; 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.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n\n#define MAXCOL 10   \/* maximum column of input *\/\n#define TABLNC 8    \/* tab increment size *\/\n\nchar line[MAXCOL];\n\nint exptab(int pos);\nint findblnk(int pos);\nint newpos(int pos);\nvoid printl(int pos);\n\n\/* fold long input lines into two or more shorter lines *\/\nmain() {\n    int c, pos;\n\n    pos = 0;    \/* position in the line *\/\n    while ((c = getchar()) != EOF){\n        line[pos] = c;      \/* store current character  *\/\n        if (c == '\\t'){       \/* expand tab character     *\/\n            pos = exptab(pos);\n        } else if(c == '\\n'){\n            printl(pos);    \/* print current input line *\/\n            pos = 0;\n        } else if (++pos &gt;= MAXCOL){\n            pos = findblnk(pos);\n            printl(pos);\n            pos = newpos(pos);\n;       } \n    }\n}\n\n\/* printl: print line until pos column *\/\nvoid printl(int pos) {\n    int i;\n    for (i = 0; i &lt; pos; ++i){\n        putchar(line[i]);\n    }\n    if (pos &gt; 0){        \/* any chars printed ? *\/\n        putchar('\\n');\n    }\n}\n\n\/* exptab: expand tab into blanks *\/\nint exptab(int pos) {\n    line[pos] = ' ';  \/* tab is at least one blank *\/\n    for (++pos; pos &lt; MAXCOL &amp;&amp; pos % TABLNC != 0; ++pos){\n        line[pos] = ' ';\n    }\n    if (pos &lt; MAXCOL){   \/* room left in current line    *\/\n        return pos;\n    } else {            \/* current line is full         *\/\n        printf(pos);\n        return 0;       \/* reset current position       *\/\n    }\n}\n\n\/* findblnk: find blank's position *\/\nint findblnk(int pos) {\n    while (pos &gt; 0 &amp;&amp; line[pos] != ' ') {\n        --pos;\n    }\n    if (pos == 0){      \/* no blanks in the line?   *\/\n        return MAXCOL;\n    } else {            \/* at least one blank       *\/\n        return pos + 1; \/* position after the blank *\/\n    }\n}\n\n\/* newpos: rearrange line with new position *\/\nint newpos(int pos) {\n    int i, j;\n\n    if (pos &lt;=  0 || pos &gt;= MAXCOL){\n        return 0;   \/* nothing to rearrange *\/\n    } else {\n        i = 0;\n        for (j = pos; j &lt; MAXCOL; ++j){\n            line[i] = line[j];\n            ++i;\n        }\n        return i;   \/* new position in line *\/\n    }\n}<\/code><\/pre>\n\n\n\n<p>Exercise 1-23. Write a program to remove all comments from a C program. Don\\\\&#8217;t forget to handle quoted strings and character constants properly. C comments do not nest.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n\nvoid rcomment(int c);\nvoid in_comment(void);\nvoid echo_quote(int c);\n\n\/* remove all comments from a valid C program*\/\nmain() {\n    int c, d;\n\n    while ((c = getchar()) != EOF){\n        rcomment(c);\n    }\n    return 0;\n}\n\n\/* rcomment: read each character, remove the comments *\/\nvoid rcomment(int c) {\n    int d;\n\n    if (c == '\/'){\n        if ((d = getchar()) == '*') {\n            in_comment();       \/* beginning comment *\/\n        } else if (d == '\/') {\n            putchar(c);     \/* anther slash *\/\n            rcomment(d);\n        } else {\n            putchar(c);     \/* not a comment *\/\n            putchar(d);\n        }\n    } else if (c == '\\'' || c == '\"') {\n        echo_quote(c);      \/* quote begins *\/\n    } else {\n        putchar(c);         \/* not a comment *\/\n    }\n}\n\n\/* in_comment: inside of a valid comment *\/\nvoid in_comment(void) {\n    int c, d;\n    c = getchar();  \/* prev character *\/\n    d = getchar();  \/* curr character *\/\n    while (c != '*' || d != '\/'){   \/* search for end *\/\n        c = d;\n        d = getchar();\n    }\n}\n\n\/* echo_quote: echo characters within quotes *\/\nvoid echo_quote(int c) {\n    int d;\n    putchar(c);\n    while ((d = getchar()) != c){   \/* search for end *\/\n        putchar(d);\n        if (d == '\\\\'){\n            putchar(getchar());     \/* ignore escape seq *\/\n        }\n    }\n    putchar(d);\n}<\/code><\/pre>\n\n\n\n<p>Exercise 1-24. Write a program to check a C program for rudimentary syntax errors like unbalanced parentheses, brackets and braces. Don\\\\&#8217;t forget about quotes, both single and double, escape sequences, and comments. (This program is hard if you do it in full generality.)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"c\" class=\"language-c\">#include&lt;stdio.h&gt;\n\nint brace, brack, paren;\n\nvoid in_quote(int c);\nvoid in_comment(void);\nvoid search(int c);\n\n\/* rudimentary syntex checker for C programs *\/\nmain() {\n    int c;\n    extern int brace, brack, paren;\n    while ((c = getchar()) != EOF) {\n        if (c == '\/') {\n            if ((c = getchar()) == '*') {\n                in_comment();   \/* inside comment *\/\n            }\n            else {\n                search(c);\n            }\n        } else if (c == '\\'' || c == '\"') {\n            in_quote(c);        \/* inside quote *\/\n        } else {\n            search(c);\n        }\n        if (brace &lt; 0) {\n            printf(\"Unbalanced braces\\n\");\n            brace = 0;\n        } else if (brack &lt; 0) {\n            printf(\"Unbalanced brackets\\n\");\n            brack = 0;\n        } else if (paren &lt; 0) {\n            printf(\"Unbalanced parentheses\\n\");\n            paren = 0;\n        }\n    }\n    if (brace &gt; 0) {\n        printf(\"Unbalanced brackets\\n\");\n    } \n    if (brack &gt; 0) {\n        printf(\"Unbalanced brackets\\n\");\n    }\n    if (paren &gt; 0) {\n        printf(\"Unbalanced parentheses\\n\");\n    }\n}\n\n\/* search: search for rudimentary syntax errors *\/\nvoid search(int c) {\n    extern int brace, brack, paren;\n\n    if (c == '{') {\n        ++brace;\n    }\n    else if (c == '}') {\n        --brace;\n    }\n    else if (c == '[') {\n        ++brack;\n    }\n    else if (c == ']'){\n        --brack;\n    }\n    else if (c == '('){\n        ++paren;\n    } \n    else if (c == ')'){\n        --paren;\n    }\n}\n\n\/* in_comment: inside of a valid comment *\/\nvoid in_comment(void) {\n    int c, d;\n\n    c = getchar();  \/* prev character *\/\n    d = getchar();  \/* curr character *\/\n    while (c != '*' || d != '\/') {  \/* search for end *\/\n        c = d;\n        d = getchar();\n    }\n}\n\n\/* in_quote: inside quote *\/\nvoid in_quote(int c) {\n    int d;\n\n    while ((d = getchar()) != c){   \/* search end quote  *\/\n        if (d == '\\\\') {\n            getchar();              \/* ignore escape seq *\/\n        }\n    }\n}<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Exercise 1-1. Run the &#8220;hello world&#8221; program &hellip; <a href=\"https:\/\/blog.liuyingjie.com.cn\/?p=264\" class=\"more-link\">\u7ee7\u7eed\u9605\u8bfb<span class=\"screen-reader-text\">K&#038;R2 solutions: Chapter 1 &#8211; A Tutorial Introduction<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[8],"tags":[],"class_list":["post-264","post","type-post","status-publish","format-standard","hentry","category-c"],"_links":{"self":[{"href":"https:\/\/blog.liuyingjie.com.cn\/index.php?rest_route=\/wp\/v2\/posts\/264","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.liuyingjie.com.cn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.liuyingjie.com.cn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.liuyingjie.com.cn\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.liuyingjie.com.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=264"}],"version-history":[{"count":64,"href":"https:\/\/blog.liuyingjie.com.cn\/index.php?rest_route=\/wp\/v2\/posts\/264\/revisions"}],"predecessor-version":[{"id":966,"href":"https:\/\/blog.liuyingjie.com.cn\/index.php?rest_route=\/wp\/v2\/posts\/264\/revisions\/966"}],"wp:attachment":[{"href":"https:\/\/blog.liuyingjie.com.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=264"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.liuyingjie.com.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=264"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.liuyingjie.com.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=264"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}