K&R 代码记录

文章目录

    • 1 序章
      • 单词计数
      • 练习 1-8 统计 空白字符的个数
      • 练习 1-9 消除输入中多余的连续空格
      • 练习 1-10 将不可见字符 显示化
      • 练习1-12 将输入中 每个单词打印一行
      • 练习1-13 打印单词长度的直方图
      • 输出长度最长的行
      • 练习1-16
      • 练习1-17 打印输入中长度大于80的行
      • 练习1-18 删除空行和行末不可见字符
        • 练习1-9 reverse 函数
    • 2 类型、运算符与表达式
      • 2.1 `strlen` 函数设计
      • 练习2-2 不使用 && || 完成循环
      • 2.2 `atoi ` 函数
      • 2.3 可移植的 `rand、srand` 函数
      • 2.4 `htoi` 函数
      • 2.5 `squeeze` 函数
      • 2.6 `strcat`函数
      • 2.7 `squeeze(s1, s2)` 函数
      • 2.8 `any` 函数
      • 练习2-6 `setbits` 函数
      • 练习2-7 `invert(x, p n)` 函数
      • 练习2-8 `rightrot(x, n)` 函数
      • 练习2-9 `bitcount(x)` 函数
    • 3 控-制流
      • 3.1 `binsearch`函数
      • 3.2 `shellsort` 函数
      • 3.3 `reverse` 函数
      • 3.4 `itoa` 函数
      • 3.5 `itob`函数
      • 3.6 `lower_bound` 函数
      • 练习3.2-1 `escape` 函数
      • 练习 3.2-2 `unescape` 函数
      • 练习3.3 `expand` 函数
      • 练习3-4 `itoa` 可以处理最大负数
      • 练习3.6 itoa
    • 4 函数与程序结构
      • 4.1 字符串的模式匹配
      • 4.2 `atof` 函数
      • 4.3 后缀表达式的计算
      • 4.4 `qsort` 函数
      • 4.5 `printd`
      • 练习4.1 `strrindex`
      • 练习4.2 `atof` 处理科学计数法
      • 练习4.7 `ungets(s)` 将s整个压回栈中
      • 练习4.8 `getch & ungetch`
      • 4.9 压回EOF
      • 练习 4-12 递归版本`itoa`
      • 练习4-13 递归版本`reverse`
      • 练习4-14 `swap` 宏
    • 5 指针与数组
      • 5.1 `getint`函数
      • 5.2 `strcpy`
      • 5.3 `strcmp`
      • 5.4 文本行排序
      • 5.5 回显程序命令行参数
      • 5.6 UNIX `grep`
      • 5.7 `find` 函数
      • 5.8 利用函数指针 进行多种类型排序
      • 简化版的 命令行控制的排序
    • 6 结构
      • 6.1 结构体定义矩形相关
      • 6.2 统计输入中各个c语言关键字出现的次数 (数组版)
      • 6.3 统计输入中各个c语言关键字出现的次数 (指针版)
      • 6.4 自引用结构 统计单词个数 二叉树
      • 6.5 表查找 散列函数
    • 7 输入与输出
      • 7.1 `minprintf`
      • 7.2 cat
    • 8 UNIX 系统接口
      • 8.1

1 序章

单词计数

单词计数

#include 

#define IN 1
#define OUT 0

int main(){	
	
	/* count lines, words, and charactors in input */
	
	/* UNIX system : wc program */
	int c, nl, nw, nc, state;
	nl = nw = nc = 0;
	state = OUT;
	while((c = getchar()) != EOF){
		++nc;
		if(c == '\n') 
			++nl;
		if(c == ' ' || c == '\n' || c == '\t') 
			state = OUT;
		else if(state == OUT){
			state = IN;
			++nw;
		}
	}
	printf("%d %d %d\n", nl, nw, nc);
	
return 0; 
} 
 

练习 1-8 统计 空白字符的个数

#include 

/* 统计 空格、制表符、换行符的个数*/
void cal(){
	int sn, tn, nn, c;
	sn = tn = nn = 0;
	while((c = getchar()) != EOF ){
		if(c == '\n') 
			++nn;
		else if(c == '\t') 
			++tn;
		else if(c == ' ')
			++sn;
	} 
	printf("%d %d %d\n", sn, tn, nn);
}

int main(){
	cal();	
	
	return 0;
}

练习 1-9 消除输入中多余的连续空格

#include 
#define true 1
#define false 0


/* 将输入复制到输出,将其中连续的空格用一个空格替代 */
void cal(){
	int c;
	int firstspace = true;
	while((c = getchar()) != EOF){
		if(c == ' '){
			if(firstspace) 
				putchar(c), firstspace = false;
		}else 
			putchar(c), firstspace = true;
	}
}

#define NONBLACK 'a'
void std(){
	int c, lastc;
	lastc = NONBLACK;
	while((c = getchar()) != EOF){
		if(c != ' ' || lastc != ' ')
			putchar(c);
		lastc = c;
	}
}

int main(){
	cal();	
	
	return 0;
}

练习 1-10 将不可见字符 显示化

/* 将输入复制到输出的程序,以使制表符和回退符可以见的方式显示*/
#include 
void std(){
	int c;
	while((c = getchar()) != EOF){
		if(c == '\t') 
			printf("\\t");
		else if(c == '\n')
			printf("\\n");
		else if(c == '\\')
			printf("\\\\");
		else 
			putchar(c);
	}
}
int main(){
	std();
return 0;
}

练习1-12 将输入中 每个单词打印一行

#include 
#define IN 1
#define OUT 0 
/* 以每行一个单词的形式打印其输出 */
int main(){
	int c, state;
	state = OUT;
	while((c = getchar()) != EOF){
		if(c == ' ' || c == '\n' || c == '\t') {
			state = OUT;
			putchar('\n');
		}
		else if(state == OUT){
			putchar(c);
			state = IN;
		}else 
			putchar(c);
	}
	return 0;
}
return 0; 
} 

练习1-13 打印单词长度的直方图

#include 
#define IN 1
#define OUT 0 
#define MAXHIST 15				/* max length of histogram    */
#define MAXWORD 11             	/* max length of a word      */
/* 打印输入中单词长度的直方图,水平直方图 */
int main(){
	int c, i, nc, state;
	int len;					/* length of each bar       */
	int maxvalue;				/* maximum value for wl[]   */
	int ovflow;               	/* word length counters     */
	int wl[MAXWORD];
	
	state = OUT;
	nc = 0;
	ovflow = 0;
	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; 
		}else 
			++nc; 
	}
	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", ovflow, MAXWORD);
	return 0;
}

#include 

#define IN 1
#define OUT 0
#define MAX_WORD_LEN 10

/* its my code.*/
int count[MAX_WORD_LEN + 1]; 
int main(){
	//freopen("in.txt", "r", stdin);
	
 	int c, sz, state;
 	sz = state = 0;
 	state = OUT;
 	while((c = getchar()) != EOF){
 		if(c == '\n' || c == '\t' || c == ' '){
 			if(state == IN){ // a word is judged. 
 				++count[sz]; 
 				sz = 0;
 				state = OUT;
			 }
		 }else {
		 	++sz;
		 	if(state == OUT){
		 		state = IN;
			 }
		 }
	 }
	 
	 for(int i = 1; i <= MAX_WORD_LEN; i++){
	 	printf("%3d: ", i);
	 	while(count[i]--) putchar('*');
	 	printf("\n");
	 }	 
return 0; 
} 

