TableOfContents

1. 入门

1.1. 第一个C语言程序

写一个程序,在屏幕上输出hello, world

   1 #include <stdio.h>
   2 
   3 main()
   4 {
   5     printf("hello, world\n");
   6 }

1.2. 摄氏华氏温度对照表

使用公式℃=(5/9)(℉-32) 打印华氏温度与摄氏温度对照表

   1 #include <stdio.h>
   2 
   3 /* print Fahrenheit-Celsius table
   4    for fahr = 0, 20, ..., 300 */
   5 main()
   6 {
   7     int fahr, celsius;
   8     int lower, upper, step;
   9 
  10     lower = 0;      /* lower limit of temperature scale */
  11     upper = 300;    /* upper limit */
  12     step = 20;      /* step size */
  13 
  14     fahr = lower;
  15     while (fahr <= upper) {
  16         celsius = 5 * (fahr-32) / 9;
  17         printf("%d\t%d\n", fahr, celsius);
  18         fahr = fahr + step;
  19     }
  20 }

1.3. 温度对照表第2版

上述的温度转换程序存在两个问题。比较简单的问题是,由于输出的数不是右对齐的,所以输出的结果不是很美观。另一个较为严重的问题是,由于我们使用的是整型算术运算,因此经计算得到的摄氏温度值不太精确,例如,与0℉对应的精确的摄氏温度应该为-17.8℃,而不是-17℃。

   1 #include <stdio.h>
   2 
   3 /* print Fahrenheit-Celsius table
   4    for fahr = 0, 20, ..., 300; floating-point version */
   5 main()
   6 {
   7     float fahr, celsius;
   8     float lower, upper, step;
   9 
  10     lower = 0;      /* lower limit of temperatuire scale */
  11     upper = 300;    /* upper limit */
  12     step = 20;      /* step size */
  13 
  14     fahr = lower;
  15     while (fahr <= upper) {
  16         celsius = (5.0/9.0) * (fahr-32.0);
  17         printf("%3.0f %6.1f\n", fahr, celsius);
  18         fahr = fahr + step;
  19     }
  20 }

1.4. 温度对照表第3版

对于某个特定任务我们可以采用多种方法来编写程序。

   1 #include <stdio.h>
   2 
   3 /* print Fahrenheit-Celsius table */
   4 main()
   5 {
   6     int fahr;
   7 
   8     for (fahr = 0; fahr <= 300; fahr = fahr + 20)
   9         printf("%3d %6.1f\n", fahr, (5.0/9.0)*(fahr-32));
  10 }

1.5. 温度对照表第4版

   1 #include <stdio.h>
   2 
   3 #define LOWER  0     /* lower limit of table */
   4 #define UPPER  300   /* upper limit */
   5 #define STEP   20    /* step size */
   6 
   7 /* print Fahrenheit-Celsius table */
   8 main()
   9 {
  10     int fahr;
  11 
  12     for (fahr = LOWER; fahr <= UPPER; fahr = fahr + STEP)
  13         printf("%3d %6.1f\n", fahr, (5.0/9.0)*(fahr-32));
  14 }

1.6. 文件复制

把输入一次一个字符地复制到输出

   1 #include <stdio.h>
   2 
   3 /* copy input to output; 1st version  */
   4 main()
   5 {
   6     int c;
   7 
   8     c = getchar();
   9     while (c != EOF) {
  10         putchar(c);
  11         c = getchar();
  12     }
  13 }

1.7. 文件复制第2版

对于经验比较丰富的C语言程序员,可以把这个字符复制程序编写得更精炼一些。

   1 #include <stdio.h>
   2 
   3 /* copy input to output; 2nd version  */
   4 main()
   5 {
   6     int c;
   7 
   8     while ((c = getchar()) != EOF)
   9         putchar(c);
  10 }

1.8. 字符计数

下列程序用于对字符进行计数,它与上面的复制程序类似。

   1 #include <stdio.h>
   2 
   3 /* count characters in input; 1st version */
   4 main()
   5 {
   6     long nc;
   7 
   8     nc = 0;
   9     while (getchar() != EOF)
  10         ++nc;
  11     printf("%ld\n", nc);
  12 }

