Press "Enter" to skip to content

分类: C

K&R2 第二章提到类型转换示例

例如,假设 int 为 16 位,long 为 32 位。 然后 -1L < 1U,因为 1U 是一个 unsigned int,被提升为一个有符号的 long。 但是 -1L > 1UL 因为 -1L 被提升为无符号长整数,因此看起来是一个很大的正数。

-1L < 1U:

-1L 作为 32 位长 int = 表示为 0xFFFFFFFF。 在这种情况下不会被转换,因此解释保持 -1

1U 作为 16 位无符号整数 = 0x0001。 提升为 32 位长 int -> 0x00000001 = 解释为 1

比较结果:-1 < 1

-1L > 1UL:

-1L = 32 位长整数 = 0xFFFFFFFF。 转换为 unsigned long int = 0xFFFFFFFF。 因为它现在是无符号的,所以它会被解释为 (2^32 – 1)

1UL 作为 32 位长 int = 表示为 0x00000001。 在这种情况下不会被转换,所以解释保持 1

比较结果:(2^32 – 1) > 1

K&R2 solutions: Chapter 3 – Control Flow

Exercise 3.1 Our binary search makes two tests inside the loop, when one would suffice (at the price of more tests outside). Write a version with only one test inside the loop and measure the difference in run-time.

Original for loop code:

/* binsearch: find x in v[0] <= v[1] <= ... <= v[n-1] */
int binsearch(int x, int v[], int n)
{
    int low, high, mid;
    low = 0;
    high = n - 1;
    while (low <= high) {
        mid = (low + high) / 2;
        if (x < v[mid])
            high = mid + 1;
        else if (x > v[mid])
            low = mid + 1;
        else /* found match */
            return mid;
    }
    return -1; /* no match */
}

Modified code:

#include<stdio.h>

int binsearch(int x, int v[], int n);

main() {
    int arr[] = { 1,3,5,7,8,10,22,24,26,28,41,43,45,47,50,51 };
    printf("%d", binsearch(7,arr,10));
}

int binsearch(int x, int v[], int n) {
    int low, high, mid;

    low = 0;
    high = n - 1;

    mid = (low + high) / 2;

    while (low < high && x != v[mid]) {
        if (x > v[mid]){
            low = mid + 1;
        } else {
            high = mid - 1;
        }
        mid = (low + high) / 2;
    }
    if (x == v[mid]){
        return mid;
    } else {
        return -1;
    }
}

Exercise 3.2 Write a function escape(s,t) that converts characters like newline and tab into visible escape sequences like \n and \t as it copies the string t to s . Use a switch . Write a function for the other direction as well, converting escape sequences into the real characters.

K&R2 solutions: Chapter 2 – Types, Operators and Expressions

Exercise 2-1. Write a program to determine the ranges of char , short , int , and long variables, both signed and unsigned , by printing appropriate values from standard headers and by direct computation. Harder if you compute them: determine the ranges of the various floating-point types.

#include<stdio.h>
#include<limits.h>

/* determine ranges of types */
main() {
    /* signed types */
    printf("signed char min = %d\n", SCHAR_MIN);
    printf("signed char max = %d\n", SCHAR_MAX);
    printf("signed short min = %d\n", SHRT_MIN);
    printf("signed short max = %d\n", SHRT_MAX);
    printf("signed int min = %d\n", INT_MIN);
    printf("signed int max = %d\n", INT_MAX);
    printf("signed long min = %d\n", LONG_MIN);
    printf("signed long max = %d\n", LONG_MIN);

    /* unsigned types */
    printf("unsigned char max = %u\n", UCHAR_MAX);
    printf("unsigned short max = %u\n", USHRT_MAX);
    printf("unsigned int max = %u\n", UINT_MAX);
    printf("unsigned long max = %lu\n", ULONG_MAX);
}

Output Result:

signed char min = -128
signed char max = 127
signed short min = -32768
signed short max = 32767
signed int min = -2147483648
signed int max = 2147483647
signed long min = -2147483648
signed long max = -2147483648
unsigned char max = 255
unsigned short max = 65535
unsigned int max = 4294967295
unsigned long max = 4294967295

#include<stdio.h>

