彻底理解指针第三篇
来源:互联网 发布:golang程序员工资 编辑:程序博客网 时间:2024/05/17 16:55
今天主要看了函数指针和一个递归下降语法分析程序。感觉收益剖多。 函数本身不是变量,函数名代表函数的首地址,可以用函数指针指向,初始化函数指针要小心,不要加括弧。具体请详细看下面的代码。此题目:对输入的文本进行快速排序,如果指定参数-n,则可以进行数值排序,否则默认是字典排序。
#include <stdio.h>#include <stdlib.h>#include <string.h>#define MAXLINE 1000#define MAXLEN 500char* line[MAXLINE];//进行数组拷贝void copy(char *s,char *t){for(;(*s=*t)!='\0';s++,t++);}//读取一行 int getLine(char *s,int maxSize){int i;char c;for(i=0;(i<maxSize-1) && ((c=getchar())!=EOF) && c!='\n';i++)s[i]=c;if(c=='\n'){s[i]='\n';i++;}s[i]='\0';return i;}//读取所有文本行int readLines(char **line,int maxSize){char *p;char storelines[MAXLEN];int length;int countlines=0;while((length=getLine(storelines,maxSize))>0){p=(char *)malloc(sizeof(char)*(length+1));storelines[length-1]='\0';copy(p,storelines);printf("%d\n",length);line[countlines++]=p;}return countlines;}//交换指针void swap(void **v,int i,int j){void *temp;temp=v[i];v[i]=v[j];v[j]=temp;}//对指针进行排序//参数void**,可以排序任何类型void psort(void **v,int left,int right,int (*comp)(void*,void*)){int i,last;if(left>=right)return;swap(v,left,(left+right)/2);last=left;for(i=left+1;i<=right;i++)if((*comp)(v[i],v[left])<0)swap(v,++last,i);swap(v,left,last);psort(v,left,last-1,comp);psort(v,last+1,right,comp);}//打印void writeLines(char **line,int lines){int i;for(i=0;i<lines;i++)printf("%s\n",line[i]);}//按数值顺序比较字符串//atof()把字符串转换成浮点数// atof()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时('\0')才结束转换,并将结果返回int numcmp(char *s1,char *s2){double v1,v2;v1=atof(s1);v2=atof(s2);if(v1<v2)return -1;else if(v1>v2)return 1;elsereturn 0;}int main(int argc,char *argv[]){int lines;int numeric=0;if(argc>1 && strcmp(argv[1],"-n")==0)numeric=1;if((lines=readLines(line,MAXLEN))>0)if(lines<=MAXLINE){psort((void**)line,0,lines-1,(int (*)(void*,void*))(numeric?numcmp:strcmp));writeLines(line,lines);}elseprintf("too many lines\n");return 0;}
接下来是一个将C语言的声明转化为文字描述。也就是所谓的递归下降语法分析器,因
为程序中相互递归调用。
C语言语法形式:
dcl: 前面带有可选的*的dir-dcl
dir-dcl: name
(dcl)
dir-dcl()
dir-dcl[可选长度]
写程序之前首先要搞懂程序的逻辑功能,对程序的输入,执行,输出有彻底的理解,才
能进行编写程序。举个小例子才可以彻底的弄明白。
这个程序的逻辑很简单,但是实现却相当的复杂。
1.读取数据类型
2.调用dcl函数处理输入的剩余部分。
3.不断的调用gettoken函数,读取下一个记号,进行判断。
4.根据判定结果显示相应的字符串。
整个程序只要理解3点就很简单:
1.gettoken()函数是读取下一个记号。每次调用它,都会读取token和tokentype。
2.getch和ungetch,这是确保输入的完整性函数,利用一个共享数组来实现。
3.对于dcl和dir-dcl,两个函数的递归调用,这个根据语法来理解。
具体实现如下:不得不佩服这个程序写的真是太棒了。真不愧是C语言发明者。
/*递归语法定义,递归下降语法分析程序*//*将C语言的声明转化为文字描述*/#include <stdio.h>#include <string.h>#include <ctype.h>#define MAXTOKEN 100#define BUFSIZE 100enum{NAME,PARENS,BRACKETS};void dcl(void);void dirdcl(void);char buf[BUFSIZE];//用于xieungetch函数的缓冲区int bufp=0;//buf中下一个空间的位置int gettoken(void);int tokentype;//下一个记号的类型char token[MAXTOKEN];//下一个记号字符串char name[MAXTOKEN];//标志符名char datatype[MAXTOKEN];//数据类型为char int等char out[1000];//输出串//调用xiegetch和xieungetch,用来确定程序它已经读入的输入是否足够//读取下一个待处理的字符//这样,此后在调用xiegetch函数时,在读入新的输入之前先返回ungetch函数放回的那个字符int xiegetch(void){ return (bufp > 0) ? buf[--bufp] : getchar();}//xieungetch函数则用于把字符放回到输入中//xieungetch函数把要压回的字符放到一个共享缓冲区(字符数组)中,当该缓冲区不空时,xiegetch函数就从//缓冲区中读取字符;当缓冲区为空时,xiegetch函数调用getchar函数直接从输入中读字符void xieungetch(int c){ if (bufp >= BUFSIZE) printf("ungetch: too many characters "); else buf[bufp++] = c;}//返回下一个标记的类型,标记可以是一个名字,一对圆括号,包含一个数字的一对方括号,也可以其他的单个字符(如EOF)int gettoken(void){int c;char *p=token;//p永远指向token数组首地址while((c=xiegetch())==' ' || c=='\t');if(c=='('){if((c=xiegetch())==')'){strcpy(token,"()");return tokentype=PARENS;}else{xieungetch(c);return tokentype='(';}}else if(c=='['){for(*p++=c;(*p++=xiegetch())!=']';);*p='\0';return tokentype=BRACKETS;}else if(isalpha(c)){for(*p++=c;isalnum(c=xiegetch());)*p++=c;*p='\0';xieungetch(c);return tokentype=NAME;}elsereturn tokentype=c;}int main(){while(gettoken()!=EOF)//gettoken()返回下一个标记{strcpy(datatype,token);//该行的第一个记号是数据类型char intout[0]='\0';//保证打印正常dcl();//分析该行的其余部分if(tokentype!='\n')printf("syntax error\n");printf("%s: %s %s\n",name,out,datatype);}return 0;}//分析一个直接声明void dirdcl(void){int type;if(tokentype=='('){dcl();//再递归调用原来的dir函数if(tokentype!=')')printf("error:missing)\n");}else if(tokentype == NAME)//变量名strcpy(name,token);else printf("error:expected name or (dcl)\n");//必须是名字或者括弧while((type=gettoken())==PARENS || type==BRACKETS)//gettoken返回了type和token串if(type==PARENS)strcat(out," function returning");else{strcat(out," array");strcat(out,token);strcat(out," of");}}//对一个声明符进行语法分析void dcl(void){int ns;//gettoken()已经取了下一个token了,放在token中了//gettoken()已经返回下一个tokentype了,放在tokentype中了for(ns=0;gettoken()=='*';);dirdcl();while(ns-->0)strcat(out," point to");}
- 彻底理解指针第三篇
- 彻底理解指针第二篇
- 彻底理解指针第四篇
- 彻底理解指针第五篇
- 彻底理解指针第六篇
- 《彻底搞定C指针》第三篇
- 彻底搞定C语言指针 第三篇
- 彻底理解指针
- 彻底理解指针第一篇
- 指针两个要素,彻底理解指针
- C语言(彻底理解指针和地址,彻底!)
- 指针二次理解(第三篇)如何安全的使用指针
- JavaScript中this指针指向的彻底理解
- 1分钟彻底理解C语言指针的概念
- 1分钟彻底理解C语言指针的概念
- 90 1分钟彻底理解C语言指针的概念
- JavaScript中this指针指向的彻底理解
- 深入理解c语言指针-第三章
- 如何把FLAC+CUE刻录成CD
- 解决VC++6.0启动_【打开文件】_对话框时出现的“0x5003eaed”问题!!!
- ==与equals方法
- html 日记本
- android整合--UI基本控件Button,ImageButton,EditText,ChcekBox,ToggleButton,RadioButton
- 彻底理解指针第三篇
- linux常用内容总结(一)
- 20130919
- Spring AOP 基本方式(Advice方式)
- 大文本文件阅读器设计
- hadoop集群datanode冲突异常
- 样式与主题
- 高性能网站设计
- ejb一些杂的代码