[总结]C语言真是博大精深(一)

易忽略的C语言细节(上)

(最终解释权归原作者所有,侵权必究)

1、编辑(.c)à 编译(.obj)à 连接(.exe)

   .c文件à(预处理)à.i文件à(编译)à.s文件à(汇编)à.o文件à(链接)à可执行文件

2、整型常量后加l或L è long;整型常量后加u或U è unsigned;实型常量后加f或F è 单精度;

实型数存储:数符  尾数  阶符  阶码

3、转义字符:\a:响铃,\b退格,\r回车不换行,\f换页,\ddd 1~3位八进制数所代表的字符,\xhh 1~2位十六进制数所代表的字符

4、不把输入输出作为C语言提供语句的目的是使C语言编译系统简单,因为将语句翻译成二进制的指令是在编译阶段完成的,没有输入输出语句就可以避免在编译阶段处理时出现与硬件有关的问题,可以使编译系统简化,而且通用性强,可移植性好,对各种型号的计算机都适用。

5、修正符:0:高位补0;+:输出+/-号;-:左对齐;l/L:双精度型数据的输入要用此修正;h/H:短整型数据的格式控制;*:表示输入项在读入后不赋给相应的变量。

6、格式符:%g:按照数值的特点,自动选择合适的浮点数形式输出;%u:十进制无符号整数的输出;%p:指针的的值的输出;%e:用于指数形式的浮点数的输出;%x:用于以十六进制表示的无符号整数的输出;%o:用于以八进制表示的无符号整数的输出

7、在整数0~127范围内,用”%c”和”%d”均可正确输出。如果输出的参数时整型,格式控制符使用%c时,输出的是字符。如果输出的参数是字符型,格式控制使用的是%d,输出的是字符对应的ASCII码值。在整数范围128~255范围内,如果输出的参数是整型,格式控制使用%c,输出的是一些特殊字符。如果输出的参数是字符型,用大于127为其赋值,由于字节最高位为1,输出用%d时,得到的是一个负整数。如果不想按有符号处理,可以将字符变量定义为unsigned char类型,其取值范围是0~255。

8、格式控制符x、e、g可以用小写字母,也可以用大写字母,其他必须用小写字母。

9、当需要输出字符%时,在格式控制字符串中要用两个连续的%表示。当需要输出字符\时,要用两个\表示。

10、scanf中的%c处理:缓冲区中有数据,取走排在队头的第一个字符,存放到对应的char型变量空间里。缓冲区无数据,等待用户从键盘输入数据,回车后按有数据处理。

11、双精度数据输入时,格式输入函数必须使用”%lf”格式符。

12、随机数的生成:0~32767:给srand()提供一个随机数的种子;调用rand(),它会根据提供给srand()的种子值返回一个随机数;根据需要多次调用rand(),从而不间断地得到新的随机数;无论何时,都可以给srand()提供一个新的种子,从而进一步对rand()的输出结果随机化。要调用库函数产生随机数的函数,需要在程序中加入库函数头文件#include<stdlib.h>。 RAND_MAX是一个系统预定义好的常量,它表示最大随机数整数。如果每一次执行程序要产生不同的随机数序列,则在调用函数rand()之前先调用srand((unsigned int) time(NULL))或srand(time(0));函数time()的头文件是#include <time.h>。该处理方式可以使计算机读取当前的时钟值,并把该值自动设置为随机数的种子,类似的还有randomize(),它是个无参数的函数。在调用rand()函数产生随机数前,必须先利用srand()设好随机数种子,如果未设随机数种子,则默认为1,每次的随机数都是一样的。

13、产生一个0~整数m-1之间的随机数,用rand( )%m

  产生一个大于0且小于1的随机小数,用(float)rand()%RAND_MAX

14、数组初始化时初值数据比数组元素个数只能多不能少。否则会报错。

15、一维数组应用:冒泡法排序、直接选择排序、顺序查找、折半查找

16、多维数组的初始化可全部初始化、部分初始化和第一维长度省略初始化。

17、定义字符数组时,如果初始化{}中数据包含串尾字符’\0’时定义数组时可以省略数组长度。用字符串常量为字符数组初始化时可以省略定义中的数组长度。

