1. 入门
1.1. 第一个C语言程序
写一个程序,在屏幕上输出hello, world
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版
对于某个特定任务我们可以采用多种方法来编写程序。上面这个程序如果把while循环改成for循环,程序可以更简洁。
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.7. 文件复制第2版
对于经验比较丰富的C语言程序员,可以把这个字符复制程序编写得更精炼一些。
1.8. 字符计数
下列程序用于对字符进行计数,它与上面的复制程序类似。
1.9. 字符计数第2版
1.10. 行计数
接下来的这个程序用于统计输入中的行数。
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.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. 字符串长度
写一个函数求字符串的长度
2.2. 字符串转整数
写一个函数将包含一串数字的字符串转换成整数
2.3. 大写变小写
写一个函数,将大写字母变成小写字母,其他字符不变。
2.4. 随机函数
写一个函数,用来产生随机的整数
2.5. 字符串删除
写一个函数squeeze(s, c),删除字符串s中所有的字符c。
2.6. 字符串连接
写一个函数strcat(s,t),它将字符串t连接到字符串s的尾部
2.7. 位运算
写一个函数getbits(x,p,n),它返回x中从右边数第p位开始向右数n位的字段
2.8. 位计数
函数bitcount统计其整型参数的值为1的二进制位的个数
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. 字符串翻转
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. 字符串裁剪
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
4.4. 字符串转整数第3版
在函数atof的基础上,我们可以利用它编写出函数atoi(将字符串转换为int类型)
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. 打印整数
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 }
5. 指针与数组
5.1. 交换两个变量的值
5.2. 读取整数
1 #include <ctype.h>
2
3 int getch(void);
4 void ungetch(int);
5
6 /* getint: get next integer from input into *pn */
7 int getint(int *pn)
8 {
9 int c, sign;
10
11 while (isspace(c = getch())) /* skip white space */
12 ;
13 if (!isdigit(c) && c != EOF && c != '+' && c != '-') {
14 ungetch(c); /* it is not a number */
15 return 0;
16 }
17 sign = (c == '-') ? -1 : 1;
18 if (c == '+' || c == '-')
19 c = getch();
20 for (*pn = 0; isdigit(c), c = getch())
21 *pn = 10 * *pn + (c - '0');
22 *pn *= sign;
23 if (c != EOF)
24 ungetch(c);
25 return c;
26 }
5.3. 求字符串长度
5.4. 内存分配程序
1 #define ALLOCSIZE 10000 /* size of available space */
2
3 static char allocbuf[ALLOCSIZE]; /* storage for alloc */
4 static char *allocp = allocbuf; /* next free position */
5
6 char *alloc(int n) /* return pointer to n characters */
7 {
8 if (allocbuf + ALLOCSIZE - allocp >= n) { /* it fits */
9 allocp += n;
10 return allocp - n; /* old p */
11 } else /* not enough room */
12 return 0;
13 }
14
15 void afree(char *p) /* free storage pointed to by p */
16 {
17 if (p >= allocbuf && p < allocbuf + ALLOCSIZE)
18 allocp = p;
19 }
5.5. 字符串拷贝
5.6. 字符串拷贝第2版
5.7. 字符串拷贝第3版
5.8. 字符串拷贝第4版
5.9. 字符串比较
5.10. 字符串比较第2版
5.11. 文本行排序
该程序按字母顺序对由文本行组成的集合进行排序。
1 #include <stdio.h>
2 #include <string.h>
3
4 #define MAXLINES 5000 /* max #lines to be sorted */
5
6 char *lineptr[MAXLINES]; /* pointers to text lines */
7
8 int readlines(char *lineptr[], int nlines);
9 void writelines(char *lineptr[], int nlines);
10
11 void qsort(char *lineptr[], int left, int right);
12
13 /* sort input lines */
14 main()
15 {
16 int nlines; /* number of input lines read */
17
18 if ((nlines = readlines(lineptr, MAXLINES)) >= 0) {
19 qsort(lineptr, 0, nlines-1);
20 writelines(lineptr, nlines);
21 return 0;
22 } else {
23 printf("error: input too big to sort\n");
24 return 1;
25 }
26 }
27
28 #define MAXLEN 1000 /* max length of any input line */
29 int getline(char *, int);
30 char *alloc(int);
31
32 /* readlines: read input lines */
33 int readlines(char *lineptr[], int maxlines)
34 {
35 int len, nlines;
36 char *p, line[MAXLEN];
37
38 nlines = 0;
39 while ((len = getline(line, MAXLEN)) > 0)
40 if (nlines >= maxlines || p = alloc(len) == NULL)
41 return -1;
42 else {
43 line[len-1] = '\0'; /* delete newline */
44 strcpy(p, line);
45 lineptr[nlines++] = p;
46 }
47 return nlines;
48 }
49
50 /* writelines: write output lines */
51 void writelines(char *lineptr[], int nlines)
52 {
53 int i;
54
55 for (i = 0; i < nlines; i++)
56 printf("%s\n", lineptr[i]);
57 }
5.12. 输出所有行函数第2版
5.13. 文本行排序函数
1 /* qsort: sort v[left]...v[right] into increasing order */
2 void qsort(char *v[], int left, int right)
3 {
4 int i, last;
5 void swap(char *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);
10 last = left;
11 for (i = left+1; i <= right; i++)
12 if (strcmp(v[i], v[left]) < 0)
13 swap(v, ++last, i);
14 swap(v, left, last);
15 qsort(v, left, last-1);
16 qsort(v, last+1, right);
17 }
5.14. 日期转换
我们考虑一个日期转换的问题:把某月某日这种日期表示形式转换为某年中第几天的表示形式,反之亦然。
1 static char daytab[2][13] = {
2 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
3 {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
4 };
5
6 /* day_of_year: set day of year from month & day */
7 int day_of_year(int year, int month, int day)
8 {
9 int i, leap;
10 leap = year%4 == 0 && year%100 != 0 || year%400 == 0;
11 for (i = 1; i < month; i++)
12 day += daytab[leap][i];
13 return day;
14 }
15
16 /* month_day: set month, day from day of year */
17 void month_day(int year, int yearday, int *pmonth, int *pday)
18 {
19 int i, leap;
20
21 leap = year%4 == 0 && year%100 != 0 || year%400 == 0;
22 for (i = 1; yearday > daytab[leap][i]; i++)
23 yearday -= daytab[leap][i];
24 *pmonth = i;
25 *pday = yearday;
26 }
5.15. 月份名称
考虑这样一个问题:编写一个函数month_name(n),它返回一个指向第n个月名字的字符串的指针。
1 /* month_name: return name of n-th month */
2 char *month_name(int n)
3 {
4 static char *name[] = {
5 "Illegal month",
6 "January", "February", "March",
7 "April", "May", "June",
8 "July", "August", "September",
9 "October", "November", "December"
10 };
11
12 return (n < 1 || n > 12) ? name[0] : name[n];
13 }
5.16. 参数回显
写一个程序echo,它将命令行参数回显在屏幕上的一行中,其中命令行中各参数之间用空格隔开。
5.17. 参数回显第2版
5.18. 模式查找第2版
通过命令行的第一个参数指定待匹配的模式
1 #include <stdio.h>
2 #include <string.h>
3 #define MAXLINE 1000
4
5 int getline(char *line, int max);
6
7 /* find: print lines that match pattern from 1st arg */
8 main(int argc, char *argv[])
9 {
10 char line[MAXLINE];
11 int found = 0;
12
13 if (argc != 2)
14 printf("Usage: find pattern\n");
15 else
16 while (getline(line, MAXLINE) > 0)
17 if (strstr(line, argv[1]) != NULL) {
18 printf("%s", line);
19 found++;
20 }
21 return found;
22 }
5.19. 模式查找第3版
用-x(代表except)表示打印所有与模式不匹配的文本行,用-n(代表number)表示打印行号
1 #include <stdio.h>
2 #include <string.h>
3 #define MAXLINE 1000
4
5 int getline(char *line, int max);
6
7 /* find: print lines that match pattern from 1st arg */
8 main(int argc, char *argv[])
9 {
10 char line[MAXLINE];
11 long lineno = 0;
12 int c, except = 0, number = 0, found = 0;
13
14 while (--argc > 0 && (*++argv)[0] == '-')
15 while (c = *++argv[0])
16 switch (c) {
17 case 'x':
18 except = 1;
19 break;
20 case 'n':
21 number = 1;
22 break;
23 default:
24 printf("find: illegal option %c\n", c);
25 argc = 0;
26 found = -1;
27 break;
28 }
29 if (argc != 1)
30 printf("Usage: find -x -n pattern\n");
31 else
32 while (getline(line, MAXLINE) > 0) {
33 lineno++;
34 if ((strstr(line, *argv) != NULL) != except) {
35 if (number)
36 printf("%ld:", lineno);
37 printf("%s", line);
38 found++;
39 }
40 }
41 return found;
42 }
5.20. 行排序程序
在给定可选参数-n的情况下,该函数将按数值大小而非字典顺序对输入行进行排序。
1 #include <stdio.h>
2 #include <string.h>
3
4 #define MAXLINES 5000 /* max #lines to be sorted */
5 char *lineptr[MAXLINES]; /* pointers to text lines */
6
7 int readlines(char *lineptr[], int nlines);
8 void writelines(char *lineptr[], int nlines);
9
10 void qsort(void *lineptr[], int left, int right,
11 int (*comp)(void *, void *));
12 int numcmp(char *, char *);
13
14 /* sort input lines */
15 main(int argc, char *argv[])
16 {
17 int nlines; /* number of input lines read */
18 int numeric = 0; /* 1 if numeric sort */
19
20 if (argc > 1 && strcmp(argv[1], "-n") == 0)
21 numeric = 1;
22 if ((nlines = readlines(lineptr, MAXLINES)) >= 0) {
23 qsort((void**) lineptr, 0, nlines-1,
24 (int (*)(void*,void*))(numeric ? numcmp : strcmp));
25 writelines(lineptr, nlines);
26 return 0;
27 } else {
28 printf("input too big to sort\n");
29 return 1;
30 }
31 }
1 /* qsort: sort v[left]...v[right] into increasing order */
2 void qsort(void *v[], int left, int right,
3 int (*comp)(void *, void *))
4 {
5 int i, last;
6
7 void swap(void *v[], int, int);
8
9 if (left >= right) /* do nothing if array contains */
10 return; /* fewer than two elements */
11 swap(v, left, (left + right)/2);
12 last = left;
13 for (i = left+1; i <= right; i++)
14 if ((*comp)(v[i], v[left]) < 0)
15 swap(v, ++last, i);
16 swap(v, left, last);
17 qsort(v, left, last-1, comp);
18 qsort(v, last+1, right, comp);
19 }
5.21. 复杂声明
1 /* dcl: parse a declarator */
2 void dcl(void)
3 {
4 int ns;
5
6 for (ns = 0; gettoken() == '*'; ) /* count *'s */
7 ns++;
8 dirdcl();
9 while (ns-- > 0)
10 strcat(out, " pointer to");
11 }
12
13 /* dirdcl: parse a direct declarator */
14 void dirdcl(void)
15 {
16 int type;
17
18 if (tokentype == '(') { /* ( dcl ) */
19 dcl();
20 if (tokentype != ')')
21 printf("error: missing )\n");
22 } else if (tokentype == NAME) /* variable name */
23 strcpy(name, token);
24 else
25 printf("error: expected name or (dcl)\n");
26 while ((type=gettoken()) == PARENS || type == BRACKETS)
27 if (type == PARENS)
28 strcat(out, " function returning");
29 else {
30 strcat(out, " array");
31 strcat(out, token);
32 strcat(out, " of");
33 }
34 }
1 #include <stdio.h>
2 #include <string.h>
3 #include <ctype.h>
4
5 #define MAXTOKEN 100
6
7 enum { NAME, PARENS, BRACKETS };
8
9 void dcl(void);
10 void dirdcl(void);
11
12 int gettoken(void);
13 int tokentype; /* type of last token */
14 char token[MAXTOKEN]; /* last token string */
15 char name[MAXTOKEN]; /* identifier name */
16 char datatype[MAXTOKEN]; /* data type = char, int, etc. */
17 char out[1000];
18
19 main() /* convert declaration to words */
20 {
21 while (gettoken() != EOF) { /* 1st token on line */
22 strcpy(datatype, token); /* is the datatype */
23 out[0] = '\0';
24 dcl(); /* parse rest of line */
25 if (tokentype != '\n')
26 printf("syntax error\n");
27 printf("%s: %s %s\n", name, out, datatype);
28 }
29 return 0;
30 }
1 int gettoken(void) /* return next token */
2 {
3 int c, getch(void);
4 void ungetch(int);
5 char *p = token;
6
7 while ((c = getch()) == ' ' || c == '\t')
8 ;
9 if (c == '(') {
10 if ((c = getch()) == ')') {
11 strcpy(token, "()");
12 return tokentype = PARENS;
13 } else {
14 ungetch(c);
15 return tokentype = '(';
16 }
17 } else if (c == '[') {
18 for (*p++ = c; (*p++ = getch()) != ']'; )
19 ;
20 *p = '\0';
21 return tokentype = BRACKETS;
22 } else if (isalpha(c)) {
23 for (*p++ = c; isalnum(c = getch()); )
24 *p++ = c;
25 *p = '\0';
26 ungetch(c);
27 return tokentype = NAME;
28 } else
29 return tokentype = c;
30
31 }
6. 结构
6.1. 坐标点和矩形结构
6.2. 创建坐标结构
6.3. 坐标相加
6.4. 判断点是否在矩形中
6.5. 矩形规范化
1 #define min(a, b) ((a) < (b) ? (a) : (b))
2 #define max(a, b) ((a) > (b) ? (a) : (b))
3
4 /* canonrect: canonicalize coordinates of rectangle */
5 struct rect canonrect(struct rect r)
6 {
7 struct rect temp;
8
9 temp.pt1.x = min(r.pt1.x, r.pt2.x);
10 temp.pt1.y = min(r.pt1.y, r.pt2.y);
11 temp.pt2.x = max(r.pt1.x, r.pt2.x);
12 temp.pt2.y = max(r.pt1.y, r.pt2.y);
13 return temp;
14 }
6.6. 关键字统计
编写这样一个程序,它用来统计输入中各个C语言关键字出现的次数。
1 #include <stdio.h>
2 #include <ctype.h>
3 #include <string.h>
4
5 #define MAXWORD 100
6
7 int getword(char *, int);
8 int binsearch(char *, struct key *, int);
9
10 /* count C keywords */
11 main()
12 {
13 int n;
14 char word[MAXWORD];
15
16 while (getword(word, MAXWORD) != EOF)
17 if (isalpha(word[0]))
18 if ((n = binsearch(word, keytab, NKEYS)) >= 0)
19 keytab[n].count++;
20 for (n = 0; n < NKEYS; n++)
21 if (keytab[n].count > 0)
22 printf("%4d %s\n",
23 keytab[n].count, keytab[n].word);
24 return 0;
25 }
26
27 /* binsearch: find word in tab[0]...tab[n-1] */
28 int binsearch(char *word, struct key tab[], int n)
29 {
30 int cond;
31 int low, high, mid;
32
33 low = 0;
34 high = n - 1;
35 while (low <= high) {
36 mid = (low+high) / 2;
37 if ((cond = strcmp(word, tab[mid].word)) < 0)
38 high = mid - 1;
39 else if (cond > 0)
40 low = mid + 1;
41 else
42 return mid;
43 }
44 return -1;
45 }
1 /* getword: get next word or character from input */
2 int getword(char *word, int lim)
3 {
4 int c, getch(void);
5 void ungetch(int);
6 char *w = word;
7
8 while (isspace(c = getch()))
9 ;
10 if (c != EOF)
11 *w++ = c;
12 if (!isalpha(c)) {
13 *w = '\0';
14 return c;
15 }
16 for ( ; --lim > 0; w++)
17 if (!isalnum(*w = getch())) {
18 ungetch(*w);
19 break;
20 }
21 *w = '\0';
22 return word[0];
23 }