/*	SampleInput:
	in any case, a word will be judged only if 
	the charactor current which is upper or lower letter follows 
	that is not (upper or lower) letter. 
	
	SampleOutput:
	  1: *
	  2: *******
	  3: ***
	  4: ****
	  5: ****
	  6: ****
	  7: ***
	  8:
	  9: *
	 10:
	*/

 

 /* 打印输入中单词长度的直方图,垂直直方图*/
#include 
#define IN 1
#define OUT 0 
#define MAXHIST 15				/* max length of histogram    */
#define MAXWORD 11             	/* max length of a word      */

int main(){
	int c, i, j, nc, state;
	int len;					/* length of each bar       */
	int maxvalue;				/* maximum value for wl[]   */
	int ovflow;               	/* word length counters     */
	int wl[MAXWORD];
	
	state = OUT;
	nc = 0;
	ovflow = 0;
	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; 
		}else 
			++nc; 
	}
	maxvalue = 0;
	for(i = 1; i < MAXWORD; i++){
		if(wl[i] > maxvalue)
			maxvalue = wl[i];
	}
	for(i = MAXHIST; i > 0; --i){
		for(j = 1; j < MAXWORD; ++j)
			if(wl[j] * MAXHIST / maxvalue >= i)
				printf(" * ");
			else 
				printf("   ");
		putchar('\n');
	}
	for(i = 1; i < MAXWORD; ++i)
		printf("%4d ", i);
	putchar('\n');
	for(i = 1; i < MAXWORD; ++i)
		printf("%4d ", wl[i]);
	putchar('\n');
	if(ovflow > 0) 
		printf("There are %d words >= %d", ovflow, MAXWORD);
	return 0;
}

#include 

#define IN 1
#define OUT 0
#define MAX_WORD_LEN 10
/* its my code.*/
int count[MAX_WORD_LEN + 1]; 
int main(){
	//freopen("in.txt", "r", stdin);
	// 当单词长度大于10时候,该程序无法正确显示。
 	int c, sz, state;
 	sz = state = 0;
 	state = OUT;
 	int mx_cnt = 0;
 	while((c = getchar()) != EOF){
 		if(c == '\n' || c == '\t' || c == ' '){
 			if(state == IN){ // a word is judged. 
 				++count[sz]; 
 				mx_cnt = (mx_cnt > sz) ? mx_cnt : sz;
 				sz = 0;
 				state = OUT;
			 }
		 }else {
		 	++sz;
		 	if(state == OUT){
		 		state = IN;
			 }
		 }
	 }
	 for(int i = mx_cnt; i >= 0; --i){
	 	for(int j = 1; j <= MAX_WORD_LEN; ++j){
	 		if(count[j] >= i) 
	 			putchar('*'); 
	 		else 
	 			putchar(' '); 
			 putchar(' ');
	 	}	
	 	putchar('\n');
	 }
	for(int j = 1; j <= MAX_WORD_LEN; j++){
		printf("%d ", j);
	}
return 0; 
} 

/*	SampleInput:
	in any case, a word will be judged only if 
	the charactor current which is upper or lower letter follows 
	that is not (upper or lower) letter. 
	
	SampleOutput:
	
	  *
	  *
	  *
	  *   * * *
	  * * * * * *
	  * * * * * *
	* * * * * * *   *
	* * * * * * * * * *
	1 2 3 4 5 6 7 8 9 10
	
	*/

 

输出长度最长的行


#include 
#define MAXLINE 1000 

/* 读取一行字符串,并返回长度,长度最小为1 (包括换行符) */
int getline(char s[], int lim);
/* 将字符串t 复制到s上 */
void copy(char s[], char t[]);

int main(){
	int len, maxl = 0;
	char line[MAXLINE], longest[MAXLINE]; 
	
	while(( len = getline(line, MAXLINE) ) != 0){
		if(len > 1 && len > maxl){
			maxl = len;
			copy(longest, line);
		}
	}
	if(maxl > 0) 
		printf("%s", longest);
return 0;
}

int getline(char s[], int lim){
	int c, i = 0;
	while(i < lim - 1 && (c = getchar()) != EOF && c != '\n') // i < lim - 1 是因为最后还要存一个'' 
		s[i++] = c;
	if(c == '\n')
		s[i++] = c;
	s[i] = '\0';
	return i; 
}

void copy(char s[], char t[]){
	int i = 0;
	while((s[i] = t[i++]) != '\0') 
		;
}

练习1-16

/*打印最长文本行的程序,它可以打印任意长度的输入行的长度,并尽可能多地打印文本。*/


练习1-17 打印输入中长度大于80的行

/* 编写一个程序,打印长度大于80个字符的所有输入行 */
#include 
#define MAXLINE 1000 
#define LONGLINE 80

/* 读取一行字符串,并返回长度,长度最小为1 (包括换行符) */
int getline(char s[], int lim);

int main(){
	int len, maxl = 0;
	char line[MAXLINE], longest[MAXLINE]; 
	
	while(( len = getline(line, MAXLINE) ) > 0){
		if(len > LONGLINE) 
			printf("%s", line);
	} 
return 0;
}

int getline(char s[], int lim){
	int c, i = 0;
	while(i < lim - 1 && (c = getchar()) != EOF && c != '\n') // i < lim - 1 是因为最后还要存一个'' 
		s[i++] = c;
	if(c == '\n')
		s[i++] = c;
	s[i] = '\0';
	return i; 
}


练习1-18 删除空行和行末不可见字符

/*编写一个程序,删除每个输入行末尾的空格以及制表符,并删除完全是空格的行*/

#include 
#define MAXLINE 1000 


/* 读取一行字符串,并返回长度,长度最小为1 (包括换行符) */
int getline(char s[], int lim);
int Remove(char s[]);

int main(){
	int len, maxl = 0;
	char line[MAXLINE], longest[MAXLINE]; 
	
	while(( len = getline(line, MAXLINE) ) > 0){
		//printf("%s", line);
	 	if(Remove(line) > 0)
			printf("%s", line); 
	} 
return 0;
}

int getline(char s[], int lim){
	int c, i = 0;
	while(i < lim - 1 && (c = getchar()) != EOF && c != '\n') // i < lim - 1 是因为最后还要存一个'' 
		s[i++] = c;
	if(c == '\n')
		s[i++] = c;
	s[i] = '\0';
	return i; 
}

int Remove(char s[]) {
	int i = 0;
	while(s[i] != '\n') 
		++i;
	--i;
	while(i >= 0 && (s[i] == ' ' || s[i] == '\t'))
		--i;
	if(i >= 0){
		s[++i] = '\n';
		s[++i] = '\0';
	}
	return i;
}

练习1-9 reverse 函数

/*编写函数reverse(s),将字符串s中的字符顺序颠倒过来*/

#include 
#define MAXLINE 1000 


/* 读取一行字符串,并返回长度,长度最小为1 (包括换行符) */
int getline(char s[], int lim);
void reverse(char s[], int len);

int main(){
	int len, maxl = 0;
	char line[MAXLINE], longest[MAXLINE]; 
	
	while(( len = getline(line, MAXLINE) ) > 0){
		if(len > 1) {
			reverse(line, len);
			printf("%s", line); 	
		}
	} 
return 0;
}

