C 语言 第五章 指针与数组

第五章  指针与数组

  指针是一种保存变量地址的变量。指针常常是表达某个计算的唯一途径,并且可以生成更高效、更紧凑的代码。指针与数组关系密切。

  NASI C使用类型void  *(指向void的指针)代替char *作为通用指针的类型。

5.1  指针与地址

  通常的机器都是有一系列连续编号或编址的存储单元,这些存储单元可以单个进行操纵,也可以连续成组的方式操作。通常机器的一个字节可以存放一个char类型的数据,两个相邻的字节存储单元可存储一个short类型的数据,4个相邻的字节存储单元可存储一个long类型数据。指针是能够存放一个地址的一组存储单元(通常是两个或4个字节)。

  一元运算符&可用于取一个对象的地址

  p = &c; 把c的地址复制给变量p,称p为”指向“ c的指针。地址运算符&只能应用于内存中的对象,即变量与数组元素。它不能作用于表达式、常量或register类型的变量。

  一元运算符* 是间接寻址或间接引用运算符。当他作用于指针时,将访问指针所指向的对象。

  double *dp, atof (char   *);

  在表达式中,*dp和atof(s)的值都是double类型,且atof 的参数是一个指向char 类型的指针。

  指针只能指向某种特定类型的对象,也就是说,每个指针都必须指向某种特定的数据类型。(一个例外情况是指向void类型的指针可以存放指向任何类型的指针,但不能简洁引用其自身。)

  一元运算符*和&的优先级比算术运算符的优先级高,因此赋值语句 y  =  *ip  +  1,取出*ip指向的对象的值加1赋值给Y

  *ip  + =  1  是将ip指向对象的值加1,等同于++*ip或(*ip)++,语句 (*ip)++中的圆括号是必须的,否则,该表达式将对ip惊醒加1运算,而不是对ip指向的对象进行加1运算,类似于*和++这样的一元运算符遵循从右至左的结合顺序。

  指针也是变量,所以在程序中可以直接使用。

 

5.2  指针与函数参数

  由于C语言是以传值的方式将参数值传递给被调用函数。被调用函数不能直接修改主调函数中变量的值。

  指针参数使得被调用函数能够访问和修改主调函数中对象的值。

  int  n,  array[SIZE],  getint(int  *)

  for  (n  =  0;  n  <  SIZE  &&  getint(&array[n])  != EOF;  n++)       &array[n]可以作为指针传递值

  

