C语言运算符的优先级_第1页
C语言运算符的优先级_第2页
C语言运算符的优先级_第3页
C语言运算符的优先级_第4页
C语言运算符的优先级_第5页
已阅读5页,还剩9页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、 优先级运算符名称或含义()-(类型)+数组下标圆括号成员选择(对象)成员选择(指针)负号运算符强制类型转换自增运算符自减运算符sizeof运算符及其优先级使用形式结合方向数组名常量表达式(表达式)/函数名(形参表)对象成员名对象指针-成员名-表达式(数据类型)表达式+变量名/变量名+变量名/变量名一取值运算符取地址运算符逻辑非运算符按位取反运算符长度运算符除乘余数(取模)加左移右移*指针变量&变量名!表达式表达式sizeof(表达式)表达式/表达式表达式*表达式整型表达式/整型表达式表达式+表达式表达式-表达式变量表达式变量表达式大于表达式表达式=大于等于表达式=表达式小于表达式表达式=小于

2、等于表达式=表达式左到右优先级运算符名称或含义使用形式结合方向7=等于表达式=表达式左到右!=不等于表达式!=表达式8&按位与表达式&表达式左到右9按位异或表达式表达式左到右10|按位或表达式I表达式左到右11&逻辑与表达式&表达式左到右12|逻辑或表达式|表达式左到右13?:条件运算符表达式1?表达式2:表达式3右到左14=赋值运算符变量=表达式右到左/=除后赋值变量/=表达式*=乘后赋值变量*=表达式%=取模后赋值变量%=表达式+=加后赋值变量+=表达式二减后赋值变量-=表达式=右移后赋值变量=表达式&二按位与后赋值变量&=表达式=按位异或后赋值变量=表达式|=按位或后赋值变量匸表达式15

3、逗号运算符表达式,表达式,左到右左到右右到左左到右左到右左到右数组和指针一、指向一维数组元素的指针inta10,*p;p=&a0;/*与语句p=a;等价*/此时p指向数组中的第0号元素,即a0,*p就是*a,就是a0的值,*(a+i)就是ai的值。由于数组元素在内存中是连续存放的,根据地址运算规则,p+i和a+i都表示为ai的地址(即&ai)。二、二维数组元素的地址为了说明问题,我们定义以下二维数组:inta34=0,l,2,3,4,5,6,7,8,9,10,11;二维数a也可这样来理解:数组a由三个元素组成:a0,a1,a2,而每个元素又是一个一维数组,且都含有4个元素(相当于4列)。如图所

4、示:a|a0|0|1|2|3|(0 x1000)|_|_|_|_|a1|4|5|6|7|(0 x1010)|_|_|_|_|a2|8|9|10|11|(0 x1020)但从二维数组的角度来看,a代表二维数组的首地址,当然也可看成是二维数组第0行的首地址,a+1就代表第1行的首地址,依次。如果此二维数组的首地址为0 x1000,由于第0行有4个整型元素,所以a+1为0 x1010。既然我们把a0,a1,a2看成是一维数组名,可以认为它们分别代表它们所对应的数组的首地址,也就是讲a0代表第0行中第0列元素的地址,即&a00,a1是第1行中第0列元素的地址,即&a10,根据地址运算规则,a0+1即代

