软件研究室培训(C语言)

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

C语言主要内容一、学习编程语言的一些建议二、指针三、预处理器四、结构、联合和枚举五、sizeof六、参考书籍和资料(1)多动手学习编程唯一方法是编写调试程序。看再多的书,效果也比不上设计调试一个简单程序。(2)养成良好的编程习惯养成好习惯很难。所以良好的编程习惯要从一开始培养。(3)注意细节不应漏过任何一个技术细节。只有细节的日积月累,才能有技术上的提高。(4)了解开发环境在学习编程语言的同时,也需要了解编程语言的开发、使用环境。如硬件平台(51、MSP430、PC)、操作系统(uCOS、Linux、DOS)、集成开发环境(KeilC,BorlandC)等。(5)多看书、勤思考很多国外的经典书籍是由拥有几十年经验的质深程序员编写的。这些书里最重要的是融入了作者多年的编程经验。多看书,再结合自身平时的积累,不断思考总结是提高编程技术最有效的办法。第一章学习编程语言的一些建议第二章指针2.1指针的基本概念2.1.1指针是什么?指针是一个变量,它的值是另外一个变量的地址。例12.1.2指针的类型指针所存储的那个变量类型,就称为指针的类型。例2有三个不同类型的指针:intI[2],*pI=&I[0];右边的三个运算有何不同?pI++;charC[2],*pC=&C[0];pC++;floatF[2],*pF=&F[0];pF++;0x00C7指针变量int*p0x00C7变量inta上面例中的两个0x00C7有什么区别?2.1.3指针的三个要素1.指针指向的地址(指针的内容);2.指针指向的地址上的内容;3.指针本身的地址。例3:intA,*pA,**ppA;pA=&A;ppA=&pA;在复杂的指针都可以通过下表来分析:&ppAppA*ppA**ppA&pApA*pA&AA第二章指针第二章指针2.1.4指针的大小(指针变量占用的内存空间)与所用的CPU寻址空间大小和类型有关,而与指针类型无关。8位CPU的指针长度为1~2个字节(51单片机的情况较为复杂,是1~3个字节);16位CPU的指针长度为2个字节(如MSP430);32位CPU的指针长度为4个字节(如Intel80386)。上面所述是通常情况,并不是全部符合。第二章指针2.1.5指针的初始化变量在没有赋值之前,其值不定的。对于指针变量,可以表述为:指向不明。程序访问了一个没有初始化的指针:int*p;p的内存是随机的一个数,比如:0x3FF0073D程序随即访问内存地址:0x3FF0073D0x3FF0073D是哪里的内存?说不定正好是Windows老大要用的内存,你竟敢访问!Windows一生气,蓝屏。一个指向不明的指针,是非常危险的!!!因此,指针在使用前一定要初始化;在使用前一定要确定指针是非空的!!!第二章指针2.2数组与指针对于数组的两个概念:1.C语言中只有一维数组,数组的大小必须在编译时作为一个常数确定下来。数组的元素可以是任何类型,甚至是数组,由此可以方便地得到多维数组;2.数组的任何操作,即使采用数组下标进行的运算都等于对应的指针运算。可以用指针行为替代数组下标的运算。例4:inta[4],*p;p=a;//等价于p=&a[0];*(a+2)=0;//等价于a[2]=0;p[2]=0;//等价于a[2]=0;但数组不同于指针:数组名a是指向数组起始位置的“常量”。因此,不能对数组名进行赋值操作。例5:inta[4],*p;p=a;//正确a=p;//错误p++;//正确a++;//错误第二章指针第二章指针2.3空指针与通用指针(1).空指针是个特殊指针值,也是唯一对任何指针类型都合法的指针值。一个指针变量具有空指针值,表示它当时没指向有意义的东西,处于闲置状态。空指针值用0表示,这个值绝不会是任何程序对象的地址。给一个指针赋值0就表示要它不指向任何有意义的东西。为了提高程序的可读性,标准库定义了一个与0等价的符号常量NULL,程序里可以写:p=NULL;//注意不要与空字符NUL混淆,NUL等价于‘\0’或者:p=0;注意:在编程时,应该将处于闲置的指针赋为空指针;在调用指针前一定要判断是否为空指针,只有在非空情况下才能调用。(2).通用指针通用指针可以指向任何类型的变量。通用指针的类型用(void*)表示,因此也称为void指针。下面的第三行定义了两个通用指针:intn,*p;double*q;void*gp1,*gp2;可以直接把任何变量的地址赋给通用指针。例如,有了上面定义,下面赋值是合法的:gp1=(void*)&n;可以把通用指针的值赋给普通的指针。如果被赋值指针与通用指针所指变量的类型不符,需要写强制转换:p=(int*)gp1;第二章指针第二章指针2.4函数指针2.4.1函数指针的定义函数指针即指向函数地址的指针。利用该指针可以知道函数在内存中的位置。因此也可以利用函数指针调用函数。函数指针的定义方法:类型(*函数指针名)(......)例如:int(*func)(void)这里,func就是一个函数指针。注意:int*func(void)和int(*func)(void)的区别int*func(void);//这是返回一个整型指针的函数int(*func)(void);//这是一个函数指针2.4.2函数指针的使用例6:假定有下面的函数声明intptr;intfn(int);int(*fp)(int);指出下面的语句是否合法?,为什么?。fp=fn;//正确,将函数fn的地址赋给fpfp=fn(5);//错误,返回给fp的结果不是一个函数地址。fp=&ptr;//错误,ptr的地址不在程序代码区,两种数据类型不能转换。从上面的例子可以看出:(1)不能将普通变量的地址赋给函数指针;(2)不能将函数的调用赋给函数指针(3)可以将函数名赋给一个函数指针第二章指针第二章指针2.4.2函数指针的用途一旦函数可以通过指针被传递、被记录,这开启了许多应用,特别是下列三者:1.多态(polymorphism):指用一个名字定义不同的函数,这函数执行不同但又类似的操作,从而实现“一个接口,多种方法”。2.多线程(multithreading):将函数指针传进负责建立多线程的API中:例如Win32的CreateThread(...pF...)。3.回调(call-back):所谓的回调机制就是:「当发生某事件时,自动呼叫某段程序代码」。事件驱动(event-driven)的系统经常透过函数指针来实现回调机制,例如Win32的WinProc其实就是一种回调,用来处理窗口的讯息。2.4.3函数指针数组例7:在一个计算器的例子中,有如下一些语句:switch(oper){caseADD:result=add(op1,op2);break;caseSUB:result=sub(op1,op2);break;...}对于一个复杂的计算器,switch语句将非常长。我们可以用函数指针数组来完成。doubleadd(double,double);doublesub(double,double);...double(*oper_func[])(double,double)={add,sub,...};第2个步骤是用下面语句替换前面整条switch语句:result=oper_func[oper](op1,op2);oper从数组中选择正确的函数指针,而函数调用操作符将执行这个函数。第二章指针第三章预处理器3.1预处理器的作用可以将预处理器看作为一个文本编辑器。它只对程序的文本起作用,而不会进行其他任何依赖于C语言语法的工作。它负责在正式编译前将源程序进行转换,替换宏定义、删去无需编译的代码、插入包含的文件等等。出于几个主要原因,预处理器为我们提供了一些简化的途径:首先,可以通过改变一个数字并重新编译程序来改变一个特殊量的所有实例。其次,可以定义一些东西,它们看起来象函数但没有函数调用所需的运行开销。例如,putchar()和getchar()通常实现为宏以避免对每一个字符的输入输出都要进行函数调用。第三章预处理器3.2#define3.2.1带参数的宏定义当需要有一个程序块,看上去和用起来像函数一样,但是没有函数调用时的开销时,可以采用宏定义。宏定义可以象函数一样带参数,如:例8:#defineAdd(a,b)((a)+(b))注意:(1)括号的作用预防由运算符优先级引起有关的问题。例9:#defineAdd(a,b)a+b……Average=Add(Num1,Num2)/2;例中,运算式最终由预处理器展开为:Average=Num1+Num2/2;(2)不要忽视空格的作用例10:#definef(x)((x)-1)……Num=f(Num);上面这个语句会被展开成什么,a还是b,为什么?a.Num=((Num)-1);b.Num=(x)((x)-1)(Num);(3)宏不是类型定义例11:#definePWORDint*typedefPBYTEchar*;……PWORDpA,pB;//pB是什么类型?PBYTEpC,pD;//pD是什么类型?第三章预处理器3.3#include和#include“”有什么区别?#include:在使用时,编译器将会到指定的系统或标准头文件目录查找头文件。通常用于标准或系统提供的头文件。#include“”:在使用“”时,编译器将会到用户创建的项目文件所在目录查找头文件。通常用于程序自己的头文件。例12:#includestdio.h#includemath.h#include“disp.h”#include“output.h”第三章预处理器第三章预处理器3.4条件编译(1).条件编译可以按照不同的编译条件,组织成不同的代码。例13:#defineMCS51……#ifdefMCS51Baud=9600;#elifMSP430Baud=4800;#elifPC104Baud=115200;#endif……(2).条件编译可用于调试。将用于调试的语句放入条件编译中。例14:#defineDEBUG……TotalNum=a+b;#ifdefDEBUGprintf(“Thetotalnumis:%d”,TotalNum);#endif……当程序调试结束后,只需将#defineDEBUG一句取消,即可将程序中所有的调试语句删去。第三章预处理器(3).在通用的模块中,可以通过条件编译实现功能的可裁减。例14:#defineTMR_SET_EN……#ifdefTMR_SET_ENvoidTMR_Set(chartmr_init,chartmr_mod,chartmr_fnct){……}#endif……如果不需要TMR_Set功能,只需将#defineTMR_SET_EN语句删除即可。轻松实现TMR模块的可裁减特性。第三章预处理器(4).在宏定义时,避免重复定义。例15:#ifndefTRUE#defineTRUE1#endif#ifndefFALSE#defineFALSE0#endif第三章预处理器第四章结构、联合和枚举4.1结构体结构是由若干(可不同类型的)数据项组合而成的复合数据对象,这些数据项称为结构的成分或成员。(1)字段C语言的结构还提供了一种定义字段的机制,使人在需要时能把几个结构成员压缩到一个基本数据类型成员里存放,这可以看作是一种数据压缩表示方式。例16:structpack{unsigneda:2;unsignedb:8;unsignedc:6;}pk1,pk2;结构变量pk1或者pk2的三个成员将总共占用16位存储,其中a占用2位,b占用8位,c占用6位。(2)结构体内部的成员的对齐在计算结构体长度(尤其是用sizeof)时,需要注意!根据不同的编译器和处理器,结构体内部的成员有不同的对齐方式,这会引起结构体长度的不确定性。例17:#includestdio.hstructa{chara1;chara2;chara3;}A;structb{shorta2;chara1;}B;voidmain

1 / 40
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功