当前位置:松语文学 > 其他类型 >C语言设计最新章节 > C语言设计TXT下载
错误举报

第 22 章

  其中函数名之前加了“*”号表明这是一个指针型函数,即返回值是一个指针。类型说明符

  表示了返回的指针值所指向的数据类型。

  如:

  int *ap(int x,int y)

  {

  ......    /*函数体*/

  }

  表示 ap 是一个返回指针值的指针型函数,它返回的指针指向一个整型变量。

  【例 10.32】本程序是通过指针函数,输入一个 1~7 之间的整数,输出对应的星期名。

  main(){

  int i;

  char *day_ncom(int n);

  printf("input Day No:\n");

  scanf("%d",&i);

  if(i<0) exit(1);

  谭浩强   C 语言程序设计        2001 年 5 月 1 日

  printf("Day No:%2d-->%s\n",i,day_ncom(i));

  }

  char *day_ncom(int n){

  static char *ncom[]={ "Illegal day",

  "Monday",

  "Tuesday",

  "Wednesday",

  "Thursday",

  "Friday",

  "Saturday",

  "Sunday"};

  return((n<1||n>7) ? ncom[0] : ncom[n]);

  }

  本例中定义了一个指针型函数 day_ncom,它的返回值指向一个字符串。该函数中定义

  了一个静态指针数组 ncom。ncom 数组初始化赋值为八个字符串,分别表示各个星期名及出

  错提示。形参 n 表示与星期名所对应的整数。在主函数中,把输入的整数 i 作为实参,在

  printf 语句中调用 day_ncom 函数并把 i 值传送给形参 n。day_ncom 函数中的 return 语句

  包含一个条件表达式,n 值若大于 7 或小于 1 则把 ncom[0]指针返回主函数输出出错提示字

  符串“Illegal day”。否则返回主函数输出对应的星期名。主函数中的第 7 行是个条件语句,

  其语义是,如输入为负数(i<0)则中止程序运行退出程序。exit 是一个库函数,exit(1)表

  示发生错误后退出程序,exit(0)表示正常退出。

  应该特别注意的是函数指针变量和指针型函数这两者在写法和意义上的区别。如

  int(*p)()和 int *p()是两个完全不同的量。

  int (*p)()是一个变量说明,说明 p 是一个指向函数入口的指针变量,该函数的返回

  值是整型量,(*p)的两边的括号不能少。

  int *p()则不是变量说明而是函数说明,说明 p 是一个指针型函数,其返回值是一个

  指向整型量的指针,*p 两边没有括号。作为函数说明,在括号内最好写入形式参数,这样

  便于与变量说明区别。

  对于指针型函数定义,int *p()只是函数头部分,一般还应该有函数体部分。

  10.7 指针数组和指向指针的指针

  10.7.1 指针数组的概念

  一个数组的元素值为指针则是指针数组。 指针数组是一组有序的指针的集合。 指针数

  组的所有元素都必须是具有相同存储类型和指向相同数据类型的指针变量。

  指针数组说明的一般形式为:

  类型说明符 *数组名[数组长度]

  其中类型说明符为指针值所指向的变量的类型。

  例如:

  int *pa[3]

  谭浩强   C 语言程序设计        2001 年 5 月 1 日

  表示 pa 是一个指针数组,它有三个数组元素,每个元素值都是一个指针,指向整型变量。

  【例 10.33】通常可用一个指针数组来指向一个二维数组。指针数组中的每个元素被赋予

  二维数组每一行的首地址,因此也可理解为指向一个一维数组。

  main(){

  int a[3][3]={1,2,3,4,5,6,7,8,9};

  int *pa[3]={a[0],a[1],a[2]};

  int *p=a[0];

  int i;

  for(i=0;i<3;i++)

  printf("%d,%d,%d\n",a[i][2-i],*a[i],*(*(a+i)+i));

  for(i=0;i<3;i++)

  printf("%d,%d,%d\n",*pa[i],p[i],*(p+i));

  }

  本例程序中,pa 是一个指针数组,三个元素分别指向二维数组 a 的各行。然后用循环

  语句输出指定的数组元素。其中*a[i]表示 i 行 0 列元素值;*(*(a+i)+i)表示 i 行 i 列的元

  素值;*pa[i]表示 i 行 0 列元素值;由于 p 与 a[0]相同,故 p[i]表示 0 行 i 列的值;*(p+i)

  表示 0 行 i 列的值。读者可仔细领会元素值的各种不同的表示方法。

  应该注意指针数组和二维数组指针变量的区别。这两者虽然都可用来表示二维数组,但

  是其表示方法和意义是不同的。

  二维数组指针变量是单个的变量,其一般形式中"(*指针变量名)"两边的括号不可少。

  而指针数组类型表示的是多个指针(一组有序指针)在一般形式中"*指针数组名"两边不能有

  括号。

  例如:

  int (*p)[3];

  表示一个指向二维数组的指针变量。该二维数组的列数为 3 或分解为一维数组的长度为

  3。

  int *p[3]

  表示 p 是一个指针数组,有三个下标变量 p[0],p[1],p[2]均为指针变量。

  指针数组也常用来表示一组字符串,这时指针数组的每个元素被赋予一个字符串的首地

  址。指向字符串的指针数组的初始化更为简单。例如在例 10.32 中即采用指针数组来表示一

  组字符串。其初始化赋值为:

  char *ncom[]={"Illagal day",

  "Monday",

  "Tuesday",

  "Wednesday",

  "Thursday",

  "Friday",

  "Saturday",

  "Sunday"};

  完 成 这 个 初 始 化 赋 值 之 后 , ncom[0] 即 指 向 字 符 串 "Illegal day" , ncom[1] 指 向

  "Monday"......。

  指针数组也可以用作函数参数。

  谭浩强   C 语言程序设计        2001 年 5 月 1 日

  【例 10.34】指针数组作指针型函数的参数。在本例主函数中,定义了一个指针数组 ncom,

  并对 ncom 作了初始化赋值。其每个元素都指向一个字符串。然后又以 ncom 作为实参调用

  指针型函数 day_ncom,在调用时把数组名 ncom 赋予形参变量 ncom,输入的整数 i 作为第二

  个实参赋予形参 n。在 day_ ncom 函数中定义了两个指针变量 pp1 和 pp2,pp1 被赋予 ncom[0]

  的值(即*ncom),pp2 被赋予 ncom[n]的值即*(ncom+ n)。由条件表达式决定返回 pp1 或 pp2

  指针给主函数中的指针变量 ps。最后输出 i 和 ps 的值。

  main(){

  static char *ncom[]={ "Illegal day",

  "Monday",

  "Tuesday",

  "Wednesday",

  "Thursday",

  "Friday",

  "Saturday",

  "Sunday"};

  char *ps;

  int i;

  char *day_ncom(char *ncom[],int n);

  printf("input Day No:\n");

  scanf("%d",&i);

  if(i<0) exit(1);

  ps=day_ncom(ncom,i);

  printf("Day No:%2d-->%s\n",i,ps);

  }

  char *day_ncom(char *ncom[],int n)

  {

  char *pp1,*pp2;

  pp1=*ncom;

  pp2=*(ncom+n);

  return((n<1||n>7)? pp1:pp2);

  }

  【例 10.35】输入 5 个国名并按字母顺序排列后输出。现编程如下:

  #include"string.h"

  main(){

  void sort(char *ncom[],int n);

  void print(char *ncom[],int n);

  static char *ncom[]={ "CHINA","AMERICA","AUSTRALIA",

  "FRANCE","GERMAN"};

  int n=5;

  sort(ncom,n);

  print(ncom,n);

  }

  void sort(char *ncom[],int n){

  char *pt;

  int i,j,k;

  for(i=0;i<n-1;i++){

  k=i;

  for(j=i+1;j<n;j++)

  谭浩强   C 语言程序设计        2001 年 5 月 1 日

  if(strcmp(ncom[k],ncom[j])>0) k=j;

  if(k!=i){

  pt=ncom[i];

  ncom[i]=ncom[k];

  ncom[k]=pt;

  }

  }

  }

  void print(char *ncom[],int n){

  int i;

  for (i=0;i<n;i++) printf("%s\n",ncom[i]);

  }

  说明:

  在以前的例子中采用了普通的排序方法,逐个比较之后jiāo换字符串的位置。jiāo换字符串

  的物理位置是通过字符串复制函数完成的。反复的jiāo换将使程序执行的速度很慢,同时由于

  各字符串(国名)的长度不同,又增加了存储管理的负担。用指针数组能很好地解决这些问题。

  把所有的字符串存放在一个数组中,把这些字符数组的首地址放在一个指针数组中,当需要

  jiāo换两个字符串时,只须jiāo换指针数组相应两元素的内容(地址)即可,而不必jiāo换字符串本

  身。

  本程序定义了两个函数,一个名为 sort 完成排序,其形参为指针数组 ncom,即为待排

  序的各字符串数组的指针。形参 n 为字符串的个数。另一个函数名为 print,用于排序后字

  符串的输出,其形参与 sort 的形参相同。主函数 main 中,定义了指针数组 ncom 并作了初

  始化赋值。然后分别调用 sort 函数和 print 函数完成排序和输出。值得说明的是在 sort

  函数中,对两个字符串比较,采用了 strcmp 函数,strcmp 函数允许参与比较的字符串以指

  针方式出现。ncom[k]和 ncom[j]均为指针,因此是合法的。字符串比较后需要jiāo换时,只

  jiāo换指针数组元素的值,而不jiāo换具体的字符串,这样将大大减少时间的开销,提高了运行

  效率。

  10.7.2 指向指针的指针

  如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的

  指针变量。

  在前面已经介绍过,通过指针访问变量称为间接访问。由于指针变量直接指向变量,所

  以称为“单级间址”。而如果通过指向指针的指针变量来访问变量则构成“二级间址”。

  谭浩强   C 语言程序设计        2001 年 5 月 1 日

  从下图可以看到,ncom 是一个指针数组,它的每一个元素是一个指针型数据,其值为

  地址。Ncom 是一个数据,它的每一个元素都有相应的地址。数组名 ncom 代表该指针数组的

  首地址。ncom+1 是 mane[i]的地址。ncom+1 就是指向指针型数据的指针(地址)。还可以设

  置一个指针变量 p,使它指向指针数组元素。P 就是指向指针型数据的指针变量。

  怎样定义一个指向指针型数据的指针变量呢?如下:

  char **p;

  p 前面有两个*号,相当于*(*p)。显然*p 是指针变量的定义形式,如果没有最前面的*,那就

  是定义了一个指向字符数据的指针变量。现在它前面又有一个*号,表示指针变量 p 是指向

  一个字符指针型变量的。*p 就是 p 所指向的另一个指针变量。

  从下图可以看到,ncom 是一个指针数组,它的每一个元素是一个指针型数据,其值为

  地址。ncom 是一个数组,它的每一个元素都有相应的地址。数组名 ncom 代表该指针数组

  的首地址。ncom+1 是 mane[i]的地址。ncom+1 就是指向指针型数据的指针(地址)。还可以

  设置一个指针变量 p,使它指向指针数组元素。P 就是指向指针型数据的指针变量。

  如果有:

  p=ncom+2;

  printf(“%o\n”,*p);

  printf(“%s\n”,*p);

  则,第一个 printf 函数语句输出 ncom[2]的值(它是一个地址),第二个 printf 函数语句

  以字符串形式(%s)输出字符串“Great Wall”。

  【例 10.36】使用指向指针的指针。

  main()

  {char *ncom[]={"Followcom","BASIC","Great Wall","FORTRAN","Computer desighn"};

  char **p;

  int i;

  for(i=0;i<5;i++)

  {p=ncom+i;

  printf("%s\n",*p);

  }

  }

  说明:

  p 是指向指针的指针变量。

  谭浩强   C 语言程序设计        2001 年 5 月 1 日

  【例 10.37】一个指针数组的元素指向数据的简单例子。

  main()

  {static int a[5]={1,3,5,7,9};

  int *num[5]={&a[0],&a[1],&a[2],&a[3],&a[4]};

  int **p,i;

  p=num;

  for(i=0;i<5;i++)

  {printf("%d\t",**p);p++;}

  }

  说明:

  指针数组的元素只能存放地址。

  10.7.3 main 函数的参数

  前面介绍的 main 函数都是不带参数的。因此 main 后的括号都是空括号。实际上,main

  函数可以带参数,这个参数可以认为是 main 函数的形式参数。C语言规定 main 函数的参

  数只能有两个,习惯上这两个参数写为 argc 和 argv。因此,main 函数的函数头可写为:

  main (argc,argv)

  C语言还规定 argc(第一个形参)必须是整型变量,argv( 第二个形参)必须是指向字符串的

  指针数组。加上形参说明后,main 函数的函数头应写为:

  main (int argc,char *argv[])

  由于 main 函数不能被其它函数调用,因此不可能在程序内部取得实际值。那么,在何

  处把实参值赋予 main 函数的形参呢? 实际上,main 函数的参数值是从cāo作系统命令行上获

  得的。当我们要运行一个可执行文件时,在 DOS 提示符下键入文件名,再输入实际参数即可

  把这些实参传送到 main 的形参中去。

  DOS 提示符下命令行的一般形式为:

  C:\>可执行文件名 参数

  松语文学免费小说阅读_www.16sy.com