第0篇 C语言基本语法4
第第 0 章章 C 语言基本语法语言基本语法 一共 80 学时,分两部分:C、数据结构。其中 C 大概 32 学时,数据结构 48 学时。 0.1 C 编译环境编译环境 C 语言一般可使用两种编程环境: 1、Turbo C 2.0 版本,重要的三个热键: 1)编译:F9 2)运行:Ctrl+F5 3)观察结果:Alt+F5 2、Visual C+ 6.0 版本:只适合在 Windows 操作系统下,是微软开发出来 的,在这个环境下进行 C、C+、Visual C+进行编程非常方便。 在 VC+6.0 看来,每个程序都应该以“Project” (工程、项目)的形式来进 行。而每个 Project 又应该包含在一个 WorkSpace(工作区)之中。当然,一个 Workspace 中可以有多个 Project。因此,我们每创建一个程序,都应该首先创 建一个工程,这个工程就是一个整体,经过编译连接等操作,这个工程最终就 能够变成一个在 Windows 下可执行的程序。 在 VC6.0 中的 Project 有以下几种常用类型: 1)Win32 Console Application:Win32 控制台应用程序,适合所有的 C 程 序,由它创建出来的应用程序一般没有独立的窗口。这种程序的入口函数为 main 函数。 2)Win32 Application:Win32 应用程序,适合 C/C+程序,这个与上面的 区别在于,可以创建出有独立窗口的应用程序,特别地,它可以使用 Win API 函数库。入口函数不是 main 函数,而是 tmain 或 WinMain 等。 3)MFC AppWizard(.exe):适合使用 Visual C+语言进行编程,可以方便 地创建出普通的 Windows 窗口,能够方便地进行窗口编程。在这种程序中,连 main 或 WinMain 函数都找不到。 0.2 熟悉熟悉 Visual C+ 6.0 编程环境编程环境 每一个程序都以“工程(Project) ”的形式出现,在 VC 中,又将一个或多 个工程包装成一个“工作区(WorkSpace) ” ,所以,我们在每个程序编程时都 需要创建一个工程,再在这个工程中创建文件(.cpp、.h 文件等) 。 编译微型条 0.3 顺序程序设计顺序程序设计 0.3.1 数据类型数据类型 1、基本类型(整型、浮点型、字符型) ,枚举类型、复合类型(数组、指 针、结构体、共用体) 。 2、整型:int、short int、long int,都是使用补码的形式来表示。 如要将-123 表示成 16 位(2B)的补码 1)先将 123 化为原码二进制形式:0000 0000 0111 1011 2)最高位取 1,其它位按位取反:1111 1111 1000 0100,得到的是反码。 3)末尾加 1:1111 1111 1000 0101 显然,16 位所能表示的数据,最大的那个是:0111 1111 1111 1111215- 1,最小的那个数:1000 0000 0000 0000-215,而 1111 1111 1111 1111-1 intshort intlong intchar Turbo C2B,-215215- 1 2B,-215215- 1 4B, -231231-11B,-128127 Visual C+4B, -231231-12B,-215215- 1 4B, -231231-1ASCII:1B Unicode:2B unsigned:无符号,也就是没有负数,全部是正数。如 unsigned int 所以,如果对于 int 来说,1111 1111 1111 1111-1,而对于 unsigned int 来说,1111 1111 1111 1111216-1 另外还有一个关键字:signed,代表有符号,如 signed int 实际上就是 int。 long int 可以简写为 long,而 short int 可简写为 short 3、浮点数:float、double, float 称为单精度浮点数,由 4B 表示,它只有 6 个有效数字。能表示的数 据范围:0 及 1.2X10-383.4X1038 double 称为双精度浮点数,由 8B 表示,它有 15 个有效数字。能表示:0 及 2.3 X10-3083.4X10308 long double 长双精度浮点数,一般不太使用,它一般可以有有 16B。 注意一个细节:不准确,可能有些数明明是有限小数,但在计算机中无法 表示,将表示成无限的近似的数,如 0.1,所以,我们有两点要注意的: 1)不要用浮点数来控制循环次数。 float f; for( f=0; fint-long-double 如: double f; int a, b; float t; char c; f=(t= a+c ); 2)如果不满意,可以强制类型转换 a=(int)( f + t); 由 doube 或 float 强制向 int 转换方式,是直接将小数点后面的所有的数据 摸掉,不会自动进行四舍五入。如: double d=12.89; int a; a=(int)d;/a=12 如果我们想要四舍五入,得用技巧,加 0.5 后再取整。如: double e=12.89, f=34.46; int a=(int)(e+0.5);/a=13 int b=(int)(f+0.5);/b=34; 这个小技巧可以扩展:精确到小数点后几位,如: double d=12.345678; 现在,要想精确到小数点后 3 位,应该得到:12.346,方法为先乘以 1000,再加 0.5,再取整,再除以 1000.0: d=(int)(d*1000+0.5)/1000.0; 0.3.4 自增和自减自增和自减 +、,形式有两种:a+,+a, a+规定,先取 a 的值在本表达式中进行计算应用,再将 a 加一,只影响后 面的语句,如: int a=4; int b=a+;/b=4,a=5 int c=+a;/a=5, c=5 a=4; int d=(a+)+(a+)+(a+); 在 VC 中,相当于四条语句: d=a+a+a;a+;a+;a+; 其结果,a=7, d=12; +a 规定:先将 a 的值加一,再应用 a 的值,并影响这条语句。如: int a=4; int b=+a;/a=b=5; int c=(+a)+(+a)+(+a); 在 Turbo C 中,相当于四条语句: +a;+a;+a; c=a+a+a; 0.3.5 数据的输入与输出数据的输入与输出 1、输出:printf、putchar、puts 等 注意: 1)特殊字符的输出:n、b 2)输出各种字符的方式:整型%d,字符%c,字符串%s,小数形式的浮点 数%f,指数形式的浮点数:%e,长整型%ld,double 型%lf,后面的指针类型 (地址)%lp 3)对于整型宽度问题:%5d,这个数字点 5 个位置,多出的位置用前置空 格被齐,被在数字的前面。如果%-5d,空格被在数字的后面。如果这个数字的 长度大于 5,则将该数字完整的打印出来。 4)对于浮点数,用%f 打印小数,用%e 打印指数。 5)可以指定小数点后几位,如%.3f,或%10.3f,意思是说,小数点后占 3 位,一共占 10 位(包括小数点位,因此,只有 9 位数字) 6)对于整数,输出八进制数:%o,输出十六进制数:%x 或%X 7)输出无符号整数:%u,如果该数实际上已经是有符号的数,按%u 输出 后,负数会变成正数。 8)输出长整型数:%l(注:字母 l) ,在 VC 中完全不需要。 9)如果想输出特殊的字符如、%本身,可,%输出 10)输出地址:%lp, 11)输出单个字符可用 putchar( )进行。 2、输入:scanf、getchar、gets 等 可接收的输入数据包括:整数、浮点数、字符、字符串,且均以回车键结 束输入。格式与输出相同。 1)可以指定宽度:如: scanf(“%3d%4d%d“, /如果输入 123456789,则 a=123,b=4567,c=89,但是,如果用户输入的是:12 345678 9,则 a=12,b=3456,c=78,9 多余舍弃掉。 2)常见错误: (1)后面的变量必须用地址,如果不用地址,会出错。 scanf(“%3d%4d%d“,a,b,c);/错误,a、b、c 必须用地址表示 (2)如果变量本身就是地址(指针) ,那么不能再用地址,如: int a; int *p= scanf(“%d“,p);/正确,因为 p 就是 a 的地址,就是输入到 a 中去了。 scanf(“%d“,/错误,变成将整数输入到 p 中去,可是,p 又是指针。 (3)在 scanf 中,除了格式符外,不要出现多余的文字,如: scnaf(“a=%d,b=%d“,/用户在输入数据时,必须 a=5,b=10 才能正确 输入。 3)输入字符:可用%c,如果混合输入,非常麻烦: 4)还可以使用 getchar()输入字符,方式为: c=getchar( ); 5)还可以使用 getch( )输入字符,方式 为: c=getch( ); 该函数应该包括头文件,且用户不需要按回车键就输入,在制作 游戏中比较有用。 6)还可以使用 getc( stdin )输入字符,其中参数 stdin 就是标准输入设备, 由 VC 定义好的。 c=getc( stdin ); 这种方法在文件操作中比较有用,其中的参数 stdin 可以换成是我们已经通 过 fopen 打开的文件指针,就能够从该文件中输入一个字符。 0.4 C 语言中的选择结构程序设计语言中的选择结构程序设计 0.4.1 关系运算符和关系表达式关系运算符和关系表达式 关系运算符有 6 种:、=、=、!= 其中:、=的优先级相同,=、!=优先级相同,且前者的优先级 高于后者。 而且,优先级:算术运算符高于关系运算符高于赋值。 关系表达式:就是用关系运算符将若干个数值、数值表达式连接起来的式。 如: ab,(a=3)b+(c=4) 在 C 中,并不存在“真“和“假“,只有非 0 和 0,规定:凡是结果为 0 的,认 为“假” (不成立) ,凡是结果为非 0 的,都认为是“真” (成立) ,哪怕结果为 0.000001、A,也是真。且在 C 语言中,没有所谓的 BOOL 型。因此,有时我 们会看到类似这样的式子: if( a=b+c )/判断 a 是 0 还是非 0,如果为非 0,则说明“真” 注意与: if( a=b+c ) 的区别。 在编程的时候,有时可以用 C 的检查机制来检查我们的错误。可以写为: if( b+c=a ) 因为如果你写错成: if( b+c=a ) C 语言能够查找出这个错误:赋值运算符规定左边必须是一个变量。同样 地,如果要写判断一个变量是否与某个常数相等: if( a=12 ) 可写成:if( 12=a ),因为如果写错成:if( 12=a ),则 C 语言能发现这个错 误。 再次强调:通过关系运算的结果只有两种:1 表示真,0 表示假。 所以: int a=3, b=4, c=5, d=0; 表达式 cba 在数学上的结果为“真” ,但是在 C 语言中,这个表达式的 结构为 0(假) ,其计算过程为先计算:cb,为真得到 1,再计算 1a 为假,得 到 0.也正因为如此,如果我们就是要表达数学上的 cba 的真实含义,则需要 使用逻辑运算符来连接起来:cb /c=10 c=(ab) ? (ad) ? d: (d=0 来表示一个语句的结束,如: if( ab ) ; if( cd ) e+; else e; 0.4.6 switch-case 语句语句 switch 语句又称为多分支选择语句,它可以提供多条路进行选择,它完全 可用 if 语句来取代。其一般格式: switch( 表达式 )/表达式是可以计算出的结果,建议应该是 int 型或 char 型,不要是 float 或者 double case 值 1: break; case 值 2: break; default: 如判断成绩: switch( s/10 ) case 0: case 1: case 2: case 3: case 4: case 5: printf(“差n“); break; case 6: printf(“及格n“); break; 关于 switch-case 的注意事项: 1)应该具有必要的 break 语句来跳出 switch,否则结果可能会出错,如: int a=3, b=10; switch( a ) case 1: b+; break; case 2: b+; case 3: b-; break; case 4: b-; case 5: b+; default: b-; break; 课后思考题:请问 2012 年 11 月 23 日是这一年的第几天?已知 1 月 1 日是 第 1 天。如果 2012 年 1 月 1 日是星期天,问 2012 年 11 月 23 日是星期几? 0.4.7 选择语句编程时的错误小结选择语句编程时的错误小结 1、在判断两个值是否相等时,=误写成=,变成了赋值,如: int a=5, b=-2; if( a=b ) 误写成: if( a=b ) 2、经常 if 复合语句忘记写大括号,如: if( ) 语句 1; 语句 2; 误写成: if( ) 语句 1; 语句 2; ; 3、/a=1000101,b=111010 if ( a switch ( c )/错误 case 0.1: case 0.2: 6、switch 中忘记写 break 语句。如: int a=5, b=-2, c=20; switch( a ) case 3: b+; case 5: b-; case 7: b+; case 9: c-; 7、不是错误:default 语句可以在 switch 中的任意位置,最前面、最后面、 中间都行。如果没有 default 语句,则当所有的 case 均不满足时,会直接退出 switch 语句。 8、不是错误:指针可以参加大小、相等比较,意义为: 1)比较是否相等,其实就是问两个指针是否指向同一个变量; 2)比较大小,一般用于数组中,看哪个指针指向的位置在前还是在后。如: int a100; int *p= if ( pq )/成立的,因为 a45在 a23的后面,地址更高(大) else 但是如果写成: if ( *p*q )/不一定成立,这是在判断 a45和 a23的值 else if ( *pq )/语法错误,指针不能与某个非指针比较 else 不得将一个指针值与某个整数进行比较大小、相等,如: int *p, *q, a=5, b=-7; p=q= if( p=a )/语法错误 if( pa )/语法错误 if( pq )/正确 唯一的与整数进行比较的指针就是比较是否为 0(NULL) ,如: if( p=NULL ) 或者写成:if( p=0 ) 或者写成:if( !p ) 9、关于字符串的比较,常见的错误如: char str1 =“China“, *str2=“Chinese“; 现在要判断两个字符串的大小,下面写法是错误的: if ( str1str2 )/错误!实际上在判断两个指针的大小 if( *str1*str2 )/语法正确,但结果不是我们要的。 正确的判断应该是: if( strcmp( str1, str2)=0)/说明两个字符串相等 if( strcmp( str1, str2)0) /说明 str1str2 if( strcmp( str1, str2)头文件。 0.4.8 课后练习课后练习 1、企业发放的奖金根据利润 I 提成。利润 I 低于或等于 100000 元的,奖 金可提 I 的 10%;利润高于 100000 元,低于 200000 元(100000I200000) 时,低于 100000 元的部分按 10%提成,高于 100000 元的部分,可提成 7.5%;200000I400000 时,低于 200000 元的部分仍按上述办法提成(下同) ,高于 200000 的部分按 5%提成;400000I600000 时,高于 400000 元的部分 按 3%提成;400000I600000 时,高于 600000 元的部分按 1.5%提成; i=1, s=0; s+=i; i+; i3 | b+ ) 再如: if( (a3 | b+) i100 ? Y N s+=i; i+; 打印 s i=1, s=0; i100) goto code2; s+=i; i+; goto code1; code2: printf(“%d n“, s); 0.5.2 do-while 构成循环构成循环 一般结构: 语句; do 语句 1;/循环体 while(条件); 语句 int i=1, s=0; do s+=i; i+; while(i判断语句 2 是否满足如果满足,进入循环体,如果不满足, 则退出循环执行循环体语句 3判断语句 2 是否满足 语句 0 语句 1 语句 2? 循环体 语句 3 N Y 语句 4 int i,s=0; for(i=1; i100) break; s+=i; i+; 这四种循环,都可以互相取代,其中 for 用得最灵活,也最常用。goto 语 句目前处于淘汰状态,尽量不要用。 0.5.5 continue 语句语句 用在循环(do-while、while、for)中,目的是结束本次循环,进入下次循 环。注意与 break 区别:break 是结束整个循环。如: Eg:输出 100200 之间的能被 3 整除的数。 思路:从 100200,一个一个进行检查,如果它不能被 3 整除,则继续下次 循环,否则,打印之,用 for 很容易实现: int i; for(i=100;i=10) break; if(x%2=1) x+=5; continue; x-=3; x=1 6 3 8 5 10 y=1 2 3 4 5 6 break 和 continue 用在 while 和 do-while 中的效果是一样的,但是,它 们不能用在 if-goto 的循环中。 0.5.6 循环的嵌套循环的嵌套 嵌套:在循环内又有循环。 如:计算 1+(1+2)+(1+2+3)+(1+2+3+100) 考虑:第 i 项:1+2+3+i,可以编程: s=0; for(j=1;j0.000001); printf(“PI=%f n“,p1); 课后练习:请将其换成 while 循环,还可以考虑用 for 也行。 ExEx 5.7.25.7.2:瞎子爬山法:瞎子爬山法:主要用在解高次方程上,作为课后的思考题。 让你猜一个小数:123.56789 0 10000 1000 100 200 110 120 130 121 122 123 124 123.1 ExEx 5.7.35.7.3:判断一个数是否是素数:判断一个数是否是素数: 24 不是素数:因为它能被 2 整除。 35 也不是素数,它能被 5 整除 37 是素数,因为:从 2、3、4、36 都不能够整除它。 用程序表达:假设这个数为 n,则让 i=2、3、4、sqrt(n)去除它, 只要中间有一个数能除尽,则 n 不是素数,否则,是素数。 int n=123123; int flag=1;/先假设 n 是素数 for( i=2; i0,说明根在(x,h)之间,只需要 l=x,再进行上面的循环 3)如果 ya01-a09-a10- -a49 3 0234567891 a I 426455656 k 3 0234567891 a 423435656 3423435656 3423435656 3423435656 3423435656 0 1 2 3 4 q q 可以计算他们的地址: 已知有一个二维数组 float f100200;的首地址是 1000,问 f3467 的地址是多少?(每个 float 数据都占 4 字节) Addr=1000+34*200*4+67*4 公式:对于 fmn的地址: Addr=首地址+(m*200+n)*4 二维数组的编程主要是使用一个二重循环,一般使用两个 for 来完成: int i, j; for(i=0;ij s+=eij; 5)矩阵的乘法(A X G,要求 A 的列数与 G 的行数相等) 2019181716 1514131211 109876 54321 A 555 444 333 222 111 G xxx xHx xxx xxx H 12 则 HA X G 结果为 A 的行数和 G 的列数,就是 4 X 3,其中 Hij这个 元素来自于 A 矩阵的所有第 i 行(共有 5 个元素)与 G 中的第 j 列(共有 5 个 元素)的对应的乘积的和。换句话说,要求元素 Hij,需要使用一个循环: s=0; for(k=0;kstr2,返回 1,如果 str1b) return a; return b; 有时,还会写一个函数体为空的函数,这是为了编程的方便,以后可以再 将这个函数补写完整。 0.7.3 函数的调用方法函数的调用方法 分两种: 1)如果函数没有类型(也就是 void 型) ,则该函数的调用只能单独进行。 如: void f1(.) /. main() f1(.);/正确 a=f1(.);/错误,因为这个函数为 void 型,也就没有返回值 2)如果函数有返回值,则该函数的调用可以单独进行,也可以让其参与计 算,如: int f2(.) /. return X; main( ) f2(.);/正确,可以单独使用 a=f2(.);/正确 0.7.4 函数调用时的数据传递函数调用时的数据传递 1、两个名词:实际参数、形式参数 形式参数:指函数定义时,括号里的参数,形式参数一定是变量。如: int f1(int a, float f) /. 其中的 int a, float f,a 与 f 都是函数在定义时声明的,它们就是形 式参数。 实际参数:指函数在被调用时,括号里的参数,它既可以是变量,也可以 是常量。如: y=f1( x, 5.2 ); 其中的 x 与 5.2 就是实际参数。 形式参数和实际参数的身份是不一样的,形式参数一定是变量,且是局部 变量,而实际参数则即可以是变量,也可以是常量或直接数,如:上面的 y=f1( x, 5.2 )中,x 是变量,而 5.2 是常量,也是直接数。 2、传递方向:值的单向传递(就是值由“实际参数”传递给“形式参数” , 这个传递实际上就是赋值,至于在函数体中对形式参数做了什么修改,对于实 际参数没有任何影响) ,值不会再由实际参数还给形式参数。如: int f(int a, int b) int t; t=a;a=b;b=t;/ 交换 a 和 b 的值 void main() int x=5, y=-7; f(x, y); printf(“x=%d, y=%d n“,x,y); main 函数 x=5 y= -7 f(5, -7) f 函数 a=-7 b= 5 t=a;a=b;b=t 3、指针作为实际参数,则函数的值的传递还是单向传递,但其结果不一样, 如: int g(int *p, int *q) int t; t=*p;*p=*q; *p=t;/交换 p 和 q 所指向的变量的值 void main( ) int x=5, y=-7; g( printf(“x=%d, y=%d n“,x,y);/x 和 y 会发生变化 4、但是,下面这个例子: int h(int *p, int *q) main 函数 x=5y=-7 g( *p=*q; *q=t; int *t; t=p;p=q;p=t;/交换 p 和 q 指针的指向,使得 p 指向了原来 q 指向的变量 void main( ) int x=5, y=-7; int *pp= g(pp, qq);/注意,pp 还是指向 x,qq 还是指向 y printf(“*pp=%d, *qq=%d n“,*pp,*qq);/还是 x 和 y 的值 5、下面的例子有错误: 1) int h(int *p, int *q) int *t;/指针 t 没有指向,因此它没有空间 *t=*p;/将 p 指向的那个元素的值 5 赋给 t 指向的那个元素,但 是/t 没有指向,所以出错 *p=*q; *p=*t; 2)语法错误: int g(int *p, int *q) int *t; t=*p;*p=*q; *p=t; 课堂练习: 1、在 main 函数中,定义两个变量 int a=5, b=-7; 请用三种以上方法(指针、全局变量、数组、引用等) ,各写一个函数,交 换 a 和 b 的值。 用全局变量方式 main 函数 x=5 y= -7 g(pp,qq) g 函数 p= p=q; q=t; pp= void f( ) int t; t=a;a=b;b=t; 用数组方式: void f( int arr )/void f( int *arr ) int t; t=arr0; arr0=arr1;arr1=t; void main( ) int a=5, b=-7; int c2; c0=a;c1=b; f( c ); a=c0;b=c1; 6、在 C+中,函数还有一种形式参数,可以影响实际参数引用,如: int f(int t=a;a=b;b=t;/ 交换 a 和 b 的值 void main() int x=5, y=-7; f(x, y);/会交换 x 和 y 的值 printf(“x=%d, y=%d n“,x,y); 0.7.5 函数的声明与定义函数的声明与定义 在 C 中规定,函数必须先定义(声明)后使用,所有,被调用的函数必须 在调用函数之前。如: void f(int, float, double);/函数的声明,参数类型需要,但 名称可以没有,我们就称为该函数的原型 void g( ) /使用 f() void f(int a, float b, double *d ) 0.7.6 函数的参数类型函数的参数类型 1、数组元素可以作为参数如: main() int a10=.; f(a5);/将元素 a5作为参数传递给函数 f,它实际上就是一 个普通的 int void f(int x) 将数组元素作为参数传递给函数,则仍然遵循值的单向传递,如: void f(int x, int y) int t; main 函数 x=5 y= -7 f(x, y) f 函数 t=a; a=b; b=t; 别名 a别名 b t=x;x=y;y=t; void main( ) int a2=5, -7; f(a0,a1);/结果,不会影响 a0和 a1的值。 2、一维数组名作为实际参数,则会影响数组中的值 main() int a10=.; f(a);/将数组名作为参数传递给函数 f, g(a); void f(int *x) /使用:*(x+5)或 x5等 /其中可以使用 x+;这条语句,但意义不大 void g(int b) /使用:*(b+5)或 b5等 /因为 b 明确是数组,则 b+和 b都是错误的 例子:将数组反转例子:将数组反转 void inverse(int *b) int i, t; for(i=0;inum=110; 0.9.4 结构体指针的使用结构体指针的使用 STU s1,s2,a10,*p,*q; /下面使用数组 a q=a;/q 指向了数组 a a0.num=120; (*q).num=120;/实际上就是 a0.num=120 q-num=120; (*(q+5).num=150;/实际上是 a5.num=150; 结构体指针主要用在链表中,关于链表,后面开始数据结构中进行介 绍。 0.10 共用体共用体 关键字:union,定义类型的一般格式: union 共用体类型名 成员列表; ; 如: typedef union uData int i; char ch2 float f; UD; struct sData int i; char ch2 float f; ; union uData a,b; UD a,b; a.i=12345; 问,此时 a 中的 ch0是什么?ch1里面又是什么? 12345=(0011 0000 0011 1001)2 则 ch0的值为其低 8 位(0011 1001)2579 而 ch1的值为其高 8 位(0011 0000)2480 共用体总结: 1、共用体中的所有的成员均共用一段内存; 2、一个共用体变量所占的空间多大?最大的那个成员的空间,其中数组中 一个成员,其所占的空间是其所有的元素之和。 3、修改某个成员的值,将影响其它所有成员的值我们在编程时,一定 要小心。 4、共用体与结构体的使用方法类似,指针方法也类似。 0.11 枚举枚举 枚举(enumeration),其关键字:enum,一般格式如下: enum 枚举类型名值 1,值 2,,值 n; 如: enum Weekdaysun,mon,tue,wed,thu,fri,sat; 1、用枚举类型定义变量: enum Weekday workday, weekend; 其变量的值可以是其对应的枚举类型中列举出来的字符串,如 sun. i ch2 f sData,共 8B 2 2 4 ch0 ch1 f,共 4B i,共 2B workday=mon;/等价于:workday=1; weekend=sun;/等价于:weekend=0; 2、可以在定义类型时,指定某个串的值,如: enum Weekdaysun,mon=5,tue,wed,thu=10,fri,sat; 3、可以将枚举类型的变量之间进行比较,也可以于其类型中的串进行比较, 如: if(workday=mon) if(workday=weekend) if(workday!=wed) 0.12 位运算位运算 0.12.1 位运算符位运算符 结果,c=0; 2)任何一个数与 0 异或,结果为它本身。 3)任何一个数与-1(就是二进制中的全 1)异或,结果为:它自己取反 4)满足交换律:ab=ba 5)如果 c=a b; d=c a;则 d=b; d=aba=b;称为异或运算的吸收律 证明:d=aba=aab=0b=b; 6)可以用异或运算来交换两个整数: int a=5, b=-7; t=a;a=b;b=t; a=ab;b=ab;a=ab; 7)寄存器清零运算: 如果要让 AX 的值变为 0,可以使用的方法: MOV ax, 0 SUB ax,ax MUL ax,0 XOR ax,ax;异或运算,速度最快 2、特殊用途 1)已知有一个数 a=(1010 0011)2,现在要让低四位全 1: b=a | 0000 1111 2)已知有一个数 a=(1010 0011)2,现在要让低四位全 0: c=a int b=a1=0000 0100=4. 仍然存在着正数与负数的问题:如果原来是负数,则向右移位后,前面总 是补 1,而如果原来是正数,前面补 0. 0.13 文件操作文件操作 0.13.1 文件的相关概念文件的相关概念 1、流(Stream),在 C 语言中,也包括 C+、Java,都有流的概念。一般分 为输入流、输出流。可以理解为流水(大量的数据)很顺畅地流动。 假设我们需要读取数据,如果从键盘上读,用户按键的速度有限,一般形 不成流。但是,如果从网卡上、硬盘上读取,则速度非常快,一次性可以读取 大量的数据,也就形成了流。在计算机内部,流是通过“传输通道”来实现。 2、文件名:一般来说,一个完整的文件名由三部分组成: d:xyzabc.txt 其中的 abc 称为文件名,.txt 称为文件后缀,d:xyz称为路径,表示一 个完整的文件,一般都需要这三部分才能精确定位。 3、文件的分类: 根据数据的组织形式,数据文件可分为两类:ASCII 文件(文本文件) 、二 进制文件。在 C 语言中,对于这两种文件的存取方式是不同,他们在硬盘上的 存放方式也不同。 如:要存放数字 12345 在文件中, 对于二进制文件来说,存放的只是一个整数(用二进制表示的) ,也就是存 放的是 00000000 00000000 00110000 00111001 对于 ASCII 码文件来说,存放的是几个数字的字符:1 2 3 4 5 的 ASCII 码: 1的 ASCII 码490011 0001 2的 ASCII 码500011 0010 也就是说,存放的是:00110001 00110010 需要注意的是,在 C 中,ASCII 码文件与二进制文件的读写方式不同,且 不能混用(不能以 ASCII 文件存放用二进制文件的方式来读) 4、文件缓冲区 计算机组成原理有介绍:为了加快读取速度(一般文件都是存放在外存上) , 对于 CPU、内存来说,实在是太慢了。从硬盘上读取 1M 的数据,对于 CPU 来说, 可能只需要 1us,而对于硬盘来说,可能需要 100ms,CPU 不会等待,数据由硬盘 上的缓冲区读取,存放在其缓冲区中,等数据全部到位后,才通知 CPU 去取。 这样能大大地加快速度。对于写文件也是一样的:CPU 先将数据写到缓冲区中, 然后由其再慢慢地(一般只有当缓冲区满了后)写到硬盘上去。 这就导致一个问题:有可能我们向某个文件中写一个整数,可是不会真正 地写到文件中去,只是写到缓冲区去了,如果此时程序崩溃,则该数据没有写 入文件。 在 C 中提供了两个办法:1)关闭文件,数据会写到文件中去;2)强制刷 新文件。 5、文件类型的指针 称为文件指针,这是一个最重要的概念。在 C 中,对每个被使用的文件都 在内存中开辟一个相应的文件信息区,用来存放文件的有关信息: typedef struct short level;/缓冲区“满”或“空”的程度 unsigned flags;/文件状态标志 cha