/* determine ranges of types */
main() {
    /* signed types */
    printf("signed char min = %d\n",
                    -(char)((unsigned char)~0 >> 1));
    printf("signed char max = %d\n",
                    (char)((unsigned char)~0 >> 1));
    printf("signed short min = %d\n",
                    -(short)((unsigned short)~0 >> 1));
    printf("signed short max = %d\n",
                    (short)((unsigned short)~0 >> 1));
    printf("signed int min = %d\n",
                    -(int)((unsigned int)~0 >> 1));
    printf("signed int max = %d\n",
                    (int)((unsigned int)~0 >> 1));
    printf("signed long min = %d\n",
                    -(long)((unsigned long)~0 >> 1));
    printf("signed long max =  %d\n",
                    (long)((unsigned long)~0 >> 1));

    /* unsigned types */
    printf("unsigned char max = %u\n", 
                    (unsigned char)~0);
    printf("unsigned short max = %u\n",
                    (unsigned short)~0);
    printf("unsigned int max = %u\n",
                    (unsigned int)~0);
    printf("unsigned long max = %u\n",
                    (unsigned long)~0);
}

Output Result:

signed char min = -127
signed char max = 127
signed short min = -32767
signed short max = 32767
signed int min = -2147483647
signed int max = 2147483647
signed long min = -2147483647
signed long max =  2147483647
unsigned char max = 255
unsigned short max = 65535
unsigned int max = 4294967295
unsigned long max = 4294967295

Exercise 2-2. Write a loop equivalent to the for loop above without using && or ||.

Original for loop code:

for(i=0; i<lim-1 && (c=getchar()) != '\n' && c != EOF; ++i)
  s[i] = c;

Modified code:

#include<stdio.h>

/*
  for(i=0; i<lim-1 && (c=getchar()) != '\n' && c != EOF; ++i)
    s[i] = c;
*/

enum loop {NO, YES};
enum loop okloop = YES;
#define MAXLINE 80

main(){
    int c, i = 0, s[MAXLINE];
    int lim = MAXLINE;
    while (okloop == YES){
        if (i >= lim-1){
            okloop = NO;
        } else if ((c = getchar()) != '\n'){
            okloop = NO;
        } else if (c != EOF){
            okloop = NO;
        } else {
            s[i] = c;
            ++i;
        }
    }
}

Exercise 2-3. Write the function htoi(s) , which converts a string of hexadecimal digits (including an optional 0x or 0X) into its equivalent integer value. The allowable digits are 0 through 9, a through f, and A through F .

#include<stdio.h>

#define MAXLINE 100
#define YES 1
#define NO  0

int getline(char line[], int maxline);
int htoi(char s[]);

main(){
    int value;
    char line[MAXLINE];
    getline(line, MAXLINE);
    value = htoi(line);

    printf("The value of %s is %d \n", line, value);
}

int getline(char s[], int lim){
    int c, i;
    for (i = 0; i < lim-1 && ((c = getchar()) != EOF) && c != '\n'; ++i){
        s[i] = c;
    }
    if (c == '\n'){
        s[i] = c;
        ++i;
    }
    s[i] = '\0';
    return i;
}

/* htoi: convert hexadecimal string's to integer*/
int htoi(char s[]){
    int hexdigit, i, inhex, n;

    i = 0;
    if (s[i] == '0'){       /* skip optionel 0x or 0X*/
        ++i;
        if (s[i] == 'x' || s[i] == 'X'){
            ++i;
        }
    }
    n = 0;                  /* integer value to be returned    */
    inhex = YES;            /* assume valid hexedecimal digit  */
    for ( ; inhex == YES; ++i){
        if (s[i] >= '0' && s[i] <= '9'){
            hexdigit = s[i] - '0';
        } else if (s[i] >= 'a' && s[i] <= 'f'){
            hexdigit = s[i] - 'a' + 10;
        } else if (s[i] >= 'A' && s[i] <= 'F'){
            hexdigit = s[i] - 'A' + 10;
        } else {
            inhex = NO;     /* not a valid hexadecimal digit    */
        }
        if (inhex == YES){
            n = 16 * n + hexdigit;
        }
    }
    return n;
}

For example to convert 0XAF.

  1. We strip off 0X.
  2. For A, we get the value hexdigit = 10
  3. n = 16 * 0 + 10 = 10
  4. We gather F, we store hexdigit = ‘F’ – ‘A’ + 10;= 70 – 65 + 10; (70 is ascii value for F, 65 is ascii value for A) = 15
  5. n = 16 n + hexdigit = 16 10 + 15 = 160 + 15 = 175

Exercise 2-4. Write an alternate version of squeeze(s1,s2) that deletes each character in the string s1 that matches any character in the string s2 .