int getline(char s[], int lim){
	int c, i = 0;
	while(i < lim - 1 && (c = getchar()) != EOF && c != '\n') // i < lim - 1 是因为最后还要存一个'' 
		s[i++] = c;
	if(c == '\n')
		s[i++] = c;
	s[i] = '\0';
	return i; 
}

void reverse(char s[], int len){
	len --;
	int i;
	for(i = 0; i  <= len / 2; i++){
		char t = s[i];
		s[i] = s[len - i - 1];
		s[len - i - 1] = t;
	}
} 

2 类型、运算符与表达式

2.1 strlen 函数设计

int strlen(char s[]){
	int i = 0;
	while(s[i++] != '\0') 
	;
	return i - 1;
}

练习2-2 不使用 && || 完成循环


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

int main(){
	enum loop{ NO, YES};
	enum loop okloop = YES;
	int i = 0;
	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;
		}
		
return 0;
}


2.2 atoi 函数

10进制的字符串转化为 int类型

int atoi(char s[]){
	int x = 0;
	for(int i = 0; s[i]; i++) {
		x = x * 10 + (s[i] - '0');
	}
	return x;
}


#include 
int atoi(char s[]){
	int i, n, sign;
	for(i = 0; isspace(s[i]); i++)
		;
	sign = s[i] == '-' ? -1 : 1;
	if(s[i] == '+' || s[i] == '-') 
		i++;
	for(n = 0; isdigit(s[i]); i++) 
		n = n * 10 + s[i] - '0';
	return n * sign;
}

2.3 可移植的 rand、srand 函数

unsigned long int next = 1;
int rand(void){
	next = next * 1103515245 + 12345;
	return (unsigned int)(next / 65536) % 32768;
}
void srand(unsigned int seed){
	next = seed;
}

2.4 htoi 函数

Function:将十六进制数 转化为int

#define YES 
#define NO

int htoi(char *s){
	int hexdigit, i, inhex, n;
	i = 0;
	if(s[i] == '0'){
		++i;
		if(s[i] == 'x' || s[i] == 'X') 
			++i;
	}
	n = 0;
	inhex = YES;
	for( ; inhex == YES ; ++i){
		if(s[i] >= '0' && s[i] <= '9')
			hexdigit = s[i] - '0';
		else if(s[i] >= 'a' && s[i] <= 'z') 
			hexdigit = s[i] - 'a' + 10;
		else if(s[i] >= 'A' && s[i] <= 'Z')
			hexdigit = s[i] - 'A' + 10;
		else 
			inhex = NO;
		if(inhex == YES) 
			n = 16 * n + hexdigit;
	}
	return n;
}


2.5 squeeze 函数

/* squeeze: delete all c from s */
void squeeze(char s[], int c){
	int j = 0;
	for(int i = 0; s[i]; i++){
		if(s[i] != c)
			s[j++] = s[i];
	}
	s[j] = 0;
}

2.6 strcat函数


char *strcat(char s[], char t[]){
	int j, i;
	i = j = 0;
	while(s[j] != '\0') 
		j++;
	while((s[j++] = t[i++]) != '\0')
		;
	return s;
}

2.7 squeeze(s1, s2) 函数

/* 删除s1中任何与s2中字符匹配的字符*/
void squeeze(char s[], char t[]){
	int i, j, k;
	for(i  = k = 0; s[i] != '\0'; i++){
		for(j = 0; t[j] != '\0' && t[j] != s[i]; j++)
			;
		if(t[j] == '\0')
			s[k++] = s[i];
	}
	s[k] = '\0';
}

2.8 any 函数

/* 将字符串s2中的任一字符在字符串s1中第一次出现的位置返回,如果不存在返回-1*/
int any(char s1[], char s2[]){
	
	for(int i = 0; s1[i]; i++){
		int j = 0;
		while(s2[j] != '\0' && s1[i] != s2[j])
			j++;
		if(s2[j] != '\0')
			return i;
	}
	return -1;
} 
int std_any(char s1[], char s2[]) {
	int i, j;
	for(i = 0; s1[i] != '\0' ; ++i){
		for(j = 0; s2[j] != '\0'; ++j){
			if(s1[i] == s2[j])
				return i;
		}
	}
	return -1;
}

练习2-6 setbits 函数

/* 将x中从第p位开始的n个(二进制位设置为y中最右边n位的值,x的其余各位不变 */
unsigned setbits(unsigned x, int p, int n, unsigned y){
	return x & ~(~(~0 << n) << (p + 1 -n)) | (y & ~(~0 << n)) << (p + 1 - n);
}

练习2-7 invert(x, p n) 函数

/* 将x中从第p位开始的n个(二进制)位求反,x的其余各位不变 */
// 用全是1和其亦或,相当于取反 
unsigned invert(unsigned x, int p, int n){ 
	return x ^ (~(~0 << n) << (p + 1 - n)); 
}

练习2-8 rightrot(x, n) 函数

/* 将x循环右移n的值 */
unsigned rightrot(unsigned x, int n){
	int wordlength(void);
	int rbit;
	while(n -- > 0){
		rbit = (x & 1) << (wordlength() - 1);
		x = x >> 1;
		x = x | rbit;
	}
	return x;
} 
// another solution:
unsigned rightrot(unsigned  x, int n){
	int wordlength(void);
	unsigned rbits;
	if((n = n % wordlength()) > 0){
		rbits = ~(~0 << n) & x;
		rbits = rbits << (wordlength() - n) ;
		x = x >> n;
		x |= rbits;
	}
	return x;
}

int wordlength(void){
	int i;
	unsigned v = (unsigned) ~0;
	for(i = 1; (v = v >> 1) > 0; ++i)
		;
	return i;
}


练习2-9 bitcount(x) 函数

/* 计算一个数字中二进制位中有几个1 */
int bitcount(unsigned x){
	int b;
	for(b = 0; x != 0; x &= x - 1)
		b++;
	return b;
}

3 控-制流

3.1 binsearch函数

function:在一个有序序列中,快速判断一个数字所在的位置。


int binsearch(int x,int v[], int n){
	int low, hight, mid;
	low = 0;
	hight = n - 1;
	while(low <= hight){
		mid = (low + hight) / 2;
		if(x < v[mid] )
			hight = mid - 1;
		else if(x > v[mid])
			low = mid + 1; 
		else return mid;
	}
	return -1;
}

3.2 shellsort 函数

排序,默认由小到大的排序

void shellsort(int v[], int n){
 	int gap, i, j, tmp;
 	for(gap = n / 2; gap > 0; gap /= 2){
 		for(int i = gap; i < n; i++){
 			for(int j = i - gap; j >= 0 && v[j] > v[j + gap]; j -= gap){
 				tmp = v[j];
 				v[j] = v[j + gap];
 				v[j + gap] = tmp;
			 }
		 }
	 }
}

3.3 reverse 函数

funciton : 翻转一个字符串


void reverse(char s[]){
	int n = strlen(s), tmp;
	for(int i = 0; i < n / 2; i++){
		tmp = s[i];
		s[i] = s[n - i - 1];
		s[n - i - 1] = tmp;
	}
}

3.4 itoa 函数

将int转化为字符串