1.9. 字符计数第2版

   1 #include <stdio.h>
   2 
   3 /* count characters in input; 2nd version */
   4 main()
   5 {
   6     double nc;
   7 
   8     for (nc = 0; gechar() != EOF; ++nc)
   9         ;
  10     printf("%.0f\n", nc);
  11 }

1.10. 行计数

接下来的这个程序用于统计输入中的行数。

   1 #include <stdio.h>
   2 
   3 /* count lines in input */
   4 main()
   5 {
   6     int c, nl;
   7 
   8     nl = 0;
   9     while ((c = getchar()) != EOF)
  10         if (c == '\n')
  11             ++nl;
  12     printf("%d\n", nl);
  13 }

1.11. 单词计数

写一个程序用于统计行数、单词数与字符数

   1 #include <stdio.h>
   2 
   3 #define IN   1  /* inside a word */
   4 #define OUT  0  /* outside a word */
   5 
   6 /* count lines, words, and characters in input */
   7 main()
   8 {
   9     int c, nl, nw, nc, state;
  10 
  11     state = OUT;
  12     nl = nw = nc = 0;
  13     while ((c = getchar()) != EOF) {
  14         ++nc;
  15         if (c == '\n')
  16             ++nl;
  17         if (c == ' ' || c == '\n' || c = '\t')
  18             state = OUT;
  19         else if (state == OUT) {
  20             state = IN;
  21             ++nw;
  22         }
  23     }
  24     printf("%d %d %d\n", nl, nw, nc);
  25 }

1.12. 数字字符计数

编写一个程序,以统计各个数字、空白符(包括空格符、制表符及换行符)以及所有其他字符出现的次数

   1    #include <stdio.h>
   2 
   3    /* count digits, white space, others */
   4    main()
   5    {
   6        int c, i, nwhite, nother;
   7        int ndigit[10];
   8 
   9        nwhite = nother = 0;
  10        for (i = 0; i < 10; ++i)
  11            ndigit[i] = 0;
  12 
  13        while ((c = getchar()) != EOF)
  14            if (c >= '0' && c <= '9')
  15                ++ndigit[c-'0'];
  16            else if (c == ' ' || c == '\n' || c == '\t')
  17                ++nwhite;
  18            else
  19                ++nother;
  20 
  21        printf("digits =");
  22        for (i = 0; i < 10; ++i)
  23            printf(" %d", ndigit[i]);
  24        printf(", white space = %d, other = %d\n",
  25            nwhite, nother);
  26    }

1.13. 函数

写一个求幂的函数power(m,n)

   1    #include <stdio.h>
   2 
   3    int power(int m, int n);
   4 
   5     /* test power function */
   6     main()
   7     {
   8         int i;
   9 
  10         for (i = 0; i < 10; ++i)
  11             printf("%d %d %d\n", i, power(2,i), power(-3,i));
  12         return 0;
  13     }
  14 
  15     /* power:  raise base to n-th power; n >= 0 */
  16     int power(int base, int n)
  17     {
  18         int i,  p;
  19 
  20         p = 1;
  21         for (i = 1; i <= n; ++i)
  22             p = p * base;
  23         return p;
  24     }

1.14. power函数第2版

   1    /* power:  raise base to n-th power; n >= 0; version 2 */
   2    int power(int base, int n)
   3    {
   4        int p;
   5 
   6        for (p = 1; n > 0; --n)
   7            p = p * base;
   8        return p;
   9    }

1.15. 最长的行

写一个程序读入一组文本行,并把最长的文本行打印出来。

   1    #include <stdio.h>
   2    #define MAXLINE 1000   /* maximum input line length */
   3 
   4    int getline(char line[], int maxline);
   5    void copy(char to[], char from[]);
   6 
   7    /* print the longest input line */
   8    main()
   9    {
  10        int len;            /* current line length */
  11        int max;            /* maximum length seen so far */
  12        char line[MAXLINE];    /* current input line */
  13        char longest[MAXLINE]; /* longest line saved here */
  14 
  15        max = 0;
  16        while ((len = getline(line, MAXLINE)) > 0)
  17            if (len > max) {
  18                max = len;
  19                copy(longest, line);
  20            }
  21        if (max > 0)  /* there was a line */
  22            printf("%s", longest);
  23        return 0;
  24    }
  25 
  26    /* getline:  read a line into s, return length  */
  27    int getline(char s[],int lim)
  28    {
  29        int c, i;
  30 
  31        for (i=0; i < lim-1 && (c=getchar())!=EOF && c!='\n'; ++i)
  32            s[i] = c;
  33        if (c == '\n') {
  34            s[i] = c;
  35            ++i;
  36        }
  37        s[i] = '\0';
  38        return i;
  39    }
  40 
  41    /* copy:  copy 'from' into 'to'; assume to is big enough */
  42    void copy(char to[], char from[])
  43    {
  44        int i;
  45 
  46        i = 0;
  47        while ((to[i] = from[i]) != '\0')
  48            ++i;
  49    }