#include<stdio.h>
#define MAXLINE 1000

int mgetline(char line[], int maxline);
void squeeze(char s1[], char s2[]);

main(){
    char s1[MAXLINE], s2[MAXLINE];
    putchar('s');
    putchar('1');
    mgetline(s1, MAXLINE);

    putchar('s');
    putchar('2');
    mgetline(s2, MAXLINE);

    squeeze(s1, s2);

    printf("%s",s1);

    return 0;

}

int mgetline(char s[], int lim){
    int i, c;

    for (i = 0; 1 < lim-1 && (c = getchar()) != EOF && c != '\n'; ++i){
        s[i] = c;
    }
    if (c == '\n'){
        s[i++] = c;
    }
    s[i] = '\0';
}

void squeeze(char s1[],char s2[]){
    int i, j, k;
    k = 0;

    for (i = 0; s1[i] != '\0'; ++i){
        for (j = 0; (s1[i] != s2[j]) && s2[j] != '\0'; ++j)
            ;
        if (s2[j] == '\0'){
            s1[k++] = s1[i];
        }
    }
    s1[k] = '\0';
}

Explanation:

Let’s take the two inputs strings as:

s1: Hello,World

s2: ol

Our desired output is:

He,Wrd

This has removed the characters o and l from the first string. The way squeeze works is, it take each character from the first string and if there is no match found, stores it with a new index k. If there is a match found in s2, it simply skips it. The way it skips is realized by the following:

for(j=0; (s1[i]!=s2[j]) && s2[j]!='\0' ;++j)
    ;
if(s2[j]=='\0')
    s1[k++] = s1[i];

When the match is found s1[i] == s2[j] so our first for loop will end. The second if condtion will fail too as s2 is not iterated till the end, so we do not place the character in s1[k++] and we have successfully skipped it.

Exercise 2-5: Write the function any(s1,s2) , which returns the first location in the string s1 where any character from the string s2 occurs, or -1 if s1 contains no characters from s2 . (The standard library function strpbrk does the same job but returns a pointer to the location.)

#include<stdio.h>
#define MAXLINE 1000

int getline(char line[], int maxline);
int any(char s1[], char s2[]);

main(){
    char s1[MAXLINE], s2[MAXLINE];
    int val;

    getline(s1, MAXLINE);

    getline(s2, MAXLINE);

    val = any(s1, s2);
    printf("%d", val);
    return 0;
}

int getline(char s[], int lim){
    int i, c;
    for (i = 0; i < lim-1 && (c = getchar()) != EOF && c != '\n'; ++i){
        s[i] = c;
    }
    if (c == '\n'){
        s[i++] = c;
    }
    s[i] = '\0';
}

int any(char s1[], char s2[]){
    int i, j;
    for (i = 0; s1[i] != '\0'; ++i){
        // iterate through s2 while trying to find matching character from s1
        for (j = 0; (s1[i] != s2[j]) && s2[j] != '\0'; ++j)
            ;   //continue
        if (s2[j] != '\0' && s2[j] != '\n'){
            return i;
        }

    }
    return -1;
}

K&R2 solutions: Chapter 1 – A Tutorial Introduction

Exercise 1-1. Run the “hello world” program on your system. Experiment with leaving out parts of the program, to see what error messages you get.

#include<stdio.h>

main(){
    printf("Hello, World\n");
}

Exercise 1-2. Experiment to find out what happens when printf \\’s argument string contains \c, where c is some character not listed above.

#include<stdio.h>

main() {
    /*
    newline NL  (LF)        \n  backslash       \       \
    horizontal  tab HT      \t  question mark   ?       \?
    vertical    tab VT      \v  single quote    '      \'
    backspace   BS          \b  double quote    "      
    carriage    return CR   \r  octal number    ooo     \ooo
    formfeed    FF          \f  hex number      hh      \xhh
    audible     alert BEL   \a
    */
    printf("newline (0x0A): '\n'\n");
    printf("horizontal tab (0x09): '\t'\n");
    printf("vertical tab (0x0B):'\v'\n");
    printf("backspace (0x08): ' \b'\n");
    printf("carriage return (0x0D): '\r'\n");
    printf("formfeed (0x0C): '\f'\n");
    printf("alert (0x07) - added in C89: '\a'\n");
    printf("backslash (0x5C): '\'\n");
    printf("question mark (0x3F): '\?'\n");
    printf("single quote (0x27): '\''\n");
    printf("double quote: (0x22)''\n");
    printf("octal number (ooo): '\101'\n");
    printf("hex number (xhh): '\x41'\n");
}

