友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
八二电子书 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

C语言程序设计-第14部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!


【例9。7】
#define SQ(y) (y)*(y)
main(){
  int a;sq;
  printf(〃input a number:〃);
  scanf(〃%d〃;&a);
  sq160/SQ(a+1);
  printf(〃sq%dn〃;sq);

本程序与前例相比,只把宏调用语句改为:
sq160/SQ(a+1);
运行本程序如输入值仍为3时,希望结果为10。但实际运行的结果如下:
input a number:3
sq160
为什么会得这样的结果呢?分析宏调用语句,在宏代换之后变为:
sq160/(a+1)*(a+1);
a为3时,由于“/”和“*”运算符优先级和结合性相同,则先作160/(3+1)得40,再作40*(3+1)最后得160。为了得到正确答案应在宏定义中的整个字符串外加括号,程序修改如下:
【例9。8】
#define SQ(y) ((y)*(y))
main(){
  int a;sq;
  printf(〃input a number:〃);
  scanf(〃%d〃;&a);
  sq160/SQ(a+1);
  printf(〃sq%dn〃;sq);

以上讨论说明,对于宏定义不仅应在参数两侧加括号,也应在整个字符串外加括号。
5。  带参的宏和带参函数很相似,但有本质上的不同,除上面已谈到的各点外,把同一表达式用函数处理与用宏处理两者的结果有可能是不同的。
【例9。9】
main(){
  int i1;
  while(i  intl3;w4;h5;sa;sb;sc;vv;
  SSSV(sa;sb;sc;vv);
  printf(〃sa%dnsb%dnsc%dnvv%dn〃;sa;sb;sc;vv);

程序第一行为宏定义,用宏名SSSV表示4个赋值语句,4 个形参分别为4个赋值符左部的变量。在宏调用时,把4个语句展开并用实参代替形参。使计算结果送入实参之中。
9。3  文件包含
文件包含是C预处理程序的另一个重要功能。
文件包含命令行的一般形式为:
#include〃文件名〃 
在前面我们已多次用此命令包含过库函数的头文件。例如:
#include〃stdio。h〃
  #include〃math。h〃
文件包含命令的功能是把指定的文件插入该命令行位置取代该命令行,从而把指定的文件和当前的源程序文件连成一个源文件。
在程序设计中,文件包含是很有用的。一个大的程序可以分为多个模块,由多个程序员分别编程。有些公用的符号常量或宏定义等可单独组成一个文件,在其它文件的开头用包含命令包含该文件即可使用。这样,可避免在每个文件开头都去书写那些公用量,从而节省时间,并减少出错。
对文件包含命令还要说明以下几点:
1。  包含命令中的文件名可以用双引号括起来,也可以用尖括号括起来。例如以下写法都是允许的:
#include〃stdio。h〃
#include
但是这两种形式是有区别的:使用尖括号表示在包含文件目录中去查找(包含目录是由用户在设置环境时设置的),而不在源文件目录去查找;
使用双引号则表示首先在当前的源文件目录中查找,若未找到才到包含目录中去查找。用户编程时可根据自己文件所在的目录来选择某一种命令形式。
2。  一个include命令只能指定一个被包含文件,若有多个文件要包含,则需用多个include命令。
3。  文件包含允许嵌套,即在一个被包含的文件中又可以包含另一个文件。
9。4  条件编译
预处理程序提供了条件编译的功能。可以按不同的条件去编译不同的程序部分,因而产生不同的目标代码文件。这对于程序的移植和调试是很有用的。
条件编译有三种形式,下面分别介绍:
1。  第一种形式:
#ifdef  标识符
  程序段1
#else
  程序段2
#endif
它的功能是,如果标识符已被 #define命令定义过则对程序段1进行编译;否则对程序段2进行编译。如果没有程序段2(它为空),本格式中的#else可以没有,即可以写为:
#ifdef  标识符
程序段
#endif
【例9。12】
#define NUM ok
main(){
  struct stu
  {
int num;
char *name;
char sex;
float score;
  }  *ps;
  ps(struct stu*)malloc(sizeof(struct stu));
  ps》num102;
  ps》name〃Zhang ping〃;
  ps》sex'M';
  ps》score62。5;
  #ifdef NUM
  printf(〃Number%dnScore%fn〃;ps》num;ps》score);
  #else
  printf(〃Name%snSex%cn〃;ps》name;ps》sex);
  #endif
  free(ps);

由于在程序的第16行插入了条件编译预处理命令,因此要根据NUM是否被定义过来决定编译那一个printf语句。而在程序的第一行已对NUM作过宏定义,因此应对第一个printf语句作编译故运行结果是输出了学号和成绩。
在程序的第一行宏定义中,定义NUM表示字符串OK,其实也可以为任何字符串,甚至不给出任何字符串,写为:
#define NUM
也具有同样的意义。只有取消程序的第一行才会去编译第二个printf语句。读者可上机试作。
2。  第二种形式:
#ifndef 标识符  
程序段1  
#else  
 程序段2  
  #endif
  与第一种形式的区别是将“ifdef”改为“ifndef”。它的功能是,如果标识符未被#define命令定义过则对程序段1进行编译,否则对程序段2进行编译。这与第一种形式的功能正相反。
3。  第三种形式:
#if 常量表达式
程序段1
#else  
 程序段2
  #endif
它的功能是,如常量表达式的值为真(非0),则对程序段1 进行编译,否则对程序段2进行编译。因此可以使程序在不同条件下,完成不同的功能。
【例9。13】
#define R 1
main(){
  float c;r;s;
  printf (〃input a number:  〃);
  scanf(〃%f〃;&c);
  #if R
r3。14159*c*c;
printf(〃area of round is: %fn〃;r);
  #else
sc*c;
printf(〃area of square is: %fn〃;s);
#endif

本例中采用了第三种形式的条件编译。在程序第一行宏定义中,定义R为1,因此在条件编译时,常量表达式的值为真,故计算并输出圆面积。
上面介绍的条件编译当然也可以用条件语句来实现。 但是用条件语句将会对整个源程序进行编译,生成的目标代码程序很长,而采用条件编译,则根据条件只编译其中的程序段1或程序段2,生成的目标程序较短。如果条件选择的程序段很长,采用条件编译的方法是十分必要的。
9。5  本章小结
1。  预处理功能是C语言特有的功能,它是在对源程序正式编译前由预处理程序完成的。程序员在程序中用预处理命令来调用这些功能。
2。  宏定义是用一个标识符来表示一个字符串,这个字符串可以是常量、变量或表达式。在宏调用中将用该字符串代换宏名。
3。  宏定义可以带有参数,宏调用时是以实参代换形参。而不是“值传送”。
4。  为了避免宏代换时发生错误,宏定义中的字符串应加括号,字符串中出现的形式参数两边也应加括号。
5。  文件包含是预处理的一个重要功能,它可用来把多个源文件连接成一个源文件进行编译,结果将生成一个目标文件。
6。  条件编译允许只编译源程序中满足条件的程序段,使生成的目标程序较短,从而减少了内存的开销并提高了程序的效率。
7。  使用预处理功能便于程序的修改、阅读、移植和调试,也便于实现模块化程序设计。 
?语言 10  
10  指针  
10。1  地址指针的基本概念  
10。2  变量的指针和指向变量的指针变量  
10。2。1  定义一个指针变量  
10。2。2  指针变量的引用  
10。2。3  指针变量作为函数参数  
10。2。4  指针变量几个问题的进一步说明  
10。3  数组指针和指向数组的指针变量  
10。3。1  指向数组元素的指针  
10。3。2  通过指针引用数组元素  
10。3。3  数组名作函数参数  
10。3。4  指向多维数组的指针和指针变量  
10。4  字符串的指针指向字符串的针指变量  
10。4。1  字符串的表示形式  
10。4。2  使用字符串指针变量与字符数组的区别  
10。5  函数指针变量  
10。6  指针型函数  
10。7  指针数组和指向指针的指针  
10。7。1  指针数组的概念  
10。7。2  指向指针的指针  
10。7。3  main函数的参数  
10。8  有关指针的数据类型和指针运算的小结  
10。8。1  有关指针的数据类型的小结  
10。8。2  指针运算的小结  
10。8。3  void指针类型  
10  指针
指针是C语言中广泛使用的一种数据类型。运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构;能很方便地使用数组和字符串;并能象汇编语言一样处理内存地址,从而编出精练而高效的程序。指针极大地丰富了C语言的功能。学习指针是学习C语言中最重要的一环,能否正确理解和使用指针是我们是否掌握C语言的一个标志。同时,指针也是C语言中最为困难的一部分,在学习中除了要正确理解基本概念,还必须要多编程,上机调试。只要作到这些,指针也是不难掌握的。
10。1  地址指针的基本概念
在计算机中,所有的数据都是存放在存储器中的。一般把存储器中的一个字节称为一个内存单元,不同的数据类型所占用的内存单元数不等,如整型量占2个单元,字符量占1个单元等,在前面已有详细的介绍。为了正确地访问这些内存单元,必须为每个内存单元编上号。根据一个内存单元的编号即可准确地找到该内存单元。内存单元的编号也叫做地址。 既然根据内存单元的编号或地址就可以找到所需的内存单元,所以通常也把这个地址称为指针。 内存单元的指针和内存单元的内容是两个不同的概念。 可以用一个通俗的例子来说明它们之间的关系。我们到银行去存取款时, 银行工作人员将根据我们的帐号去找我们的存款单, 找到之后在存单上写入存款、取款的金额。在这里,帐号就是存单的指针, 存款数是存单的内容。对于一个内存单元来说,单元的地址即为指针,其中存放的数据才是该单元的内容。在C语言中,允许用一个变量来存放指针,这种变量称为指针变量。因此,一个指针变量的值就是某个内存单元的地址或称为某内存单元的指针。
图中,设有字符变量C,其内容为“K”(ASCII码为十进制数 75),C占用了011A号单元(地址用十六进数表示)。设有指针变量P,内容为011A,这种情况我们称为P指向变量C,或说P是指向变量C的指针。
严格地说,一个指针是一个地址,是一个常量。而一个指针变量却可以被赋予不同的指针值,是变量。但常把指针变量简称为指针。为了避免混淆,我们中约定:“指针”是指地址,是常量,“指针变量”是指取值为地址的变量。定义指针的目的是为了通过指针去访问内存单元。
既然指针变量的值是一个地址,那么这个地址不仅可以是变量的地址,也可以是其它数据结构的地址。在一个指针变量中存放一个数组或一个函数的首地址有何意义呢? 因为数组或函数都是连续存放的。通过访问指针变量取得了数组或函数的首地址,也就找到了该数组或函数。这样一来,凡是出现数组,函数的地方都可以用一个指针变量来表示,只要该指针变量中赋予数组或函数的首地址即可。这样做,将会使程序的概念十分清楚,程序本身也精练,高效。在C语言中,一种数据类型或数据结构往往都占有一组连续的内存单元。 用“地址”这个概念并不能很好地描述一种数据类型或数据结构,而“指针”虽然实际上也是一个地址,但它却是一个数据结构的首地址,它是“指向”一个数据结构的,因而概念更为清楚,表示更为明确。 这也是引入“指针”概念的一个重要原因。
10。2  变量的指针和指向变量的指针变量
变量的指针就是变量的地址。存放变量地址的变量是指针变量。即在C语言中,允许用一个变量来存放指针,这种变量称为指针变量。因此,一个指针变量的值就是某个变量的地址或称为某变量的指针。
为了表示指针变量和它所指向的变量之间的关系,在程序中用“*”符号表示“指向”,例如,i_pointer代表指针变量,而*i_pointer是i_pointer所指向的变量。
因此,下面两个语句作用相同:
i3;
*i_pointer3;
第二个语句的含义是将3赋给指针变量i_pointer所指向的变量。
10。2。1  定义一个指针变量
对指针变量的定义包括三个内容:
(1)  指针类型说明,即定义变量为一个指针变量;
(2)  指针变量名;
(3)  变量值(指针)所指向的变量的数据类型。
其一般形式为:
类型说明符  *变量名;
其中,*表示这是一个指针变量,变量名即为定义的指针变量名,类型说明符表示本指针变量所指向的变量的数据类型。
例如:int *p1;
表示p1是一个指针变量,它的值是某个整型变量的地址。或者说p1指向一个整型变量。至于p1究竟指向哪一个整型变量,应由向p1赋予的地址来决定。
再如:
int *p2;  /*p2是指向整型变量的指针变量*/
float *p3;  /*p3是指向浮点变量的指针变量*/
char *p4;   /*p4是指向字符变量的指针变量*/
应该注意的是,一个指针变量只能指向同类型的变量,如P3 只能指向浮点变量,不能时而指向一个浮点变量,时而又指向一个字符变量。
10。2。2  指针变量的引用
指针变量同普通变量一样,使用之前不仅要定义说明,而且必须赋予具体的值。未经赋值的指针变量不能使用,否则将造成系统混乱,甚至死机。指针变量的赋值只能赋予地址, 决不能赋予任何其它数据,否则将引起错误。在C语言中,变量的地址是由编译系统分配的,对用户完全透明,用户不知道变量的具体地址。
两个有关的运算符:
1)  &:取地址运算符。
2)  *:指针运算符(或称“间接访问” 运算符)。
C语言中提供了地址运算符&来表示变量的地址。
其一般形式为:
&变量名
返回目录 上一页 下一页 回到顶部 0 0
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!