版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、1. #得作用#就是将其后得变量直接转换为字符串void WriteLog(arg)printf("%s=%d",#arg,arg)2. #得作用#得作用就是连接两个变量 如#define combine_converse_str(x,y) x#y int Err;int Num;printf("%s",combine_converse_str(Err,Num);结果为: ErrNum再如 :int a=1;int b=2;int ab=3;printf("%d",a#b);结果为 : 3后面那句相当于 printf("%d
2、",ab);3. do while(0) 作用1,空得宏定义避免 warning:#define foo() dowhile(0)2,存在一个独立得 block,可以用来进行变量定义,进行比较复杂得实现。 3,用在宏定义上并且当宏定义需要定义成多条语句得组合时,可以保证这几条语句就是一 个整体得,并且可以消除使用这个宏定义后添加"" 所带来得报错,例如: 襪崍恒论飛惱说。#define aaa(x,y)do int a=0;int b=0;函数 1(x); 函数 2(y); while(0)调用 aaa(x,y); 时不会报错并且如果使用 if (m)aaa(1,
3、2);elseaaa(3,4);时运行也不会使某些语句没有被运行到。4. 数组名得使用A数组名作为函数参数 :数组名用在某个函数 A 得参数中时,处于函数传递效率原因,会 被强制转换成了指针, 此后在函数 A 内就完全就是一个值等于对应数组首地址得指针变 量,可自加自减等 謔鈦泽闲钔擾朧。 注意!只有在作为函数参数得情况下才会将数组名强制转换成指针, 另:数组名作为函数参数传递时,函数声明得写法有多种 int aaa(char x) int aaa(char x1) int aaa(char x100) int aaa(char *x) 作为函数参数时得参数声明也与普通得数组定义一样要合法,比
4、如不能其她得都不会转换。int aaa(charx0),因为定义一个数组也不能用char x0来定义,编译器在检查参数得声明合法后,如果发现参数就是数组, 就会强制转换成指针, 所以 int aaa(char x1) 与 int aaa(char x100) 得结果就是一样得。 齿騏恹繢鶯绫谩。B数组名用在 sizeof 上:结果返回得就是整个数组所占空间得大小,而不就是一个指针得 长度C数组名与&与*: a与&a与&a0得值都相等,a就是数组名,&a就是整个数组地址,&a0 就是数组首元素得地址,她们都相等 贛罌嚣穎詭講脓。int a5=1,2,3,4
5、,5; printf("a=%xn",a); printf("&a=%xn",&a);printf("*&a=%xn",*&a); printf("&a0=%xn",&a0);printf("*&a0=%xn",*&a0); printf("*(&a0)=%xn",*(&a0);printf("*(int *)(&a)=%xn",*(int *)(&a); pr
6、intf("*(*(&a)=%xn",*(*(&a);结果:a=12ff34&a=12ff34*&a=12ff34 &a0=12ff34*&a0=1*(&a0)=1*(int *)(&a)=1-*与&消掉,*&a=a=0x12ff34-*与 &消掉,-* 与&消掉,-*与&之间有个强制类型转换 (int *) ,无法直接消掉,所*&a0=a0=1*(&a0)=*&a0=a0=1 蘄葦氇蔹萧驽惊。以按照括号次序来运算(int *)(&a)=0
7、x12ff34, *(i nt *)(&a)=*(0x12ff34)=1*(*(&a)=1-* 与& 消掉,*(*(&a)=*a=1D.指针数组:定义:基类型*数组名腡镪賅槍詆胁費。使用:像普通得数组一样使用,数组名代表首地址,数组名以此类推。常见得就是字符串数组,例如:Char *Names=Bill,Sami,Jim为汇颖齜鳴骐鈧实际内存中保存得就就是aQ12FF0C1«29Ji200F42F鮭.«e.-ZB.1C29ll2aeOftoee»eenniPFFii;nrnnnnmtnnnneei2FFaJiQESilea0015a
8、nsaeeGei2FF2C1£SBeeQO17SQaaeeBei2FF341799QBoe1FQG9aee2UDUuaDU21auDUDBr0表示第一个元素得内容,E ftHampOk 0012Be axatn7ffcic - 叶 "脈閃e "Dill"即首地址 0x12ff0c0x00423018,0x0042f2f4,0042201c,其中 0x00423018 地址所保存得就 就 是 "Bill”, 所 以 数 组 名 Name=0x12ff0c,& Name=0x12ff0c,*Name=0x00423018,*Name=0x4
9、2 撿贾审鹕廢鈽蝸。prin tf("Name=%x n",Name);prin tf("&Name=%xn ”,&Name);prin tf("*&Name=%xn ",*&Name);printf("&Name0=%xn",&Name0);prin tf("*Name=%xn",*Name);prin tf("*Name=%xn",*Name);prin tf("Name0=%xn",Name0);prin tf(
10、"*Name0=%xn ",*Name0);prin tf("*&Name0=%xn",*&Name0);prin tf("*(&Name0)=%xn",*(&Name0);prin tf("(*(i nt *)(&Name)=%xn",(*(i nt *)(&Name);缔鹵進鍰袭鹼俠。prin tf("(*(*(&Name)=%xn",(*(*(&Name);结果就是Name=&Name=*&Name=&
11、Name0=0x12ff0c*Name=Name0=*&Name0=*(&Name0)=(*(i nt*)(&Name)=(*(*(&Name)=0x00423018 鬮況窝愷业鵡媼。*Name=*Name0=0x42注意!指针就是一级,数组就是又一级,所以指针数组就是二级指针,定义对应得指针 变量要用二级指针,比如int *p=Name; 不能直接用int *p=Name钊怀齔桧軫骛驄。5. 常量得定义与指针常量得定义及使用1、常量得定义:const int a=10; / 在其她地方不允许修改 a 得值,否则会编译不通过、 也可以写成 int const a
12、=10;/ 一样得2、指针常量得定义与使用 :有 3 种定义 : const int *pi; 与 int const *pi; 以及 int * const pi; 镒鐳荡窮鸽织黾。 1)前两种情况一样得,没有区别。1)如果const修饰在*pi前(前2种情况)则不能改得就是*pi (即不能 类似这样:*pi=50 ;赋 值)而不就是指 pi、 丢筹鷸觀錨餛蓋。2)如果const就是直接写在pi前(后一种情况)则 pi不能改(即不能类似 这样:pi=&i ;赋 值)。 質维鵓溆兖訪艫。6. 函数参数传递得 4 种类型 :1、值传递void Exchg1(int x, int y) i
13、nt tmp;tmp = x;x = y;y = tmp;printf("x = %d, y = %dn", x, y); main()int a = 4,b = 6;Exchg1(a, b);printf("a = %d, b = %dn", a, b);return(0);2、地址传递void Exchg2(int *px, int *py)int tmp = *px;*px = *py;*py = tmp;printf("*px = %d, *py = %d 、n", *px, *py); main()int a = 4;int
14、 b = 6;Exchg2(&a, &b);printf("a = %d, b = %d 、 n", a, b); return(0);3、引用传递void Exchg3(int &x, int &y)int tmp = x;x = y;y = tmp;printf("x = %d,y = %dn", x, y);main()int a = 4;int b = 6;Exchg3(a, b);printf("a = %d, b = %dn", a, b); return(0);4、变长参数传递:使用省略号
15、指定参数表使用得宏及其定义( x86 中): #define va_start _crt_va_start #define va_arg _crt_va_arg #define va_end _crt_va_end typedef char * va_list;#define _ADDRESSOF(v) ( &(v) )(ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(V鸬户诱庐疯蠶緙。( *(t *)(ap += _INTSIZEOF(t) - _INTSIZEOF(t) 铴)閻纭释軹澗炀。 ( ap = (va_list)0 )#define _I
16、NTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & (sizeof(int) - 1) ) 穩赓諸諼谕贱酱。 #define _crt_va_start(ap,v) #define _crt_va_arg(ap,t) #define _crt_va_end(ap) 实例:注意括号内得省略号 */#include "stdafx 、 h" #include "stdio 、 h" #include "string 、 h" #include "stdarg 、 h" /
17、* 至少需要一个确定得参数, int demo(char *fmt, 、 ) va_list argp; int argno = 0;char *para;va_start(arg p, fmt);while (1)para = va_arg(arg p, char *);if (strcm p(p ara, "") = 0)break;printf("P arameter #%d is: %sn", argno, p ara); argn o+;va_e nd(arg p);return 0;int mai n()demo("DEMO1&qu
18、ot;, "This", "is", "a", "demo!", ""); return 0;运行结果:Paraineteris :Thisttiis :isParaneteris :aFaranetertt3I?=dena*1.2.3.4.函数得参数与局部变量都就是存储在栈里栈得内存分配就是按从高地址到低地址分配得(而其她得正常就是从小到大分配,比如全局变量定义等),即先分配高地址得,再分配低地址得内存枫賡鐫脉钾蝕颍。所有得函数参数(不管就是定长参数还就是变长参数)入栈都就是从右到左入栈,如调
19、 函数a(x,y,z),则z先入栈,并存在栈底(高地址),其次y,其次x。枫揚奮掺糴摜剂。数据在内存里得存储默认都按照字节对齐来存储(X86按照4字节对齐),如:int aaa(char a, char b, char c)retur n (in t)(a+b+c);调用函数aaa(5,6,7);时,内存中就是这样得:IMI:OxCOlZfcfOUU1(IEII uanUUUbuuuuuuUU12I-LI-HU>ttUHDHUUUUUUH肿»ui7Fi-iiuUUPHnnmimi/f1值0 29汕酮2F(?F0 ”¥E fcb8K8012fer41+1 be H H
20、H . . H H H H H . H OKQOlZFeFS,则会把指针廟璦缡所以,如果就是数值,则会直接存储在栈中,如果就是指针类型(如字符串) 值(即字符串首地址得值)存储在栈中,从右到左依次按照从高地址到低地址存储。 龔驀赙輒。如实例得程序调用 demo("DEMO1", "This", "is", "a", "demo!", "");得到得堆栈为:呐闕廁鉚縈吓耻。arqp;ittt jryno = V: rhnr ipjri;« Fnt):ubilr (1J
21、par# - va arqCarqpch-ar >M fstrcAf(para, "1 ) brpjh:pri ntf("Paraiwtrr vVf 1咛=片prrino. argno*:return ;inkr>d jn()弓 上T它山上E.Whjir气iia=若It曰fmtxDtlrlD EFFTDR mrrfFH 叮 ZBP IBVI-tl-Uhu m?FF fin IBIZFFIDccccccccdUpc2UAH7UMtaa542BDktflUiuWUM«» eu?FCCCCccCCttCcccocCtcccucc< H nr
22、Btl JU C> IRL E芯“神垃垃枷氓強建 CI722ACCUC9 出匸 xjuEJCU即0x0012FEFb开始往低地址方向得部分为此函数得栈空间,存入得值分别为0x00422058 , 0x0042204C,0x00422034 , 0x00422044 , 0x0042203C, 得实际上就就是静态存储区存储”,”emo!", "a", "is","This","DEMO1"浹。H)fe 址:eQU22028642e733A202573dis:竜sQQU22030onoe0000l6Q7
23、300皿.15._QBU22038BeQB»eee45即D即FDEMO盹42204031oeQB5目6869731.This盹踊SDeoeeeee00BO朋 3 QQ422Q5665«F2100003ad e HID t.QB422058oeQSeeeeeeBOeoea0凹220厲600oe00000000000Q1I22O680000ee00000000oa0x00422038另:如果改成 图蘋龈齊謝鰍栊刍demo("DEMO1", 1,2, "a", "demo!", ”);则其中得数字地址:0xa012fee
24、40ei2FEEl|餉2e420001000000eO12FEEC02ee00e»44204200O012FEF11562042o»SS2042000012FEFCUO000000oeOUBQeaDei2FFe«toec«FD7FccCCCCccaB12FF0CccccCCCccCCCCCGBB12FF1*lccccCCCCccCCCCCGXZJUa tfnt0x00422038,这6个地址分别所指向得地方,见图 濁鉗籬镉镄缤1,2直接保存在栈中,见0 B.3 G_5. #define _INTSIZEOF( n)得运算结果实际上就就是当 数傷騎騙埚呓鯛
25、還。其结果实际上就就是一个参数所占得空间大小,所以每次调用 里只需移动_INTSIZEOF(r长度就对了。6. 所以实际上变长参数得实现原理很简单,明栈中保存这些参数得长度就是多少,(sizeof(n) + sizeof(int) - 1) & (sizeof(int) - 1)输窮苋鸲與點闥1<=sizeof(n)<=4 时取 4, 5<=sizeof(n)<=8 时取 8即va_arg取参数时,赣渙諄哜眾謊厅。不过要注意一点,就就是由于没有哪个地方表 所以其实调用va arg逐个取里面得参数时,4得倍va_arg就是HCXKtKKI匕上 apECJiXiKU
26、; tiTtr: Op4e!LH-l2f=ee4 9地址传递得实质也就是值传递,只就是通过地址来可以对实参进行操作; 引用传递就就是在定义函数得时候各参数加一个 &取地址符号,其她得都跟值传递一样 使用,同样可以改变实参变量得内容。引用传递实际上跟地址传递过程就是一样得,只 就是函数压栈得时候由于函数(以引用参数部分得实例为例)得参数定义为voidExchg3(int &x, int &y),所以就告诉编译器压栈就是要压调用者Exchg3(a, b)实参a,b得地址,即&a与&b,而在void Exchg3(int &x, int &y)
27、函数内部使用得时候就是用x与y,即*(&x)与*(&y),所以其实就是与地址传递完全一样得,只就是换了一种表达形式而已,编译成汇编语言后就是一模一样得。 懍嗩嵘婭幂蒇镍。 函数参数传递过程就是在一个新得栈空间中对实参进行压栈,然后在函数内部读取这些栈内得数据得过程,只不过如果在函数定义时参数就是数值型得话(例如值传递得intaaa(int a, int b, int c) )就将这个参数得值压栈,如果在函数定义时参数就是地址型得话(例如地址传递 int aaa(int *a,int *b) 与引用传递 int aaa(int &a, int &b) )就将地址值
28、压栈。 所谓在新得栈空间中压栈实质就就是把当前需要压栈得数值或地址按照一定次序拷贝 到新得栈空间中。 錐鵝籜嫵銜賧鎖。函数压栈过程与汇编程序对应解析3.不知道取多少得,所以需要: 樺挚虧獎蘚擴庙。1) 、从demo(n,)得第一个已知参数 n传入,例如demo(4,1,2,3,4)2) 、或者从demo(string,)得string中利用格式化字符串来间接标识后面有多少个参数,例如demo( fest1=%s,test2=%d",str,i)通过判断得个数来得到要调用 2遍va_arg (其实 这种有种简便得方法就就是调用 va_start 后直接使用 sprintf 或者 vsp
29、rintf 或者 vnsprintf 来打印格式化得字符串) 賽缩荭禄蔣悦鯇。3) 、或者通过实例中那样最后一个用0 来标识4) 、或者还有其她得方法,总之需要有所标识然后再在函数里做相应判断,使 va_arg 得调用次数正确。总说明 :1.2.附:传值方式 C 语言代码: void changefunc(char a, char b) char temp; temp=a; a=b; b=temp;int main()char x=5,y=6; changefunc(x,y);demo("DEMO1", 1, 2, "a", "demo!&qu
30、ot;, "");return 0;编译成汇编对应得代码:8: 0040D880 push ebp-步骤 5、将 ebp 得值 0x0012ff48 压栈,此语句执行后 esp=0x0012fee4=M-0x10,ebp=0x0012ff48 測还蕁鳆錫頏缯。- 步 骤 6 、 此 语 句 执 行 后0040D881movebp,espesp=0x0012fee4=M-0x10,ebp=0x0012fee4 騰举鳐毿戇飛沒。0040D883subesp,44h- 步 骤 7 、 此 语 句 执 行 后esp=0x0012fea0=M-0x54,ebp=0x0012fee4
31、44h 为编译器预留得栈空间,提供函数内申请 局部变量等使用(这个值得大小编译器会自动根据实际函数使用空间来定,无需上层干涉) 铤嶇领鹂鈁饬龚。0040D886 push ebx esp=0x0012fe9c=M-0x58,ebp=0x0012fee4 0040D887pushesiesp=0x0012fe98=M-0x5c,ebp=0x0012fee4 0040D888pushediesp=0x0012fe94=M-0x60,ebp=0x0012fee4 0040D889 0040D88C锲颧荛闞緇鋸籃玛鲲驚壟赣鍛压这訶鳌戆诚针緱leamov0040D891mov- 步 骤- 步 骤- 步
32、骤8、9、10 、此语句执行后此语句执行后此语句执行后0040D8969:10:0040D898rep stos char temp; temp=a;movedi,ebp-44h ecx,11h eax,0CCCCCCCCh dword ptr edi0040D89Bmoval,byte ptr ebp+8 byte ptr ebp-4,al11:0040D89Ea=b;mov0040D8A1movcl,byte ptr ebp+0Ch byte ptr ebp+8,cl12:0040D8A4b=temp;mov0040D8A7movdl,byte ptr ebp-4 byte ptr ebp
33、+0Ch,dl13: 0040D8AA popedi- 步 骤11 、此语句执行后esp=0x0012fe98=M-0x5c,ebp=0x0012fee4懒启駔驗绒为杨。0040D8AB popesi- 步 骤12 、此语句执行后esp=0x0012fe9c=M-0x58,ebp=0x0012fee4灃鹰纸瞼側亵夺。0040D8AC popebx-步骤13 、此语句执行后esp=0x0012fea0=M-0x54,ebp=0x0012fee4矶詠瘫锡诟輦毕。0040D8AD movesp,ebp- 步 骤14 、此语句执行后esp=0x0012fee4=M-0x10,ebp=0x0012fee
34、4蚬嘗傯邮贴呐锵。0040D8AF popebp-步骤15 、此语句执行后esp=0x0012fee8=M-0xc,ebp=0x0012ff48 徠鍬潆齟没祷喽。0040D8B0 ret- 步 骤16 、此语句执行后esp=0x0012feec=M-0x8,ebp=0x0012ff48 苁擲惯渎鱧蝼蔼。33: int main()34: 004010F0pushebp004010F1movebp,esp004010F3subesp,48h004010F6pushebx004010F7pushesi004010F8pushedi004010F9leaedi,ebp-48h004010FCmove
35、cx,12h00401101moveax,0CCCCCCCCh00401106rep stosdword ptr edi35:char x=5,y=6;00401108movbyte ptr ebp-4,50040110Cmovbyte ptr ebp-8,636:changefunc(x,y);-步 骤 1 、 此 时esp=0x0012fef4,ebp=0x0012ff48记 0x0012fef4 值为 M 岿嵝錒骖误釩飑。00401110moval,byte ptr ebp-800401113pusheax-步骤2、将y得值6压栈,此语句执行后esp=0x0012fef0=M-4,ebp
36、=0x0012ff48 歡鹦诈缀傖贐與。00401114movcl,byte ptr ebp-400401117pushecx-步骤 3、将 x 得值 5 压栈,此语句执行后esp=0x0012feec=M-8,ebp=0x0012ff48 骋骣诜鈔討颟氽。00401118callILT+65(changefunc) (00401046)-步骤 4、行00401046就是一条跳转 语句 jmpchangefunc(0040D880), 压 入 返 回 地 址 , 所 以 跳 转 后esp=0x0012fee8=M-0xc,ebp=0x0012ff48 訶队譾搅顎帼离。0040111Daddes
37、p,8-步骤 17、因为 call2*4 ,此语句执Changefunc函数之前有2个参数压栈,所以要恢复此前得esp,就需要加上行后 esp=0x0012fef4=M,ebp=0x0012ff48 烁歿头签哝離认。37:00401120pushoffset string "" (00422038)00401125pushoffset string "demo!" (00422058) 乡驕瓔頤惫肾紂。0040112Apushoffset string "This" (00422044) 緄纵讴綿諉讹紓。0040112Fpush200
38、401131push100401133pushoffset string "DEMO1" (0042203c) 鴻撫獫顧阵资鱒。00401138callILT+5(demo) (0040100a)0040113Daddesp,18h38:return 0;00401140xoreax,eax39: 00401142popedi00401143popesi00401144popebx00401145addesp,48h00401148cmpebp,esp0040114Acall_chkesp (00401270)0040114Fmovesp,ebp00401151popebp
39、demo("DEMO1", 1, 2, "a", "demo!", "");00401152 ret7. EBP与 ESPEBP Exte nd base poi nter:用于存取栈得指针ESP Extend stack pointer:栈顶指针ESP就就是一直指向栈顶得指针,而EBP只就是存取某时刻得栈顶指针 地址按照从小到大排列,压栈都就是从高地址从低地址压栈,栈顶esp某时刻临时保存 得栈指针ebp0x0012fee00012FEEOeo08eeOSoo00saoeeO12FEES02eoeeOQ4C32e
40、e6012FEF083000000no000000CB12FEFe00eooeoeeeCOFO7F0012FFeOccccccccccccccCCccccccccccccccCCeD12FFieccccccccccccccccCei2FF18ccccccccccccccccCB12FF2BccccccccccccccGGfiO12FF2eccccccccccccccCC0012FF30ccccccccccccccCC8. 多个字符串可以直接连在一起写如:#defi ne P RINT(NAME) prin tf("to""ke rr#NAME"=%dn&
41、quot;, NAME)颢滤鮑兒鏡齐洶。 a=1; PRINT(a); 得结果就就是toke na=1;9. 大小端得记忆口诀小弟小,大弟大。即小端低位在小得地址,大端低位在大得地址。一般x86使用小端,Powerpc使用大端,ARM可以设置使用大端还就是小端10. 函数名得使用函数名可以理解为就就是函数得入口地址(指针常量)1.,在使用函数名时,如果只使用函数名进行赋值,后不带(),则会直接使用函数入口地址,例如:函数指针pfunc=func;此时会把函数func得入口地址赋给函数指针pfunc棗懸惮酱馁飾輝。2.3.如果函数名后带(),则编译器知道就是调用函数,就会跳转到函数得入口地址。t
42、est就是一个函数名,则 test,&test与*test得值都就是函数得入口地址,*test可以这样理解,test就是函数得入口地址,*test就是取函数入口地址所指向得,也就就是函数名,=test,而函数名也就是函数得入口地址,所以*test得值也等于函数入口地址。棄铯饭吳滗双儻。11. 指针函数与函数指针指针函数就是个函数(返回值就是一个指针得函数)函数指针就是个指针变量(只能指向 函数得指针)指针函数 : int *a(int x,int y) 就就是指针函数, ()得优先级高于 * ,所以就是先 a(int x,int y) ,表 示函数,又因为返回值就是指针,所以就声明函数
43、就是指针类型得,所以就在其前面加 否则如果没有不加 * 得话, 緞駕靈烫倾窮诠。int *ret;int a(int x,int y);ret = a(1,2);最后一句ret = a(1,2);就会出错,因为等号左边就是个指针,而右边却就是个数值,编译会报错。函数指针 :强调就是个指针变量,所以变量名前得*要用 ()括起来(为了与指针函数区分) ,例如 (*a), 又因为就是只能指向函数得,所以指针变量后要跟与其对应得函数一样得参数列 表,例如int (*a)(int x, int y),这表示它就是个指针变量(因为 *a就是用()括起来得),就是 个指向函数得指针变量。 鲍澗暢诬讕嶧談。函
44、数指针只就是在声明得时候强制一定要使用(*a)(参数)这种形式,在使用得时候(赋值与调用)可以随意,就是否使用*都可以,比如: 请枫諢網珲荜糝。int (*a)(int x,int y);/ 声明int test(int x,int y)a=test; /使用,也可以*a=test,或者a=&test,或者*a=&test,都一样得稱寵濃戋呛殯钏。 a(1,2);/使用,也可以 (*a)(1,2)因为函数指针得作用就一个, 就就是指向函数, 所以不管怎么写, 都就是要使用所指向得函 数,没有歧义,所以为了使用者不至于不好理解应该怎么写,随便爱怎么写就怎么写。缗墜鴯轧曠间诨。另外
45、:函数指针数组得写法就是 int (*a )(int, int) 可以对比定义指针数组 int *a 资确铍昼 辑訌艫。12. 用 tepedef 定义函数指针得类型使用方法就是:定义: typedef void (*INTFUNC)(int)声明: INTFUNC pfunc; 当成普通得定义变量一样 例如:typedef void (*INTFUNC)(int)void aaa(int x)void main()INTFUNC yyy; yyy=aaa;13. 开头得数值会被视为八进制数例如 printf( “%d”,021); 结果打印 17 而非 21 ,因为八进制得 21 就就是十进
46、制得 1714. 多维数组与指针1.2.3.4.二维数组实际上就就是数组得数组,多维数组就就是数组得数组得数组二维数组定义 :类型 数组名 行总数 列总数 例如 int a23=1,2,3,4,5,6;amn可以理解为a得第一维元素个数就是m,第二维为n,即a中有m个元素,m个元素当中每个元素有 n 个元素,所以最后一个就就是最小维得,所以最里头得数组得长 度要瞧最后一维得数字。 记樣忧价烦鲥櫝。下标运算符:am完全等价于*(a+m) , amn完全等价于 *(*(a+m)+n) 指向多维数组得指针定义 ,例如指向 int a50100 得定义 int (*p)100=a; 这样定义就 是表示
47、 p 就是一个指向具有长度 100 数组得指针(而不就是指针数组) ,类似地,三维 数组可以这样定义: 拣踊诗藓轹擲钽。inta234=111,112,113,114,121,122,123,124,131,132,133,134,211,212,213,214,22 1,222,223,224,231,232,233,234; 數冪冯憂鋒餒瞞。int (*p)34=a;使用时 ,指针就相当于跟数组名完全等价了,完全可以像 p122 这样来使用,也可以 用*(*(*( p+1)+2)+2) 湿刪寵暢鵪谍鷴。注意!1)、一定要用()括起来(*p),表明P就是个指针,而不就是指针数组(如果没有括号
48、,就 变成了指针数组了)2)、定义指针时,总比对应得数组少一维(少第一维),也就就是指针运算并不需要知道第一维得长度。 (可以这样理解记忆:指针算一维,所以指针那一维代替了第一维,因 为像一维得时候 int a2=1,2; int *p=a; 相当于指针算作一维了。 )縲戰狹艱贩爭產。15. do while 语句与 while 语句do while语句得语法就是:do语句while(表达式);while 语句得语法就是:while( 表达式 )语句 注意! do while 语句后面有一个 ”;”而 while 语句没有因为c语言在编译阶段会把所有得空格与回车都忽略掉,而如果do语句whil
49、e(表达式)后面没有;得话,会引起误解,以为while就是跟下一句与在一起得, 所以必须要;号来隔开,while(表 达式 )则不需要,因为有 ,如果没有 得话,也会就是一条语句,而语句后面就有 ;,所以不 会因为误解,不需要 ; 。惧马幟屿轅麸鳩。16. main 函数参数C语言规定可以带2个参数:int main(int argc, char *argv)第一个参数就是 int 型,表示操作系统传递上来给 main 函数得参数个数,第二个就是个指 针数组(字符串数组)例如:int main(int argc, char* argv) char *p=argv;printf("ar
50、gc=%d",argc);doprintf("argv=%sn",*p);*p+;while(-argc>=1);return 0;这个函数编译出来为test3、exe,然后在dos命令行中调用,得到:D:>test3 、 exe aaa bbb cccargc=4argv=test3、 exeargv=aaaargv=bbbargv=ccc其中,test3、exe文件名本身也算一个参数,所以dos命令行调用test3、exe时,操作系统传递给test3、exe得实参实际上就就是参数个数就是4,参数为鍺睜滯剑處鎣刚。“test3、 exe”,“aaa”
51、,”bbb ”,”ccc”,如17. 哪些语句句尾要用分号?C 语言规定,所有得语句必须要以分号;结尾,而预编译命令不属于语句,末尾不加分号#include #if #else #elif #endif #define 等嫒療釵馱摈铅唄。18. volatile 关键字得作用volatile 修饰得量就是不稳定得,可能会经常被改变或者被其她线程使用并改变其值,所以 用 volatile 关键字就限制了执行器在执行得时候每次访问其值必须去内存中去取,而不能被 编译器优化在内部寄存器中。 據储鶻桤懒纳鉦。19. typedef 得用法用于对普通数据类型定义别名:例如, typedef unsign
52、ed int UINT;用于定义指针:例如,typedef int *PINT;(注意!虽然*与PINT之间没有空格,但就是实际上跟 typedef int* PINT 就是一样得, *就是跟前面得结合得。 )闳縟阑劳闻缗惱。 用于对结构体 /枚举 /联合体类型定义别名:例如:typedef unionint uid;unsigned char mid; ID_U;用来定义数组:例如 ,typedef int aNum2; aNum x;用来定义函数相关 ,一般都就是定义函数指针:例如typedef int (*pf)(int, char);用来简化复杂得定义,其实就就是前面几个得综合。 注意
53、!定义普通类型与指针以及结构体 /联合体 /枚举,都就是“ typedef 原定义 别名;” 得方式,而定义数组与函数指针就是按照“替换原定义得变量”得定义方式来定义,就 是不同得。 硨离殡铄铄聽识。typedef 使用范例 :#include "stdafx 、 h"1.2.3.4.5.6.#include "stdio 、 h"typedef unsigned int UINT; typedef structUINT uid;char mid; STU_T;typedef STU_T *STU_T_REF;typedef int aArray2;typedef void (*fFunc)(int); void print1(int x)printf("%d",x);int main(int argc, char* argv)UINT i=3;STU_T st1; STU_T_REF tStu; aArray b;fFunc fTestPrint;tStu = &st1;tStu->uid = i;b0=1;b1=2;fTestPrint = &print1; fTestPrint(tStu->
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 医管科岗位工作制度
- 医院医调办工作制度
- 医院质控科工作制度
- 华谊新材料工作制度
- 南充市弹性工作制度
- 卫生室各项工作制度
- 卫生院会计工作制度
- 卫生院药具工作制度
- 危险品自查工作制度
- 县委资料科工作制度
- DB29-296-2021 海绵城市雨水控制与利用工程设计规范
- 资源教室工作方案设计
- 新供应商QSA-QPA审核checklist及审核报告
- 2015版ISO90001标准课件教学
- 溺水自救与施救课件
- GB/T 12451-2023图书在版编目数据
- 年产万吨电铜电解车间的设计
- 无机及分析化学说课
- 家庭装修施工合同
- 2021年湖南省衡阳市国家公务员公共基础知识真题二卷(含答案)
- 物业品质服务提升计划表最终版
评论
0/150
提交评论