1.16. 最长的行第2版

使用全局变量来实现

   1    #include <stdio.h>
   2 
   3    #define MAXLINE 1000    /* maximum input line size */
   4 
   5    int max;                /* maximum length seen so far */
   6    char line[MAXLINE];     /* current input line */
   7    char longest[MAXLINE];  /* longest line saved here */
   8 
   9    int getline(void);
  10    void copy(void);
  11 
  12    /* print longest input line; specialized version */
  13    main()
  14    {
  15        int len;
  16        extern int max;
  17        extern char longest[];
  18 
  19        max = 0;
  20        while ((len = getline()) > 0)
  21            if (len > max) {
  22                max = len;
  23                copy();
  24            }
  25        if (max > 0)  /* there was a line */
  26            printf("%s", longest);
  27        return 0;
  28    }
  29 
  30    /* getline:  specialized version */
  31    int getline(void)
  32    {
  33        int c, i;
  34        extern char line[];
  35 
  36        for (i = 0; i < MAXLINE - 1
  37             && (c=getchar)) != EOF && c != '\n'; ++i)
  38                 line[i] = c;
  39        if (c == '\n') {
  40            line[i] = c;
  41            ++i;
  42        }
  43        line[i] = '\0';
  44        return i;
  45    }
  46 
  47    /* copy: specialized version */
  48    void copy(void)
  49    {
  50        int i;
  51        extern char line[], longest[];
  52 
  53        i = 0;
  54        while ((longest[i] = line[i]) != '\0')
  55            ++i;
  56    }

2. 类型、运算符和表达式

2.1. 字符串长度

写一个函数求字符串的长度

   1    /* strlen:  return length of s */
   2    int strlen(char s[])
   3    {
   4        int i;
   5 
   6        while (s[i] != '\0')
   7            ++i;
   8        return i;
   9    }

2.2. 字符串转整数

写一个函数将包含一串数字的字符串转换成整数

   1    /* atoi:  convert s to integer */
   2    int atoi(char s[])
   3    {
   4        int i, n;
   5 
   6        n = 0;
   7        for (i = 0; s[i] >= '0' && s[i] <= '9'; ++i)
   8            n = 10 * n + (s[i] - '0');
   9        return n;
  10    }

2.3. 大写变小写

写一个函数,将大写字母变成小写字母,其他字符不变。

   1    /* lower:  convert c to lower case; ASCII only */
   2    int lower(int c)
   3    {
   4        if (c >= 'A' && c <= 'Z')
   5            return c + 'a' - 'A';
   6        else
   7            return c;
   8    }

2.4. 随机函数

写一个函数,用来产生随机的整数

   1    unsigned long int next = 1;
   2 
   3    /* rand:  return pseudo-random integer on 0..32767 */
   4    int rand(void)
   5    {
   6        next = next * 1103515245 + 12345;
   7        return (unsigned int)(next/65536) % 32768;
   8    }
   9 
  10    /* srand:  set seed for rand() */
  11    void srand(unsigned int seed)
  12    {
  13        next = seed;
  14    }

2.5. 字符串删除

写一个函数squeeze(s, c),删除字符串s中所有的字符c。

   1    /* squeeze:  delete all c from s */
   2    void squeeze(char s[], int c)
   3    {
   4       int i, j;
   5 
   6       for (i = j = 0; s[i] != '\0'; i++)
   7           if (s[i] != c)
   8               s[j++] = s[i];
   9       s[j] = '\0';
  10    }

2.6. 字符串连接

写一个函数strcat(s,t),它将字符串t连接到字符串s的尾部

   1    /* strcat:  concatenate t to end of s; s must be big enough */
   2    void strcat(char s[], char t[])
   3    {
   4        int i, j;
   5 
   6        i = j = 0;
   7        while (s[i] != '\0') /* find end of s */
   8            i++;
   9        while ((s[i++] = t[j++]) != '\0') /* copy t */
  10            ;
  11    }

