第 6 章 数据类型和表达式
Post on 01-Jan-2016
126 Views
Preview:
DESCRIPTION
TRANSCRIPT
1
第 6章 数据类型和表达式数据类型:对某些具有共同特点的数据集合的总称
数据类型
指针类型
空类型
数组结构联合枚举
单精度型双精度
整型实型字符
表达式:
用运算符将运算对象及括弧按语法规则连接起来的式子
基本类型
构造类型
各种数据在内存的存储方式 ( 书写形式 ) 、数的表示范围
2
§6.1 基本数据类型和数据的存储6.1.16.1.1 整型(整数)整型(整数)1. 整型类型基本类型 int
差别: 数据存储单元的字节数多少 ? 1 字节为 8 位二进制位
2 个字节 16位
运算符 sizeof (2 级 ) 可以求出数据类型、常量、变量的字节数如 sizeof(long)4
sizeof(e)4
例 int ai,bi,ci;
扩展类型 短整型 short长整型 long
例 unsigned short c,d; long e,f ;
以及无 ±
ANSI C(TC) VC++
4 个字节 32位
2 个字节 16位4 个字节 32位
2 个字节 16位4 个字节 32位
unsigned int 或 unsignedunsigned shortunsigned long
3
2.2. 整型数的取值范围整型数的取值范围
± 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1+ 1
符号位 + 0- 1
1 2 1 3276715 由于负数补码表示,最小值 -32768
最大值
以 short ( 16 位)为例:
所以 -32768 ~ 32767
同理 unsigned short 取值范围范围1 2 1 6553516 在 0 ~65535
int 、 long (32 位)取值范围范围12~2 3131 -2147483648 ~ 2147483647
unsigned int 、 unsigned long (32 位)取值 12~0 32 0 ~ 4294967295
4
注:数据不能超过表达范围
设 int 定义的变量为 2 个字节,下面程序段输出结果是 _______ 。 int i=65536;printf("%d\n",i); A 、 65536B 、 0C 、语法错误,无输出结果D 、 -1
6553610= 2000008= 10,000,000,000,000,000
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0则 i=
答案 B
5
原代码、反码、补码的概念
原代码 存储单元的最高位作为符号 , 其 0 为正 ,1 为负 , 值为二进制
例 -5 10000101 ( 设存储单元为一个字节 )
计算机带符号运算实现起来十分复杂 , 一般都作为无符号运算 , 采用补码运算。补码 补码 =X+K
其中 X 带符号的数
K 为模 , 比存储单元多一位 , 最高位为 1 ,其余位均为0
如 K=100000000 ( 设存储为 1 个字节 )
注 X+K 运算后 K的最高位不存在 ,因为只有规定的存储位数
6
例 求 +13 的补码 +13 的补码 =00001101+100000000=100001101=00001101
结论 正数的补码 = 原代码
反码 代码的 0 变为 1,1 变为 0
利用反码求解负数的补码公式为 补码 = 反码 +1
注:符号位不参加反码运算。
例 求 -13 的补码 -13 的补码 = -00001101+100000000=11110011
按上述方法求负数的补码比较麻烦 , 一般利用反码求解
例 -13 的原代码 =10001101
-13 的反码 = 11110010
-13 的补码 = 11110011
7
short ( 16 位)的最小值 -32768, 其存储表示:
-32767 的原代码 =11111111 11111111
反码 =10000000 00000000
补码 =10000000 00000001因此
-32768= -32767-1
-32768 的补码 =10000000 00000000
8
例下列程序的输出结果是 ____ 。#include <stdio.h>void main( ){ int x,k; x=12; for(k=0;x!=0;x=x+2) k=k+1; printf(“k=%d,x=%d\n”,k,x);}
答案 k=32762,x=0
x=12x=12+2=14x=14+2=16......x=32766+2=-32768(32766+1=01111111 11111111 32767+1=10000000 00000000-32768 的补码 =10000000 00000000)
x=-32768+2=-32766.....x=-2+2=0则 k 的值即为循环次数计算x 正值循环次数 :(32766-12)/2=16377x 负值循环次数 :32768/2=16384x=32766 到 x=-32768 1 次
k=16377+16384+1=32762
按 ANSI C int 为 2 字节 16 位 ,取值范围 -32768 ~ 32767
9
6.1.26.1.2 实型(浮点数)实型(浮点数)1. 实型类型单精度 float 4 个字节 32 位双精度 double 8 个字节 64 位
例如 float x,y ; double a,b ;
2.2. 数的取值范围数的取值范围 以 float ( 4 个字节)为例
指数符号
± ±
7 位指数值 数值符号
23 位小数值
所有实型数以二进制规格化浮点形式存储:
±0.××...×e±××
10
求最大值,此时指数、小数位全为“ 1”
指数值 1111111+ 110000000
2 1 1277 2127
小数值 .1111111...1 + 1
1.0
1 2 23
则 2 1 2 17014118 10127 23 38( ) .
同理最小值 2 2 2 2 938759 10127 1 128 38.
所以取值范围同理 double 型 8 个字节、指数位 10 位、小数位 52 位
所以取值范围 ±(10-38 ~ 1038)
±(10-308 ~ 10308)
11
3.3. 有效位数有效位数十进制 0 1 2 3 4 5 6 7 8 9二进制 000 001 010 011 100 101 110 111 1000 1001
由此可判断 3~4 位二进制可以表示 1 位十进制
float 23/3~4 一般称为 7~8 位
double 52/3~4 15~16 位
注注 在使用实型数要注意有效位数
如 float a ;
a=1234567.89;
语法不错,但 a= 1234567.875 ,只接受前 8 位有效值
12
6.1.36.1.3 字符型1. 字符类型 char 1 个字节 8 位例如 char ch;
2. 存储形式 所有数据以二进制形式存储 , 字符数据不能例外 字符数据以 ASCII 编码存储 , 存储形式同整型数据 int, 但 1 字节
例 字符 10 进制 8 进制 2 进制 a 的 ASCAII 编码 97 141 01100001 b 的 ASCAII 编码 98 142 01100010 1 的 ASCAII 编码 49 61 00110001
13
§6.2 常量和变量每种数据类型有常量和变量
常量:在程序运行过程中,其值不能被改变6.2.1 常量
1. 符号常量 用一个标识符代表一个常数。格式 #define 标识符 常数其中 标识符:字符序列,字母、数字符和底划线组成 第一个字符必须是字母或底划线 字符长度不限,但长度 >8 时只认前 8 个如 #define PI 3.14
14
例 6-1 输入球的半径,计算球的表面积和体积。#define PI 3.14#include <stdio.h>main(){float r,s,v; scanf("%f",&r); s=4.0*PI*r*r; v=4.0/3.0*PI*r*r*r; printf("s=%f,v=%f\n",s,v);}
s=4.0*3.14*r*r;
v=4.0/3.0* 3.14 *r*r*r;
注注 使用符号常量的好处是修改方便,便于移植 , 。例如在例 6-1 增加的精度 #define PI 3.1415926
增加程序的可读性,符号常量可以见名知义。定义符号常量标识符一般使用大写字母,与定义变量名区别
15
2.2. 整型常量 ( 整数 )
十进制:如 123 、 -456 、 0 与日常习惯同八进制: 0123 、 -011 以 0先导,以 0~7 构成16 进制: 0x123 、 -0x11 以 0x先导,以 0~9 和 A~F 或 a~f 构成任何一个整数都可以用 3 种形式来表示,
例如 10 、 012 、 0xa 它们的数值相同。
在内存均以二进制存储: 00001010
(1) 整数表示
16
(2)(2)数制转换数制转换
十进制 →八进制十进制 →八进制
整数转换:除 8 取余例如 17510=2578
175212
88
余数75
读数
一般数转换:整数、小数分别转换, 然后合写例如 175.82510=2578+0.6463...8=257.6463...8
小数转换:乘 8 取整
0.825× 8 6.600× 8 4.8× 8 6.4× 8
3.2
读数
例如 0.82510=0.6463...8
17
八进制与二进制转换八进制与二进制转换 3 位二进制表示一位八进制,对应关系: 八进制 0 1 2 3 4 5 6 7
二进制 000 001 010 011 100 101 110 111
由此可知 八→二:以小数点为界,一位拉三位 二→八:以小数点为界,三位合 一位 如 257.64638=10101111.1101001100112
十进制 → 十进制 → 1616 进制进制 十进制 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
16 进制 0 1 2 3 4 5 6 7 8 9 a b c d e f
整数转换:除 16 取余 小数转换:乘 16 取整如 175.82510=af.d3333...16
18
二进制与二进制与 1616 进制转换进制转换16 进制 0 1 2 3 4 5 6 7 8 9 a b c d e f
二进制 0 1 10 11 100 101 110 111 1000 1001 1010 1011 1100 1101 1110 1111
由此可知 16→ 二:以小数点为界,一位拉四位 二→ 16 :以小数点为界,四位合 一位 二、八、二、八、 16 16 进制→十进制进制→十进制
12345 1 10 2 10 3 4 10 4 10 5 10
257 6462 2 8 5 8 7 6 8 4 8 6 8 3 8
33 10 16 15 13 16 3 16 3 16
102 1 1 2 3
82 1 1 2 3 4
161 0 1 2
.
.
.
af d
例如
直接将数值用多项式展开 , 计算而得 .
19
(3)(3) 整数的类型整数的类型
(1)(1)根据数据计算机自动给定整型常量的类型 , 按最少字节数为原则 例 123 、 -567 short 50000 unsigned short
-50000 long (int)
判断整数的类型次序:
先根据整数后的字母,如果没有字母,再根据值的大小
(2)(2) 用 L 或 l 在数据的尾部强制定义 long 型 用 U 或 u 在数据的尾部强制定义 unsigned 型 用 LU 或 lu 在数据的尾部强制定义 unsigned long 型 例 123L 、 0L long
12u 、 034u 、 0x2fdu unsigned
4294967295lu unsigned long
20
3.3. 实型常数实型常数((实数))
实型数(又称浮点数):带小数点的数,只能表示十进制数
基本型基本型(浮点数) 格式 ±a.b ±.b ±a .其中 a 、 b 是若干位十进制数 0~9 ,“ +” 可省略。例如 123.0 0.123 .123 123.
指数型指数型(科学记数法)(科学记数法)如 12 10 5. 1.210-5 → 1.2e-5 或 1.2E-5格式 ±a.bE±d ±.bE±d ±a.E±d ±aE±d其中 a 、 b 是若干位十进制数 0~9 , d 为 1~3 位 十进制数, “+” 可省略。例如 123.123e-5 .123e-1 -123.E-2 123E2
(1) 实数的表示
(2) 实常数的类型均为 doulbe
21
4 字符型常量 (1) 单个字符 , 用单引号括起的单个字符 格式 ' 单个字符 ' 例 'A' 、 'a'
(2) 使用转义字符 \ 表示 格式 '\单个字符 ' 或 '\数字 ' 参见表 6-3 \n 换行 \t 横向跳格 \v 竖向跳格 \\ 反斜杠 \ \' 单引号 \" 双引号 \ddd 1~3位八进制 \xhh 1~2 位 16 进制
例 A 65(+) 101(八 ) 41(16) '\101'='A' 或 '\x41'='A' 换行 10(+) 12 (八 ) '\012' = '\n' 或 '\12'='\n'
22
6.2.2 变量变量:在程序运行过程中,其值可以被改变1. 变量定义 类型名 变量名表;
例如:int a, b; char ch; double x, y;
定义变量做了 3件事:变量取名、确定数据类型、分配内存 注注变量在使用之前必须定义。变量定义的位置在函数体的说明部分选择变量类型根据存储数据形式、数值范围、有效位确定
23
2. 变量赋初值 定义变量的同时当即给变量赋值 格式 类型关键字 变量名 = 数据;
例 int a=3; 相当于 int a; a=3
float f=3.56; 相当于 float f; a=3.56
char c= 'a' 相当于 char c; a= 'a'
double x,y,z=5; 相当于 double x,y,z; z=5;
注 注 变量在引用之前必须先赋值。
24
数据输入:通过外设将数据输入内存。数据输出:将内存的数据通过外设输出。
§6.3 数据的输入和输出
输入和输出通过调用函数实现输出函数: printf( 格式控制,输出表列 ); putchar( 输出字符 ); 仅用于字符型输入函数: scanf( 格式控制,地址表列 ); getchar() 仅用于字符型格式控制由 % 格式符和普通字符构成
% 格式符:控制数据输入 / 输出的类型普通字符:输出,照原样输出 输入,作为数据的分隔符,输入数据时同时输入
%格式符与表列数据的个数、类型、位置必须一一对应
25
6.3.1 整型格式符
输出时可以域宽控制: %md 、 %mo 、 %mx
%-md 、 %-mo 、 %-mx
m 为正整数 , 指定输出长度 (包含符号位 ) 。 若数据位数小于 m,
若无 - 号,则数据按右对齐,左端补上空格。 若有 - 号,则数据按左对齐,右端补上空格。 若数据位数大于 m, 数据按实际位数输出
26
例 6-2
输出:10,12,a
#include <stdio.h>void main( ){ printf("%d,%o,%x\n",10,10,10); }
# include <stdio.h>
void main( )
{int a, b;
printf("input a, b:");
scanf("%o%d", &a, &b);
printf("%d%d\n", a, b);
}
例
input a, b: 17 17
15 17
27
#include <stdio.h>void main( ){int i,j; printf(" |"); for(i=1;i<10;i++)printf("%5d",i); printf("\n"); for(i=1;i<=10;i++)printf("-----"); printf("-\n"); for(i=1;i<10;i++) {printf("%5d|",i); for(j=1;j<10;j++)printf("%5d",i*j); printf("\n"); }}
| 1 2 3 4 5 6 7 8 9---------------------------------------------------- 1| 1 2 3 4 5 6 7 8 9 2| 2 4 6 8 10 12 14 16 18 3| 3 6 9 12 15 18 21 24 27 4| 4 8 12 16 20 24 28 32 36 5| 5 10 15 20 25 30 35 40 45 6| 6 12 18 24 30 36 42 48 54 7| 7 14 21 28 35 42 49 56 63 8| 8 16 24 32 40 48 56 64 72 9| 9 18 27 36 45 54 63 72 81
例 输出乘法九九表
28
6.3.2 实型格式符
输出时域宽控制: %m.nf 、 %m.ne %-m.nf 、 %-m.ne
m,n 为正整数 , m 输出长度 (包含符号和小数点的位 ),n 指定小数位。 若数据位数 <m,
若无 - 号,则数据按右对齐,左端补上空格。 若有 - 号,则数据按左对齐,右端补上空格。 若数据位数 >m, 数据按实际位数输出 n缺省 , 小数为 6 位。 m缺省 , 数据按实际位数 ,
注:指数形式 ±0.××...×e±×××
29
例 #include <stdio.h>
void main()
{double d=3.1415926;
printf("%f,%e\n",d,d);
printf("%10f,%10.2f,%-10.2f,%.2f,%0.f\n",d,d,d,d,d);
}
输出 3.141593, 3.141593e+000
%f %e小数 6 位 , 整数按实际 小数 6 位 , 整数 1 位 , 指数 3位
输出 3.141593, 3.14,3.14 ,3.14,3
%10f %10.2f %-10.2 %.2f %0.f
30
6.3.3 字符型格式符char %c
注在 %c 格式输入时忽略空格分隔符 , 即不需要分隔符 ,而空格作 为字符输入。若要输入字符之间空格分隔,则 scanf("%c %c %c",&ch1,&ch2,&ch3);
若输入 abc
则输出 a#b#c表示输入 / 输出一个字符。例 6-3 #include <stdio.h>
void main(){char ch1,ch2,ch3; scanf("%c%c%c",&ch1,&ch2,&ch3); printf("%c%c%c%c%c",ch1,'#',ch2,'#',ch3);}
若输入 a b c
则输出 a# #b
键入的字符不需单引号
31
整型与字符型输入 / 输出转换
例 main() {int i; char c; i='a';c=97; printf("%c,%d\n",c,c); printf("%c,%d\n",i,i); }
输出 a,97
a,97
整型与字符型互换运算
例 main() {char c1,c2; c1='a';c2='b'; c1=c1-32; c2=c2-32; printf("%c %c\n",c1,c2); }
输出 A B
解释 A,a 的 ASCII 码分别为 65 、 97, 两者之差为 32, 则 大写字母 = 小写字母 -32 小写字母 = 大写字母 +32 所以 'B'='b'-32 或 'B'='b'-('a'-'A')同理 把数字字符 c转成数字 c-'0' 如 c='5' '5' 的 ASCII 码 53 '0' 的 ASCII 码 48 53-48--->5
32
字符存储同 int, 则存储单元的最高位应是符号位例 字符 十进制 八进制 二进制 按 %d 输出 a 97 141 01100001 97
■ 254 376 11111110 -2
( 补码 10000010)
解释 由于存储单元的最高位是 1, 表示为负数 , 则按补码输出 ASCII 为 128~255之间的字符均存在此问题
例 main() { char c; c='\376'; printf("%d\n",c); }输出 -2解决办法使用 unsigned char 定义字符变量
例 main() { unsigned char c; c='\376'; printf("%d\n",c); }
输出 254
33
§6.4 类型转换不同类型数据的混合运算,由于类型数据存储形式不一样,必须转换为同一类型,才能运算。6.4.1 自动类型转换(1) 非赋值运算的类型转换 水平方向:自动 垂直方向:低 高
高 double ←float
↑
long
↑
unsigned ← unsigned short
↑
低 int ←char,short
例 int i; float f; double d; long e;
10 + 'a' + i * f - d / e
int
double
double
double double
34
(2) 赋值运算的类型转换
变量 = 表达式
当表达式的类型与被赋值的变量不一致时 , 表达式的值类型自动制转成变量的类型
double x;x = 1; x = 1.0
short a = 1000;char b = 'A';long c;c = a + b; c = 1065
int ai;ai = 2.56;
ai = 2
int bi;bi = 0x12345678L;
bi = ?printf(“%x”,bi);
vc: 12345678
tc: 5678
35
6.4.2 强制类型转换对表达式的值强制转换格式 ( 类型关键字 ) ( 表达式 )
例 (double) a
(int) (x+y)
(float) (5%3)
(int) (10+ 'a' +i*f-d/e)
注 括号用法 (int) x+y 仅对 x 有效 强制转换仅对表达式的值 , 原变量的类型不改变 将实型数强制转换成整型 , 即为取整
36
§6.5 表达式表达式:用运算符将运算对象及括弧按语法规则连接起来的式子
6.5.1 算术表达式
+ - 正 负 单目运算 2 级 从左到右+ - 加 减 双目运算 4 级 从左到右* / % 乘 除 取余 双目运算 3 级 从左到右++ -- 自增 自减 单目运算 2 级 从右到左
算术运算符:
37
自增、自减运算 ++ 自增 -- 自减 单目运算操作 对操作的变量在运算前或后使其值加 (自增 ) 或减 (自减 ) 1 如 ++i, --i 在使用 i之前先使 i 的值加 (减 ) 1 i++, i-- 在使用 i之后使 i 的值加 (减 ) 1例 i=3; ++i; i++;
printf("%d",i);
可认为 ++i; i++; 相当于 i=i+1
--i; i--; 相当于 i=i-1
但这仅适合自增自减对单个变量操作的表达式 , 如表达式有其它运算符就不一样了例 j=++i; 设 i=3 则 j 的值为 4 i 的值为 4
j=i++; 设 i=3 则 j 的值为 3 i 的值为 4
输出 5
38
注自增自减 运算对象仅是一个整型变量 如 5++; (a+b)--; 是不允许 ++,--优先级为 2 级 , 从右到左 结合 如 -j++ 理解为 -(j++)
j+++k 理解为 (j++)+k + 比 ++ 级别低自增自减 的副作用
C 语言中,根据运算符的优先级和结合性决定表达式的计算顺序,但对运算符两侧操作数的求值顺序并未做出明确的规定,不同编译系统采取不同的处理方式。
例 f()+g() 可以 先 f(),再 g(), 最后 +也可 先 g(),再 f(), 最后 +
但自增自减 将产生歧义性结果。
39
如 s=(i++)+(i++)+(i++) 设 i=3 可能 s=3+4+5 也可能 s=3+3+3
得到不同的结果。尽量避免使用。如果原意得到 12 ,语句可用多句表示i=3;a=i++;b=i++;c=i++;s=a+b+c;
如 s=(++ i)+(++ i)+(++ i)
设 i=3
可能 s=4+5+6 也可能 s=6+6+6
ANSI C
ANSI C
在 ANSI C自增或自减规定 :
对表达式中变量前的自增或自减 , 整个表达式计算之前完成计算对表达式中变量后的自增或自减 , 整个表达式计算完成后再计算
40
6.5.2 赋值表达式
例 a=5
a=b=5 相当于 a=(b=5)
a=(b=4)+(c=6) 得 a=10,b=4,c=6
1.赋值运算符= 赋值运算 双目运算 14 级 从右到左
格式 变量 = 表达式计算表达式的值将表达式的值赋给变量将变量的值作为赋值表达式的值
操作
注:当表达式的类型与被赋值的变量不一致时 , 表达式的值类型强制转成变量的类型
41
2. 复合赋值运算符格式 < 算术运算符 > =
+= 加赋值 x+=exp 等价于 x=x+exp-= 减赋值 x-=exp 等价于 x=x-exp*= 乘赋值 x*=exp 等价于 x=x*exp/= 除赋值 x/=exp 等价于 x=x/exp%= 取余赋值 x%=exp 等价于 x=x%exp
例 a+=3 等价于 a=a+3 x*=y+8 x=x*(y+8) x%=3 x=x%3
注 赋值运算符的优先级为 14 级 , 运算从右到左 例 a+=a- =a*a 等价于 a+=(a=a-a*a) a=a+(a=a-a*a)
a=a-a*a; a=a+a;
42
关系运算符< 小于 < = 小于或等于> 大于> = 大于或等于= = 等于! = 不等于
6 级从左到右 双目运算
6.5.3 关系表达式
6.5.4 逻辑表达式 逻辑运算符&& 逻辑与 11 级
| | 逻辑或 12 级
! 逻辑非 2 级
双目运算 从左自右
单目运算 从右自左
7 级
43
注关系运算符连写无意义如 x>y>z 应为 x>y&&y>z
逻辑运算操作数可以是任意类型的数据,对非 1 或 0 的数据在进行逻辑运算之前转换成 1 或 0 ,非 0 数都转成 1 。例 5>3 && 2 | | 8 < 4 - ! 0
11
1
1
3
0
1
44
逻辑表达式从左到右的顺序计算运算符两侧的操作数,一旦已经能明确答案了,剩余计算就不再做了。
如 exp1&&exp2
当计算 exp1 为 0 时 ,exp1&&exp2 的值一定是 0 。对 exp2就不再计算例 设 x=5,y=5,z=0 计算 x&&z&&(y=1)
x&&z&&(y=1) 0x=5y=5 z=0又如 exp1||exp2
当计算 exp1 为 1 时 ,exp1&&exp2 的值一定是 1 。对 exp2就不再计算
45
逻辑表达式的等价关系x==0 和 !x等价
x x==0 !x非 0 0 0 0 1 1
!(x==0&&y==0) 、 x!=0||y!=0 和 x||y等价 x y !(x==0&&y==0) x!=0||y!=0 x||y
非 0 非 0 1 1 1非 0 0 1 1 1 0 非 0 1 1 1 0 0 0 0 0
x x&&1 A)x==0 B)x==1 C) x!=0 D) x!=1 0 0 1 0 0 1非 0 1 0 0 1 0
答案: C表达式 x&&1等价于 ( ) 。 A. x==0 B. x==1 C. x!=0 D. x!=1
46
6.5.5 条件表达式格式 表达式 1? 表达式 2: 表达式 3
其中 ? 与 : 是运算符 ,唯一的三目运算符操作 先计算表达式 1,若表达式 1 的为非0
, 则计算表达式 2 的值作为条件表达 式的值 ;否则计算表达式 3 的值作为 条件表达式的值。
表达式 1
表达式 2 表达式 3
非 0
0
例如 设 a 、 b 是整型变量 , 将 a 、 b 的最大值赋给 z 。
if(a>b) z=aelse z=b;
if 语句 : 条件表达式 :
z=(a>b)?z=a:z=b;
47
注 1.条件表达式运算符 ? 和 : 的计算优先级为 13 级 ,从右至左结合 例 max=((a>b)?a:b)
max=(a>b)?a:b max=a>b?a:b
均等价
例 a>b?a:c>d?c:d 等价于 a>b?a:(c>d?c:d) 2.条件表达式中的三个表达式的类型可以不同 , 但表达式的
值取表达式 2 与表达式 3 的高者类型例 x>y?1:1.5 得到是实型
3条件表达式中自增、自减的计算的次序执行下列程序后, a 的值为: int a,b; a=15;b=12; a=(a--= =b++)?a/5:a%5; A) -1 B) 3 C) 4 D) 0 答案 C
15==12--->0a-- a=14b++ b=13a%5 14%5--->4
48
4. 使用条件表达式描述某些函数 , 语句非常简练
例 (a>b)?a:b 表示为 max(a,b)
(a>0)?a:-a 表示为 |a|
a>0?1:(a<0?-1:0) 表示为 sign(a)
a>b?(a>c?a:c):(b>c?b:c) max(a,b,c)
简单的 if 语句程序用条件表达式来实现更为方便例 计算分段函数 if(x<=1) f=exp(x); else f=x*x-1;
f=(x<=1)?exp(x): x*x-1;
例 小写字母转换大写字母
if(ch>='a'&&ch<='z') ch=ch-'a'+'A';
(ch>='a'&&ch<='z')?ch=ch-'a'+'A':ch;
49
格式 表达式 1, 表达式 2,.. 表达式 n
用逗号将各表达式分割 , 整个式子称为逗号表达式 其中逗号是运算符 , 其优先级为最低级 (15 级 ),从左到右计算表达式 最后的表达式 n 的值作为逗号表达式的整体值例 3+5,6+8 得 14
a=3*5,a*4 60
x=(a=3,6*3) 18 x=18注 不是任何地方出现的逗号都作为逗号运算符 例 函数参数之间使用逗号分割 printf("%d,%d,%d",a,b,c); a,b,c 不是逗号表达式 printf("%d,%d,%d",(a,b,c),b,c); (a,b,c) 是逗号表达式
6.5.6 逗号表达式
函数参数从右到左计算例 i=1;printf(“%d %d %d”,i,i=i+1,i=i+1); 输出 3,3,2
50
#include <stdio.h>void main( ){int a,b,t; printf("input a, b: "); scanf("%d%d", &a, &b); if(a<b) {t=a;a=b;b=t;} printf("%d %d", a,b);}
1.逗号表达式简化复合语句
2.逗号表达式用于 for 的循环表sum=0;
for(i=0;i<=100;i++)
sum=sum+i;
for(i=0,sum=0;i<=100; i++)
sum = sum + i;
if(a<b) t=a,a=b,b=t;
逗号表达式的用途
51
6.5.76.5.7 位运算位运算
位二进制数上的一个位
位运算二进制的位运算
1. 位运算和位运算符
位运算有: ~ 按位取反 2 级 单目运算 从右到左& 按位与 8 级 双目运算 从左到右^ 按位异或 9 级 双目运算 从左到右| 按位或 10 级 双目运算 从左到右<< 字位左移 5 级 双目运算 从左到右>> 字位右移 5 级 双目运算 从左到右
52
(1) ~ 按位取反 格式 ~ 整数 操作 将整数按位取反 , 每位 0→1,1→0
例 ~025=0177752
025(8) =0000000000010101(2) →1111111111101010(2)
53
(2) & 按位与 格式 整数 1 & 整数 2
操作 将两个整数按二进制位按位取与 , 即
0 & 0 = 0 0 & 1 = 0 1 & 0 = 0 1 & 1 = 1
例 3&5=1 00000011& 00000101 00000001
特殊用法 取指定位的数 , 指定位的数 &1→ 原值 , 其他位的数 &0→0 例 取整数的低字节位表示的数
a&0377 0010110010101100& 0000000011111111 0000000010101100
54
(3) ^ 按位异或 格式 整数 1 ^ 整数 2
操作 将两个整数按二进制位不进位相加 , 即 0 ^ 0 = 0 0 ^ 1 = 1 1 ^ 0 = 1 1 ^ 1 = 0例 071^052=023
00111001^ 00101010 00010011
例 将 01111010 的低 4 位翻转 , 高 4 位不变 01111010 ^ 00001111 01110101
特殊用法 指定数的某些位翻转 0→1,1→0 。要使位翻转 ^1, 要使位不变^0
55
交换两个数 , 不用临时过渡变量例 a<=>b a=a^b;b=b^a;a=a^b;
类同两个变量交换值 a=a-b;b=a+b;a=a-b; 或 a=a+b;b=a-b;a=a-b;
a^a = 0
a^~a = 二进制全为 1
~(a^~a)=0
设 a=3,b=4
a=011b=100a=111b=100b=011a=111a=100
^
^
^
a=a^b;
b=b^a;
a=a^b;
证明 :a=a^b; (1)b=b^a; (2)a=a^b; (3)证明 ab (1) 代入 (2),得 (4) b=b^(a^b)=b^a^b =a^b^b=a^0=a证明 ba (1)(4) 代入 (3)a=a^b=(a^b)^(b^a^b) =a^b^b^a^b =a^a^b^b^b=b
56
(4) | 按位或 格式 整数 1 | 整数 2
操作 将两个整数按二进制位按位取或 , 即 0 | 0 = 0 0 | 1 = 1 1 | 0 = 1 1 | 1 = 1
例 061^017=077 00110001| 00101111 00111111
特殊用法 使指定位为 1 ,该位值 |1→1
例 使整数 a 的低 8 位均为 1 a | 0377
57
(5) << 字位左移 格式 整数 <<左移位数操作 将整数的二进制位左移规定的位数 ,左移出位舍去 ,右补 0例 15<<2=60 0000000000001111 2← 000000000000111100 074(8)=7*8+4=60
特殊用法 整数 <<左移位数 相当于 整数2位数
如 15<<2
15 2 602 但左移出位舍去位不能有 1
58
(6) >> 字位右移 格式 整数 >>右移位数操作 将整数的二进制位右移规定的位数 ,右移出位舍去 ,左补 0 或1
TC 、 VC根据整数的正负决定左补 0还是 1, 即正补 0, 负补1
但 unsigned 数均补 0例 15>>2 =3 0113755>>1=0145766 0000000000001111 1001011111101101 000000000000001111 →2 11001011111101101 →1
特殊用法 整数 >>右移位数 相当于 整数2位数
如 15>>2
15 2 32 但被除数需是正值
注位运算符能作为复合赋值运算符 &=,|=,>>=,<<=,^=
例 a&=b; 等价 a=a&b;
两个整型长度不同也能进行位运算 , 以右对齐 ,左补 0
位运算只对整数 , 一般使用 unsigned 数据
59
例 取一个整数 a从右端开始的 4~7 位
a
15 14 7 6 5 4 3 2 1 0
(1)右移 4 位 a>>4
0 0 0 0
15 14 7 6 5 4 3 2 1 0
(2)屏蔽 4~15 位 a&017
a
main(){unsigned int a; scanf("%o",&a); a=a>>4; a=a&017; printf("%o\n",a);}
60
表达式 (7<<1>>2^2 ) 的值是 _______ 。 答案: 1
表达式 (10>>1^-1) 的值是 ________ 。 答案: -6
00000111<<1 ----> 00001110
00001110>>2 ----> 00000011
00000011^2 ----> 00000011^10 ----> 00000001
10 ----> 00001010
00001010>>1 ----> 00000101-1 的补码:原码 10000001
反码 11111110
补码 = 反码 +1 11111111
00000101^-1 ----> 00000101^1111111
反码 = 补码 -1 11111010-1 ----> 11111001
原代码 =~ 反码 ~11111001----> 10000110 ---->-6
---->11111010
top related