void itoa(int n, char s[]){
	int sign, i;
	i = 0;  if(n < 0) n = -n, sign = -1;
	do{
		s[i++] = n % 10 + '0';
		n /= 10;
	}while(n != 0);
	if(sign < 0) s[i++] = '-';
	s[i] = '\0';
	reverse(s);
}

3.5 itob函数

将n转化为任意进制的数

void  itob(int n, char s[], int b){ // b 
	int sign, i, c;
	
	i = 0;
	if(n < 0) sign = -1, n = -n;  // 注意这里 不能够处理最大的负数
	do{
		c = n % b;
		s[i++] = c > 9 ? c - 10 + 'A' : c + '0';
		n /= b;  
	}while(n > 0);
	if(sign < 0) s[i++] = '-';
	s[i] = '\0';
	reverse(s);
 
}

3.6 lower_bound 函数

快速找到有序序列中第一个大于等于x的位置

int lowerbound(int v[], int low, int upp, int x){
	int mid, pos = upp + 1;
	while(low <= upp){
		mid = (low + upp) / 2;
		if(x <= v[mid]) 
			upp = mid - 1, pos = mid; 
		else 
			low = mid + 1;
	}
	return pos;
} 

练习3.2-1 escape 函数

将字符串t复制到字符串s中,并在复制过程中将换行符和制表符转换为可见字符。

void escape(char s[], char t[]){
	int i, j;
	for(i = j = 0; t[j] != '\0'; i++){
		switch(t[i]){
			case '\n': 
				s[j++] = '\\';
				s[j++] = 'n';
				break;
			case '\t':
				s[j++] = '\\';
				s[j++] = 't';
				break;
			default :
				s[j++] = t[i];
				break;
		}
	}
	s[j] = '\0';
}

练习 3.2-2 unescape 函数

功能与escape相反

void unescape(char s[], char t[]){
	int i, j; 
	for(i = j = 0; s[i] && s[i + 1]; i++){
		switch(s[i]){
			case '\\':
				switch(s[i + 1]){
					case 'n':
						t[j++] = '\n';
						i++;
						break;
					case 't':
						t[j++] = '\t';
						i++;
						break;
					default:
						t[j++] = '\\';
						break; 
				}
				break;
			default :
				t[j++] = s[i];
				break;
		}
	}
	if(s[i] != '\0') 
		t[j++] = s[i++];
}

练习3.3 expand 函数

#include 
/*
	将字符串s1中类似于a-z一类的速记符号在字符串s2
	中扩展为等价的完整列表abc...xyz。
	该函数可以处理大小写字母和数字 ,并可以处理a-b-c、
	a-z0-9与a-z等类似的情况。作为前导和尾随的字符照原样复制。 
	
	eg:
		a-c 扩展为 abc 
	*/


void expand(char s1[], char s2[]){
	char c;
	int i, j;
	i = j = 0;
	while((c = s1[i++]) != '\0')
		if(s1[i] == '-' && s1[i + 1] >= c){
			i++;
			while(c < s1[i])
				s2[j++] = c++;
		}else 
			s2[j++] = c;
	s2[j] = '\0'; 
}
int main(){
 	
	return 0;
} 

练习3-4 itoa 可以处理最大负数


/*
	我们编写的 itoa函数不能够处理最大的负数,即n=-(2^(字长-1)) 
	修改这个函数,使其可以再任何机器上运行时都可以打印出正确的值
	
	*/
#define abs(x) ((x) > 0 ? (x) : -(x))

void  itoa(int n, char *s){
	int i, sign;
	void reverse(char *s);
	sign = n;
	i = 0;
	do{
		s[i++] = abs(n % 10) + '0'; // 此处取绝对值 
	}while((n /= 10) != 0)  // 这里就不是 > 0 啦。 
	if(sign < 0)
		s[i++] = '-';
	s[i] = '\0';
	reverse(s);
}

练习3.6 itoa

#define abs(x) ((x) > 0 ? (x) : -(x))

void  itoa(int n, char *s, int w){
	int i, sign;
	void reverse(char *s);
	sign = n;
	i = 0;
	do{
		s[i++] = abs(n % 10) + '0'; // 此处取绝对值 
	}while((n /= 10) != 0)  // 这里就不是 > 0 啦。 
	if(sign < 0)
		s[i++] = '-';
	while(i < w)  // 添加空格, 
		s[i++] = ' ';  
	s[i] = '\0';
	reverse(s);
}


4 函数与程序结构

4.1 字符串的模式匹配


/*  
	Description: 输出 多行文本中 包含模式串的 文本行。 
	 
	*/
#include 
#include 
#define MAXLEN 100

int getline(char *line, int lim); // 从文本流中获取一行, 包含'\n', 返回获取字符个数 
int strindex(char *s, char *t); // 返回s中第一次出现t的位置
 
char *pattern = "ould"; // 模式串 

int main(){
	char line[MAXLEN];	
	while(getline(line, MAXLEN) > 0){
		
		if(strindex(line, pattern) >= 0)
			printf("%s", line);
	}
	
	return 0;
}

int getline(char *line, int lim){
	int c, i;
	i = 0;
	while(--lim > 0 && (c = getchar() ) != EOF && c != '\n')
		line[i++] = c;
	if(c == '\n')  // 由换行中断的 
		line[i++] = c;
	line[i] = '\0';
	return 	i;
}

int strindex(char *s, char *t){
	int i, j, k;
	for(i = 0; s[i] != '\0'; ++i){
		for(j = 0, k = i; t[j] != '\0' && s[k] == t[j]; k++, j++)
			;
		if(j > 0 && t[j] == '\0') // 匹配完成
			return i; 
	}
	return -1;
}

4.2 atof 函数

#include 
#include 

double atof(char *s){
	double val, power;
	int i, sign;
	
	for(i = 0; isspace(s[i]); i++) // 跳过空白符 
		;
	sign = s[i] == '-' ? -1 : 1;   // 获取符号 
	if(s[i] == '-' || s[i] == '+')
		i++;
	for(val = 0; isdigit(s[i]); i++)  // 收集整数部分 
		val = val * 10 + s[i] - '0';
		
	if(s[i] == '.') 
		i++;
	for(power = 1.0; isdigit(s[i]); i++){  // 收集小数部分 
		val = val * 10 + s[i] - '0';
		power *= 10;
	}
	return sign * val / power;
}

int main() {
	printf("%f\n", atof("100.11"));
	
	return 0;
}

4.3 后缀表达式的计算

#include 
#include 
#include  // 为了使用atof()

#define MAXOP 100  // 操作符或运算符的最大长度
#define NUMBER '0' // 标识找到了一个操作数  

int getop(char *);
void Push(double);
double Pop(void);
double gettop(void);

/* 
	1 2 - 4 5 + *
*/
int main(){
	int type;
	double op2;
	char s[MAXOP];
	while((type = getop(s)) != EOF){
		switch(type){
			case NUMBER:
				Push(atof(s));
				break;
			case '+':
				Push(Pop() + Pop()) ;
				break;
			case '*':
				Push(Pop() * Pop());
				break;
			case '-':
				op2 = Pop();
				Push(Pop() - op2);
				break;
			case '/':
				op2 = Pop();
				if(op2 != 0.0)
					Push(Pop() / op2);
				else 
					printf("error : zero divisor\n");
				break;
			case '\n':
				printf("##\tans = %.8g\n", Pop());
				break;
			default:
				printf("error: unknown command %s\n", s);
				break;
		} 
	}
	return 0;
}