2.7. 位运算

写一个函数getbits(x,p,n),它返回x中从右边数第p位开始向右数n位的字段

   1    /* getbits:  get n bits from position p */
   2    unsigned getbits(unsigned x, int p, int n)
   3    {
   4        return (x >> (p+1-n)) & ~(~0 << n);
   5    }

2.8. 位计数

函数bitcount统计其整型参数的值为1的二进制位的个数

   1    /* bitcount:  count 1 bits in x */
   2    int bitcount(unsigned x)
   3    {
   4        int b;
   5 
   6        for (b = 0; x != 0; x >>= 1)
   7            if (x & 01)
   8                b++;
   9        return b;
  10    }

3. 控制流

3.1. 折半查找

   1    /* binsearch:  find x in v[0] <= v[1] <= ... <= v[n-1] */
   2    int binsearch(int x, int v[], int n)
   3    {
   4        int low, high, mid;
   5 
   6        low = 0;
   7        high = n - 1;
   8        while (low <= high) {
   9            mid = (low+high)/2;
  10            if (x < v[mid])
  11                high = mid + 1;
  12            else if (x  > v[mid])
  13                low = mid + 1;
  14            else    /* found match */
  15                return mid;
  16        }
  17        return -1;   /* no match */
  18    }

3.2. 数字字符计数第2版

   1    #include <stdio.h>
   2 
   3    main()  /* count digits, white space, others */
   4    {
   5        int c, i, nwhite, nother, ndigit[10];
   6 
   7        nwhite = nother = 0;
   8        for (i = 0; i < 10; i++)
   9            ndigit[i] = 0;
  10        while ((c = getchar()) != EOF) {
  11            switch (c) {
  12            case '0': case '1': case '2': case '3': case '4':
  13            case '5': case '6': case '7': case '8': case '9':
  14                ndigit[c-'0']++;
  15                break;
  16            case ' ':
  17            case '\n':
  18            case '\t':
  19                nwhite++;
  20                break;
  21            default:
  22                nother++;
  23                break;
  24            }
  25        }
  26        printf("digits =");
  27        for (i = 0; i < 10; i++)
  28            printf(" %d", ndigit[i]);
  29        printf(", white space = %d, other = %d\n",
  30            nwhite, nother);
  31        return 0;
  32    }

3.3. 字符串转整数第2版

   1    #include <ctype.h>
   2 
   3    /* atoi:  convert s to integer; version 2 */
   4    int atoi(char s[])
   5    {
   6        int i, n, sign;
   7 
   8        for (i = 0; isspace(s[i]); i++)  /* skip white space */
   9            ;
  10        sign = (s[i] == '-') ? -1 : 1;
  11        if (s[i] == '+' || s[i] == '-')  /* skip sign */
  12            i++;
  13        for (n = 0; isdigit(s[i]); i++)
  14            n = 10 * n + (s[i] - '0');
  15        return sign * n;
  16    }

3.4. 希尔排序

   1    /* shellsort:  sort v[0]...v[n-1] into increasing order */
   2    void shellsort(int v[], int n)
   3    {
   4        int gap, i, j, temp;
   5 
   6        for (gap = n/2; gap > 0; gap /= 2)
   7            for (i = gap; i < n; i++)
   8                for (j=i-gap; j>=0 && v[j]>v[j+gap]; j-=gap) {
   9                    temp = v[j];
  10                    v[j] = v[j+gap];
  11                    v[j+gap] = temp;
  12                }
  13    }

3.5. 字符串翻转

   1    #include <string.h>
   2 
   3    /* reverse:  reverse string s in place */
   4    void reverse(char s[])
   5    {
   6        int c, i, j;
   7 
   8        for (i = 0, j = strlen(s)-1; i < j; i++, j--) {
   9            c = s[i];
  10            s[i] = s[j];
  11            s[j] = c;
  12        }
  13    }