Exercise 1-3. Modify the temperature conversion program to print a heading above the table.

#include<stdio.h>

/* print Fahrenheit-Celsius table
    for fahr = 0, 20, ..., 300; floating-point version */
main() {
    float fahr, celsius;
    float lower, upper, step;

    lower = 0;      /* lower limit of temperatuire scale */
    upper = 300;    /* upper limit */
    step = 20;      /* step size */

    fahr = lower;
    printf("Fahrenheit\tCelsius\n");
    while (fahr <= upper){
        celsius = (5.0 / 9.0) * (fahr - 32.0);
        printf("%3.0f\t\t%6.1f\n", fahr, celsius);
        fahr = fahr + step;
    }
}

Exercise 1-4. Write a program to print the corresponding Celsius to Fahrenheit table.

#include<stdio.h>

main() {
    float fahr, celsius;
    float lower, upper, step;

    lower = 0;      /* lower limit of temperatuire scale */
    upper = 300;    /* upper limit */
    step = 20;      /* step size */

    celsius = lower;
    printf("Fahrenheit\tCelsius\n");
    while (celsius <= upper){
        fahr = (9.0 / 5.0) * celsius + 32.0;
        printf("%3.0f\t\t%6.1f\n", celsius, fahr);
        celsius = celsius + step;
    }
}

Exercise 1-5. Modify the temperature conversion program to print the table in reverse order, that is, from 300 degrees to 0.

#include<stdio.h>

main() {
    float fahr, celsius;
    float lower, upper, step;

    lower = 0;      /* lower limit of temperatuire scale */
    upper = 300;    /* upper limit */
    step = 20;      /* step size */

    fahr = upper;
    printf("Fahrenheit\tCelsius\n");
    while (fahr >= lower){
        celsius = (5.0 / 9.0) * (fahr - 32.0);
        printf("%3.0f\t\t%6.1f\n", fahr, celsius);
        fahr = fahr - step;
    }
}

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

/* This program prompts for input, and then captures a character
 * from the keyboard. If EOF is signalled (typically through a
 * control-D or control-Z character, though not necessarily),
 * the program prints 0. Otherwise, it prints 1.
 *
 * If your input stream is buffered (and it probably is), then
 * you will need to press the ENTER key before the program will
 * respond.
 */
#include<stdio.h>

main() {
    printf("Press any key or type CONTROL-Z, then type ENTER. :-)\n\n");
    printf("The expression getchar() != EOF evaluates to %d\n", getchar() != EOF);
}

Exercise 1-7. Write a program to print the value of EOF .

#include<stdio.h>

main() {
    printf("The value of EOF is %d\n",EOF);
}

Exercise 1-8. Write a program to count blanks, tabs, and newlines.

#include<stdio.h>

main() {
    int c, nb, nt, nl;
    nb = nt = nl = 0;
    while ((c = getchar()) != EOF) {
        if (c == ' ') {   //ASCII value for " "
            ++nb;
        }
        if (c == '\t') {  //ASCII value for "\t"
            ++nt;
        }
        if (c == '\n') {  //ASCII value for "\n"
            ++nl;
        }
    }
    printf("Total spaces:%d \nTotal tabs:%d \nTotal lines:%d\n", nb, nt, nl);
}

Using ASCII values

#include<stdio.h>

//Using ASCII values

main() {
    int c, nb, nt, nl;
    nb = nt = nl = 0;
    while ((c = getchar()) != EOF) {
        if (c == 32) {  //ASCII value for " "
            ++nb;
        }
        if (c == 9) {   //ASCII value for "\t"
            ++nt;
        }
        if (c == 10) {  //ASCII value for "\n"
            ++nl;
        }
    }
    printf("Total spaces:%d \nTotal tabs:%d \nTotal lines:%d\n", nb, nt, nl);
}

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.

#include<stdio.h>

main() {
    char c;
    char prev_c;  /* previous character */

    prev_c = 0;
    while ((c = getchar()) != EOF){
        /* output c if it's not a blank OR if the previous c is not a blank */
        if (c != ' ' || prev_c != ' ') {
            putchar(c);
            prev_c = c;
        }
    }
}

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.

#include<stdio.h>