int getop(char *s){
	int getch(void);
	void ungetch(int c);
	int i, c;
	while((s[0] = c = getch()) == ' ' || c == '\t') 
		;
	s[1] = '\0';
	if(!isdigit(c) && c != '.') // 不是数 
		return c;
		
	i = 0;
	if(isdigit(c))
		while(isdigit(s[++i] = c = getch())) // 收集数字 
			;	
	if(c == '.')
		while(isdigit(s[++i] = c = getch()))  // 收集小数部分 
			;
	s[i] = '\0'; 
	
	if(c != EOF)
		ungetch(c);
	return NUMBER;
}

#define BUFSIZE 100
char buf[BUFSIZE];
int bufp = 0;
int getch(void){
	return bufp > 0 ? buf[--bufp] : getchar();
}
void ungetch(int c){
	if(bufp >= BUFSIZE)
		printf("ungetch: too much char\n");
	else 
		buf[bufp++] = c;
}

#define MAXSIZE 100 // 栈的最大深度 
double stack[MAXSIZE];
int top = 0;

double gettop(void){
	return top > 0 ? stack[top - 1] : printf("stack: empty\n");
}
double Pop(void){
	return top > 0 ? stack[--top] : printf("stack: empty\n");
}
void Push(double val){
	top < MAXSIZE ? stack[top++] = val : printf("stack : cant push.\n");	
}

4.4 qsort 函数

#include 


void qsort(int v[], int left, int right){
	if(left >= right) 
		return;
	int i, j, last;
	void swap(int *v, int i, int j);
	swap(v, left, (left + right) / 2);
	last = left;
	for(i = left + 1; i <= right; i++)
		if(v[i] < v[left])
			swap(v, ++last, i);
	swap(v, left, last);
	qsort(v, left, last - 1);
	qsort(v, last + 1, right);
}

void swap(int *v, int i, int j){
	int c = v[i];
	v[i] = v[j];
	v[j] = c;
}
int main(){
	int v [] = {1,2,1,2,13,45,45,4156,46,456,465};	
	int n = (sizeof v) / sizeof(*v);
	qsort(v, 0, n - 1);
	int i = 0;
	while(i < n)
		printf("%d ", v[i++]); 
	return 0;
}

4.5 printd


void printd(int n){
	if(n < 0){
		putchar('-');
		n = -n;
	}
	if(n / 10)
		printd(n / 10);
	putchar('0' + n % 10);
}

练习4.1 strrindex


/*	
	返回字符串t在s中最右边出现的位置,
	如果不包括t,则返回-1. 
	*/
int strrindex(char *s, char *t){
	int i, j, k, pos;
	pos = -1;
	for(i = 0; s[i] != '\0'; i++){
		for(j = i, k = 0; t[k] != '\0' && s[j] == t[k]; j++, k++)
			;
		if(k > 0 && t[k] == '\0')
			pos = i; // 最后一次出现 的位置 
	}
	return pos;
}

int std2(char *s, char *t){ // 倒着寻找 
	int i, j, k;
	for(i = strlen(s) - strlen(t); i >= 0; i--){
		for(j = i, k = 0; t[k] != '\0' && s[j] == t[k]; j++, k++)
			;
		if(k > 0 && t[k] == '\0')
			return i;
	}
	return -1;
}

练习4.2 atof 处理科学计数法

#include 

/*
	对atof函数进行扩充,使它可以处理形如
	123.45e-6
	的科学计数法,其中,浮点数后面
	可能会紧跟着一个e或E以及一个指数(可能有正负号) 
	*/
#include 
double atof(char *s){
	double val, power;
	int exp, i, sign;
	for(i = 0; isspace(s[i]); i++)
		;
	sign = (s[i] == '-') ? -1 : 1;
	if(s[i] == '-' || s[i] == '+')
		i++;
	for(val = 0.0; isdigit(s[i]); i++)
		val = val * 10 + s[i] - '0';
	if(s[i] == '.')
		i++;
	for(power = 1.0; isdigit(s[i]); i++){
		val = val * 10 + s[i] - '0';
		power *= 10.0;
	}
	val = sign * val / power;
	
	if(s[i] == 'e' || s[i] == 'E'){
		sign = (s[++i] == '-') ? -1 : 1;
		if(s[i] == '-' || s[i] == '+')
			i++;
		for(exp = 0; isdigit(s[i]); i++)
			exp = 10 * exp + s[i] - '0';
		// 0.1 无法用二进制数精确到表示,故/10 比*0.1 精确度更好
		while(exp -- > 0) 
			sign == 1 ? (val *= 10) : (val /= 10);
	}
	return val;
}
int main(){
 	printf("%lf\n", atof("123.45e-6"));
	return 0;
} 

练习4.7 ungets(s) 将s整个压回栈中

void ungets(char s[]){
	int len = strlen(s);
	void ungetch(int);
	while(len > 0)
		ungetch(s[--len]);
}

练习4.8 getch & ungetch


/* 
	假定最多只压回一个字符
	*/
char buf = 0;
int getch(void){
	int c;
	if(buf != 0)
		c = buf;
	eles 
		c = getchar();
	buf = 0;
	return c;
}
void ungetch(int c){
	if(buf != 0) 
		printf("ungetch : too many char.\n");
	else 
		buf = c;
} 

4.9 压回EOF

/*
	c 语言不要求char是有符号还是无符号,所以这里容易出问题
	能够正确压回EOF 
	*/

#define BUFSIZE 100
int buf[BUFSIZE];  // 原先的 缓冲中是字符数组 
int bufp = 0;
int getch(void){
	return (bufp > 0) buf[--bufp] : getchar();
} 
void ungetch(int c){
	if(bufp >= BUFSIZE)
		printf("too many char.\n");
	else 
		buf[bufp++] = c;
}


练习 4-12 递归版本itoa


void itoa(int n, char *s){
	static int i = 0;  // ******* 
	if(n / 10)
		itoa(n / 10, s);
	else {
		i = 0;
		if(n < 0)
			s[i++] = '-';
	}
	s[i++] = abs(n) % 10 + '0';
	s[i] = '\0'; 
}


练习4-13 递归版本reverse

// 这种题 真无聊,强行把递归用做for的功能 
void reverser(char *s, int i, int len){
	int c, j;
	j = len - (i + 1);
	if(i < j){  // 只用交换一半
		c = s[i];
		s[i] = s[j];
		s[j] = c;
		reverser(s, ++i, len);
	}
}



练习4-14 swap

/* 
	用宏交换t类型的两个参数
	*/
#define swap(t, x, y)  {  t _z;  \
						  _z = y; \
						  y = x; \
						  x = _z; }

5 指针与数组

5.1 getint函数


/*
	将输入中的下一个整形数赋值给*pn 
	*/ 
int getint(int *pn){
	int c, i, sign;
	while(isspace(c = getch())) // 跳过空白符 
		;
	if(!isdigit(c) && c != EOF && c != '+' && c != '-'){
		ungetch(c); // 输入不是一个数字 
		return c;
	}
	
	sign = (c == '-') ? -1 : 1;
	if(c == '+' || c == '-')
		c = getch();
	for(*pn = 0; isdigit(c); c = getch())
		*pn = *pn * 10 + c - '0';
	if(c != EOF)
		ungetch(c);
	*pn *= sign;
}