18、scanf()只能读入不含空格的字符串。gets()输入的字符串中允许包含空格。

   puts()把一个字符串,输出到标准输出设备,并用\n代替字符串的结束标志\0,所以用puts()函数输出字符串时,不用另外加换行符\n

19、空指针:当指针的值为0时,用NULL表示,作为指针异常事件的标志。

   悬挂指针:如果只说明了指针变量,而没有为指针变量进行初始化或赋值之前,此时的指针变量存放的是一个随机值,对悬挂指针的目标进行访问是很危险的。

20、通用指针:可以指向任何类型变量的指针,指针类型用void *表示,也可称为void指针。

   注意:不能用通用指针表示其目标变量,即表达式(* 通用指针)是错误的,通用指针能指向变量,但不能像有类型的普通指针那样做取目标运算。将通用指针的值赋值给有确定类型的指针前,一定要做强制转换。

21、指针运算:指针+n,指针-n,指针++,指针--,指针相减(结果是整数)、指针相加没有意义。两个指针间的关系运算表示它们指向的变量地址位置之间的关系,即地址值的大小。不同数据类型的指针之间关系运算没有意义,指针与一般整型量之间的关系运算没有意义。

22、一维数组元素的不同表示方法:用数组名加下标表示;用地址计算公式表示;用指向数组元素的指针变量表示。注意:指针是地址变量,数组名是地址常量。

23、在处理一般数组时,要考虑的是数组的规模,而字符串,则是检查当前字符是否为串尾标志字符\0。字符串常量可以直接作为字符型指针初始化的值,可将一个字符串常量赋给指针,但不允许用指针变量修改字符串常量。读字符串时必须有足够的存储空间来存储字符串。

24、二维数组元素地址的不同表示方法:用变量地址表示&a[i][j];用列地址表示a[0]+i*4+j, *a+i*4+j,&a[0][0]+i*4+j;用行地址表示*(a+i)+j

25、行指针变量的说明:数据类型 (*行指针变量名)[整型常量表达式];如int (*p) [4];

   例:inta[3][4],(*p)[4]=a; 则a[m][n]元素可表示为*(*(p+m)+n)或p[m][n]。

   注意:()和*不可省略;[整型常量表达式]一定不能少,它表示一行中的元素个数,该指针每一次++,都将从当前地址跨过该个数据;用行指针变量引用二维数组元素时,行指针指向的行的大小必须与数组定义的列的大小一致。

26、在定义函数时,当函数的返回值类型为整型时,函数的类型说明部分可以缺省。

27、函数间参数的传递:值传递、地址传递。

28、传递数组时,允许将形参写成:数据类型 指针变量名[ ],方格[ ]中不要写任何整数,写什么整数,系统都将其忽略,编译时系统将其转换为:数据类型 *指针变量名的形式。

29、调用二维数组的形参:func(int d[][4]),func(int d[3][4]),func(int (*d)[4]),调用时都是func(a);即无论哪种方式,列下标是不能默认的。

30、传递二维数组的通用函数:将二维数组视为一维数组,传递二维数组首地址、行数、列数。在函数体中,用表达式*(指针变量+行下标*列数+列下标)或指针变量[行下标*列数+列下标]表示二维数组元素。

31、C语言中不允许函数的嵌套定义,允许嵌套调用。

32、根据变量的作用域,变量可分为局部变量(函数内部)、形式参数(函数的参数)、全局变量(函数的外部)。

33、如果再说明全局变量位置之前的函数要使用该全局变量,必须在函数内对全局变量进行声明。声明形式为extern 数据类型 全局变量名;

   注意:全局变量存在的问题:占用内存时间长;全局变量是所有函数都可以操作的量,任何一个函数对该变量的误操作都会影响到后面的结果,存在一定的危险;虽然增加了函数的联系,但降低了函数作为一个程序模块的相对独立性。

34、函数间传参:return表达式(1个);用函数参数的地址传递;全局变量

35、变量的存储类型:规定了该变量数据在内存中的存储区域。在不同存储区域的数据,有着不同的生存期。

   ① 具有自动经存储期的变量

auto型变量(堆栈型或自动型):用时申请,不用时释放,当存储类型默认时则说明该变量为auto型,且一定是局部变量。