main() {
    int c;
    while ((c = getchar()) != EOF){
        if (c == '\\' || c == '\t' || c == '\b'){
            putchar('\\');
            if (c == '\\'){
                putchar('\\');
            }
            if (c == '\t'){
                putchar('t');
            }
            if (c == '\b'){
                putchar('b');
            }
        }else{
            putchar(c);
        }
    }
}

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?

Exercise 1-12. Write a program that prints its input one word per line.

#include<stdio.h>

#define IN 1
#define OUT 0

main() {
    int c, state;

    state = OUT;
    while ((c = getchar()) != EOF){
        if (c == '\n' || c == ' ' || c == '\t'){
            if (state == IN){
                state = OUT;
                putchar('\n');
            }
            continue;
        }
        state = IN;
        putchar(c);
    }
}

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.

#include<stdio.h>

#define MAXHIST 15      /* max length of histogram  */
#define MAXWORD 11      /* max length of a word     */
#define IN  1           /* inside a word            */
#define OUT 0           /* outside a word           */

/* print horizontal histogram */
main() {
    int c, i, nc, state;
    int len;            /* length of each bar       */
    int maxvalue;       /* maximum value for wl[]   */
    int ovflow;         /* number of overflow words */
    int wl[MAXWORD];    /* word length counters     */

    state = OUT;
    nc = 0;             /* number of chars in a word*/
    ovflow = 0;         /* number of words >= MAXWORD*/
    for (i = 0; i < MAXWORD; ++i){
        wl[i] = 0;
    }
    while ((c = getchar()) != EOF){
        if (c == ' ' || c == '\n' || c == '\t'){
            state = OUT;
            if (nc > 0){
                if (nc < MAXWORD) {
                    ++wl[nc];
                } else {
                    ++ovflow;
                }
            }
            nc = 0;
        }else if(state == OUT){
            state = IN;
            nc = 1;     /* beginning of a new word  */
        }else{
            ++nc;       /* inside a word            */
        }
    }

    maxvalue = 0;
    for (i = 1; i < MAXWORD; ++i){
        if (wl[i] > maxvalue){
            maxvalue = wl[i];
        }
    }
    for (i = 1; i < MAXWORD; ++i) {
        printf("%5d - %5d : ", i, wl[i]);
        if (wl[i] > 0) {
            if ((len = wl[i] * MAXHIST / maxvalue) <= 0) {
                len = 1;
            }
        } else {
            len = 0;
        }
        while (len > 0) {
            putchar('*');
            --len;
        }   
        putchar('\n');
        }
    if (ovflow > 0) {
        printf("There are %d words >= %d\n", ovflow, MAXWORD);
    }
}

Exercise 1-14. Write a program to print a histogram of the frequencies of different characters in its input.

#include<stdio.h>
#include<ctype.h>

#define MAXHISI 15      /* max length of histagram  */
#define MAXCHAR 128     /* max different characters */

/* print horizontal histcgram freq. if different characters */
main() {
    int c, i;
    int len;            /* length of each bar       */
    int maxvalue;       /* maximum value for cc[]   */
    int cc[MAXCHAR];    /* character counters       */

    for (i = 0; i < MAXCHAR; i++){
        cc[i] = 0;
    }
    while((c =  getchar()) != EOF)
        if (c < MAXCHAR){
            ++cc[c];
        }
    maxvalue = 0;
    for (i = 1; i <MAXCHAR; i++){
        if (cc[i] > maxvalue){
            maxvalue = cc[i];
        }
    }
    for (i = 1; i < MAXCHAR; i++){
        if (isprint(i)){    /* isprint(c) printing character including space    */
            printf("%5d - %c - %5d : ", i, i, cc[i]);
        } else {
            printf("%5d -  - %5d : ", i, cc[i]);
        }
        if (cc[i] > 0){
            if ((len = cc[i] * MAXHISI / MAXCHAR <= 0)) {
                len = 1;
            }
        } else {
            len = 0;
        }
        while (len > 0){
            putchar('*');
            --len;
        }
        putchar('\n');
    }
}

Exercise 1-15. Rewrite the temperature conversion program of Section 1.2 to use a function for conversion.

#include<stdio.h>

int fahr_celsius(int fahr);

main() {
    int i;
    for (i = 0; i <= 300; i = i + 20){
        printf("%3.1d %6.1d\n", i, fahr_celsius(i));
    }
}

int fahr_celsius(int fahr) {
    int celsius;
    celsius = (5.0 / 9.0) * (fahr - 32.0);
    return celsius;
}

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.

