C语言运算符的优先级资料下载.pdf
- 文档编号:5970365
- 上传时间:2023-05-05
- 格式:PDF
- 页数:11
- 大小:166.59KB
C语言运算符的优先级资料下载.pdf
《C语言运算符的优先级资料下载.pdf》由会员分享,可在线阅读,更多相关《C语言运算符的优先级资料下载.pdf(11页珍藏版)》请在冰点文库上搜索。
三三、指向一个由指向一个由nn个元素所组成的数组指针个元素所组成的数组指针数组指针用的比较少,但在处理二维数组时,还是很方便的。
例如:
int(*p)4;
/*在数组指针的定义中,圆括号是不能少的,否则它是指针数组*/inta34;
p=a;
开始时p指向二维数组第0行,当进行p+1运算时,根据地址运算规则,此时放大因子为4x4=16,所以此时正好指向二维数组的第1行。
和二维数组元素地址计算的规则一样,*p+1指向a01,*(p+i)+j则指向数组元素aij。
四四、指针数组指针数组因为指针是变量,因此可设想用指向同一数据类型的指针来构成一个数组,这就是指针数组。
数组中的每个元素都是指针变量,根据数组的定义,指针数组中每个元素都为指向同一数据类型的指针。
格式:
类型标识*数组名整型常量表达式;
int*a10;
以上指针数组中包含10个指针变量a0,a1,a2,.,a9,可以指向10个不同的地址。
3指针函数和函数指针指针函数和函数指针一一、指针函数指针函数指针函数是指声明其返回值为一个指针的函数,实际上就是返回一个地址给调用函数。
类型说明符*函数名(参数)例如:
void*GetDate(intID);
二二、函数指针函数指针指向函数的指针包含了函数的地址,可以通过它来调用函数。
类型说明符(*函数名)(参数)例如:
int(*fptr)(intID);
其实这里不能称为函数名,应该叫做指针的变量名。
这个特殊的指针指向一个返回整型值的函数。
指针的声明笔削和它指向函数的声明保持一致。
指针名和指针运算符外面的括号改变了默认的运算符优先级。
如果没有圆括号,就变成了一个返回整型指针的函数的原型声明。
可以采用下面的形式定义函数指针数据类型:
typedefint(*T_MY_FUNC)(intID);
/*此时”T_MY_FUNCfptr;
”等价于”int(*fptr)(intID);
”*/可以采用下面的形式把函数的地址赋值给函数指针:
fptr=&
Function;
/*或用“fptr=Function;
”*/可以采用下面的形式通过指针来调用函数:
(*fptr)(ID);
/*或用“fptr(ID);
”的格式,使用这种调用格式看上去与调用普通函数无异,因此使用前一种调用格式可以明确指出是通过指针而非函数名来调用函数的。
*/三三、指针的指针指针的指针指针的指针用于指向指针的地址,它的声明有两个星号。
char*cp;
如果有三个星号,那就是指针的指针的指针,有四个星号那就是指针的指针的指针的指针,依次类推。
四四、指向指针数组的指针指向指针数组的指针指针的指针另一用法是处理指针数组。
有些程序员喜欢用指针数组来代替多维数组,一个常见的用法就是处理字符串。
char*Names=Bill,Sam,Jim,0;
main()char*nm=Names;
/*定义一个指向指针数组的指针的指针*/while(*nm!
=0)printf(%sn,*nm+);
4可变参数可变参数的的函数函数下面是一个简单的可变参数的函数,该函数至少有一个整数参数,第二个参数也是整数,是可选的。
#includevoidsimple_va_fun(inti,.)va_listarg_ptr;
intj=0;
va_start(arg_ptr,i);
/*va在这里是可变参数(variable-argument)的意思*/j=va_arg(arg_ptr,int);
va_end(arg_ptr);
printf(%d%dn,i,j);
return;
从这个函数的实现可以看到,使用可变参数应该有以下步骤:
1)#include2)在函数里定义一个va_list型的变量,这里是arg_ptr,这个变量是指向参数的指针。
3)用va_start宏初始化变量arg_ptr,该宏的第二个参数是第一个可变参数的前一参数,是一固定的参数。
4)用va_arg返回可变的参数,并赋值给j。
va_arg的第二个参数是要返回的参数的类型,这里是int型。
5)最后用va_end宏结束可变参数的获取。
下面的例子可以进一步加深对可变参数的理解,该函数的效果与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;
对于位域的定义尚有以下几点说明:
1.一个位域必须存储在同一个字节中,不能跨两个字节。
如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。
也可以有意使某位域从下一单元开始。
52.由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。
3.位域可以无位域名,这时它只用来作填充或调整位置。
无名的位域是不能使用的。
链链表表typedefstructstudentintnumber;
intscore;
structstudent*next;
STUDENT_LINK;
/*建立一个有cnt个结点的链表,返回链表头*/STUDENT_LINK*link_creat(intcnt)STUDENT_LINK*head=NULL;
/*head始终指向链表头,用于返回*/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(STUDENT_LINK*head,intnum)STUDENT_LINK*cur_node;
/*cur_node始终指向当前操作的节点*/STUDENT_LINK*pre_node;
/*pre_node始终指向当前操作的节点的上一个节点*/6if(head=NULL)printf(这个链表是空的,请先建立一个链表.n);
cur_node=head;
while(cur_node-number!
=num&
cur_node-next!
=NULL)/*当前节点不是要删除的也不是最后的节点*/pre_node=cur_node;
cur_node=cur_node-next;
/*将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);
/*插入一个新结点到链表的最后,并返回链表头*/STUDENT_LINK*link_insert(STUDENT_LINK*head,STUDENT_LINK*node)STUDENT_LINK*cur_node;
/*cur_node始终指向当前操作的节点*/if(head=NULL)head=node;
elsecur_node=head;
while(cur_node-next!
=NULL)7cur_node=cur_node-next;
/*将cur_node向后移一个结点*/cur_node-next=node;
node-next=NULL;
/*不要忘记让最后的节点的next指向NULL*/printf(这个节点已经插入当前链表的最后.n);
/*用户输入一个节点*/voidlink_input(STUDENT_LINK*node)/*输出一个链表*/voidlink_output(STUDENT_LINK*head)STUDENT_LINK*cur_node;
intcnt=0;
printf(IDt学号tt分数n);
while(cur_node!
=NULL)printf(%dt%dtt%dn,+cnt,cur_node-number,cur_node-score);
printf(合计有%d条记录n,cnt);
/*链表接口调用范例*/voidlink_main(void)STUDENT_LINK*new_list=NULL;
STUDENT_LINKnew_stud;
/*要插入的新结点*/intcnt=5;
intnum=100;
new_list=link_creat(cnt);
printf(您创建的列表为:
n);
link_output(new_list);
new_list=link_delete(new_list,num);
printf(删除结点后的列表为:
8link_output(new_list);
link_input(&
new_stud);
new_list=link_insert(new_list,&
printf(插入新结点后的列表为:
预处理预处理一一、预处理预处理过程和预处理指令过程和预处理指令在C语言中,并没有任何内在的机制来完成如下一些功能:
在编译时包含其他源文件、定义宏、根据条件决定编译时是否包含某些代码,要完成这些工作,就需要使用预处理程序。
尽管在目前绝大多数编译器都包含了预处理程序,但通常认为它们是独立于编译器的。
预处理过程读入源代码,检查包含预处理指令的语句和宏定义,并对源代码进行响应的转换,预处理过程还会删除程序中的注释和多余的空白字符。
下面是部分预处理指令:
指令用途指令用途#空指令,无任何效果#include包含一个源代码文件#if如果给定条件为真,则编译下面代码#define定义宏#ifdef如果宏已经定义,则编译下面代码#undef取消已定义的宏#ifndef如果宏没有定义,则编译下面代码#elif如果前面的#if给定条件不为真,且当前条件为真,则编译下面代码#else如果前面的#if给定条件不为真,则编译#else下面的代码#endif结束一个#if#else条件编译块二二、预定义的宏名预定义的宏名ANSI标准说明了五个预定义的宏名。
它们是:
_LINE_:
当前语句所在的行号_FILE_:
当前语句所在文件的文件名_DATE_:
该宏指令含有形式为月日年的串,表示源代码翻译到目标代码的日期_TIME_:
该宏指令含有形式为时:
分:
秒的串,表示源代码翻译到目标代码的时间_STDC_:
如果实现是标准的,则该宏含有十进制常量1,如果它含有任何其它数,则表示实现是非标准的注:
如果编译不是标准的,则可能仅支持以上宏名中的几个,或都不支持,但也许还提供其它预定义的宏名。
三三、#运算符运算符#的功能是将其后面的宏参数进行字符串化操作(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.”*/再比如:
#definePASTE(n)adhfkj#nprintf(%sn,PASTE(15);
/*宏定义中的#运算符告诉预处理程序,把源代码中任何传递给该宏的参数转换成一个字符串。
所以输出应该是adhfkj15。
*/9四四、#运算符运算符#被称为连接符(concatenator),#运算符用于把参数连接到一起。
预处理程序把出现在#两侧的参数合并成一个符号。
先看一个简单的例子:
#defineNUM(a,b,c)a#b#c#defineSTR(a,b,c)a#b#c/*#前后可以加空格*/printf(%dn,NUM(1,2,3);
printf(%sn,STR(aa,bb,cc);
最后程序的输出为:
123aabbcc再比如要做一个菜单项命令名和函数指针组成的结构体的数组,并且希望在函数名和菜单项命令名之间有直观的、名字上的关系,那么下面的代码就非常实用:
structcommandchar*name;
/*菜单项命令名*/void(*function)(void);
/*命令名对应的函数指针*/;
#defineCOMMAND(NAME)#NAME,NAME#_commandstructcommandmy_commands=COMMAND(quit),/*相当于quit,quit_command*/COMMAND(help)/*相当于help,help_command*/;
五五、#error#error指令指令#error指令用于程序的调试,当编译中遇到#error指令就停止编译,并显示相应的出错信息。
#error命令的基本形式为:
#error出错信息六六、#lineline指令指令命令#line主要用于调试及其它特殊应用,#line改变_LINE_与_FILE_的内容,它们是在编译程序中预先定义的标识符。
#line命令的基本形式为:
#linenumberfilename其中的数字为任何正整数,可选的文件名为任意有效文件标识符,行号为源程序中当前行号,文件名为源文件的名字。
例如,下面的行计数从100开始,printf()语句输出为102,因为它是语句#line100后的第3行。
#line100/*初始化行计数器*/main()/*行号100*/*行号101*/printf(%dn,_line_);
/*行号102*/七七、#pragma#pragma指令指令在所有的预处理指令中,#pragma指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。
#pragma指令对每个编译器给出了一个方法,在保持与C和C+语言完全兼容的情况下,给出主机或操作系统专有的特征。
依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。
其格式一般为:
#pragmapara其中para为参数,下面来看一些常用的参数。
#pragmamessage(“_X86macroactivated!
”)10当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来,这对于源代码信息的控制是非常重要的。
当我们在程序中定义了许多宏来控制源代码版本的时候,我们自己有可能都会忘记有没有正确的设置这些宏,此时我们可以用这条指令在编译的时候就进行检查。
#pragmacomment(lib,xxx.lib)导入lib。
#pragmacode_seg(section-name,section-class)它能够设置程序中函数代码存放的代码段,当我们开发驱动程序的时候就会使用到它。
#pragmaonce只要在头文件的最开始加入这条指令就能够保证头文件被编译一次,这条指令实际上在VC6中就已经有了,但是考虑到兼容性并没有太多的使用它。
#pragmahdrstop表示预编译头文件到此为止,后面的头文件不进行预编译。
BCB可以预编译头文件以加快链接的速度,但如果所有头文件都进行预编译又可能占太多磁盘空间,所以使用这个选项排除一些头文件。
#pragmastartup有时单元之间有依赖关系,比如单元A依赖单元B,所以单元B要先于单元A编译。
可以用#pragmastartup指定编译优先级,如果使用了#pragmapackage(smart_init),BCB就会根据优先级的大小先后编译。
pragmaresource*.dfm表示把*.dfm文件中的资源加入工程。
*.dfm中包括窗体外观的定义。
#pragmawarning(disable:
450734;
once:
4385;
error:
164)#pragmawarning(disable:
164)等价于:
450734)/不显示4507和34号警告信息#pragmawarning(once:
4385)/4385号警告信息仅报告一次#pragmawarning(error:
164)/把164号警告信息作为一个错误。
同时这个pragmawarning也支持如下格式:
#pragmawarning(push,n)#pragmawarning(pop)这里n代表一个警告等级(1-4)。
#pragmawarning(push):
保存所有警告信息的现有的警告状态。
#pragmawarning(push,n):
保存所有警告信息的现有的警告状态,并且把全局警告等级设定为n。
#pragmawarning(pop):
向栈中弹出最后一个警告信息,取消在入栈和出栈之间所作的一切改动。
#pragmaargsused如果没有在函数内部使用某个参数,编译时会报告Parameternameisneverusedinfunctionfunc-name,使用#pragmaargsused,编译时就不再警告了。
VC+不支持这条指令。
#pragmapack#pragmapack(n),C编译器将按照n个字节对齐,n必须是1,2,4,8,16,32,64等值。
#pragmapack(),取消自定义字节对齐方式。
#pragmapack规定的对齐长度,实际使用的规则是:
结构,联合,或者类的数据成员,第一个放在偏移为0的地方,以后每个数据成员的对齐,按照#pragmapack指定的数值和这个数据成员自身长度中,比较小的那个进行。
也就是说,当#pragmapack的值等于或超过所有数据成员长度的时候,这个值的大小将不产生任何效果。
而结构整体的对齐,则按照结构体中最大的数据成员和#pragmapack指定值之间较小的那个进行。
#pragmapack
(2)structTestchara;
/放在偏移0的位置。
intb;
/自身长为4,大于2,故按2字节对齐,放在2,5偏移的位置,11charc;
/自身长为1,小于2,故按1字节对齐,所以放在偏移6的位置。
intd;
/自身长为4,大于2,故按2字节对齐,放在8,11的位置。
chare;
/自身长为1,小于2,故按1字节对齐,所以放在偏移12的位置。
;
这个结构体实际占据的内存空间是13字节,但结构体之间的对齐是按照结构体内部最大的成员的长度和#pragmapack规定的值之中较小的一个对齐的,所以这个例子中,结构体之间对齐的长度是min(sizeof(int),2),也就是2,所以sizeof(structTest)是14。
如果上例中使用#pragmapack(4)代替#pragmapack
(2),则chara;
/自身长为4,故按4字节对齐,放在4,7偏移的位置,charc;
/自身长为1,小于4,故按1字节对齐,所以放在偏移8的位置。
/自身长为4,故按4字节对齐,放在12,15的位置。
/自身长为1,小于4,故按1字节对齐,所以放在偏移16的位置。
使用#pragmapack(4)后这个结构体实际占据的内存空间是17字节,结构体之间对齐的长度是min(sizeof(int),4),也就是4,所以sizeof(structTest)是20。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 语言 运算 优先级