3.6. 整数转字符串

   1    /* itoa:  convert n to characters in s */
   2    void itoa(int n, char s[])
   3    {
   4        int i, sign;
   5 
   6        if ((sign = n) < 0)  /* record sign */
   7            n = -n;          /* make n positive */
   8        i = 0;
   9        do {      /* generate digits in reverse order */
  10            s[i++] = n % 10 + '0';  /* get next digit */
  11        } while ((n /= 10) > 0);    /* delete it */
  12        if (sign < 0)
  13            s[i++] = '-';
  14        s[i] = '\0';
  15        reverse(s);
  16    }

3.7. 字符串裁剪

   1    /* trim:  remove trailing blanks, tabs, newlines */
   2    int trim(char s[])
   3    {
   4        int n;
   5 
   6        for (n = strlen(s)-1; n >= 0; n--)
   7            if (s[n] != ' ' && s[n] != '\t' && s[n] != '\n')
   8                break;
   9        s[n+1] = '\0';
  10        return n;
  11    }

4. 函数

4.1. 模式查找

设计并编写一个程序,它将输入中包含特定“模式”或字符串的各行打印出来(这是UNIX程序grep的特例)

   1    #include <stdio.h>
   2    #define MAXLINE 1000 /* maximum input line length */
   3 
   4    int getline(char line[], int max)
   5    int strindex(char source[], char searchfor[]);
   6 
   7    char pattern[] = "ould";   /* pattern to search for */
   8 
   9    /* find all lines matching pattern */
  10    main()
  11    {
  12        char line[MAXLINE];
  13        int found = 0;
  14 
  15        while (getline(line, MAXLINE) > 0)
  16            if (strindex(line, pattern) >= 0) {
  17                printf("%s", line);
  18                found++;
  19            }
  20        return found;
  21    }
  22 
  23    /* getline:  get line into s, return length */
  24    int getline(char s[], int lim)
  25    {
  26        int c, i;
  27 
  28        i = 0;
  29        while (--lim > 0 && (c=getchar()) != EOF && c != '\n')
  30            s[i++] = c;
  31        if (c == '\n')
  32            s[i++] = c;
  33        s[i] = '\0';
  34        return i;
  35    }
  36 
  37    /* strindex:  return index of t in s, -1 if none */
  38    int strindex(char s[], char t[])
  39    {
  40        int i, j, k;
  41 
  42        for (i = 0; s[i] != '\0'; i++) {
  43            for (j=i, k=0; t[k]!='\0' && s[j]==t[k]; j++, k++)
  44                ;
  45            if (k > 0 && t[k] == '\0')
  46                return i;
  47        }
  48        return -1;
  49    }

4.2. 字符串转浮点数

函数atof把字符串s转换为相应的双精度浮点数,是atoi函数的扩展

   1    #include <ctype.h>
   2 
   3    /* atof:  convert string s to double */
   4    double atof(char s[])
   5    {
   6        double val, power;
   7        int i, sign;
   8 
   9        for (i = 0; isspace(s[i]); i++)  /* skip white space */
  10            ;
  11        sign = (s[i] == '-') ? -1 : 1;
  12        if (s[i] == '+' || s[i] == '-')
  13            i++;
  14        for (val = 0.0; isdigit(s[i]); i++)
  15            val = 10.0 * val + (s[i] - '0');
  16        if (s[i] == '.')
  17            i++;
  18        for (power = 1.0; isdigit(s[i]); i++) {
  19            val = 10.0 * val + (s[i] - '0');
  20            power *= 10;
  21        }
  22        return sign * val / power;
  23    }

4.3. 调用atof

   1    #include <stdio.h>
   2 
   3    #define MAXLINE 100
   4 
   5    /* rudimentary calculator */
   6    main()
   7    {
   8        double sum, atof(char []);
   9        char line[MAXLINE];
  10        int getline(char line[], int max);
  11 
  12        sum = 0;
  13        while (getline(line, MAXLINE) > 0)
  14            printf("\t%g\n", sum += atof(line));
  15        return 0;
  16    }

4.4. 字符串转整数第3版

在函数atof的基础上,我们可以利用它编写出函数atoi(将字符串转换为int类型)

   1    /* atoi:  convert string s to integer using atof */
   2    int atoi(char s[])
   3    {
   4        double atof(char s[]);
   5 
   6        return (int) atof(s);
   7    }

4.5. 计算器

