C语言程序设计复习笔记

第六节 函数与程序结构

6-1

例1 将带有某个子串的语句输出出来

        编写一个程序,将带有某个子串(“ould”)的语句输出出来

// output the line with a certain string

#include <stdio.h>
#include <string.h>
#define MAXLEN 10000
int main(){
	int mygetline(char s[]);
	void withsentence(char s[],char sentence[],int n);

	char s[MAXLEN];
	char sentence[]="ould";
	int i=0;

	i=mygetline(s);
	while(i!=0){
		withsentence(s,sentence,i);
		i=mygetline(s);
	}

	return 0;
}

int mygetline(char s[]){
	char c;
	int i=0;

	while((c=getchar())&&c!=EOF&&c!='\n'){
		s[i++]=c;
	}
	if(c=='\n'){
		s[i]='\0';
	}

	return i;
}

void withsentence(char s[],char sentence[],int n){
    // 这里可以用检测当前到达的字符是否为'\0'来避免使用strlen函数
	int slen=strlen(sentence);   
	int sign;

	for(int i=0;i<n;i++){
		sign=0;
		for(int j=0;j<slen&&s[j+i]!='\0';j++){
			if(s[j+i]!=sentence[j])
				sign=1;
		}
        // 也可以通过让withsentence函数返回某个值(例如对应上的字符串长度,
        // 然后在main程序里printf,这样可以避免使用sign变量)
		if(sign==0){
			printf("%s\n",s);  
		}
	}
}

将上文中的注释付诸实践后的另一个代码:

// output the line with a certain string

#include <stdio.h>
#include <string.h>
#define MAXLEN 10000
int main(){
	int mygetline(char s[]);
	int withsentence2(char s[],char senten[]);

	char s[MAXLEN];
	char sentence[]="ould";
	int i=0;

	i=mygetline(s);
	while(i!=0){
		if(withsentence2(s,sentence)>0)
			printf("%s\n",s);
		i=mygetline(s);
	}

	return 0;
}

int mygetline(char s[]){
	char c;
	int i=0;

	while((c=getchar())&&c!=EOF&&c!='\n'){
		s[i++]=c;
	}
	if(c=='\n'){
		s[i]='\0';
	}

	return i;
}


int withsentence2(char s[],char sentence[]){
	int i,j,slen; // slen="similiar_len"
	for(i=0;s[i]!='\0';i++){
		for(j=0;sentence[j]!='\0';j++){
			if(s[i+j]==sentence[j]){
				slen++;
			}
			else
				break;
		}
		if(sentence[j]=='\0')  // 这里一开始没想到,要注意一下
			return slen;
	}
	return 0;
}

例2 atof

将字符串s转换为相应的双精度浮点数

#include <stdio.h>
#include <ctype.h>
#define MAXLEN 10000
int main(){
	double atof();

	double answer;

	answer=atof();
	if(answer!=-1)
		printf("%lf\n",answer);
	return 0;
}

double atof(){
	char c;
	double number=0;
	int sign=0,power=1;

	while(isspace(c=getchar()))
		;
	sign=(c=='-')?-1:1;
	while(isdigit(c=getchar())){
		number=number*10+(c-'0');
	}
	while(isdigit(c=getchar())){
		number=number*10+(c-'0');
        // 这里一开始使用的是计算小数点后面数字的位数,但是那样的话后面还会多加一个循环,
        // 因此用power更好
		power*=10;   
	}
	number/=power;
	number=number*sign;
	return number;
}

6-2

例5 逆波兰表达式

#include <stdio.h>
#include <ctype.h>
#define MAX 10000
#define NUMBER '0'
#define BUFSIZE 100

double stack[MAX];
int bufp=0;
char buf[BUFSIZE];
// k是push和pop的栈要用到的,代表当前栈用到哪一位了
int k=0;

char getch();
void ungetch(char c);

int main(){
	void push(double n);
	double pop();
	char getop(char s[]);
	double atof(char s[]);

	int temp;
	char s[MAX];
	char type;

	while((type=getop(s))!=EOF){
		switch(type){
			case(NUMBER):
				push(atof(s)); break;
			case('+'):
				push(pop()+pop()); break;
			case('-'):
				push(-pop()!=pop()); break;
			case('*'):
				push(pop()*pop()); break;
			case('/'):
				temp=pop();
				if(temp!='0')
					push(pop()/temp);
				else
					printf("Error! Dividing zero!\n");
				break;
			case('\n'):
				printf("%f\n",pop()); break;
			default:
				printf("Error!\n"); break;
		}
	}
	return 0;
}

