设为首页 | 加入收藏
文献检索:

指针与函数


□ 王立柱

摘 要:

存储和处理是程序设计的基本矛盾。存储中也有处理,是基本处理,例如,机器指令中的操作码,C语言内置类型中的运算符。随着处理越来越复杂,程序设计的基本矛盾不断向前发展,从而推动了程序语言的发展。指针(在机器语言中是地址)是存储和处理的“媒介”、“中介”,是语言的要素,它随着处理越来越复杂也在同时向前发展。


  存储和处理是程序设计的基本矛盾。存储中也有处理,是基本处理,例如,机器指令中的操作码,C语言内置类型中的运算符。随着处理越来越复杂,程序设计的基本矛盾不断向前发展,从而推动了程序语言的发展。指针(在机器语言中是地址)是存储和处理的“媒介”、“中介”,是语言的要素,它随着处理越来越复杂也在同时向前发展。
  
  1函数参数与指针
  
  C语言程序是由函数构成的,函数表示处理,实参表示存储,函数的指针参量表示存储和处理的中介,实参初始化形参,函数通过指针处理存储中的数据。以表1为例。
  
  在下面的函数原型中,形参pa的声明是等价的,都表示指针,都是存储与处理的中介:
  int Sum(int *pa,int n);
  int Sum(int pa[6],int n);
  int Sum(int pa[],int n);
  
  2模块化设计与指针
  
  一组存储中的数据通过传址在函数之间传递。如果这组数据是“只读”的,那么如何保证它不被改写?在模块化程序设计中,程序按模块编译,如果在模块单独编译阶段就对“只读”数据的安全性进行控制,即保证“只读”数据把地址传给的是“只读”函数,就会减少连接调试阶段的工作负担。const限定修饰符便是这种控制的工具。
  const限定符既可以限定存储中的“只读”数据,也可以限定“只读”函数。被const修饰的数据称为const常量,它必须初始化;被const修饰的函数具有被const修饰的指针参量,这个指针称为指向const常量的指针,表示函数对该指针指向的数据是“只读”的。const常量的声明格式为:
  const 类型标识符 变量标识符=初始化数据;
  或
  类型标识符 const 变量标识符=初始化数据;
  指向const常量的指针,其声明格式为:
  const 类型标识符 *指针变量标识符;
  或
  类型标识符 const *指针变量标识符;
  应用举例:
   void Display(const int *pa,int n); //终端显示。“只读”函数。
  void Selection(int *pa,int n);
   //选择排序。非“只读”函数。
   const int a[5]= {1,3,2,5,4};
   //const常量数组。
   int b[5]= {1,3,2,5,4};
   //非const常量数组。
  Selection(a,5); //非法!
  Display(a,5); //合法。
  Selection(b,5); //合法。
  Display(b,5); //合法。
  指针是复合类型,它有两个值,一个是指针自身的数据(无符号整型值),表示地址,另一个是它指向的数据(指针基类型值),是指针间接引用的对象。const修饰的部分不同,意义不同。
  如果const修饰的是指针指向的数据,那么它是在修饰在修饰函数,表示以该指针为参量的函数对该指针指向的数据是“只读”的,该指针就是指向const常量的指针。对这样的指针,有下面几点需要认识:
  ① 数据无论是不是const常量型,都可以传址给指向const常量的指针。例如上面的调用语句Display(b,5),其中数组b并不是const常量型的。用实参和形参的关系来表示便是
  const int *pa=b;
  但是const常量型数据只能传址给代表函数“只读”性质的指向const常量的指针。可以把带有指向const常量指针参量的函数比作一个认真办事的人,什么样的事情交给他,他都认真处理,而一件需要认真处理的事情一定要交给他。
  ② 因为指向const常量的指针表示的是函数的“只读”性质,而不是指针本身的数据的只读性质,所以与const常量不同,这种指针不必初始化。例如:
   const int *pa=b;
  可以分解为
   const int *pa;
   pa=b;
  而且对它本身的数据可以改变,例如:
   const int *pa;
   pa=b; //指向数组b
   pa=a; //又指向数组a
  ③ 传递性。指向const常量的指针表示的是函数的“只读”性质,任何数据传址给这样的指针,不仅具有这种指针参量的函数对该数据是“只读”的,而且该函数调用的其它函数对该数据也是“只读”的,这就是说,指向const常量的指针只能传值给同类指针。仿佛一个认真办事的人,什么事情交给他,他都认真处理,不仅如此,他所寻求的合作伙伴,也一定是认真办事的人。例如:
  void Display(const int*pa,int n); //输出函数。
  int Sum(const int* ps,int n) //求和函数。
  {
   Display(ps,n); // const int* pa=ps;
   ……
   }
  ④ 引入const修饰符之后,任何函数,如果对某一指针参量指向的数据是“只读”的,都必须把该指针参量限定为指向const常量的指针,表明该函数的“只读”性质,以保证const常量型数据通过传址调用该函数,被编译器检错。
  如果const修饰的是指针本身,那么它是在修饰数据,表示指针本身的值const常量型的,这样的指针称为const常量指针。与const常量型一样,const常量指针必须初始化,而且其值不能改变。声明格式为:
  类型标识符 *const指针标识符=初始化数据;
  例如:
  const int a[5]= {1,3,2,5,4}; //const常量数组。
  int b[5]= {1,3,2,5,4}; //非const常量数组。
  int c[5]= {1,3,2,5,4}; //非const常量数组。
  int *const pc=b; //const常量指针必须初始化。
  pc=c; //非法!const常量指针的值不能改变。
  因为const常量指针不是限定函数,对它指向的数据可以修改,所以不能把const常量型数据的地址赋给const常量指针。例如:
  pc[0]=10; //合法。
  int *const ps=a; //非法。
  
  3运算符函数与指针
  
  3.1运算符函数
  运算符处理的对象如果是语言内置基本类型(整型、浮点型、字符型等),它的意义是内定的。如果是用户定义的结构,意义就是待定的。以结构数组的查找Find为例:
  struct Student //用户结构
  {
   long ID; double g; //ID表示学号,g表示成绩。
  };
  typedef Student Type; //形式数据类型Type。
  int Find(const Type *pa,int n,Type item)//查找。
  {
   for(int i=0;i   if(pa[i]==item) //待定。
   return(i);
   return(-1);
   }
  阴影部分中的关系运算对象是结构,系统无法确定是比较学号还是比较成绩。我们可以进入函数体直接改造:
  if(pa[i].g==item.g)
  
  不过这是权宜之计。结构各式各样,数组的处理程序数不胜数,都一一改造吗?这显然不符合代码的复用性要求。解决这个问题的方法是运算符重载。
  运算符重载的思路是,首先把以内置类型为处理对象的运算符从观念上看作函数,然后通过对该函数重载,扩大运算符的操作对象。这样的函数称为运算符函数,运算符函数名为operator @,@代表某一种运算符。运算符重载就是运算符函数重载。
  以比较运算符“==”为例,首先把该运算符从观念上看作一个函数:
  int operator==(int,int);
  于是两个整数的比较运算表达式
  x==y
  被看作运算符函数的调用
  Operator== (x,y
  然后反过来,重载运算符函数operator==:
   bool operator== (Student a,Student b)//重载运算符函数的定义
   {
   return(a.g==b.g); //比较成绩
  }
  重载之后,运算符“==”的处理对象就增加了结构Student。具体的执行过程是,编译器如果发现内部无法解释的运算符处理,就会去寻找重载的运算符函数,找到之后,调用这个函数。例如,函数Find中的表达式
   pa[i]==item
  被编译器替换成
   operator==(pa[i],item)
  运算符重载是函数的一种调用形式。对用户自定义类型重载的运算符运算,可以等价地表示为运算符函数的调用,但是内部基本类型的运算符运算是内定的,不能实际的替换成运算符函数的调用形式,例如,不能把表达式5==6替换为operator==(5,6)。 ......(暂无全文信息,请到维普官网检索)
特别说明:本文献摘要信息,由维普资讯网提供,本站只提供索引,不对该文献的全文内容负责,不提供免费的全文下载服务。

关于我们 | 网站声明 | 合作伙伴 | 联系方式 | IP查询
金月芽期刊网 2021 触屏版 繁體版 电脑版 京ICP备13008804号-2