C语言中,指针一直是让学习者望而却步的知识点,然而,正如Brian W.Kernighan和Dennis M.Rithie在书中第五章5.4中所说, "C is consistent and regular in its approach to address arithmetic;its integration of pointers,arrays,and address arithmetic is one of the strength of the language"(C中地址的算术运算是一致和有规律的不知道这里这样翻译是不是理解正确的。指针、数组和地址算术运算等这些功能的集合恰是C语言之所以强大的原因之一),所以,这里就C语言的指针且其对一般人较不熟悉的一面(或者说一个用处)作一下笔记。
如下一个程序,功能是根据选项对输入的多行字符串进行排序,如果给了"-n"选项,则按数值进行排序,而不是按字符串字典序(lexicographically)。
这虽是一个小程序,但里面却有许多闪光点:如涉及到指针数组与数组(的)指针、void *(泛型指针)和快速排序算法及从中体会如何写程序(尽量的功能分解、独立性、以及从上而下地一步一步从有大思路到细节实现)。。。。
我们知道,一个排序过程涉及三大步:
1、比较对象(从而决定出对象间的正确顺序)
2、交换1中应该换序的对象
3、完全排好序
我们会学会,对于这个程序,先按照上述方向有了思路,再来进入其中每一小步中去解决,比如,1中的比较——对于字典序(lexicographic),可以通过strcmp()函数库来实现,当然,对于按数值来排序,则我们需要同strcmp()类似机能的函数numcmp(),这个函数具体实现又再去具体去想算法。
#include <stdio.h>
#include <string.h>
#define MAXLINES 50000//max #lines to be sorted
char *lineptr[MAXLINES];//pointers to text lines,即指针数组,
int readlines(char *lineptr[],int nlines);
void writelines(char *lineptr[],int nlines);
void qsort(void *lineptr[],int left,int right,int (*comp)(void *,void *));/*注意到了吧:这里用了void *指针,这可使其能用>来对任何数据类型的行文本进行排序,一劳永逸之效啊,还有,(*comp)函数指针也用到了,我觉得也许你不太容易记住函数指针,但>与我们常见的函数返回什么指针情况进行对比记忆就较好记住了,也知道要用括号*/
int numcmp(char *,char *);
/*sort input lines*/
int main(int argc,char *argv)/*注意到:ärgv也是指针数组哦*/
{
int nlines;//number of input lines read
int numeric=0;//1 if numeric sort
if(argc>1&&strcmp(argv[1],"-n")==0){/*only when argc>1,we do strcmp(,)*/
numeric=1;
}
if((nlines=readlines(lineptr,MAXLINES))>=0){
qsort((void **)lineptr,0,nlines-1,(int (*)(void *,void *))(numeric?numcmp:strcmp));/*the ? : skill for here,A ha!,and the numcmp here is the pointer to function*/
writelines(lineptr,nlines);
return 0;
}else{
printf("input too big to sort\n");
return 1;
}
}
#define MAXLEN 1000 /*max length of any input line*/
int getline(char *,int);
char *alloc(int);
/*readlines:read input lines*/
int readlines(char *lineptr[],int maxlines)
{
int len,nlines;
char *p,line[MAXLEN];
nlines=0;
while((len=getline(line,MAXLEN))>0)
if(nlines>=maxlines||(p=alloc(len))==NULL)/*每行申请一个空间,line相当于中间临时缓存*/
return -1;
else{
line[len-1]=´\0´;/*delete newline*/
strcpy(p,line);
lineptr[nlines++]=p;
}
return nlines;
}
/*writelines:write output lines*/
void writelines(char *lineptr[],int nlines)
{
int i;
for(i=0;i<nlines;i++)
printf("%s\n",lineptr[i]);
}
/*getline:read a line into s,return length*/
int getline(char s[],int lim)
{
int c,i;
for(i=0;i<lim-1&&(c=getchar())!=EOF&&c!='\n';++i)
s[i]=c;
if(c=='\n'){
s[i]=c;
++i;
}
s[i]='\0';
return i;
}
#define ALLOCSIZE 10000/*size of available space*/
static char allocbuf[ALLOCSIZE];/*storage for alloc*/
static char *allocp=allocbuf;/*next free position*/
char *alloc(int n)/*return pointer to n characters*/
{
if(allocbuf+ALLOCSIZE-allocp>=n){
/*it fits*/
allocp+=n;
return allocp-n;/*old p*/
}
else /*not enough room*/
return 0;
}
/*qsort:sort v[left]...v[right] into increasing order*/
void qsort(void *v[],int left,int right,int (*comp)(void *,void *))
{
int i,last;
void swap(void *v[],int,int);
if(left>=right)/*do nothing if array contains*/
{
return ;/*fewer than two elements*/
}
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);
qsort(v,left,last-1,comp);
qsort(v,last+1,right,comp);
}
/*here is numcmp,which compares two strings on a leading numeric value,computed by calling atof*/
#include<stdlib.h>
/*numcmp:compare s1 and s2 numerically*/
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;
else
return 0;
}
void swap(void *v[],int i,int j)
{
void *temp;
temp=v[i];
v[i]=v[j];
v[j]=temp;
}
注意程序中指针数组用在这里的妙处,可以通过与固定的二维数组对比来体会,这里一时也不能说详尽,以后有时间再补
好了,这里回过头来再说说数组指针与指针数组的区别:
char * argv[];//这个是数组指针,还是指针数组?
char (*argv)[];//与上面式子比,又有什么不同?
相信很多人碰到这种情况的很少,当碰到时,查一下,也许就说“哦,原来是这样!”,但当再碰到相同的情况时,必有疑云重重,当初笔者也经常遇到这种情况,且看过<<C深度解剖>>之后,依然常常陷入忘了又记的痛苦回环中。那么,这里再提一下,我认为这或许是直接记住的法则 :
* 号比[]、()的优先级低,因此, char *argv[];中[]先与arg结合,argv是指针数组,因为argv是数组,其数组元素内容是char *;(我想,只要记住这一个,那么,什么是数组指针,就较清楚了)
而char (*argv)[];则声明了一个数组,那么数组名是什么,不知道,只知道argv指向这个数组。我想,我的这种解释或许对你有用!