Original code:

#include<stdio.h>
#define MAXLINE 1000    /* maximum input line size */

int getline(char s[], int lim);
void copy(char to[], char from[]);

/* print the longest input line */
main() {
    int len;        /* current line length          */
    int max;        /* maximum length seen so far   */
    char line[MAXLINE];     /* current input line   */
    char longest[MAXLINE];  /* longest line saved here */

    max = 0;
    while ((len = getline(line,MAXLINE)) > 0){
        if (len > max){
            max = len;
            copy(longest, line);
        }
    }
    if (max > 0){    /* there was a line */
        printf("Longest line: %s", longest);
    }
    return 0;
}

/* getline: read a line into s, return length */
int getline(char s[], int lim) {
    int c, i;
    for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; i++){
        s[i] = c;
    }
    if (c == '\n'){
        s[i] = c;
        ++i;
    }
    s[i] = '\0';
    return i;
}

/* copy: copy 'from' into 'to'; assume to is big enough */
void copy(char to[], char from[]) {
    int i;

    i = 0;
    while ((to[i] = from[i]) != '\0') {
        ++i;
    }
}

Revised code:

#include<stdio.h>
#define MAXLINE 1000    /* maximum input line size */

int getline(char s[], int lim);
void copy(char to[], char from[]);

/* print the longest input line */
main() {
    int len;        /* current line length          */
    int max;        /* maximum length seen so far   */
    char line[MAXLINE];     /* current input line   */
    char longest[MAXLINE];  /* longest line saved here */

    max = 0;
    while ((len = getline(line, MAXLINE)) > 0) {
        printf("%d %s\n", len, line);
        if (len > max) {
            max = len;
            copy(longest, line);
        }
    }
    if (max > 0) {    /* there was a line */
        printf("Longest line: %s", longest);
    }
    return 0;
}

/* getline: read a line into s, return length */
int getline(char s[], int lim) {
    int c, i, j = 0;
    for (i = 0; (c = getchar()) != EOF && c != '\n'; i++) {
        if (i < lim - 2) {
            s[j] = c;       /* line stall in boundariea */
            ++j;
        }
        if (c == '\n') {
            s[j] = c;
            ++j;
            ++i;
        }   
    }
    s[j] = '\0';
    return i;
}

/* copy: copy 'from' into 'to'; assume to is big enough */
void copy(char to[], char from[]) {
    int i;

    i = 0;
    while ((to[i] = from[i]) != '\0') {
        ++i;
    }
}

Exercise 1-17. Write a program to print all input lines that are longer than 80 characters.

#include<stdio.h>

#define MAXLINE 1000
#define LONGLINE 80

int getline(char line[], int maxline);

main() {
    int len;
    char line[MAXLINE];

    while ((len = getline(line, MAXLINE)) > 0){
        if (len > LONGLINE){
            printf("%s", line);
        }
    }
    return 0;
}

int getline(char s[], int lim) {
    int c, i, j = 0;
    for (i = 0; (c = getchar()) != EOF && c != '\n'; i++){
        if (i < lim - 2) {
            s[j] = c;
            ++j;
        }
    }
    if (c == '\n'){
        s[j] = c;
        ++j;
        ++i;
    }
    s[j] = '\0';
    return i;
}

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

#include<stdio.h>
#define MAXLINE 1000 /* maximun input line size */

main() {
    char line[MAXLINE];     /* current input line   */

    while(getline(line, MAXLINE) > 0)
        if (remove(line) > 0){
            printf("%s", line);
        }
    return 0;
}

/* getline: read a line into s, return length */
int getline(char line[], int maxline) {
    int c, i, j = 0;
    for (i = 0; (c = getchar()) != EOF && c != '\n'; i++){
        if (i < maxline - 2){
            line[j] = c;       /* line stall in boundariea */
            ++j;
        }
    }
    if (c == '\n'){
        line[j] = c;
        ++j;
        ++i;
    }
    line[j] = '\0';
    return i;
}

/* remove tariling blanks and tabs from character string */
int remove(char s[]) {
    int i = 0;

    while (s[i] != '\n') {        /* find newline character */
        ++i;
    }
    --i;                        /* back off from '\n' */
    while (i >= 0 && (s[i] == ' ' || s[i] == '\t')) {
        --i;
    }
    if (i >= 0){             /* is it a nonblank line? */
        ++i;
        s[i] = '\n';          /* put newline character back */
        ++i;
        s[i] = '\0';          /* terminate the string */
    }
    return i;
}