5、表第0行第1列元素的地址,即&a01,般而言,ai+j即代表第i行第j列元素的地址,即&aij。另外,在二维数组中我们还可用指针的形式来表示各元素的地址,如a0与*(a+0)等价,ai与*(a+i)等价,它表示数组元素ai的地址&ai0。而二维数组元素aij可表示成*(ai+j)或*(*(a+i)+j),或者写成(*(a+i)j。三、指向一个由n个元素所组成的数组指针数组指针用的比较少,但在处理二维数组时,还是很方便的。例如:int(*p)4;/*在数组指针的定义中,圆括号是不能少的,否则它是指针数组*/inta34;p=a;开始时p指向二维数组第0行,当进行p+1运算时,根据地址运算规则,此

6、时放大因子为4x4=16,所以此时正好指向二维数组的第1行。和二维数组元素地址计算的规则一样,*p+1指向a01,*(p+i)+j则指向数组元素aij。四、指针数组因为指针是变量,因此可设想用指向同一数据类型的指针来构成一个数组,这就是指针数组。数组中的每个元素都是指针变量,根据数组的定义,指针数组中每个元素都为指向同一数据类型的指针。格式:类型标识*数组名整型常量表达式;例如:int*a10;以上指针数组中包含10个指针变量a0,a1,a2,.,a9,可以指向10个不同的地址。指针函数和函数指针一、指针函数指针函数是指声明其返回值为一个指针的函数,实际上就是返回一个地址给调用函数。格式:类型

7、说明符*函数名(参数)例如:void*GetDate(intID);二、函数指针指向函数的指针包含了函数的地址,可以通过它来调用函数。格式:类型说明符(*函数名)(参数)例如:int(*fptr)(intID);其实这里不能称为函数名,应该叫做指针的变量名。这个特殊的指针指向一个返回整型值的函数。指针的声明笔削和它指向函数的声明保持一致。指针名和指针运算符外面的括号改变了默认的运算符优先级。如果没有圆括号,就变成了一个返回整型指针的函数的原型声明。可以采用下面的形式定义函数指针数据类型:typedefint(*T_MY_FUNC)(intID);/*此时”T_MY_FUNCfptr;等价于”i

8、nt(*fptr)(intID);”*/可以采用下面的形式把函数的地址赋值给函数指针:fptr二&Function;/*或用“fptr二Function;*/可以采用下面的形式通过指针来调用函数:(*fptr)(ID);/*或用“fptr(ID);”的格式,使用这种调用格式看上去与调用普通函数无异,因此使用前一种调用格式可以明确指出是通过指针而非函数名来调用函数的。*/三、指针的指针指针的指针用于指向指针的地址,它的声明有两个星号。例如:char*cp;如果有三个星号,那就是指针的指针的指针,有四个星号那就是指针的指针的指针的指针,依次类推。四、指向指针数组的指针指针的指针另一用法是处理指针数

9、组。有些程序员喜欢用指针数组来代替多维数组,一个常见的用法就是处理字符串。char*Names=Bill,cSam,丁Jim,0;main()char*nm=Names;/*定义一个指向指针数组的指针的指针*/while(*nm!=0)printf(%sn,*nm+);可变参数的函数下面是一个简单的可变参数的函数,该函数至少有一个整数参数,第二个参数也是整数,是可选的。#includestdarg.hvoidsimple_va_fun(inti,.)va_listarg_ptr;intj=0;va_start(arg_ptr,i);/*va在这里是可变参数(variable-argument)

10、的意思*/j=va_arg(arg_ptr,int);va_end(arg_ptr);printf(%d%dn,i,j);return;从这个函数的实现可以看到,使用可变参数应该有以下步骤:#includestdarg.h在函数里定义一个va_list型的变量,这里是arg_ptr,这个变量是指向参数的指针。用va_start宏初始化变量arg_ptr,该宏的第二个参数是第一个可变参数的前一参数,是一固定的参数。用va_arg返回可变的参数,并赋值给j。va_arg的第二个参数是要返回的参数的类型,这里是int型。最后用va_end宏结束可变参数的获取。下面的例子可以进一步加深对可变参数的理解

11、,该函数的效果与sprintf函数完全相同:voidmy_printf(char*buffer,constchar*format,.)va_listarg_ptr;va_start(arg_ptr,format);vsprintf(buffer,format,arg_ptr);/*将arg_ptr按format格式打印到buffer中*/va_end(arg_ptr);位域的使用位域的定义和位域变量的说明与结构定义相仿,其形式例如为:structbsinta:8;intb:2;int:2/*无位域名,该2bit不能使用*/intc:4;对于位域的定义尚有以下几点说明:一个位域必须存储在同一个字

12、节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。链表typedefstructstudentintnumber;intscore;structstudent*next;STUDENT_LINK;/*建立一个有cnt个结点的链表,返回链表头*/STUDENT_LINK*link_creat(intcnt)STUDENT_LINK*head=NULL;/*head始

13、终指向链表头,用于返回*/STUDENT_LINK*new_node;/*new_node始终指向新申请的节点*/STUDENT_LINK*cur_node;/*cur_node始终指向当前操作的(也是最后的)节点*/intn=1;while(nnext=new_node;cur_node=new_node;/*让cur_node始终指向当前的(也是最后的)节点*/cur_node-next=NULL;/*不要忘记让最后的节点的next指向NULL*/n+;return(head);/*删除链表中number字段为num的结点,并返回链表头*/STUDENT_LINK*link_delete(

14、STUDENT_LINK*head,intnum)STUDENT_LINK*cur_node;/*cur_node始终指向当前操作的节点*/STUDENT_LINK*pre_node;/*pre_node始终指向当前操作的节点的上一个节点*/if(head=NULL)printf(这个链表是空的,请先建立一个链表.n);return(head);cur_node=head;while(cur_node-number!=num&cur_node-next!=NULL)/*当前节点不是要删除的也不是最后的节点*/pre_node=cur_node;cur_node=cur_node-next;/*

15、将cur_node向后移一个结点*/if(cur_node-number=num)/*在链表中找到了要删除的结点*/if(cur_node=head)/*要删除的是头结点*/head=cur_node-next;elsepre_node-next=cur_node-next;free(cur_node);printf(学号为%d的节点已经从链表中删除.n,num);else/*在链表中没有找到要删除的结点*/printf(您想要删除的结点不在此链表中.n);return(head);/*插入一个新结点到链表的最后,并返回链表头*/STUDENT_LINK*link_insert(STUDENT

16、_LINK*head,STUDENT_LINK*node)STUDENT_LINK*cur_node;/*cur_node始终指向当前操作的节点*/if(head=NULL)head=node;elsecur_node=head;while(cur_node-next!=NULL)cur_node=cur_node-next;/*将cur_node向后移一个结点*/cur_node-next=node;node-next=NULL;/*不要忘记让最后的节点的next指向NULL*/ printf(这个节点已经插入当前链表的最后.n);return(head);voidlink_input(ST

17、UDENT_LINK*node)voidlink_output(STUDENT_LINK*head)STUDENT_LINK*cur_node;intcnt=0;cur_node=head;printf(IDt学号tt分数n);while(cur_node!=NULL)printf(%dt%dtt%dn,+cnt,cur_node-number,cur_node-score);cur_node=cur_node-next;printf(合计有%d条记录n,ent);voidlink_main(void)STUDENT_LINK*new_list=NULL;STUDENT_LINKnew_stu

18、d;/*要插入的新结点*/intent=5;intnum=100;new_list=link_ereat(ent);printf(您创建的列表为:n);link_output(new_list);new_list=link_delete(new_list,num);printf(删除结点后的列表为:n);link_output(new_list);link_input(&new_stud);new_list=link_insert(new_list,&new_stud);printf(插入新结点后的列表为:n);link_output(new_list);预处理一、预处理过程和预处理指令在C语

19、言中,并没有任何内在的机制来完成如下一些功能:在编译时包含其他源文件、定义宏、根据条件决定编译时是否包含某些代码,要完成这些工作,就需要使用预处理程序。尽管在目前绝大多数编译器都包含了预处理程序,但通常认为它们是独立于编译器的。预处理过程读入源代码,检查包含预处理指令的语句和宏定义,并对源代码进行响应的转换,预处理过程还会删除程序中的注释和多余的空白字符。下面是部分预处理指令:指令用途#include包含一个源代码文件#define定义宏#undef取消已定义的宏指令用途#空指令,无任何效果#if如果给定条件为真,则编译下面代码#ifdef如果宏已经定义,则编译下面代码#ifndef如果宏没有

20、定义,则编译下面代码#elif如果前面的#if给定条件不为真,且当前条件为真,则编译下面代码#else如果前面的#if给定条件不为真,则编#else下面的代码#endif结束一个#if#else条件编译块二、预定义的宏名ANSI标准说明了五个预定义的宏名。它们是:_LINE_:当前语句所在的行号_FILE_:当前语句所在文件的文件名_DATE_:该宏指令含有形式为月日年的串,表示源代码翻译到目标代码的日期_TIME_:该宏指令含有形式为时:分:秒的串,表示源代码翻译到目标代码的时间_STDC_:如果实现是标准的,则该宏含有十进制常量1,如果它含有任何其它数,则表示实现是非标准的注:如果编译不是

21、标准的,则可能仅支持以上宏名中的几个,或都不支持,但也许还提供其它预定义的宏名。三、#运算符#的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号,有时把这种用法的#称为字符串化运算符。比如:#defineWARN_IF(EXP)if(EXP)fprintf(stderr,Warning:#EXP.n);那么语句WARN_IF(divider=0)将被替换为:if(divider=0)fprintf(stderr,Warning:divider=0.n);/*会打印出“Warning:divider=0.”*

22、/再比如:#definePASTE(n)adhfkj#nprintf(%sn,PASTE(15);/*宏定义中的#运算符告诉预处理程序,把源代码中任何传递给该宏的参数转换成一个字符串。所以输出应该是adhfkjl5。*/四、#运算符#被称为连接符(concatenator),#运算符用于把参数连接到一起。预处理程序把出现在#两侧的参数合并成一个符号。先看一个简单的例子:#defineNUM(a,b,c)a#b#c#defineSTR(a,b,c)a#b#c/*#前后可以加空格*/printf(dn,NUM(l,2,3);printf(%sn,STR(aa,bb,cc);最后程序的输出为:123

23、aabbcc再比如要做一个菜单项命令名和函数指针组成的结构体的数组,并且希望在函数名和菜单项命令名之间有直观的、名字上的关系,那么下面的代码就非常实用:structcommandchar*name;/*菜单项命令名*/void(*function)(void);/*命令名对应的函数指针*/;#defineCOMMAND(NAME)#NAME,NAME#_commandstructcommandmy_commands=COMMAND(quit),/*相当于quit,quit_command*/COMMAND(help)/*相当于help,help_command*/;五、#error指令#err

24、or指令用于程序的调试,当编译中遇到#error指令就停止编译,并显示相应的出错信息。#error命令的基本形式为:#error出错信息六、#line指令命令#line主要用于调试及其它特殊应用,#line改变_LINE_与_FILE_的内容,它们是在编译程序中预先定义的标识符。#line命令的基本形式为:#linenumberfilename其中的数字为任何正整数,可选的文件名为任意有效文件标识符,行号为源程序中当前行号,文件名为源文件的名字。例如,下面的行计数从100开始,printf()语句输出为102,因为它是语句#line100后的第3行。#line100/*初始化行计数器*/mai

25、n()/*行号100*/*行号101*/printf(%dn,_line_);/*行号102*/七、#pragma指令在所有的预处理指令中,#pragma指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma指令对每个编译器给出了一个方法,在保持与C和C+语言完全兼容的情况下,给出主机或操作系统专有的特征。依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。其格式一般为:#pragmapara其中para为参数,下面来看一些常用的参数。#pragmamessage(“_X86macroactivated!)当编译器遇到这条指令时就在

26、编译输出窗口中将消息文本打印出来,这对于源代码信息的控制是非常重要的。当我们在程序中定义了许多宏来控制源代码版本的时候,我们自己有可能都会忘记有没有正确的设置这些宏,此时我们可以用这条指令在编译的时候就进行检查。#pragmacomment(lib,xxx.lib)导入lib。#pragmacode_seg(section-name,section-class)它能够设置程序中函数代码存放的代码段,当我们开发驱动程序的时候就会使用到它。#pragmaonce只要在头文件的最开始加入这条指令就能够保证头文件被编译一次,这条指令实际上在VC6中就已经有了,但是考虑到兼容性并没有太多的使用它。#pr

27、agmahdrstop表示预编译头文件到此为止,后面的头文件不进行预编译oBCB可以预编译头文件以加快链接的速度,但如果所有头文件都进行预编译又可能占太多磁盘空间,所以使用这个选项排除一些头文件。#pragmastartup有时单元之间有依赖关系,比如单元A依赖单元B,所以单元B要先于单元A编译。可以用#pragmastartup指定编译优先级,如果使用了#pragmapackage(smart_init),BCB就会根据优先级的大小先后编译。pragmaresource*.dfm表示把*.dfm文件中的资源加入工程。*.dfm中包括窗体外观的定义。#pragmawarning(disable

28、:450734;once:4385;error:164)#pragmawarning(disable:450734;once:4385;error:164)等价于:#pragmawarning(disable:450734)/不显示4507和34号警告信息#pragmawarning(once:4385)/4385号警告信息仅报告一次#pragmawarning(error:164)/把164号警告信息作为一个错误。同时这个pragmawarning也支持如下格式:#pragmawarning(push,n)#pragmawarning(pop)这里n代表一个警告等级(14)。#pragmawarning(push):保存所有警告信息的现有的警告状态。#pragmawarning(push,n):保存所有警告信息的现有的警告状态,并且把全局警告等级设定为n。#pragmawarning(pop):向栈中弹出最后一个警告信息,取消在入栈和出栈之间所作的一切改动。#pragmaargsused如果没有在函数内部使用某个参数,编译时会报告Parameternameisneverusedinfunction

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论