5.2 strcpy


void strcpy(char *s, char *t){
	int i;
	i = 0;
	while((s[i] = t[i]) != '\0')
		++i;
}
void strcpy(char *s, char *t){
	while(*s++ = *t++)
	 	;
}

5.3 strcmp

int strcmp(char *s, char *t){
	int i;
	for(i = 0; s[i] == t[i]; i++)
		if(s[i] == '\0')
			return 0;
	return s[i] - t[i]; 
}
int strcmp(char *s, char *t){
	for(; *s == *t; s++, t++)
		if(*s == '\0')
			return 0;
	return *s - *t;
}

5.4 文本行排序

/*
	从输入中获取字符串行,然后排序,后输出。
	 
	*/
#include 
#include  
#define MAXLINES 1000


char *lineptr[MAXLINES];  // 字符指针数组 

int readlines(char *lines[], int maxlines);
void qsort(char *v[], int left, int right);
void writelines(char *line[], int nlines); 

int main(){
	int nlines; // 读取的行数目 
	if((nlines = readlines(lineptr, MAXLINES)) >= 0) {
		
		qsort(lineptr, 0, nlines - 1);
		writelines(lineptr, nlines);
		return 0;		
	}else {
		printf("error: input too big to sort!\n");
		return 1;
	}
}
#define MAXLEN 1000
int readlines(char *lines[], int maxlines){
	int nlines, len;
	int getline(char *line, int lim);
	char *aalloc(int len);
	char *p, line[MAXLEN];
	nlines = 0;
	while((len = getline(line, MAXLEN)) > 0){
		if(nlines >= maxlines || (p = aalloc(len)) == NULL) //  行数过多、没内存分配空间 
			return -1;
		else 
		{
			line[len - 1] = '\0'; // 删除换行符 
			strcpy(p, line);
			lines[nlines++] = p;
		
		}
	}
	return nlines;
}

int getline(char *line, int lim){
	int c, i;
	i = 0;
	while(--lim > 0 && (c = getchar() ) != EOF && c != '\n')
		line[i++] = c;
	if(c == '\n')  // 由换行中断的 
		line[i++] = c;
	line[i] = '\0';
	
	return 	i;
}

#define BUFSIZE 100000
char buf[BUFSIZE];
char *bufp = buf;

char *aalloc(int len){
	if(buf + BUFSIZE - bufp > len + 1) // 大小比长度大一 
	{
		bufp += len + 1;
		return bufp - (len + 1);
	}
	return NULL;
}
void qsort(char *v[], int left, int right){
	if(left >= right) 
		return;
	int i, j, last;
	void swap(char *v[], int i, int j);
	swap(v, left, (left + right) / 2);
	last = left;
	for(i = left + 1; i <= right; i++)
		if(strcmp(v[i], v[left]) < 0)
			swap(v, ++last, i);
	swap(v, left, last);
	qsort(v, left, last - 1);
	qsort(v, last + 1, right);
}

void swap(char *v[], int i, int j){
	char *t = v[i];
	v[i] = v[j];
	v[j] = t;
}

void writelines(char *line[], int nlines){
	while(nlines -- > 0)
		printf("%s\n", *line++);
}

5.5 回显程序命令行参数

#include 

int main(int argc, char *argv[]){
	while(--argc > 0)
		printf("%s%s", *++argv, argc > 1 ? " " : ""); 
	puts("");
   return(0);
}

5.6 UNIX grep


/*	
	通过命令行第一个参数指定带匹配的模式
	 
	*/
#include 
#include 
#define MAXLEN 1200

int getline(char *line, int lim);
int main(int argc, char *argv[]){
	char line[MAXLEN];
	int found;
	found = 0;
	if(argc != 2)
		puts("Usage: find pattern");
	else {
		while(getline(line, MAXLEN) > 0)
			if(strstr(line, argv[1]) != NULL){
				printf("%s", line);
				found++;
			}
	}
	return found;
}

int getline(char *line, int lim){
	int c, i;
	i = 0;
	while(--lim > 0 && (c = getchar() ) != EOF && c != '\n')
		line[i++] = c;
	if(c == '\n')  // 由换行中断的 
		line[i++] = c;
	line[i] = '\0';
	
	return 	i;
}


5.7 find 函数

#include 
#include 
#define MAXLEN 1000
/*
	命令行 调用该函数
	find -n -x pattern 
	*/

int getline(char *line, int max);

int main(int argc, char *argv[]){
	char line[MAXLEN];		
	long lineno = 0;
	int c, except = 0, number = 0, found = 0;
	while(--argc > 0 && ((*++argv)[0] == '-')){
		while(c = *++argv[0]) {
			switch (c){
				case 'x':
					except = 1;
					break;
				case 'n':
					number = 1;
					break;
				default:
					fprintf(stderr, "find: illegal option %c\n", c);
					argc = 0;
					found = -1;
					break;
			}
		}
	}
	if(argc != 1)
		fprintf(stderr, "Usage: find -x -n pattern\n");
	else 
		while(getline(line, MAXLEN) > 0){
			lineno++;
			if((strstr(line, *argv) != NULL) != except){
				if(number)
					printf("%ld: ", lineno);
				printf("%s", line);
				found++; 
			}
		}
	return found;
}
int getline(char *line, int lim){
	int c, i;
	i = 0;
	while(--lim > 0 && (c = getchar() ) != EOF && c != '\n')
		line[i++] = c;
	if(c == '\n')  // 由换行中断的 
		line[i++] = c;
	line[i] = '\0';
	
	return 	i;
}

5.8 利用函数指针 进行多种类型排序

/*
	对输入的文本行进行排序,可能为数字可能为字符串 
	sort -n 
	参数-n 表示下面排序的是数字
	 
	*/
#include 
#include  
#include 
#define MAXLINES 1000

char *lineptr[MAXLINES];  // 字符指针数组 

int readlines(char *lines[], int maxlines);
void qqsort(void *v[], int left, int right, int (*cmp)(void *, void *)); 
void writelines(char *line[], int nlines); 
int numcmp(void *a, void *b);  // 数字比较函数 
int stcmp(void *a, void *b);   // 字符串比较函数

int (*arrcmp[])(void *a, void *b) = { stcmp, numcmp};  // 指向函数的指针数组 

int main(int argc, char *argv[]){
	int nlines; // 读取的行数目 
	int cmpid = 0; // strcmp 默认为0
	if(argc > 1 && strcmp(argv[1], "-n") == 0)
		cmpid = 1; // 为数字比较
		 
	if((nlines = readlines(lineptr, MAXLINES)) >= 0) {
		
		qqsort((void **)lineptr, 0, nlines - 1, cmpid == 1 ? numcmp : stcmp);
//		qqsort((void **)lineptr, 0, nlines - 1, arrcmp[cmpid]);  //都可以
		writelines(lineptr, nlines);
		return 0;		
	}else {
		printf("error: input too big to sort!\n");
		return 1;
	}
}

#define MAXLEN 1000
int readlines(char *lines[], int maxlines){
	int nlines, len;
	int getline(char *line, int lim);
	char *aalloc(int len);
	char *p, line[MAXLEN];
	nlines = 0;
	while((len = getline(line, MAXLEN)) > 0){
		if(nlines >= maxlines || (p = aalloc(len)) == NULL) //  行数过多、没内存分配空间 
			return -1;
		else 
		{
			line[len - 1] = '\0'; // 删除换行符 
			strcpy(p, line);
			lines[nlines++] = p;
		
		}
	}
	return nlines;
}