char getop(char s[]){
	char c;
    // i用来存储当前往s里存储到了第几位,由于每次的s[]都是全新的,因此要重置i
	int i=0;

	s[0]='\0';
	while((c=getch())==' '||c=='\t')
		;
	if(c==EOF||c=='+'||c=='-'||c=='*'||c=='/'||c=='\n'){
		return c;
	}
	else if(isdigit(c)){
		s[i++]=c;
		while(isdigit(c=getch()))
			s[i++]=c;
		if(c=='.'){
			s[i++]='.';
			while(isdigit(c=getch()))
				s[i++]=c;
		}
		ungetch(c);
		s[i]='\0';
		return NUMBER; 
	}
	else
		return 'e';
}




void push(double n){
	stack[k++]=n;
}

double pop(){
	return stack[--k];
}




char getch(){
	return (bufp>0)?buf[--bufp]:getchar();
}

void ungetch(char c){
	if(bufp>=BUFSIZE)
		printf("Already full!\n");
	else
		buf[bufp++]=c;
}




double atof(char s[]){
	double number;
    // j是当前atof转换到s的哪一位了,每次都要转换一个全新的s,因此要充值
	int power=1,j=0;
	while(isspace(s[j]))
		j++;
	while(isdigit(s[j])){
		number=number*10+s[j]-'0';
		j++;
	}
	if(s[j]=='.')
		j++;
	while(isdigit(s[j])){
		number=number*10+s[j]-'0';
		power*=10;
		j++;
	}
	number/=power;
	return number;
}

几个在编写代码时遇到的问题:

1. 每次要读入一个数,而不是一个字符,我们想尽量用不同函数把功能拆开,因此这里使用getop专门读取下一个基团并识别其类型。

2. 除了在for循环里定义,其它时候不建议使用i,j,k等变量,因为这些变量里的值如果需要保留,很容易设置重复导致混乱。

3. 注意getch和ungetch中的退回字符是通过缓冲区实现的。

6-3

作业讲解 itoh

编写itoh(int x, char s[]),将x中的整型转为16进制数并存在s中,x可能为负数。

 第一种方法:未考虑负数的短除法

#include <stdio.h>
#include <string.h>
#define MAXLEN 10000

int main(){
	int x;
	char s[MAXLEN];

	void itoh(int x, char s[]);
	void reverse(char s[]);

	scanf("%d\n",&x);
	itoh(x,s);
	reverse(s);
	printf("%s\n",s);
	return 0;
}

void itoh(int x,char s[]){
	int index=0;

	do{
		if(x%16<10)
			s[index++]=x%16+'0';
		else
			s[index++]=x%16-10+'a';
		x/=16;
	} while(x!=0);
	s[index++]='\0';
}

void reverse(char s[]){
	int temp;
	int i=0,j=strlen(s)-1;
	while(j>=i){
		temp=s[i];
		s[i]=s[j];
		s[j]=temp;
		i++,j--;
	}
}

第二种方法:考虑负数,使用取二进制最后四位+右移

#include <stdio.h>
#include <string.h>
#define MAXLEN 10000
int main(){
	void itohplus(int x,char s[]);
	void reverse(char s[]);

    // 如果这里x就是unsigned int,那么如果输入负数会出现segmentation fault的报错
	int x;
	char s[MAXLEN];

	scanf("%d\n",&x);

	itohplus(x,s);
	reverse(s);
	printf("%s\n",s);
	return 0;
}

void itohplus(int x,char s[]){
	int index=0;
	unsigned int k;
	k=x;

	while(k!=0){
        // 注意如果(k&15)不使用括号,会先计算15<10产生错误
		s[index++]=((k&15)<10)?(k&15)+'0':(k&15)-10+'a';
		k>>=4;		
	}
	s[index]='\0';
}

void reverse(char s[]){
	int temp,i=0,j=strlen(s)-1;
	while(i<=j){
		temp=s[i];
		s[i]=s[j];
		s[j]=temp;
		i++,j--;
	}
}

两个注意点:

1. 因为有负数,使用unsigned int转化,但是获取输入值的仍为int,需另设一个unsigned int变量k使其等于x,否则会出现segmentation fault的报错。

2. (k&15)<10注意优先级,不使用括号会先计算<

例9 printd

#include <stdio.h>
int main(){
	void printd(int n);
	int n;

	scanf("%d\n",&n);
	printd(n);
	putchar('\n');

	return 0;
}

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

注意递归就不需要使用while了,只需要在函数里调用函数,就可以起到循环效果

例10 快速排序

#include <stdio.h>
int main(){
	int s[16]={11,8,31,9,33,19,13,1,5,34,65,13,32,23,17,41};
	void quicksort(int left,int right,int s[]);

	quicksort(0,15,s);
	for(int i=0;i<16;i++)
		printf("%d ",s[i]);
	printf("\n");
	return 0;
}