编写一个具有加(+)、减(-)、乘(*)、除(/)四则运算功能的计算器程序。为了更容易实现,我们在计算器中使用逆波兰表示法代替普通的中缀表示法,比如: (1 - 2) * (4 + 5) 采用逆波兰表示法表示为: 1 2 - 4 5 + *

   1    #include <stdio.h>
   2    #include <stdlib.h>  /* for  atof() */
   3 
   4    #define MAXOP   100  /* max size of operand or operator */
   5    #define NUMBER  '0'  /* signal that a number was found */
   6 
   7    int getop(char []);
   8    void push(double);
   9    double pop(void);
  10 
  11    /* reverse Polish calculator */
  12    main()
  13    {
  14        int type;
  15        double op2;
  16        char s[MAXOP];
  17 
  18        while ((type = getop(s)) != EOF) {
  19            switch (type) {
  20            case NUMBER:
  21                push(atof(s));
  22                break;
  23            case '+':
  24                push(pop() + pop());
  25                break;
  26            case '*':
  27                push(pop() * pop());
  28                break;
  29            case '-':
  30                op2 = pop();
  31                push(pop() - op2);
  32                break;
  33            case '/':
  34                op2 = pop();
  35                if (op2 != 0.0)
  36                    push(pop() / op2);
  37                else
  38                    printf("error: zero divisor\n");
  39                break;
  40            case '\n':
  41                printf("\t%.8g\n", pop());
  42                break;
  43            default:
  44                printf("error: unknown command %s\n", s);
  45                break;
  46            }
  47        }
  48        return 0;
  49    }

   1    #include <ctype.h>
   2 
   3    int getch(void);
   4    void ungetch(int);
   5 
   6    /* getop:  get next character or numeric operand */
   7    int getop(char s[])
   8    {
   9        int i, c;
  10 
  11        while ((s[0] = c = getch()) == ' ' || c == '\t')
  12            ;
  13        s[1] = '\0';
  14        if (!isdigit(c) && c != '.')
  15            return c;      /* not a number */
  16        i = 0;
  17        if (isdigit(c))    /* collect integer part */
  18            while (isdigit(s[++i] = c = getch()))
  19               ;
  20        if (c == '.')      /* collect fraction part */
  21            while (isdigit(s[++i] = c = getch()))
  22               ;
  23        s[i] = '\0';
  24        if (c != EOF)
  25            ungetch(c);
  26        return NUMBER;
  27    }

   1    #define BUFSIZE 100
   2 
   3    char buf[BUFSIZE];    /* buffer for ungetch */
   4    int bufp = 0;         /* next free position in buf */
   5 
   6    int getch(void)  /* get a (possibly pushed-back) character */
   7    {
   8        return (bufp > 0) ? buf[--bufp] : getchar();
   9    }
  10 
  11    void ungetch(int c)   /* push character back on input */
  12    {
  13        if (bufp >= BUFSIZE)
  14            printf("ungetch: too many characters\n");
  15        else
  16            buf[bufp++] = c;
  17    }

4.6. 打印整数

   1    #include <stdio.h>
   2 
   3    /* printd:  print n in decimal */
   4    void printd(int n)
   5    {
   6        if (n < 0) {
   7            putchar('-');
   8            n = -n;
   9        }
  10        if (n / 10)
  11            printd(n / 10);
  12        putchar(n % 10 + '0');
  13    }

4.7. 快速排序

   1    /* qsort:  sort v[left]...v[right] into increasing order */
   2    void qsort(int v[], int left, int right)
   3    {
   4        int i, last;
   5        void swap(int v[], int i, int j);
   6 
   7        if (left >= right) /* do nothing if array contains */
   8            return;        /* fewer than two elements */
   9        swap(v, left, (left + right)/2); /* move partition elem */
  10        last = left;                     /* to v[0] */
  11        for (i = left + 1; i <= right; i++)  /* partition */
  12            if (v[i] < v[left])
  13                swap(v, ++last, i);
  14        swap(v, left, last);            /* restore partition  elem */
  15        qsort(v, left, last-1);
  16        qsort(v, last+1, right);
  17    }

   1    /* swap:  interchange v[i] and v[j] */
   2    void swap(int v[], int i, int j)
   3    {
   4        int temp;
   5 
   6        temp = v[i];
   7        v[i] = v[j];
   8        v[j] = temp;
   9    }
ch3n2k.com | Copyright (c) 2004-2020 czk.