register型变量(寄存器型):该说明符建议编译器把该变量装载到寄存器中。因为机器语言程序中的数据通常要装载到寄存器中才能用于计算和其他处理,如果频繁地使用诸如循环变量、计数器和累加和等变量,可以直接把它们装载到硬件寄存器中,这样可以避免过度频繁地把变量从内存装载到寄存器并把结果返回到内存。

② 具有静态存储器的变量

static型变量(静态型):在定义时分配了一定的内存空间,并且该空间在整个程序运行中,自始至终都归该变量使用。即使该类型的变量在退出说明它的代码块后,也不释放占用的空间。

extern型变量(外部参照型):当定义全局变量时如果默认说明存储类型,则说明其类型为extern,这一类型变量作用域不仅作用于整个文件的所有函数,还可以作用于其他文件。

注意:static和extern型变量都具有空间存储永久性,但不同之处是静态局部变量是全局寿命、局部可见,有继承性,而全局变量是全局寿命、全局可见。用static对全局变量加以声明,可以将作用域限制在定义该变量的文件中,不能被其他文件引用。auto和register未初始化时,初值为随机数;static和extern未初始化时,其初值为0;对static型局部变量的初始化仅被执行一次,再次执行该代码块时,不会执行初始化的工作。

36、函数的存储类型:只有static和extern两种。static定义的函数是内部函数,只能被本文件中的其他函数调用,不能被其他文件中的函数调用。extern定义的函数是外部函数,可以被本文件和其他文件中的函数调用。存储类型默认为extern。

37、指针型函数:返回值是一个数值的存储单元地址的函数,类型标识符 * 函数名(形参表)

38、函数指针:数据类型 (* 函数指针名)(形参表);函数指针的主要作用是将一个函数作为另一个函数的参数(回调函数),即C语言中可以将一个函数在主调函数和被调函数之间传递,这种传递不是传递数据,而是传递函数的执行地址,或者是传递函数的调用控制。当函数在两个函数之间传递时,主调一方的实参应该是被传递函数的函数名,而被调函数一方的形参应该是接收函数地址的指针函数。

  注意:数据类型是函数返回值类型;定义中两个括号都不能少;不能用悬挂指针;形参表要与函数形参表一致;当有一个函数指针指向一个函数的入口地址,此时调用函数可以用函数名加上实参表,也可以用函数指针变量的目标加上实参调用;函数指针不能++、--。

39、结构体类型定义是一条单独的复合语句,右花括号后一定要有分号。如果程序规模比较大,往往将结构体类型的定义集中放到一个头文件中,使用时用#include命令包含。

40、结构体变量的存储空间分配原则:一是结构体变量中成员的偏移量必须是成员存储空间大小的整数倍;二是结构体变量存储空间的大小必须是所有成员存储空间大小的整数倍(字节对齐方式)。因此若结构体调整成员次序,存储空间占用结果可能是不同的。

41、结构体初始化:struct 结构体名 结构体变量名={初始数据}

42、空间存储分配:静态存储分配、动态存储分配。头文件#include “stdilib.h”

43、malloc函数:void *malloc(unsigned int size)在内存的动态存储区分配一个长度为size的连续存储空间,并将此存储空间的起始地址作为函数值返回,该返回值是一个指向分配域起始地址的指针,该指针为通用指针,若执行失败,则返回NULL。可配合sizeof()使用。

注意:使用malloc函数时,一定要用强制类型转换将函数返回的地址转换成所申请空间的地址类型。若因空间不足,申请空间失败时,会影响程序执行,程序中应能处理此种情况。

44、calloc函数:void *calloc(unsigned n, unsigned size)在内存的动态存储中分配n个长度为size的连续存储空间,并将此存储空间的起始地址作为函数值返回,该返回值是一个指向分配域起始地址的指针。如果此函数执行失败,则返回NULL。

 int *p; p=(int *) calloc (10,sizeof(int)); 等价于p=(int *) malloc (10*sizeof(int));

45、reallic函数:void * realloc(void *mem_address,unsighed int newsize);先判断当前指针是否有足够的连续空间,若有,则扩大mem_address指向的地址,并将其返回。如果不够,先按照newsize指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来mem_address所指内存区域,同时返回新分配内存区域的首地址。失败,则返回NULL。