Exercise 1-19. 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.

#include<stdio.h>
#define MAXLINE 1000    /* maximum input line size */

int getline(char line[], int maxline);
void reverse(char s[]);

/* reverse input lines, s line at a time */
main() {
    char line[MAXLINE];     /* current input line */

    while (getline(line, MAXLINE) > 0){
        reverse(line);
        printf("%s", line);
    }
}

/* getline: read a line into s, return length */
int getline(char line[], int maxline) {
    int c, i, j = 0;
    for (i = 0; (c = getchar()) != EOF && c != '\n'; i++) {
        if (i < maxline - 2) {
            line[j] = c;       /* line stall in boundariea */
            ++j;
        }
    }
    if (c == '\n') {
        line[j] = c;
        ++j;
        ++i;
    }
    line[j] = '\0';
    return i;
}

/* reverse: reverse string */
void reverse(char s[]) {
    int i, j;
    char temp;

    i = 0;
    while (s[i] != '\0') {        /* find the end of string */
        ++i;
    }
    --i;                        /* back off from '\0' */  
    if (s[i] == '\n'){
        --i;                    /* leave nawline in place */
    }
    j = 0;                      /* beginning of new string */
    while (j < i){
        temp = s[j];
        s[j] = s[i];            /* swap the characters */
        s[i] = temp;
        --i;
        ++j;
    }
}

Exercise 1-20. 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?

#include<stdio.h>

#define TABINC 8    /* tab increment size */

/* replace tabs with the proper number of blanks */
main() {
    int c, nb, pos;

    nb = 0;     /* number of blanks necessary */
    pos = 1;    /* position of character in line */
    while ((c = getchar()) != EOF){
        if (c == '\t'){       /* tab character */
            nb = TABINC - (pos - 1) % TABINC;
            while (nb > 0){
                putchar(' ');
                ++pos;
                --nb;
            }
        } else if (c == '\n') {       /* newline character */
            putchar(c);
            pos = 1;
        } else {                    /* all other characters*/
            putchar(c);
            ++pos;
        }
    }
}

Exercise 1-21. 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?

#include<stdio.h>

#define TABINC 8    /* tab increment size */

/* replace strings of blanks with tabs and blanks */
main() {
    int c, nb, nt, pos;

    nb = 0;     /* # of blanks necessary */
    nt = 0;     /* # of tabs necessary */
    for (pos = 1; (c = getchar()) != EOF; ++pos) {
        if (c == ' '){
            if (pos % TABINC != 0){
                ++nb;       /* increment # of blanks */
            } else {
                nb = 0;     /* reset # of blanks */
                ++nt;       /* one more tab */
            }
        } else {
            for ( ; nt > 0; --nt){
                putchar('\t');    /* output tab(s) */
            }
            if (c == '\t'){
                nb = 0;
            } else {
                for ( ; nb > 0; --nb){
                    putchar(' ');
                }
            }
            putchar(c);
            if (c == '\n'){
                pos = 0;
            } else if(c == '\t') {
                pos = pos + (TABINC - (pos - 1) % TABINC) - 1;
            }
        }
    }
}

Exercise 1-22. 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.

#include<stdio.h>

#define MAXCOL 10   /* maximum column of input */
#define TABLNC 8    /* tab increment size */

char line[MAXCOL];

int exptab(int pos);
int findblnk(int pos);
int newpos(int pos);
void printl(int pos);

/* fold long input lines into two or more shorter lines */
main() {
    int c, pos;

    pos = 0;    /* position in the line */
    while ((c = getchar()) != EOF){
        line[pos] = c;      /* store current character  */
        if (c == '\t'){       /* expand tab character     */
            pos = exptab(pos);
        } else if(c == '\n'){
            printl(pos);    /* print current input line */
            pos = 0;
        } else if (++pos >= MAXCOL){
            pos = findblnk(pos);
            printl(pos);
            pos = newpos(pos);
;       } 
    }
}

/* printl: print line until pos column */
void printl(int pos) {
    int i;
    for (i = 0; i < pos; ++i){
        putchar(line[i]);
    }
    if (pos > 0){        /* any chars printed ? */
        putchar('\n');
    }
}