练习5-1
1
int getint(int *pn) 2 { 3 int c, d, sign; 4 while (isspace(c = getchar())); 5 if (!isdigit(c) && c != EOF && c != '+' && c != '-'){ 6 ungetch(c); 7 return 0; 8 } 9 sign = (c == '-') ? -1 : 1; 10 if (c == '+' || c == '-'){ 11 d = c; //预存c 12 if(!isdigit(c = getch())){ //获得下一个如果不是数字 13 if (c != EOF) //如果不是结束符 14 ungetch(c); //存入缓存区 15 ungetch(d); //然后把符号存进去 16 return d; //返回符号 17 } 18 } 19 for (*pn = 0; isdigit(c); c = getch()) 20 *pn = 10 * *pn + (c - '0'); 21 *pn *= sign; 22 if (c != EOF) 23 ungetch(c); 24 return c; 25 }
5-2
1
int getfloat(float *pn) 2 { 3 int c, sign; 4 float power; 5 while (isspace(c = getch())); 6 if (!isdigit(c) && c != EOF && c != '+' && c != '-' && c != '.'){ 7 ungetch(c); 8 return 0; 9 } 10 sign = (c == '-') ? -1 : 1; 11 if (c == '+' || c == '-') 12 c = getch(); 13 for (*pn = 0.0; isdigit(c); c = getch()) 14 *pn = 10.0 * *pn + (c - '0'); //10乘以pn加上新的个位数,依次类推 15 if (c == '.') 16 c = getch(); 17 for (power = 1.0; isdigit(c); c = getch()){ //小数之后的数字 18 *pn = 10.0 * *pn + (c - '0'); 19 power *= 10.0; //记录小数点之后一共几位 20 } 21 *pn *= sign / power; //计算结果 22 if (c != EOF) 23 ungetch(c); 24 return c; 25 }

 

5.3  指针与数组

  通过数组下标所能完成的任何操作都可以通过指针来实现。用指针编写的程序比用数组下标编写的程序执行速度快。

  数组名和指针之间有一个不同之处,指针是一个变量,c语言中,语句pa=a 和 pa++都是合法的。但数组名不是变量,a = pa 和 a++ 形式的语句是非法的。

  当把数组名传递给一个函数时,实际上传递的是该数组的第一个元素的地址。在被调用函数中,该参数是一个局部变量,因此,数组名参加必须是一个指针,一个存储地址值的变量。

  如果确信相应的元素存在,也可以通过下标访问数组的第一个元素之前的元素。类似于p[-1]、p[-2]语法是合法的,引用数组边界之外的对象是非法的。

  

5.4  地址算术运算

  C语言中的地址算术运算方法是一致且有规律的,将指针、数组和地址的算术运算集成在一起是该语言的一大优点。

  指针有意义初始值只能是0或者是表示地址的表达式,表达式所代表的地址必须是在此前已定义的具有适当类型的数据的地址。

  指针与整数之间不能相互转换,但0是唯一的例外:常量0可以赋值给指针,指针也可以和常量0进行比较。程序中经常用符号常量null代替常量0,这样便于更清晰的说明常量0是指针的一个特殊值。

  指针算术运算的特点:

  1、在某些情况下对指针可进行比较运算。例如,p和q指向同一个数组的成员。

  2、任何指针与0进行相等或不等的比较运算都有意义。但是指向不同数组的元素指针之间的算术或比较运算没有定义。(特例:指针的算术运算中可使用数组最后一个元素的夏一个元素的地址。)

  3、指针可以和整数进行加减运算。 p + n 表示指针p当前指向的对象之后第n个对象的地址。p指向的对象的长度取决于p的声明。例如,如果类型占4个字节的存储空间,那么int类型的计算中,对应的n将按4的倍数来计算。

  4、指针的减法运算也是有意义的,如果p和q指向相同数组中的元素,且p<q,那么q-p+1就位于p和q元素之间的元素数目。

  5、指针的算术运算具有一致性,所有指针运算都会自动考虑它所指向的对象的长度。

  有效的指针运算包括同类型指针之间的赋值运算,指针同整数之间的加减法运算,指向相同数组中元素的两个指针间的减法或比较运算,指针赋值为0或指针与0之间的比较运算。

 

5.5  字符指针与函数

  char amessage[ ]  =  "now is the time";

  char *pmessage  =  "now is the time";

  amessage是一个仅仅足以存放初始化字符串以及空字符'\0'的一维数组。数组中的单个字符可以进行修改,amessage始终指向同一个存储位置。另一方面pessage是一个指针,其初值指向一个字符串常量,之后它可以被修指向其他地址,如果试图修改字符串的内容,结果是没有定义的。

 

  

关于指针
1
char s[8]; //定义一个字符集 2 char *p = s; //定义指针 3 char var = '1'; 4 *p = '2'; //让字符集的第一个等于2 5 printf("%s\n",p); //输出字符集 6 *++p = '5'; //如果不注释这个,结果会是26,上面*p是第一个字符2,这个是第二个字符5,下面*p++实际上修改的是第二个字符,所以结果会是26 7 *p++ = '6'; 8 //*p++ = '7'; 9 printf("%s\n",s); 10 putchar(*--p); //这里结果是6,原因是p指向的是第三个字符,-1操作之后指向第二个字符6 11 printf("\n"); 12 printf("%s",s);
练习5-3
1
void strcat1(char *s,char *t) 2 { 3 while (*s) //一开始使用 while(*s++)得到后面结果是多出两个的也就是超过‘\0'了 4 s++; //这种方不超过0 5 while ((*s++ = *t++)); // 6 }
练习5-4
1
int strend1(char *s,char *t) { 2 int b; 3 b = 1; 4 //putchar(a); 5 //printf("%s\n",t); 6 //putchar(*t++); 7 //printf("\n"); 8 //putchar(*(t+strlen(t)-b)); 9 while (*(s+strlen(s)-b) == *(t+strlen(t)-b)) { //指针是一个存储(字符集或数组里面,单个字符内存地址)的空间,可以通过这个地址去修改这个地址内存储的数据。 10 b++; //*(s+strlen(s)-b)是这个字符集最后一个字符,然后循环-1,这边用的是变量b,每次b+1,然后最后一个字符-b 11 if (*(t + strlen(t) - b) == '\0') //如果发现t = 0了,那说明找完了,找到了 12 return 1; //返回1 13 } 14 //否则返回0 15 //putchar(*(t+strlen(t)+1)); 16 //printf("%s",t); 17 //putchar(*t); 18 //putchar(*(t+3)); 19 //printf("%s",t); 20 return 0; 21 //putchar(*t); 22 }
练习5-5
1
void strncpy1(char *s, char *t, int n) 2 { 3 while (*t && n-- > 0) 4 *s++ = *t++; 5 while (n-- > 0) 6 *s++ = '\0'; 7 } 8 void strncat1(char *s, char *t, int n) 9 { 10 void strncpy1(char *s, char *t, int n); 11 strncpy1(s+strlen(s),t,n); 12 } 13 int strncmp1(char *s, char *t, int n) 14 { 15 for (; *s == *t; s++, t++) 16 if (*s == '\0' || --n <= 0) 17 return 0; 18 return *s - *t; 19 }

  

 

练习5-6 标准答案
1
int getline(char *s, int lim) 2 { 3 char c; 4 char *t = s; 5 while (--lim > 0 && (c=getchar()) != EOF && c != '\n') 6 *s++ = c; 7 if (c == '\n') 8 *s ++ = c; 9 *s = '\0'; 10 return s - t; 11 } 12 int atoi1(char *s) 13 { 14 int n, sign; 15 for (; isspace(*s); s++); 16 sign = (*s == '-') ? -1 : 1; 17 if (*s == '+' || *s == '-') 18 s++; 19 for (n = 0; isdigit(*s); s++) 20 n = 10 * n + *s - '0'; 21 return sign * n; 22 } 23 void reverse(char *s) 24 { 25 int c; 26 char *t; 27 for (t = s + (strlen(s)-1);s < t; s++, t--){ //C语言 for循环执行顺序,1.初始化,2判断条件 28 c = *s; //3,执行循环体 29 *s = *t; //4.执行判断条件后面的操作 30 *t = c; //5.回到第二步. 31 } 32 } 33 int strindex(char *s, char *t) 34 { 35 char *b = s; 36 char *p, *r; 37 for (; *s != '\0'; s++){ 38 for (p=s, r=t; *r != '\0' && *p == *r; p++, r++); 39 if (r > t && *r == '\0') 40 return s-b; 41 } 42 return -1; 43 } 44 double atof1(char *s) 45 { 46 double val, power; 47 int sign; 48 for (; isspace(*s); s++); 49 sign = (*s == '-') ? -1 : 1; 50 if (*s == '+' || *s == '-') 51 s++; 52 for (val = 0.0; isdigit(*s); s++) 53 val = 10.0 * val + (*s - '0'); 54 if (*s == '.') 55 s++; 56 for (power = 1.0; isdigit(*s); s++){ 57 val = 10.0 * val + (*s - '0'); 58 power *= 10.0; 59 } 60 return sign * val / power; 61 } 62 int getop(char *s) 63 { 64 int c; 65 while ((*s = c = getchar()) == ' ' || c == '\t'); 66 *(s+1) = '\0'; 67 if (!isdigit(c) && c != '.') 68 return c; 69 if (isdigit(c)) 70 while (isdigit(*++s = c = getch())); 71 if (c == '.') 72 while (isdigit(*++s = c = getch())); 73 *s = '\0'; 74 if ( c != EOF) 75 ungetch(c); 76 return NUMBER; 77 }

 

 

5.6  指针数组以及只想指针的指针

  由于指针本身也是变量,所以他们也可以像其他变量一样存储在数组中。

  使用指针来处理排序可以消除因为移动文本行本身所带来的复杂的存储管理和巨大的开销。

  排序过程包括下列三个步骤:

  1.读取所有行输入  2.对文本行进行排序  3.按次序打印文本行

  通常最好的将程序划分成若干个与问题的自然划分想一致的函数。

  输入函数必须收集和保存每个文本行中的字符,并建立一个指向这些文本行的指针的数组。同时统计输入的行数,排序和打印时要用到这一信息。由于输入函数只能处理有限数目的输入行,所以超过限定时返回某个表示非法行数的数值  char  *lineptr[MAXLINES],表示lineptr是一个具有MAXLINES个元素的数组,其中每个元素是一个指向字符类型对象的指针。lineptr[i]是一个字符指针,而*lineptr[i]是指针指向的第i个文本行的首字符。

 

练习5-8 
1
int main() 2 { 3 // char z[] = "1"; 4 // char b[] = "10"; 5 // printf("%d",(strcmp(z,b))); 6 char s[MAXSTOR]; //定义一个字符集s 7 char a[MAXSTOR]; //字符集a 8 *lineptr = s; //指向字符集s的指针 9 int nlines; 10 char *linestor = a; //指向字符集a的指针 11 if ((nlines = readlines(lineptr, linestor, MAXLINES)) >= 0){ //读取行 12 qsort2(lineptr, 0, nlines-1); //排序,数据(指针集,0,行数) 13 writelines(lineptr, nlines); //输出 14 return 0; 15 } else{ 16 printf("error: input too big to sort\n"); 17 return 1; 18 } 19 } 20 21 int getline(char *, int); 22 char *alloc(int); 23 int readlines(char *lineptr[], char *linestor, int maxlines) 24 { 25 int len, nlines; 26 char line[MAXLEN]; 27 char *p = linestor; //当前已存储的数据 28 char *linestop = linestor + MAXSTOR; //最大可存储数据 29 nlines = 0; //输入了几行 30 while ((len = getline(line, MAXLEN)) > 0) { //获得输入数据的长度 31 if (nlines >= maxlines || p+len > linestop) //判断是否有足够的空间 32 return -1; 33 else { 34 line[len - 1] = '\0'; //加上结束符,把换行符n变成0 35 strcpy(p, line); //复制 36 lineptr[nlines++] = p; //指针指向行 37 p += len; 38 } 39 } 40 return nlines; //返回行数 41 } 42 void writelines(char *lineptr[], int nlines) 43 { 44 while (nlines-- > 0) 45 printf("%s\n", *lineptr++); 46 } 47 void qsort2(char *v[], int left, int right) 48 { 49 int i, last; 50 void swap1(char *v[], int i, int j); 51 if (left >= right) //如果开始行等于结束行,说明都比对完了 52 return; 53 swap1(v, left,(left + right)/2); //交换第0行和正中间行的数据 54 last = left; 55 for (i = left+1; i <= right; i++) //初始化i等于0+1,小于最大行数,每次+1 56 if (strcmp(v[i], v[left]) < 0) //例如有6行,计算机是5,让1-5行的数据分别分和第0行对比,交换 57 swap1(v, ++last, i); 58 swap1(v, left, last); //交换0行和最后换的那一行 59 qsort2(v, left ,last-1); //重新调用 60 qsort2(v, last+1, right); //重新调用 61 } 62 void swap1(char *v[], int i, int j) 63 { 64 char *temp; 65 temp = v[i]; 66 v[i] = v[j]; 67 v[j] = temp; 68 }

 

5.7  多维数组

  二维数组实际上是一种特殊的一维数组,它的每个元素也是一个一维数组。数组小表应该写成

  daytab[i] [j]   /row col/

  数组元素按行存储,当按存储顺序访问数组时,最右边的数组下标变化的最快。数组可以用花括号括起来初值表进行初始化,二维数组的每一行由相应的子列表进行初始化。

  如果将二维数组作为参数传递给函数,那么在函数的参数声明中必须指明数组的列数。例如

  f(int daytab[2] [13] ) {}    或者  f(int daytab[ ] [13] ) {}  行数无关紧要  或者写成

  f (int  (*daytab)[13])  {}  int *daytab[13]

  

练习5-8
1
int main() 2 { 3 int m,d; 4 month_day(1988,367,&m,&d); 5 printf("%d %d",m,d); 6 } 7 static char daytab[2][13] = { 8 {0,31,28,31,30,31,30,31,31,30,31,30,31}, 9 {0,31,29,31,30,31,30,31,31,30,31,30,31} 10 }; 11 int day_of_year(int year, int month, int day) 12 { 13 int i, leap; 14 leap = (year%4 == 0 && year%100 != 0) || year%400 == 0; 15 if (month < 1 || month > 12) //月份是1-12 16 return -1; 17 if (day < 1 || day > daytab[leap][month]) //日子是1-31 18 return -1; 19 for (i = 1; i < month; i++) 20 day += daytab[leap][i]; 21 return day; 22 } 23 void month_day(int year, int yearday, int *pmonth, int *pday) 24 { 25 int i, leap; 26 if (year < 1){ 27 *pmonth = -1; 28 *pday = -1; 29 return; 30 } 31 leap = (year%4 == 0 && year%100 != 0) || year%400 == 0; 32 for (i = 1; yearday > daytab[leap][i]; i++) 33 yearday -= daytab[leap][i]; 34 if (i > 12){ //如果给的天数大于这一年的总天数(闰年366天,平年365) 35 *pmonth = -1; 36 *pday = -1; 37 } else{ 38 *pmonth = i; 39 *pday = yearday; 40 } 41 } 42 int getline(char *, int);

 

5.8  指针数组的初始化  

  

1     char *month_name[] = {
2             "Illegal month","January","February","March","April","May","June",
3             "July","August","September","October","November","December"
4     };//数组的元素为字符指针。name数组的初始化通过一个字符串列表实现,列表中的每个字符串赋值给数相应位置的元素。
5     //第i个字符串的所有字符存储在存储器中的某个位置,指向它的指针存储在name[i]中。没有指明长度时编译器将对初值个数进行统计,将准确数字填入数组长度

 

5.9  指针与多维数组

  int a[10] [20]

  int *b[10]

  a分配了200个int类型长度的存储空间,并且通过常规的巨指针下标计算公式20*row+col计算得到元素a[row][col]的位置。

  b定义仅仅分配了10个者指针,并且没有初始化,他们初始化必须显式的方式进行,比如静态代码初始化或通过代码初始化。假定b每个元素指向一个具有20个元素的数组,那么编译器就要为它分配200个int类型长度的存储空间以及10个指针的存储空间。

  指针数组的一个重要有点在于,数组的每一行长度可以不同,也就是说,b的每个元素不必都指向一个具有20个元素的向量。

  指针数组最频繁的用处是存放具有不同长度的字符串。

练习5-9
1
int main() 2 { 3 char *month_name[] = { 4 "Illegal month","January","February","March","April","May","June", 5 "July","August","September","October","November","December" 6 };//数组的元素为字符指针。name数组的初始化通过一个字符串列表实现,列表中的每个字符串赋值给数相应位置的元素。 7 //第i个字符串的所有字符存储在存储器中的某个位置,指向它的指针存储在name[i]中。没有指明长度时编译器将对初值个数进行统计,将准确数字填入数组长度 8 int m,d; 9 month_day(1988,365,&m,&d); 10 printf("%d %d",m,d); 11 //printf("%d",day_of_year(1988,6,20)); 12 } 13 static char daytab[2][13] = { 14 {0,31,28,31,30,31,30,31,31,30,31,30,31}, 15 {0,31,29,31,30,31,30,31,31,30,31,30,31} 16 }; 17 int day_of_year(int year, int month, int day) 18 { 19 int leap; 20 char *p; 21 leap = (year%4 == 0 && year%100 != 0) || year%400 == 0; 22 p = daytab[leap]; //p等于具体行,闰年,平年 23 while (--month) //减去月份 24 day += *++p; //日子相加 25 return day; 26 } 27 void month_day(int year, int yearday, int *pmonth, int *pday) 28 { 29 int leap; 30 char *p; 31 leap = (year%4 == 0 && year%100 != 0) || year%400 == 0; 32 p = daytab[leap]; 33 printf("%d\n",p); 34 while (yearday > *++p) //如果总天数大于这个月就减去这个月。 35 yearday -= *p; 36 printf("%d\n",p); 37 printf("%d\n",*p); 38 printf("%d\n",*(daytab+leap)); 39 *pmonth = p - *(daytab + leap); //p指向最后一列,*(daytab + leap)指向第一列,相减得到走了几列就是几个月。 40 *pday = yearday; //剩下几天 41 }

 

5.10  命令行参数  

  在支持C语言的环境中,可以在程序开始执行时将命令行参数传递给程序。调用主函数main时,他带有两个参数。第一个参数(argc,用于参数计数)的值表示运行程序命令中的的参数数目;第二个参数(argv,用于参数向量)是一个指向字符串数组的针,其中每个字符串对应一个参数。通常用多级指针处理这些字符串。

  UNIX系统中C语言程序有一个公共的约定:以符号开头的参数表示一个可选标志或参数。

  

练习5-10
1
#include "library.h" 2 #include <math.h> 3 #include <stdio.h> 4 #include <string.h> 5 #define MAXLINE 1000 6 #define MAXOP 100 7 #define NUMBER '0' 8 int getop(char []); 9 void ungets(char []); 10 void push(double); 11 double pop(void); 12 int main(int argc, char *argv[]) 13 { 14 char s[MAXOP]; 15 double op2; 16 while (--argc > 0){ 17 ungets(" "); 18 ungets(*++argv); 19 switch (getop(s)){ 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"); 39 break; 40 default: 41 printf("error: unknown command %s\n", s); 42 argc = 1; 43 break; 44 } 45 } 46 printf("\t%.8g\n",pop()); 47 return 0; 48 }

 

5-11.标准答案    一个制表符和下一个制表符之间差8个字符位,不管中间有没有其他字符,有字符加上字符一共8个位.
1
#include <stdio.h> 2 #include <stdlib.h> 3 4 #define MAXLINE 100 5 #define TABINC 8 6 #define YES 1 7 #define NO 0 8 9 void settab(int argc, char *argv[], char *tab); 10 void entab(char *tab); 11 int tabpos(int pos, char *tab); 12 13 int main(int argc, char *argv[]) 14 { 15 char tab[MAXLINE+1]; 16 settab(argc, argv, tab); 17 entab(tab); 18 return 0; 19 } 20 void entab(char *tab) 21 { 22 int c, pos; 23 int nb = 0; 24 int nt = 0; 25 26 for (pos = 1; (c=getchar()) != EOF; pos++) 27 if (c == ' '){                  //如果是空格 28 if (tabpos(pos, tab) == NO)        //事先设置好的如果不到8个空格,那就都算空格 29 ++nb;                   //空格计数 30 else { 31 nb = 0;                  //如果空格到8个,那tabpos(pos, tab) == YES ,然后重置空格数目, 32 ++nt;                   //制表符数目+1 33 } 34 } else {                      //如果不是空格 35 for (; nt > 0; nt--)             //如果NT(制表符数目大于1)表示已经存储有制表符了 36 putchar('\t');              //输出制表符       37 if (c == '\t')                 //如果是制表符 38 nb = 0;                   //空格数目重置 39 else                    //如果不是制表符 40 for (; nb > 0; nb--)           //如果NB大于0表示空格存在   41 putchar(' ');             //输出空格 42 putchar(c);                   //输出字符 43 if (c == '\n')                 //如果是换行符 44 pos = 0;                  //字符计数重置 45 else if (c == '\t') {             //如果当前字符是制表符 46 while (tabpos(pos, tab) != YES)     //如果tabpos(pos,tab) != YES 47 ++pos;                 //pos+1 48 } 49 } 50 } 51 52 void settab(int argc, char *argv[], char *tab) 53 { 54 int i, pos;                         55 if (argc <= 1)                      //如果给的参数小于或等于1个 56 for (i = 1; i <= MAXLINE; i++) {         //初始化制表符 57 if (i % TABINC == 0)              //如果i取余8等于0 58 tab[i] = YES;                //那tab[i]的位置就是1,代表一个制表符的停止位置 59 else 60 tab[i] = NO;                 //如果取余8不等于0则tab[i]不是结束位置 61 } 62 else{                            //如果给的参数大于一个      63 for (i = 1; i <= MAXLINE; i++)           //初始化 64 tab[i] = NO;                   //tab全部都是0 65 while (--argc > 0) {                 //如果--argc大于0 66 pos = atoi(*++argv);              //pos等于 函数字符串转数字argv[1]数值 67 if (pos > 0 && pos <= MAXLINE)        //如果pos大于0小于最大设定数 68 tab[pos] = YES;               //那么pos的位置是制表符停止位 69 } 70 } 71 } 72 73 int tabpos(int pos, char *tab) 74 { 75 if (pos > MAXLINE) 76 return YES; 77 else 78 return tab[pos]; 79 }

 

 这里记录一下clion如何使用debug带参数开始程序

 

 

 

 

 

 

 

练习5-12
1
int main(int argc, char *argv[]) 2 { 3 char tab[MAXLINE]; 4 esettab(argc, argv, tab); 5 entab(tab); 6 return 0; 7 } 8 void entab(char *tab) 9 { 10 int c, pos; 11 int nb = 0; 12 int nt = 0; 13 14 for (pos = 1; (c=getchar()) != EOF; pos++) 15 if (c == ' '){ 16 if (tabpos(pos, tab) == NO) 17 ++nb; 18 else { 19 nb = 0; 20 ++nt; 21 } 22 } else { 23 for (; nt > 0; nt--) 24 putchar('\t'); 25 if (c == '\t') 26 nb = 0; 27 else 28 for (; nb > 0; nb--) 29 putchar(' '); 30 putchar(c); 31 if (c == '\n') 32 pos = 0; 33 else if (c == '\t') { 34 while (tabpos(pos, tab) != YES) 35 ++pos; 36 } 37 } 38 } 39 void esettab(int argc, char *argv[], char *tab) 40 { 41 int i, inc, pos; 42 if (argc <= 1) 43 for (i = 1; i <= MAXLINE; i++) { 44 if (i % TABINC == 0) 45 tab[i] = YES; 46 else 47 tab[i] = NO; 48 } 49 else if (argc == 3 && *argv[1] == '-' && *argv[2] == '+'){ 50 pos = atoi(&(*++argv)[1]); //-n 是一个字符串,是一个整体,所以*++argv[1],指向1号字符串第一个元素 51 inc = atoi(&(*++argv)[1]); //-m 同上,指向2号字符串的第一个元素. 52 for (i =1; i <= MAXLINE; i++) 53 if (i != pos) 54 tab[i] = NO; 55 else { 56 tab[i] = YES; 57 pos += inc; 58 } 59 } 60 else { 61 for (i = 1; i <= MAXLINE; i++) 62 tab[i] = NO; 63 while (--argc > 0) { 64 pos = atoi(*++argv); 65 if (pos > 0 && pos <= MAXLINE) 66 tab[pos] = YES; 67 } 68 } 69 }

 

 

5-13做个标记,

 

5.11  指向函数的指针

  C语言函数本身不是变量,但可以定义指向函数的指针.这种类型的指针可以被赋值,存放在数组中,传递给函数以及作为函数的返回值等等.

  排序程序通常包括3部分:判断任何两个对象之间次序的比较操作,颠倒对象次序的交换操作,一个用于比较和交换对象直到所有对象都按正确次序排列的排序算法.由于排序算法与比较,交换操作无关,因此,通过在排序算法中调用不同的比较和交换函数,可以实现按照不同的标准排序.

  int (*comp) (void *, void *) ,它表明comp是一个指向函数的指针,该函数具有两个void *类型的参数,其返回值类型为int.

  if ((*comp) (v[i], v[left]) < 0), comp的使用和其声明是一致的,comp是一个指向函数的指针, *comp代表一个函数.

  (*comp) (v[i], v[left]) , 调用函数,圆括号是必须的,保证其中的各个部分正确结合.如果没有圆括号是错误的如下

  int *comp(void *, void *), 表明comp是一个函数,该函数返回一个指向int类型的指针.

  

 

练习5-14到5-17   整个
1
#include <string.h> 2 #include <stdlib.h> 3 #include <stdio.h> 4 #include <ctype.h> 5 #include <malloc.h> 6 7 8 #define MAXSTR 100 9 #define DIR 8 //只对字母,数字和空格进行比较。 10 #define FOLD 4 //不考虑大小写 11 #define NUMERIC 1 //标记是否是数字 12 #define DECR 2 //倒序排序 13 #define MAXLINES 5000 14 char *lineptr[MAXLINES]; 15 #define MAXLINE 100 16 #define TABINC 8 17 #define YES 1 18 #define NO 0 19 #define DEFLINES 10 20 #define LINES 100 21 #define MAXLEN 100 22 #define ALLOCSIZE 10000 23 static char allocbuf[ALLOCSIZE]; 24 static char *allocp = allocbuf; 25 26 27 int getline(char *,int); 28 void esettab(int argc, char *argv[], char *tab); 29 void entab(char *tab); 30 int tabpos(int pos,char *tab); 31 void settab(int argc, char *argv[], char *tab); 32 void detab(char *tab); 33 int readlines(char *lineptr[], int nlines); 34 void writelines(char *lineptr[],int nlines, int decr); 35 void qsort1(void *lineptr[], int left, int right, int (*comp)(void *, void *)); 36 void readargs(int argc, char *argv[]); 37 int charcmp(char *, char *); 38 int numcmp(char *,char *); 39 char *alloc(int); 40 void substr(char *s, char *t, int maxstr); 41 static char option = 0; 42 int pos1 = 0; 43 int pos2 = 0; 44 int main(int argc, char *argv[]) 45 { 46 47 char *lineptr[LINES]; 48 int nlines; 49 int c, rc = 0; 50 51 readargs(argc, argv); //查看选项参数 52 if ((nlines = readlines(lineptr, LINES)) > 0){ //获取并且复制输入的数据 53 if (option & NUMERIC) //查看是否有为数字 54 qsort1((void **) lineptr,0,nlines-1,(int(*)(void *, void *))numcmp); //排序一个指针数组,两个整数,一个函数指针,两个参数指针,返回为Int类型。 55 else 56 qsort1((void **) lineptr,0,nlines-1,(int(*)(void *, void *))charcmp); 57 writelines(lineptr, nlines, option & DECR); 58 }else{ 59 printf("input too big to sort \n"); 60 rc = -1; 61 } 62 return rc; 63 } 64 void readargs(int argc, char *argv[]) 65 { 66 int c; 67 68 while (--argc > 0 && (c = (*++argv)[0]) == '-' || c == '+'){ 69 if (c == '-' && !isdigit(*(argv[0]+1))) 70 while (c = *++argv[0]) 71 switch (c) { //查看输入选项参数 72 case 'd': //表示只对字母数字和空格进行比较 73 option |= DIR; 74 break; 75 case 'f': //排序过程不考虑大小写 76 option |= FOLD; 77 break; 78 case 'n': //是数字 79 option |= NUMERIC; 80 break; 81 case 'r': // 82 option |= DECR; 83 break; 84 default: 85 printf("sort: illegal option %c\n", c); 86 printf("Usage: sort -dfnr [+pos1] [-pos2]"); 87 break; 88 } 89 else if (c == '-') //如果发现后面有数字 90 pos2 = atoi(argv[0]+1); 91 else if ((pos1 = atoi(argv[0]+1)) < 0) 92 printf("Usage: sort -dfnr [+pos1] [-pos2]"); 93 } 94 if(argc || pos1 > pos2) 95 printf("Usage: sort -dfnr [+pos1] [-pos2]"); 96 } 97 int charcmp(char *s,char *t) 98 { 99 char a,b; 100 int i, j, endpos; 101 int fold = (option & FOLD) ? 1 : 0; // 102 int dir = (option & DIR) ? 1 : 0; 103 i = j = pos1; 104 if (pos2 > 0) 105 endpos = pos2; 106 else if ((endpos = strlen(s)) > strlen(t)) 107 endpos = strlen(t); 108 do { 109 if (dir) { 110 while (i < endpos && !isalnum(*s) && *s != ' ' && *s != '\0') //isalnum检查是不是字母或者数字 111 i++; 112 while (i < endpos && !isalnum(*t) && *t != ' ' && *t != '\0') 113 j++; 114 } 115 if (i < endpos && j < endpos){ 116 a = fold ? tolower(s[i]) : s[i]; 117 i++; 118 b = fold ? tolower(t[j]) : t[j]; 119 j++; 120 if (a == b && a == '\0') 121 return 0; 122 } 123 } while (a == b && i < endpos && j < endpos); 124 return a - b; 125 } 126 void substr(char *s, char *str,int maxstr) 127 { 128 int i, j , len; 129 len = strlen(s); 130 if (pos2 > 0 && len > pos2) 131 len = pos2; 132 else if (pos2 > 0 && len < pos2) 133 printf("substr: string too short\n"); 134 for (j = 0, i = pos1; i < len; i++, j++) 135 str[j] = s[i]; 136 str[j] = '\0'; 137 } 138 void qsort1(void *v[], int left, int right, int (*comp)(void *, void *)) 139 { 140 int i, last; 141 142 void swap(void *v[], int, int); //定义交换函数 143 144 if (left >= right) //如果从左至右已经交换完 145 return; 146 swap(v, left, (left + right)/2); //交换最左边和中间的 147 last = left; //记录最左边的数 148 for (i = left + 1;i <= right; i++) //i从1开始每次累加 149 if ((*comp)(v[i], v[left]) < 0) //让v[1-n]个字符串,和v[0]字符串进行比较,如果小于v[0],执行下面交换 150 swap(v, ++last, i); //交换指针数组的第一个指向的数据和第i个指向的数据,并且对第一个进行累加操作。 151 swap(v, left, last); //交换最左边和上面循环对比之后(最后一个小于第0个的数据) 的 数据 152 qsort1(v, left, last-1, comp); //重新执行函数,参数变换为 左边依然是0,右边是last-1,函数不变 153 qsort1(v, last+1,right,comp); //重新执行,因为last的左边已经排列好,从last开始对比后边的数据 154 } 155 int numcmp(char *s1, char *s2) 156 { 157 double v1, v2; 158 char str[MAXSTR]; //用来存储零时对比的数据 159 substr(s1,str,MAXSTR); //根据要求存储数据1 160 v1 = atof(str); //执行转换 161 substr(s2,str,MAXSTR); //存储数据2 162 v2 = atof(str); //转换数据2 163 if (v1 < v2) //根据对比结果返回不同结果 164 return -1; 165 else if (v1 > v2) 166 return 1; 167 else 168 return 0; 169 } 170 void swap(void *v[], int i, int j) 171 { 172 void *temp; 173 temp = v[i]; 174 v[i] = v[j]; 175 v[j] = temp; 176 } 177 int readlines(char *lineptr[], int maxlines) 178 { 179 int len, nlines; 180 char *p, line[MAXLEN]; 181 nlines = 0; 182 while ((len = getline(line, MAXLEN)) > 0) { 183 if (nlines >= maxlines || (p = alloc(len)) == NULL) 184 return -1; 185 else { 186 line[len - 1] = '\0'; //line是字符集,len是输入字符的长度,-1操作是因为最后一个字符原本是'\n',变成'\0' 187 strcpy(p, line); //复制到指针p 188 lineptr[nlines++] = p; //复制到指针数组中 189 } 190 } 191 return nlines; 192 } 193 int getline(char *s,int lim) 194 { 195 char c; 196 char *t=s; 197 while (--lim > 0 && (c=getchar()) != EOF && c != '\n') 198 *s++ = c; 199 if (c == '\n') 200 *s ++= c; 201 *s = '\0'; 202 return s - t; 203 } 204 char *alloc(int n) //查看是否有足够的储存空间 205 { 206 if (allocbuf + ALLOCSIZE - allocp >= n){ 207 allocp += n; 208 return allocp - n; 209 } else 210 return 0; 211 } 212 void writelines(char *lineptr[], int nlines, int decr) 213 { 214 int i; 215 if (decr) //查看是否需要倒序输出 216 for (i = nlines-1; i >= 0; i--) 217 printf("%s\n",lineptr[i]); 218 else 219 for (i = 0; i < nlines; i++) 220 printf("%s\n", lineptr[i]); 221 }

 

 

 

 

 

 

 

5.12  复杂声明

  C语言的语法力图使声明和使用相一致。如果情况复杂,容易混淆,c语言的声明不能从左至右阅读。

  如何创建复杂的声明,第一种,使用typedef通过简单的步骤合成,第二种

练习5-18到5-20,标准答案
1
#include <stdio.h> 2 #include <string.h> 3 #include <ctype.h> 4 #include <stdlib.h> 5 6 7 8 #define MAXTOKEN 100 9 10 enum { NAME, PARENS, BRACKETS }; 11 enum {NO,YES}; 12 13 void dcl(void); 14 void dirdcl(void); 15 void errmsg(char *); 16 void dclspec(void); 17 int typespec(void); 18 int typequal(void); 19 int compare(char **,char **); 20 int gettoken(void); 21 int nexttoken(void); 22 #define BUFSIZE 100 23 int bufp = 0; 24 char buf[BUFSIZE]; 25 26 27 28 int prevtoken; 29 char tokentype; 30 char token[MAXTOKEN]; 31 char name[MAXTOKEN]; 32 char datatype[MAXTOKEN]; 33 char out[1000]; 34 35 36 int main() { 37 38 int type; 39 char temp[MAXTOKEN]; 40 41 while (gettoken() != EOF) { 42 strcpy(out, token); //复制token到out 43 while ((type = gettoken()) != '\n') { //继续获取字符,直到换行符为止 44 if (type == PARENS || type == BRACKETS) //检查返回结果,是否为括号 45 strcat(out, token); //复制token到out的结尾 46 else if (type == '*') { //检查是否为‘*’ 47 if ((type = nexttoken()) == PARENS || type == BRACKETS) { //继续获取字符并且检查是否为括号 48 sprintf(temp, "(*%s)", out); //?????temp?????????????????? 49 } else //如果不是括号 50 sprintf(temp,"*%s", out); //如果没括号,那么就给之前获得的字符加上* 51 strcpy(out, temp); //复制temp到out中 52 } else if (type == NAME){ 53 sprintf(temp, "%s %s",token,out); 54 strcpy(out, temp); 55 } else 56 printf("invalid input at %s\n", token); //????????? 57 } 58 printf("%s\n",out); //如果获取的字符是换行符, 59 60 // 下面部分为练习5-20的main函数。 61 // while (gettoken() != EOF) { 62 // strcpy(datatype, token); 63 // out[0] = '\0'; 64 // dcl(); 65 // if (tokentype != '\n') 66 // printf("syntax error\n"); 67 // printf("%s: %s %s\n",name, out, datatype); 68 } 69 return 0; 70 } 71 72 int nexttoken(void) 73 { 74 int type; 75 type = gettoken(); //调用获取字符 76 prevtoken = YES; //调整预存状态为是 77 return type; //返回获取结果 78 } 79 int gettoken(void) 80 { 81 int getch(void); 82 void ungetch(int); 83 char *p = token; 84 char c; 85 86 if (prevtoken == YES){ 87 prevtoken = NO; 88 return tokentype; 89 } 90 while ((c = getch()) == ' ' || c == '\t'); 91 if (c == '('){ //检查是否为圆括号前半部分 92 if ((c = getch()) == ')'){ //检查是否为圆括号后半部分 93 strcpy(token, "()"); //????????? 94 return tokentype = PARENS; //????????? 95 } else { 96 ungetch(c); //如果不是后半部分就存入缓存区 97 return tokentype = '('; //返回圆括号的前半部分 98 } 99 } else if (c == '[') { //是否中括号 100 for (*p++ = c; (*p++ = getch()) != ']';)//如果是中括号就获得中间的全部字符 101 ; 102 *p = '\0'; //?????? 103 return tokentype = BRACKETS; //?????????? 104 } else if (isalpha(c)) { //查看是否为字母 105 for (*p++ = c; isalnum(c = getch());)//继续检查下面的字符是否为数字 106 *p++ = c; //如果是数字,那么存入token中 107 *p = '\0'; //然后加入结束符 108 ungetch(c); //非字母数字的存入缓存区 109 return tokentype = NAME; //返回名字 110 } else 111 return tokentype = c; //不是括号,字母,数字,直接返回 112 } 113 114 115 116 void dcl(void) 117 { 118 int ns; 119 for (ns = 0; gettoken() == '*';) //获取字符,并且检查是否为*号 120 ns++; //那么ns++ 121 dirdcl(); 122 while (ns-- > 0) //出现*的次数 123 strcat(out," pointer to"); //out结尾添加 124 } 125 void dirdcl(void) 126 { 127 int type; 128 void parmdcl(void); 129 130 if (tokentype == '(') { //检查当前是否圆括号前半部分 131 dcl(); 132 if (tokentype != ')') 133 errmsg("error: missing)\n"); 134 } else if (tokentype == NAME) { //检查当前返回结果是否为NAME 135 if (name[0] == '\0') //检查name字符集是否为空 136 strcpy(name, token); //复制token到name中 137 } else // 138 prevtoken = YES; 139 while ((type = gettoken()) == PARENS || type == BRACKETS || type == '(') //获取字符,并且查看是否是括号,或者圆括号的前半部分 140 if (type == PARENS) //如果是圆括号 141 strcat(out," function returning"); //在out结尾加入 fun re,函数返回 142 else if (type == '('){ //如果是前半部分 143 strcat(out, " function expecting"); 144 parmdcl(); 145 strcat(out," and returning"); 146 } 147 else { 148 strcat(out," array"); 149 strcat(out,token); 150 strcat(out," of"); 151 } 152 } 153 void errmsg(char *msg) 154 { 155 printf("%s", msg); 156 prevtoken = YES; 157 } 158 void parmdcl(void) 159 { 160 do{ 161 dclspec(); 162 }while (tokentype == ','); 163 if (tokentype != ')') 164 errmsg("missing ) in parameter declaration\n"); 165 } 166 void dclspec(void) 167 { 168 char temp[MAXTOKEN]; 169 170 temp[0] = '\0'; 171 gettoken(); 172 do { 173 if(tokentype != NAME){ 174 prevtoken = YES; 175 dcl(); 176 }else if (typespec() == YES){ //返回YES说明是类型声明 177 strcat(temp, " "); //先添加空格 178 strcat(temp,token); //在添加类型标识符 179 gettoken(); //继续获得字符 180 }else if (typequal() == YES) { //返回YES说明是类型限定符 181 strcat(temp, " "); 182 strcat(temp, token); 183 gettoken(); 184 } else 185 errmsg("unknown type in parameter list\n"); 186 }while (tokentype != ',' && tokentype != ')'); //如果获取的不是逗号,不是圆括号后半部分,就继续执行 187 strcat(out, temp); 188 if (tokentype == ',') 189 strcat(out,","); //如果返回字符为逗号,那么添加逗号 190 } 191 int typespec(void) 192 { 193 static char *types[] = { 194 "char", 195 "int", 196 "void" 197 }; 198 char *pt = token; 199 200 if (bsearch(&pt, types, sizeof(types)/sizeof(char *), sizeof(char *), compare) == NULL) //使用函数compare,查找types中是否有token的值,如果没有就是NULL 201 /* 语法: 202 #include <stdlib.h> 203 void *bsearch( const void *key, const void *buf, size_t num, size_t size, int (*compare)(const void *, const void *) ); 204 参数:第一个:要查找的关键字的指针。第二个:要查找的数组。 205 第三个:被查找数组中的元素数量。第四个:每个元素的长度(以字节为单位)。第五个:指向比较函数的指针。 206 功能: 函数用折半查找法在从数组元素buf[0]到buf[num-1] 匹配参数key。 207 如果函数compare 的第一个参数小于第二个参数,返回负值; 208 如果等于返回零值;如果大于返回正值。数组buf 中的元素应以升序排列。 209 函数bsearch()的返回值是指向匹配项,如果没有发现匹配项,返回NULL */ 210 return NO; 211 else 212 return YES; 213 } 214 int typequal(void) 215 { 216 static char *typeq[] = { 217 "const", 218 "volatile" 219 }; 220 char *pt = token; 221 222 if (bsearch(&pt, typeq, sizeof(typeq)/ sizeof(char *), sizeof(char *),compare) == NULL) 223 return NO; 224 else 225 return YES; 226 } 227 int compare(char **s,char **t) 228 { 229 return strcmp(*s, *t); 230 } 231 int getch(void) 232 { 233 return (bufp > 0) ? buf[--bufp] : getchar(); //检查缓存区是否有字符,如果有就返回,没有就获取字符 234 } 235 void ungetch(int c) 236 { 237 if (bufp >= BUFSIZE) 238 printf("ungetch: too many characters\n"); 239 else 240 buf[bufp++] = c; 241 }

 

 

 

 

 

第五章结束

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <malloc.h>


#define MAXSTR 100
#define DIR 8                   //只对字母,数字和空格进行比较。
#define FOLD 4                  //不考虑大小写
#define NUMERIC 1               //标记是否是数字
#define DECR 2                  //倒序排序
#define MAXLINES 5000
char *lineptr[MAXLINES];
#define MAXLINE 100
#define TABINC 8
#define YES 1
#define NO 0
#define DEFLINES 10
#define LINES 100
#define MAXLEN 100
#define ALLOCSIZE 10000
static char allocbuf[ALLOCSIZE];
static char *allocp = allocbuf;


int getline(char *,int);
void esettab(int argcchar *argv[]char *tab);
void entab(char *tab);
int tabpos(int pos,char *tab);
void settab(int argcchar *argv[]char *tab);
void detab(char *tab);
int readlines(char *lineptr[]int nlines);
void writelines(char *lineptr[],int nlinesint decr);
void qsort1(void *lineptr[]int leftint rightint (*comp)(void *, void *));
void readargs(int argcchar *argv[]);
int charcmp(char *, char *);
int numcmp(char *,char *);
char *alloc(int);
void substr(char *schar *tint maxstr);
static char option = 0;
int pos1 = 0;
int pos2 = 0;
int main(int argcchar *argv[])
{

    char *lineptr[LINES];
    int nlines;
    int c, rc = 0;

    readargs(argc, argv);    //查看选项参数
    if ((nlines = readlines(lineptr, LINES)) > 0){      //获取并且复制输入的数据
        if (option & NUMERIC)                           //查看是否有为数字
            qsort1((void **) lineptr,0,nlines-1,(int(*)(void *, void *))numcmp);   //排序一个指针数组,两个整数,一个函数指针,两个参数指针,返回为Int类型。
        else
            qsort1((void **) lineptr,0,nlines-1,(int(*)(void *, void *))charcmp);
        writelines(lineptr, nlines, option & DECR);
    }else{
        printf("input too big to sort \n");
        rc = -1;
    }
    return rc;
}
void readargs(int argcchar *argv[])
{
    int c;

    while (--argc > 0 && (c = (*++argv)[0]) == '-' || c == '+'){
        if (c == '-' && !isdigit(*(argv[0]+1)))
            while (c = *++argv[0])
                switch (c) {           //查看输入选项参数
                case 'd':                   //表示只对字母数字和空格进行比较
                    option |= DIR;
                    break;
                case 'f':                   //排序过程不考虑大小写
                    option |= FOLD;
                    break;
                case 'n':                   //是数字
                    option |= NUMERIC;
                    break;
                case 'r':                   //
                    option |= DECR;
                    break;
                default:
                    printf("sort: illegal option %c\n", c);
                    printf("Usage: sort -dfnr [+pos1] [-pos2]");
                    break;
            }
        else if (c == '-')               //如果发现后面有数字
            pos2 = atoi(argv[0]+1);
        else if ((pos1 = atoi(argv[0]+1)) < 0)
            printf("Usage: sort -dfnr [+pos1] [-pos2]");
    }
    if(argc || pos1 > pos2)
        printf("Usage: sort -dfnr [+pos1] [-pos2]");
}
int charcmp(char *s,char *t)
{
    char a,b;
    int i, j, endpos;
    int fold = (option & FOLD) ? 1 : 0;      //
    int dir = (option & DIR) ? 1 : 0;
    i = j = pos1;
    if (pos2 > 0)
        endpos = pos2;
    else if ((endpos = strlen(s)) > strlen(t))
        endpos = strlen(t);
    do {
        if (dir) {
            while (i < endpos && !isalnum(*s) && *s != ' ' && *s != '\0')   //isalnum检查是不是字母或者数字
                i++;
            while (i < endpos && !isalnum(*t) && *t != ' ' && *t != '\0')
                j++;
        }
        if (i < endpos && j < endpos){
            a = fold ? tolower(s[i]) : s[i];
            i++;
            b = fold ? tolower(t[j]) : t[j];
            j++;
            if (a == b && a == '\0')
                return 0;
        }
    } while (a == b && i < endpos && j < endpos);
    return a - b;
}
void substr(char *schar *str,int maxstr)
{
    int i, j , len;
    len = strlen(s);
    if (pos2 > 0 && len > pos2)
        len = pos2;
    else if (pos2 > 0 && len < pos2)
        printf("substr: string too short\n");
    for (j = 0, i = pos1; i < len; i++, j++)
        str[j] = s[i];
    str[j] = '\0';
}
void qsort1(void *v[]int leftint rightint (*comp)(void *, void *))
{
    int i, last;

    void swap(void *v[]intint);      //定义交换函数

    if (left >= right)                  //如果从左至右已经交换完
        return;
    swap(v, left, (left + right)/2);            //交换最左边和中间的
    last = left;                                //记录最左边的数
    for (i = left + 1;i <= right; i++)          //i从1开始每次累加
        if ((*comp)(v[i], v[left]) < 0)         //让v[1-n]个字符串,和v[0]字符串进行比较,如果小于v[0],执行下面交换
            swap(v, ++last, i);                 //交换指针数组的第一个指向的数据和第i个指向的数据,并且对第一个进行累加操作。
    swap(v, left, last);                        //交换最左边和上面循环对比之后(最后一个小于第0个的数据)  的  数据
    qsort1(v, left, last-1, comp);              //重新执行函数,参数变换为 左边依然是0,右边是last-1,函数不变
    qsort1(v, last+1,right,comp);               //重新执行,因为last的左边已经排列好,从last开始对比后边的数据
}
int numcmp(char *s1char *s2)
{
    double v1, v2;                              
    char str[MAXSTR];                           //用来存储零时对比的数据
    substr(s1,str,MAXSTR);                      //根据要求存储数据1
    v1 = atof(str);                             //执行转换
    substr(s2,str,MAXSTR);                      //存储数据2
    v2 = atof(str);                             //转换数据2
    if (v1 < v2)                                //根据对比结果返回不同结果
        return -1;
    else if (v1 > v2)
        return 1;
    else
        return 0;
}
void swap(void *v[]int iint j)
{
    void *temp;
    temp = v[i];
    v[i] = v[j];
    v[j] = temp;
}
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)
            return -1;
        else {
            line[len - 1] = '\0';     //line是字符集,len是输入字符的长度,-1操作是因为最后一个字符原本是'\n',变成'\0'
            strcpy(p, line);          //复制到指针p
            lineptr[nlines++] = p;    //复制到指针数组中
        }
    }
    return nlines;
}
int getline(char *s,int lim)
{
    char c;
    char *t=s;
    while (--lim > 0 && (c=getchar()) != EOF && c != '\n')
        *s++ = c;
    if (c == '\n')
        *s ++= c;
    *s = '\0';
    return s - t;
}
char *alloc(int n)                 //查看是否有足够的储存空间
{
    if (allocbuf + ALLOCSIZE - allocp >= n){
        allocp += n;
        return allocp - n;
    } else
        return 0;
}
void writelines(char *lineptr[]int nlinesint decr)
{
    int i;
    if (decr)                                               //查看是否需要倒序输出
        for (i = nlines-1; i >= 0; i--)
            printf("%s\n",lineptr[i]);
    else
        for (i = 0; i < nlines; i++)
            printf("%s\n"lineptr[i]);
}
posted @ 2019-12-18 17:56  C,python,linux,java  阅读(403)  评论(0编辑  收藏  举报