int getline(char *line, int lim){
	int c, i;
	i = 0;
	while(--lim > 0 && (c = getchar() ) != EOF && c != '\n')
		line[i++] = c;
	if(c == '\n')  // 由换行中断的 
		line[i++] = c;
	line[i] = '\0';
	
	return 	i;
}

#define BUFSIZE 100000
char buf[BUFSIZE];
char *bufp = buf;

char *aalloc(int len){
	if(buf + BUFSIZE - bufp > len + 1) // 大小比长度大一 
	{
		bufp += len + 1;
		return bufp - (len + 1);
	}
	return NULL;
}
void qqsort(void *v[], int left, int right, 
		  int (*cmp)(void *, void *)){
	if(left >= right) 
		return;
	int i, j, last;
	void swap(void *v[], int i, int j);
	swap(v, left, (left + right) / 2);
	last = left;
	for(i = left + 1; i <= right; i++)
		if(cmp(v[i], v[left]) < 0)
			swap(v, ++last, i);
	swap(v, left, last);
	qqsort(v, left, last - 1, cmp);
	qqsort(v, last + 1, right, cmp);
}

void swap(void *v[], int i, int j){
	void *temp;
	temp = v[i];
	v[i] = v[j];
	v[j] = temp;
}

void writelines(char *line[], int nlines){
	printf("the array sorded is:");
	while(nlines -- > 0)
		printf("%s%s", *line++, nlines > 0 ? " " : "\n");
}
int stcmp(void *a, void *b){
	char *aa = (char *)a;
	char *bb = (char *)b;
	return strcmp(aa, bb);
}

int numcmp(void *a, void *b){
	double aa = atof((char *) a);
	double bb = atof((char *) b);
	if(aa > bb) 
		return 1;
	else if(aa < bb)
		return -1;
	else 
		return 0;
}

简化版的 命令行控制的排序

/* 
	获取 命令行参数  
	-n 数字比较
	-s 字符串比较 , 默认 
	-d 递减顺序 
	
	下面是我能够想到的比较简洁的实现方式了。
	既然要简洁肯定不能手写qsort,所以调用了库,但 qsort 只能够排序数组 
	所以数组大小必须都固定了,这一点是和书上不同的。
	*/
#include 
#include 
#include 
#define MAXLINE 1000   /* 最多的元素个数  */ 
#define MAX 1000	  /*  最长的元素长度 */ 

int str_cmp(const void *, const void *);
int num_cmp(const void *, const void *);
int (*cmp[])(const void *, const void *) = {str_cmp, num_cmp};

char lines[MAXLINE][MAX];  // 这里只能定义固定长度的数组 
char line[MAX];
int main(int argc, char *argv[]){
	
	int sort_way = 0;  // 序列单调方式 ,0为非减,1为非增 
	int cmp_way = 0;    // 排序方式  0为字符串型,1为数字型 
	int i, nline;
	
	while(--argc > 0 && (*++argv)[0] == '-') {  // 获取命令行参数 
		while(*++argv[0])
			switch(*argv[0]){
				case 'n':
					cmp_way = 1;
					break;
				case 'd':
					sort_way = 1;
					break;
				default:
					fprintf(stderr, "sort: Usage wrong.."); 
					break;
			}
	}
 	
	for(nline = 0; scanf("%s", lines[nline]) != EOF; nline++)  // 读入 
		;	
	qsort((void **) lines, nline, sizeof(lines[0]), cmp[cmp_way]);  // 排序 
	
	if(sort_way == 0) // 正序输出 
		for(i = 0; i < nline; i++)    
			printf("%s%s", lines[i], i == nline ? "\n" : " ");	
	else   // 逆序输出
		for(i = nline - 1; i >= 0; i--)
			printf("%s%s", lines[i], i == nline ? "\n" : " ");
		
	return 0;
}

int num_cmp(const void *a, const void *b){
	double _a = atof((char *)a);
	double _b = atof((char *)b);
	if(_a > _b) return 1;
	if(_a < _b) return -1;
	return 0; 
}

int str_cmp(const void *a, const void *b){
	char * _a = (char *) a;
	char * _b = (char *) b;
 	return strcmp(_a, _b);
}


6 结构

6.1 结构体定义矩形相关

#include  

enum tm { XMAX = 100, YMAX = 100 };

struct point{
	int x;
	int y;
};

struct rect{
	struct point pt1;
	struct point pt2;
};

struct point makepoint(int x,int y){
	struct point temp;
	temp.x = x;
	temp.y = y;
	return temp;
}

struct point addpoint(struct point p1, struct point p2){
	p1.x += p2.x;
	p1.y += p2.y;
	return p1;
}
/* p 点是否在矩形r中*/
int ptinrect(struct point p, struct rect r){
	return p.x >= r.pt1.x && p.x < r.pt2.x
		&& p.y >= r.pt1.y && p.y < r.pt2.y;
}
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))

/*   返回一个规范型的 矩阵 */
struct rect canonrect (struct rect r){
	struct rect temp;
	temp.pt1.x = min(r.pt1.x, r.pt2.x);
	temp.pt1.y = min(r.pt1.y, r.pt2.y);
	temp.pt2.x = min(r.pt1.x, r.pt2.x);
	temp.pt2.y = min(r.pt1.y, r.pt2.y);
	return temp;
}

int main(){
	struct rect screen;
	struct point middle;
	struct point makepoint(int, int);
	screen.pt1 = makepoint(0, 0);
	screen.pt2 = makepoint(XMAX, YMAX);	
	middle = makepoint((screen.pt1.x + screen.pt2.x) / 2,
					 (screen.pt1.y + screen.pt2.y ) / 2);
		
	return 0;
}

6.2 统计输入中各个c语言关键字出现的次数 (数组版)

#include 
#include 
#include 

#define MAXWORD 100
#define NKEYS (sizeof keytab / sizeof(struct key)) 


struct key{
	char *word;
	int count;
};

struct key keytab[] ={
	{ "cpp", 0},
	{ "c", 0}
};;



int getword(char *, int);
int binsearch(char *, struct key *, int);

int main(){
 	
	int n; 
	char word[MAXWORD];	
	while(getword(word, MAXWORD) != EOF)
		if(isalpha(word[0]))
			if((n = binsearch(word, keytab, NKEYS)) >= 0) 
				keytab[n].count++;
				
	/* 遍历输出 次数 */
	for(n = 0; n < NKEYS; n++)
		if(keytab[n].count > 0)
			printf("%4d %s\n", keytab[n].count, keytab[n].word);
	
	return 0;
}

int binsearch(char *word, struct key tab[], int n){
	int cond;
	int left, right, mid;
	left = 0;
	right = n - 1;
	while(left <= right ){
		mid = (left + right) / 2;
		if((cond = strcmp(word, tab[mid].word)) < 0)
			right = mid - 1;
		else if(cond > 0)
			left = mid + 1;
		else 
			return mid;
	}
	return -1;
} 

int getword(char *word, int lim){
	int c, getch(void);
	void ungetch(int);
	char *w = word;
	while(isspace(c = getch()))
		;
	if(c != EOF)
		*w++ = c;
	if(!isalpha(c)){
		*w = '\0';
		return c;
	}
	for(  ; --lim > 0 ; w++)
		if(!isalnum (*w = getch())){
			ungetch(*w);
			break;
		}
	
	*w = '\0';
	return *word;
}




