410 likes | 552 Views
C 语言程序设计. 第二讲 数据类型、运算符与表达式 绍兴文理学院 自动化教研室 2010 年 7 月. 可知对不同数据类型占用的存储空间 : char<short<=int<long <=float<double. 一、 C 语言的数据类型. Let’s try …. C 语言的数据类型 P37 基本类型 字符型 ( char ) 1 字节 整型 — 短整型( short int ) 2 字节
E N D
C语言程序设计 第二讲 数据类型、运算符与表达式 绍兴文理学院 自动化教研室 2010年7月
可知对不同数据类型占用的存储空间: char<short<=int<long <=float<double 一、C语言的数据类型 Let’s try… • C语言的数据类型P37 • 基本类型 字符型(char) 1字节 整型—短整型(shortint) 2字节 基本型(int) 2字节(-32768~32767) 长整型(long int) 4字节(±21亿) 实型—单精度(float) 4字节 6~7位有效数字 长单精度(long float)8字节 15~16位有效数字 双精度(double) 8字节 15~16位有效数字 长双精度(long double)10字节20位有效数字
求某一类型数据所占存储字节数,可用运算符: sizeof(类型关键字) Example: main( ) { printf(“char:%d字节\n”,sizeof(char)); printf(“float:%d字节\n”,sizeof(float)); } 结果显示: char:1字节 float:4字节
注意事项 Why?! 运行结果: Input:12345 a=12345 Input:1234567 a= -10617 • 整型≠整数 int 的范围: - 32768~+32767 Example: #include <stdio.h> #include <conio.h> main() { int a ; clrscr( ); printf(“Input :”); scanf(“%d”,&a); printf(“a=%d\n”,a); } Because:12345的补码是0011000000111001 1234567的补码是100101101011010000111 截去多余部份(超过2个字节的左边部分)后 其原码为1010100101111001(-10617) 参见教材P44“整型数据的溢出”。
示意图 字符型 (字符'a') 用一个字节存放该字符的ASCII值(ASCII值表见P364) 整 型 (十进制数25037) 用两个字节存放该数值的补码 实 型 尾数(补码) 指数(阶码) 注:第一位均为符号位 01100001 01100001 11001101 01100001……10100010101010 11100110 注意事项 • 数据存储形式 字符型按ASCII码存储,其余以补码存储
思 考 • 如果将例中char改成int,结果如何? • 如果将c1=97改为c1=97+3,结果如何? • Let’s try… ? 注意事项 不变 • 整型和字符型均可为unsigned (无符号型)P43图3.4 即将符号位亦作为数值位(默认为signed) 此时 int 的范围 0~65535 char 的范围 0 ~255 Let’s try… • 在C程序中,字符型可与整型(≤255)互相通用P50-51 Example: (参见P50例3.6,ACII值见P374) main() main() { { char c1,c2; char c1,c2; c1=97;c2=98; c1=97;c2=98; printf(“%c,%c\n”,c1,c2); printf(“%d,%d\n”,c1,c2); } } d,b 100,98 输出结果: a,b 输出结果: 97,98
二、常量 • 整型常量 P40 十进制数 12 -12l或 -12L 700000ul 八进制数 012 -012l 十六进制数 0x12 -0x12l • 实型常量 P47 十进制形式 123.45 2.0 ( 必有小数点) 指数形式 2.45e-4 1.13E3 (e或E前为数,后为整数) 实型常量本身无单或双精度,其机内精度取决于赋给那类变量(影响有效数字位数,见P15示例) • 字符常量/字符串常量
Example: main() { char c1=‘a’ ,c2; c2=98; printf(“%d,%d\n”,c1,c2); } 字符常量 P52 结果: 97,98 • 普通字符(可显示字符) ‘A’ ‘?’(只能单字符单引号) 错误:‘ABC’ “A” ‘’’ ‘”’ ‘\’ • 转义字符(在单引号或双引号中以\开头) 如回车符、单引号、反斜杠等 在程序中这些符号用表3.3所示的“转义字符”表示。 • 字符串(用双引号括起) “A” “?” (以‘\0’为字符串结束标志) • 注意:用char定义的字符变量只能接受字符常量,而不能接受字符串常量(C语言中无字符串变量) char a=‘U’ ; char b=“U”; (b被置为某随机值) 随机值 Example:main() { char c1=“a” ,c2; c2=98; printf(“%d,%d\n”,c1,c2); } 结果: -108,98 若让c1分别等于“U”、“ABC”、“A”…结果不变
转义字符例题分析 Example: main(){ char ch; ch=‘\362’; printf(“%c,%d”,ch,ch); } 运行结果:≥,-14 ch = 3628=24210=111100102 111100102 化为原码为10001110= -1410
转义字符例题分析 Example: #include <string.h>main(){ printf(“a\n\”\x41”); printf(“%d\n”,strlen(“a\n\”\x41”)); } 运行结果:a “A 4注:strlen为求字符串字节数函数(不计结束标志‘\0‘)。
8列 8列 8列 转义字符例题分析 Example: P49例3.5 main(){ printf( “_ _ a b _ c \ t _ d e \ r f \ t g \ n ”); printf( “h \ t I \ b \ b j _ _ _ k” ); } 运行结果: _ _ a b _ c _ _ a b _ c _ _ _ d e f _ _ _ _ _ _ _ g d e f _ a b _ c _ _ _ d e h h _ _ _ _ _ _ _ l h _ _ _ _ _ _ _ h _ _ _ _ _ _ h _ _ _ _ _ _ j _ _ _ k
什么时候要使用转义字符? 转义字符只在特殊情况下才使用: • C程序中需要实现某些特定打印或显示动作时 如printf(“123\t56\n”); • C程序中需要打印或显示以下三个字符时 \(斜杠)" (双引号) ' (单引号) 如printf(“You’re a \”a bad egg!\” ” ); • C程序中需要打印或显示ASCII表中非键盘字符时 如printf(“ Look\16 and \x80!”); 注意:使用转义字符时,\后的八进制或十六进制数不应大于char类型所允许的范围(十进制值256)。
字符串常量有关问题 • ‘A’与“A”的区别 • 问题(判断正误): char c=“China”; char c=‘China’; • “China”占几个字节?‘\141’占几个字节? 等于十进制数97 即字符’a’
三、变量 • 赋值 P53 例: b=(a=3+5) a=b=c=d=3+5 (结果均为8) 例:int a=b=c=d=3+5 (语法错误,除非b,c,d定义过) 正确:int a, b=a=3+5; 例: c=3+(a=5)*6 结果:c=33,a=5(一个语句可以有几个赋值运算) • 变量必须先定义后使用 • 变量名必须符合标识符命名规则P38
四、数据间的转换(混合运算) • 数据的类型级别 P54图3.10 • 基本规则 • 不同类型运算量参加运算,遵守“向高看齐”的类型一致化规则:将长度较短的运算量转换为长度较长的运算量,以保证不丢失信息。 • 将实型常量赋给整型变量,将被自动取整 int a=7.999999 ; 等效于 int a=7; • float型只要参加运算,均自动转为double。 main() { float i=3,j=4; printf(“%d\n”,sizeof(i+j) ); } /*结果为8(双精度)*/ • 两个整型数相除,其值也一定是整型数(取商之整数部分)。 3/2的值为1而非1.5
强制类型转换 P56 一般形式: (类型名)(表达式) 转换后表达式的数据类型为新的类型,但表达式中变量本身类型不变。 例一: (int)3.5 的值是多少? 程序执行后y的类型是什么? 3 例二: main() { int x=5; float y=3.5; clrscr(); /*clear screen(清屏)*/ printf(“%d”, (int)y+x); } 结果是什么? 8
五、运算符和表达式 C语言运算符(13类)P55 1、算术运算 ①算术运算符+ - */ % + + – – 例: 14%(-4)=2 -14%(-4)=-2 20.4%2(出错) 例:若int a=7;float x=2.5,y=4.7; 则表达式 x+a%3*(int)(x+y)%2/4的值是什么? 2.500000 (1/4为0) 例: float x,y; x%y; (出错)
五、运算符和表达式(续) ②自反算术赋值运算符(复合的赋值运算符)P62 += -= *= /=等 解法:将b*=…看作b=b*(…),其余类推 例: c=b*=a+3 相当于(1)a+3 (2)b=b*(a+3) (3)c=b 例:若 i 、j 的初值分别为3和4,则执行 j+=i- =1后i 、j 的值为多少? 解题步骤: i=i-1=3-1=2 j=j+i=4+2=6 结果:i=2, j=6
五、运算符和算术表达式(续) • 关于优先级和结合方向: P56 C语言规定了运算符的优先级和结合性。在表达式求值时,先按运算符的优先级别高低次序执行。如果在一个运算对象两侧的运算符的优先级别相同,则按规定的结合方向处理。 (各种运算符的优先级和结合性见P365附录C) 【例】设i、j初值分别为3和4,则执行 j+=i-=1;后 i ,j的值为多少? 【例】若x=7;则x+=x-=x+x的值是多少? (i=2,j=6) (-14) 解法:从右到左,先做x=x-(x+x)=-7, 再做x=x+x=-14
五、运算符和表达式(续) ③自加、自减运算符P57 ++(自加运算符)--(自减运算符) 用法: +1 -1 运算 a、前缀形式 int i=5; x = ++ i ; y= i ;(x=6, i =6, y=6) int i =5; ++ i ; y= i ;( i =6, y=6) b、后缀形式 int i =5; x = i ++; y= i ;(x=5, i =6, y=6) int i =5; i ++; y= i ;( i =6, y=6) 若对某变量自加/自减而不赋值,结果都是使该变量自身±1;若某变量自加/自减的同时还要参加其他运算,则前缀运算是先变化后运算,后缀运算是先运算后变化。注意:运算对象只能是整型变量, 5++或(x+y)++均为错
五、运算符和表达式(续) 例一: main(){ int a=100; printf(“%d\n”,a); printf(“%d\n”,++a); printf(“%d\n”,a++); printf(“%d\n”,a);} 运算结果:100 101 101 102 例二: 若 int x=3,y; 求下列运算后y和x的值 y=x++ -1; (2 4)y=++x -1; (3 4)y=x - - +1; (4 2) 分析思路:先对右边的表达式进行扫描,如果x++,先取x值完成表达式运算后再让x自加1,如果++x,则先将x自加1后再代入表达式进行其他运算 例三: 若 int i=3 求下列运算后y和z的值 y=(i++)+ (i++)+ (i++); y=9 (3+3+3)z=(++i )+ (++i )+ (++i ); z=18 (6+6+6)分析思路:先对右边的表达式进行扫描,看是否需要先自加,如需要,就作若干次自加,然后再进行表达式的其他运算。 思考: y=(++ i)+ (i++)+ (++ i); y=15 (5+5+5)
五、运算符和表达式(续) ④逗号运算P65-66 C语言中逗号可作分隔符使用,将若干变量隔开 如int a,b,c; 又可作运算符使用,将若干独立的表达式隔开,并依次计算各表达式的值。其一般形式 表达式1,表达式2,…,表达式n; 逗号表达式的求解过程:先求表达式1的值,再求表达式2的值…,最后求表达式n的值。整个逗号表达式的值是最后一个表达式n的值。 在C语言所有运算符中,逗号表达式的优先级最低。
五、运算符和表达式(续) 【例一】 main( ) { int x,a; x=(a=3*5,a*4,a+5); printf(“x=%d,a=%d\n”,x,a); } 【例二】 main( ) { int x,a; x=(a=3*5,a*4),a+5; printf(“x=%d,a=%d\n”,x,a); } 运算结果:x=60,a=15 运算结果:x=20,a=15 运算结果:a=8,b=16,x=24 【例三】main() { int a,b,x; x=(a=8,b=15,b++,a+b); printf(“a=%d,b=%d,x=%d\n”,a,b,x);}
五、运算符和表达式(续) Why? ⑤关系运算(比较运算)P91 关系运算符: > < >= <= == != 关系表达式: 含有关系运算符的表达式 特别注意 a≤X≤b 之类算式的正确写法 : a<=x && x<=b(错误写法:a<=X<=b) 【例】若x=1000,则printf(“%d”,2<x<3)的结果是什么? (不管x为何值,结果恒为1) 讨论: if (1<x<2) 的条件为什么恒为真 【注意】关系表达式的值: 真—1 假—0; C语言中还规定:非0—真 0—假 优先级:算术>关系>赋值>逗号
五、运算符和表达式(续) 【例一】 main( ) { int m=5; if (m++>5) printf(“m>5”); else { printf(“m=%d,”,m--); printf(“m=%d”,m--); } } 【例二】 main( ) { int m=5; if (++m>5) printf(“m>5”); else { printf(“m=%d,”,m--); printf(“m=%d”,m--); } } 运算结果:m=6,m=5 运算结果:m>5
五、运算符和表达式(续) ⑥逻辑运算P92 逻辑运算符: &&(与运算符) 运算符两边均为真时,结果为真 ||(或运算符) 运算符两边均为假时,结果为假 !(非运算符) 将运算符右边真假倒置 逻辑运算符的任一端如果为非0数,则视为“真”,为0则视为假。 【例】printf(“%d”, !3+5) 结果为5 printf(“%d”, !0+5) 结果为6 注意:! 优先于关系运算符,与++、--同级。 常用优先级: !、++、-- >算术运算符 >关系运算符 >&& >|| >赋值>逗号
五、运算符和表达式(续) 【例一】 main( ) { int a=1,b=2,m=2,n=2; (m=a>b)&&++n; printf("%d\n",n); } 【例二】 main( ) { int a=1,b=2,m=2,n=2; (m=b>a)&&++n; printf("%d\n",n); } 运行结果:n=2 运行结果:n=3 原因: 在&&和||的左边如果能判断出结果,则右边不再作运算。 结论:在逻辑表达式的求解中,并不是所有的逻辑运算符都会被执行。只是在必须执行下一个逻辑运算符才能求出表达式的解时,才执行该运算符。 (P94)
五、运算符和表达式(续) 【例三】 有以下程序段: int a,b,c; a=b=c=1; ++a||++b&&++c; 问执行后a、b、c的值各是多少? a=2,b=1,c=1
五、运算符和表达式(续) 【例四】编程判断任一给定年份是否闰年。符合以下条件的年份为闰年: P106 ①能被4整除但不能被100整除; ②能被4整除又能被400整除(只需考虑能被400整除的情况) main() { int year; clrscr(); printf("Input year="); scanf("%d",&year); if ((year%4==0&&year%100!=0)||year%400==0) printf("\n%d is a leap year!",year); else printf("\n%d isn't a leap year!",year); }
1 (x>0) y= 0 (x=0) -1 (x<0) 五、运算符和表达式(续) ⑦条件运算 P102 条件运算符: … ?… : …(三元运算符,即需连接三个运算量) 一般形式:e1?e2:e3 (e1为条件表达式,e2,e3为任意类型表达式) 功能: 如果e1≠0(为真),运算结果为e2的值。 如果e1=0(为假),则取e3的值。 【例】分别令x=3,x=0,x= -5,求运行结果。本程序功能? main( ) { int x,y; printf(“Input x=”); scanf(“%d”,&x); y=x>0?1:x<0?-1:0; /*结合方向:由右向左*/ printf(“x=%d,y=%d\n”,x,y); } 结果: x=3,y=1 x=0,y=0 x=-5,y=-1
五、算术运算符和算术表达式(续) ⑧sizeof运算符 sizeof运算符是一个单目运算符,用以计算操作数在内存中占用的字节数。它的操作数可以是以下两种情况: ●类型标识符; ●一个表达式 main() { int a=4, b; b=a+sizeof(double)+sizeof(a+3.14); printf("b=%d\n",b); } 结果:20
五、运算符和表达式(续) ⑨C程序中的算术表达式 【例】编程求以下数学表达式的值(设x=15) #include <math.h> main( ) { int x=15; double y; y=sqrt(pow(sin(15*3.14/180),2.5))/8/log10(2*3.14) +fabs(exp(2.5)-x); printf("y=%f",y); }
六、数据的输入和输出 【例】求以下程序运行结果 #include <stdio.h> main() { char x='a'; clrscr(); putchar(x); putchar('b'); putchar(x+2); putchar('b'+2); } 一、数据输出 1、字符输出函数 P73 格式: putchar(c) 其中c为字符型或整型的常量、变量及其表达式 功能: 每次向屏幕输出一个字符供显示。 结果:abcd
六、数据的输入和输出 2.格式输出函数 printf( )P75 格式: printf( “……”,输出项1,输出项2,…,输出项n ); 例:printf( “x=%d,y=%f\n” , x , x+3 ); 格式控制 (转换控制字符串) 输出表列 (用逗号分隔的数据组,可选项) • 格式控制分为两个部分: • 格式说明—%+格式字符 (替换输出) • 普通字符—原样输出(转义字符按表3.3输出)
六、数据的输入和输出 格式说明的一般形式: % - 0 m.nl(或h) 格式字符 -左对齐输出 0数字前的空位填0 m输出域宽(长度,包括小数点) 如数据的位数小于m,则左端补以空格 如数据的位数大于m,则按实际位数输出 n输出精度(小数位数) l或 h长度修正符 l 长整型及双精度 注:long型的数据宜用%ld,double型宜用%lf h表示短整型 如 %hd%hx
六、数据的输入和输出 【例二】求运行结果。 main() { int a= -30; printf("%d,%o,%x,%u,%c",a,a,a,a,a); } 结果: -30,177742,ffe2,65506,Γ 格式字符(规定了输出的数据形式): %d输出十进制整数 %x以十六进制无符号形式输出整数 %o以八进制无符号形式输出整数 %u以无符号十进制数形式输出整数 %f输出小数形式浮点数(double型用%lf) %s输出字符串 %c输出单字符 【例一】求运行结果。 main() { int a=30; printf("%d,%o,%x,%u,%c",a,a,a,a,a); } 结果: 30,36,1e,30,▲
六、数据的输入和输出 结论: 格式字符与对应输出项类型要一致,否则正确的运算结果不能得到正确的显示结果。 【例】若float y=1234.9999;printf(“%d”,y);则输出结果为何? 0 实际上本例中实数y为任意值(如1234或1)结果都是0! 如果将程序段作些修改: printf(“|%-15s|%2.2f|\n”,”ZHANG WEI”,165.1256); printf(“|%15s|%012f|\n”,”LI CHANG”,234.45); 【例】求以下程序段运行结果。 printf(“|%-15s|%2.2f|\n”,”ZHANG WEI”,165.1256); printf(“|%s|%012f|\n”,”LI CHANG”,234.45); 运行结果: |ZHANG WEI |165.13| (注意:WEI后面补了六个空格) |LI CHANG|00234.450000| (注意:数字部分连小数点共12位) 运行结果: |ZHANG WEI |165.13| | LI CHANG|00234.450000|
六、数据的输入和输出 二、数据输入 1.格式输入函数scanf()P82 格式: scanf( “……”,&变量名1,&变量名2,…,&变量名n); 例: scanf( “%d,%d,%d ” ,&a,&b,&c ); 【例】对于 scanf(“%3d%*4d%f”,&i,&f); 如果输入 1234567890.1234567890 结果i =123, f=890.123474 格式控制 (转换控制字符串) 地址表列 (简单变量要用&开头) 格式说明的一般形式: %*m l (或h)格式字符 & —求地址的运算符 &a表示该变量所占空间的首地址 *—抑制字符(“虚读”,即读入数据后不送给任何变量)
六、数据的输入和输出 注意: scanf( )函数没有输出功能(即不会向屏幕显示任何字符) 也不能规定小数位数(m.n) 典型错误: scanf( “a=%d,b=%d,c=%d \n”,&a,&b,&c); scanf( “ %5.2f “,&x ); 正确语句: printf( “ Input a,b,c=“); scanf( “%d, %d, %d”, &a, &b, &c); printf( “\n” ); /*不必要*/ scanf( “%5f “, &x);
六、数据的输入和输出 【例一】 #include <stdio.h> main() { char a,b; a=getchar(),b=getchar(); printf(“a=%c,b=%c\n”,a,b); } 运行时,如果—— 输入:Student 输出结果为 a=S,b=t 【例二】 #include <stdio.h> main() { char i=’y’; while (i==’y’||i==’Y’){ printf(“您好!是否继续?(y/n)\n”); i=getche();} /*见注*/ printf(“再见!”); } 注: 不能用getchar(),否则会把回车符作为第二次读入值 【例三】 /*一个设置密码输入程序*/ #include <stdio.h> main( ) { char password[10],c='*'; int i =0; printf("\npassword:"); while (i<=9) { password[i]=getch(); putchar(c); if (password[i]=='\r') break; i++; } /*此处加入密码验证语句*/ printf(“\n欢迎使用本程序!”); } 2.字符输入函数 P74 格式: getchar( ) getche( ) getch( ) 功能: 从键盘上读入一个字符,但后两个函数输入后无需回车。getch( )还有一个功能,即不把读入的字符回显到屏幕上,常用于密码输入或菜单选择。getchar( )包含在stdio.h中,getche( )和getch( )包含在conio.h中。
第二讲 作业 一、编程题 要求:所有编程题须上机调试通过,源程序及运行结果用作业本上交。 源程序要求按缩进形式书写,文字端正整齐。不合格者退回重做。 1、编写一个程序,从键盘输入任意一个五位数,把这个数值分解为单个数字,然后打印出每一个数字(每个数字之间用三个空格分开)。例如用户输入了42339,屏幕输出结果为: 4 2 3 3 9 【提示】巧妙使用 / 和 % 两种运算符。 2、已知x=15,编程求: 要求输出结果以指数形式表示。 3、编程求任意系数值(a,b,c值由键盘输入)的一元二次方程任意根(实根、复根)的通用程序。要求能循环执行,直到用户选择结束为止。