/* exptab: expand tab into blanks */
int exptab(int pos) {
    line[pos] = ' ';  /* tab is at least one blank */
    for (++pos; pos < MAXCOL && pos % TABLNC != 0; ++pos){
        line[pos] = ' ';
    }
    if (pos < MAXCOL){   /* room left in current line    */
        return pos;
    } else {            /* current line is full         */
        printf(pos);
        return 0;       /* reset current position       */
    }
}

/* findblnk: find blank's position */
int findblnk(int pos) {
    while (pos > 0 && line[pos] != ' ') {
        --pos;
    }
    if (pos == 0){      /* no blanks in the line?   */
        return MAXCOL;
    } else {            /* at least one blank       */
        return pos + 1; /* position after the blank */
    }
}

/* newpos: rearrange line with new position */
int newpos(int pos) {
    int i, j;

    if (pos <=  0 || pos >= MAXCOL){
        return 0;   /* nothing to rearrange */
    } else {
        i = 0;
        for (j = pos; j < MAXCOL; ++j){
            line[i] = line[j];
            ++i;
        }
        return i;   /* new position in line */
    }
}

Exercise 1-23. 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.

#include<stdio.h>

void rcomment(int c);
void in_comment(void);
void echo_quote(int c);

/* remove all comments from a valid C program*/
main() {
    int c, d;

    while ((c = getchar()) != EOF){
        rcomment(c);
    }
    return 0;
}

/* rcomment: read each character, remove the comments */
void rcomment(int c) {
    int d;

    if (c == '/'){
        if ((d = getchar()) == '*') {
            in_comment();       /* beginning comment */
        } else if (d == '/') {
            putchar(c);     /* anther slash */
            rcomment(d);
        } else {
            putchar(c);     /* not a comment */
            putchar(d);
        }
    } else if (c == '\'' || c == '"') {
        echo_quote(c);      /* quote begins */
    } else {
        putchar(c);         /* not a comment */
    }
}

/* in_comment: inside of a valid comment */
void in_comment(void) {
    int c, d;
    c = getchar();  /* prev character */
    d = getchar();  /* curr character */
    while (c != '*' || d != '/'){   /* search for end */
        c = d;
        d = getchar();
    }
}

/* echo_quote: echo characters within quotes */
void echo_quote(int c) {
    int d;
    putchar(c);
    while ((d = getchar()) != c){   /* search for end */
        putchar(d);
        if (d == '\\'){
            putchar(getchar());     /* ignore escape seq */
        }
    }
    putchar(d);
}

Exercise 1-24. 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.)

#include<stdio.h>

int brace, brack, paren;

void in_quote(int c);
void in_comment(void);
void search(int c);

/* rudimentary syntex checker for C programs */
main() {
    int c;
    extern int brace, brack, paren;
    while ((c = getchar()) != EOF) {
        if (c == '/') {
            if ((c = getchar()) == '*') {
                in_comment();   /* inside comment */
            }
            else {
                search(c);
            }
        } else if (c == '\'' || c == '"') {
            in_quote(c);        /* inside quote */
        } else {
            search(c);
        }
        if (brace < 0) {
            printf("Unbalanced braces\n");
            brace = 0;
        } else if (brack < 0) {
            printf("Unbalanced brackets\n");
            brack = 0;
        } else if (paren < 0) {
            printf("Unbalanced parentheses\n");
            paren = 0;
        }
    }
    if (brace > 0) {
        printf("Unbalanced brackets\n");
    } 
    if (brack > 0) {
        printf("Unbalanced brackets\n");
    }
    if (paren > 0) {
        printf("Unbalanced parentheses\n");
    }
}

/* search: search for rudimentary syntax errors */
void search(int c) {
    extern int brace, brack, paren;

    if (c == '{') {
        ++brace;
    }
    else if (c == '}') {
        --brace;
    }
    else if (c == '[') {
        ++brack;
    }
    else if (c == ']'){
        --brack;
    }
    else if (c == '('){
        ++paren;
    } 
    else if (c == ')'){
        --paren;
    }
}

/* in_comment: inside of a valid comment */
void in_comment(void) {
    int c, d;

    c = getchar();  /* prev character */
    d = getchar();  /* curr character */
    while (c != '*' || d != '/') {  /* search for end */
        c = d;
        d = getchar();
    }
}

/* in_quote: inside quote */
void in_quote(int c) {
    int d;

    while ((d = getchar()) != c){   /* search end quote  */
        if (d == '\\') {
            getchar();              /* ignore escape seq */
        }
    }
}