6.3 统计输入中各个c语言关键字出现的次数 (指针版)

#include 
#include 
#include 

#define MAXWORD 100
#define NKEYS (sizeof keytab / sizeof(struct key)) 


struct key{
	char *word;
	int count;
};

struct key keytab[NKEYS];

int getword(char *, int);
struct key *binsearch(char *, struct key *, int);

int main(){
	int n; 
	char word[MAXWORD];	
	struct key *p;
	
	while(getword(word, MAXWORD) != EOF)
		if(isalpha(word[0]))
			if((p = binsearch(word, keytab, NKEYS)) != NULL) 
				p->count++;
				
	/* 遍历输出 次数 */
	for(p = keytab; p < keytab + NKEYS; p++) 
		if(p->count > 0)
			printf("%4d %s\n", p->count, p->word);
	return 0;
}

int binsearch(char *word, struct key *tab, int n){
	int cond;
	struct key *low = &tabl[0];
	struct key *high = &tab[n]; // 可以多访问一个位置 
	struct *mid;
	
	while(left <= right ){
		mid = low+ (high - low) / 2; // 指针之间只能相减 
		if((cond = strcmp(word, tab[mid].word)) < 0)
			high = mid - 1;
		else if(cond > 0)
			low = mid + 1;
		else 
			return mid;
	}
	return NULL;
} 

int getword(char *word, int lim){
	int c, getch(void);
	void ungetch(int);
	char *w = word;
	while(isspace(c = getch()))
		;
	if(c != EOF)
		*w++ = c;
	if(!isalpha(c)){
		*w = '\0';
		return c;
	}
	for(  ; --lim > 0 ; w++)
		if(!isalnum (*w = getch())){
			ungetch(*w);
			break;
		}
	
	*w = '\0';
	return *word;
}


6.4 自引用结构 统计单词个数 二叉树

#include 
#include 
#include 
#include 

#define MAXWORD 100

struct tnode{
	char *word;  // 单词 
	int count; // 单词数量 
	struct tnode *left; //左子树 
	struct tnode *right; // 右子树 
}; 

struct tnode *addtree(struct tnode *, char *); // 插入一个单词 
void treeprint(struct tnode *);  // 递归输出 
int getword(char *, int);  // 获取一个单词 

main(){
	struct tnode *root;
	char word[MAXWORD];
	root = NULL;
	while(getword(word, MAXWORD) != EOF)
		if(isalpha(word[0]))
			root = addtree(root, word);
			
	treeprint(root);
	return 0;
}
struct tnode *talloc(void);
char *strdup(char *);
struct tnode *talloc(void){
	return (struct tnode *) malloc(sizeof(struct tnode));
}
struct *strdup(char *s){
	char *p;
	p = (char *) malloc (strlen(s) + 1);
	if(p != NULL)
		strcpy(p, s);
	return p; 
}

struct treenode *addtree(struct tnode *p, char *w){
	int cond;
	if(p == NULL){ // 一个新的单词要建立 
		p = talloc(); // 分配一个 新的结点地址 
		p->word = strdup(w);  // 将字符存储,返回一个地址
		p->count = 1;
		p->left = p->right = NULL; 
	}else if((cond = strcmp(w, p->word)) == 0)
		p->count++; // 找到了,单词数++ 
	else if(cond < 0)
		p->left = addtree(p->left, w); // 向左子树查找 
	else 
		p->right = addtree(p->right, w); // 向右子树查找 
	return p; 
}

void treeprint(struct tnode *p){
	if(p != NULL){
		treeprint(p->left);
		printf("%4d %s\n", p->count, p->word);
		treeprint(p->right);
	}
} 

6.5 表查找 散列函数

#include 
#include 


struct nlist{
	struct nlist *next;
	char *name;
	char *defn;
};
#define HASHSIZE 101

static struct nlist *hashtab[HASHSIZE]; 

unsigned hash(char *s){
	unsigned hashval;
	for(hashval = 0; *s != '\0'; s++)
		hashval = *s + 31 * hashval;
	return hashval % HASHSIZE;
}
struct nlist *lookup(char *s){
	struct nlist *np;
	for(np = hahstab[hash(s)]; np != NULL; np = np->next) // 遍历一个链表 
		if(strcmp(s, np->name) == 0)
			return np;
			
	return NULL;
}
struct nlist *install(char *name, char *defn){
	struct nlist *np;
	unsigned hashval;
	if((np = lookup(name)) == NULL) { // 没找到,作为头结点 
		np = (struct nlist *) malloc (sizeof(*np)); // 此处 *np <==> struct nlist 
		if(np == NULL || (np->name = strdup(name)) == NULL)
			return NULL;
		hashval = hash(name);
		np->next = hashtab[hashval]; // 头插法,插入一个结点 
		hashtab[hashval] = np;
	}else 
		free((void *) np->defn);
	if((np->defn == strdup(defn)) == NULL)
		return NULL;
	return np;
}

void undef(char *s){
	int h;
	struct nlist *prev, *np;
	prev = NULL;
	h = hash(s);
	for(np = hashtab[h]; np != NULL; np = np->next){
		if(strcmp(s, np->name) == 0)
			break;
		prev = np; 
	}
	if(np != NULL){
		if(prev ==  NULL)
			hashtab[h] = np->next;
		else 
			prev->next = np->next;
		free((void *) np->name);
		free((void *) np->defn);
		free((void *) np);
	}
} 


7 输入与输出

7.1 minprintf

#include 
#include 

void minprintf(char *fmt, ...){
	char *p, *sval;
	double dval;
	int ival;
	va_list ap;
	va_start(ap, fmt);
	for(p = fmt; *p != '\0'; p++){
		if(*p != '%') {
			putchar(*p);
			continue;
		}
		switch(*++p){
			case 'd':
				ival = va_arg(ap, int);
				printf("%d", ival);
				break;
			case 'f':
				dval = va_arg(ap, double);
				printf("%lf", dval);
				break;
			case 's':
				for(sval = va_arg(ap, char *); *sval != '\0'; sval++) 
					putchar(*sval);
				break;
			default:
				putchar(*p);
				break;
		}
	}
	va_end(ap);
}
int main(){
	minprintf("%d\n%f\n%s\n", 123, .13, "jdfkajskf563");
	return 0;
}

7.2 cat

#include 


main(int argc, char *argv[]){
	FILE *fp;
	void filecopy(FILE *, FILE *);
	char *prog = *argv;
	if(argc == 1)
		filecopy(stdin, stdout);
	else {
		while(--argc > 0){
			if((fp = fopen(*++argv, "r")) == NULL) {
				fprintf(stderr, "cat: can't open %s \n", *argv);
				exit(1);
			}else {
				filecopy(fp, stdout);
				fclose(fp);
			}
		}
	}
	if(ferror(stdout)){
		fprintf(stderr, "%s: error writing stdout.\n", prog);
		exit(2);
	}
	exit(0);
}

void filecopy(FILE *from, FILE *to){
	int c;
	while((c = fgetc(from) )!= EOF)
		fputc(c, to);
}


8 UNIX 系统接口

8.1

你可能感兴趣的:(结构的模版)