46、free函数:void free(void *p)。释放p指向的内存区域。

47、共用体:union共用体名{成员表项;}变量表列;/union 共用体名{成员表项;};union共用体名 变量表列;注意:通常共用体类型实际占用存储空间为其最长成员所占空间,若是该最长的存储空间对其他成员的基本数据类型不满足整除关系,该最大空间自动延伸。共用体采用覆盖技术,每一瞬间只有一个成员起作用。共用体不能初始化,不能对共用体变量赋值,不能引用共用体变量名来得到一个值,不能把共用体变量作为函数参数,也不能使函数返回共用体变量,但可以使用指向共用体变量的指针。

48、枚举类型:enum枚举类型名{枚举值表}枚举变量名表;C编译中,枚举值是常量,不是变量;枚举本身由系统定义了一个表示序号的数值,这个整数值是可以输出的,也可以改变枚举元素的值,在定义时指定,如enum weekday{sun=7,mon=1,tue,wed,thu,fri=9,sat}day;

   此时sun=7,mon=1,tue=2,wed=3,thu=4,fri=8,sat=9。枚举值可以用来判断比较,不能在程序中直接用赋值语句把数值赋给枚举变量,如day=2,如果一定要赋予枚举变量,需要强制类型转换,如day=(enumweekday)2;枚举元素不是字符常量也不是字符串常量,使用时不要加单双引号。不用整数值代替枚举值原因是一个枚举值直观,见词知意,二是枚举值有一定范围,便于编译系统检查错误。

49、typedef自定义类型:typedef 原类型 新类型名;宏定义#define是由预处理完成的,只能做简单的字符串替换;typedef是在编译时完成的,不是字符串替换,是采用定义的方式的一种声明,且是有作用域的。定义数组类型格式如typedef int ARRAY[100];

50、C语言具有汇编语言才具备的直接对内存地址进行操作(指针运算),能够对数据按二进制位进行计算(位操作)。

51、位运算:~按位取反,<<、>>左移、右移,&按位与(与1按位与判断奇偶,置0位,取对应位的值),^按位异或(与全1按位异或定位反转,a=a^b/b=b^a/a=a^b数值交换),|按位或(设定数据的指定位置)位运算只能用于整型或字符型数据,两个长度不同的数据进行位运算时,系统先将二者右端(低位)对齐,然后将短的一方按符号位扩充,无符号则以0扩充。

52、实际应用中,有时存储一个信息不必用一个或多个字节,而是在一个字节中放几个信息。人为地在一个字节中设几个位段,每一个位段用于存放一个数据。位段是以位为单位定义长度的结构体类型的成员。如struct packed_data{unsigned a:2;unsigned b:1;unsigned c:3;unsignedd:2;}data;位段可以直接被操作,可以给它赋值、可以在表达式中引用、可以输出。

53、编译预处理:宏定义、文件包含、条件编译。

54、#define命令一般写在程序开头,宏名的有效范围为定义命令之后到本源程序文件结束,但可以用#undef命令终止宏定义的作用域。

55、有参宏定义:#define 宏名(参数表)字符串,宏展开时,首先将语句的宏名右边括号内的各实参字符串代替#define命令参数表中的对应形参字符串,然后按#define命令行指定的字符串从左到右进行置换,置换的原则为:如果是参数,则用参数代替;如果不是参        数,则保留字符不变。

   如:#defines(z) 3.14*(x)*(x) 宏定义中的字符串通常加上一对圆括号,最好字符串中的每一个参数都加上一对圆括号,为宏的安全可靠使用提供了保障。宏名与带参数的括号间不允许出现空格。不要把带参数的宏和函数混淆,其虽然也进行了实参和形参的结合,但只是简单的字符替换。优势:不受数据类型限制。

56、#include“文件名”文件包含是指一个源文件可以将另外一个源文件的全部内容包含到本文件中来,作为本文件一部分。注意:文件包含处理以后,两个源文件连接起来作为一个源程序参加编译,得到一个目标(.obj)文件,这种连接和link对两个.obj文件的连接是完全不同的。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值