void quicksort(int left,int right,int s[]){
	if(left<right){
		int flagloc=(left+right)/2;
		int flag=s[flagloc];

		void swap(int i,int j,int s[]);
		swap(left,flagloc,s);


		flagloc=left;
		for(int i=left+1;i<=right;i++){
			if(s[i]<flag){
				flagloc++;
				swap(i,flagloc,s);
			}
		}
		swap(left,flagloc,s);

		quicksort(left,flagloc-1,s);
		quicksort(flagloc+1,right,s);
	}
}

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

 注意设置终止条件if(left<right)

 作业 仿照printd,用递归实现itoa

先转为字符串,然后输出字符串

#include <stdio.h>
#define MAXLEN 10000

int i=0;
int main(){
	int n;
	char s[MAXLEN];
	void itoa(int n,char s[]);

	scanf("%d\n",&n);
	itoa(n,s);
	s[i]='\0';
	printf("%s\n",s);
}

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

6-4

例11 汉诺塔

#include <stdio.h>
int main(){
	void hanoi(int n,char a,char b,char c);
	int n;
	scanf("%d\n",&n);
	hanoi(n,'A','B','C');
	return 0;
}

void hanoi(int n,char a,char b,char c){
	if(n==1)
		printf("%c -> %c\n",a,c);
	else{
		hanoi(n-1,a,c,b);
		printf("%c -> %c\n",a,c);
		hanoi(n-1,b,a,c);
	}
}

第七节 指针与数组

7-1

例6 用指针完成swap操作

#include <stdio.h>
int main(){
	void swap(int *pa,int *pb);
	int a=1,b=2;
	int *pa,*pb;
	pa=&a,pb=&b;
	printf("before:%d %d\n",a,b);
	swap(pa,pb);
	printf("after:%d %d\n",a,b);
	return 0;
}

void swap(int *pa,int *pb){
	int temp=*pa;
	*pa=*pb;
	*pb=temp;
}

7-2

例7 getint函数

样例输入输出如下图,array长度为定值10,要求多读的要退回

#include <stdio.h>
#include <ctype.h>
#define LEN 10
#define BUFSIZE 100

int bufp=0;
int buf[BUFSIZE];

int getch();
void ungetch(int c);

int main(){
	int getint(int *p);
	int array[LEN]={0};
	for(int i=0;i<LEN&&(getint(&array[i]))!=EOF;i++)
		;
	for(int i=0;i<LEN;i++)
		printf("array[%d]=%d\n",i,array[i]);
	return 0;
}

int getint(int *p){
	char c;
	int sign;
	while(isspace(c=getch()))
		;
	sign=(c=='-')?-1:1;
	if(c=='+'||c=='-')
		;
	else{
		ungetch(c);
	}
	while(isdigit(c=getch())){
		*p=10* *p +c-'0';
	}
	*p*=sign;
	if(c!=EOF)
		ungetch(c);
	return c;
}

int getch(){
	return (bufp>0)?buf[--bufp]:getchar();
}

void ungetch(int c){
	if(bufp>=BUFSIZE)
		printf("No more place!");
	else
		buf[bufp++]=c;
}

例11 用指针实现不完善的内存分配器

#define ALLOCSIZE 100
static char allocbuf[ALLOCSIZE];
static char *allocp=allocbuf;

// 函数类型也可以是指针(即返回值的类型为指针)
char *alloc(int n){
    // 指针可以和常数做加减法,或与另一个指针做减法
	if((ALLOCSIZE-allocp+allocbuf)>=n)
		return allocp-n;
	else
        // 指针可以赋值为0,即空指针
		return 0;
}

void free(char *p){
	if(p>=allocbuf&&p<=allocbuf+ALLOCSIZE)
		allocp=p;
}

例12 用指针计算字符串长度

#include <stdio.h>
int main(){
	int mystrlen(char *p);
	char s[]="Hello friends!";
	int n=mystrlen(s);
	printf("%d\n",n);
}

int mystrlen(char *p){
	char *s=p;
	while(*s!='\0')
		s++;
    // 两个指针间可以做减法
	return s-p;
}

例14 strcopy(char *s, char *t)函数

#include <stdio.h>
#define MAXLEN 1000
int main(){
	void strcopy(char *s,char *t);
	char s[]="asdf";
	char t[MAXLEN];
	strcopy(s,t);
	printf("%s\n",t);
	return 0;
}

void strcopy(char *s,char *t){
	while(*s!='\0'){
		*(t++)=*(s++);
	}
    // 这里要不就单独令t最后为'\0',要不就把*t=*s放在while后面的括号里,
    // 不然的话t字符串就不是以'\0'结尾了
	*t='\0';
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值