一、十进制与二进制
十进制:逢十进一
二进制:逢二进一
0 0
1 1
2 10
3 11
4 100
5 101
6 110
7 111
8 1000
9 1001
二、进制转换
1.二进制与十进制的转换
1)位与权
93 = 9 * 10 + 3 * 1
位 权 位 权
整数93在一个字节中的二进制形式:
0 1 0 1 1 1 0 1 - 位
128 64 32 16 8 4 2 1 - 权
2)零和正数:符号位(最高位)为0
A.二转十:一位加权,零位不见
01011101=64+16+8+4+1=93
01101101=64+32+8+4+1=109
B.十转二:有权添一,无权补零
93-64=29-16=13-8=5-4=1 -> 01011101
109-64=45-32=13-8=5-4=1 -> 01101101
127-64=63-32=31-16=15-8=7-4=3-2=1 -> 01111111
3)负数:符号位(最高位)为1
A.二转十:取反加一,转十添负
10100011取反01011100加一01011101转十
64+16+8+4+1=93添负-93
10010011取反01101100加一01101101转十
64+32+8+4+1=109添负-109
B.十转二:去负转二,取反加一
-93去负93转二93-64=29-16=13-8=5-4=1->01011101取反10100010加一10100011
-109去负109转二109-64=45-32=13-8=5-4=1->01101101取反10010010加一10010011
练习:
char c = -191;
printf ("%d", c); // 65
printf ("%c", c); // A
-191去负191转二191-128=63-32=31-16=15-8=7-4=3-2=1->10111111取反01000000加一01000001=64+1=65
-------------------------------------------
short h = -191;
printf ("%h", h); // -191
-191去负191转二
0000000010111111取反
1111111101000000加一
1111111101000001 -> -191
2.二进制和十六进制的转换
四位二进制对应一位十六进制
十进制 二进制 十六进制
0 0000 0
1 0001 1
2 0010 2
3 0011 3
4 0100 4
5 0101 5
6 0110 6
7 0111 7
8 1000 8
9 1001 9
10 1010 A
11 1011 B
12 1100 C
13 1101 D
14 1110 E
15 1111 F
一个字节对应两位十六进制
93 0101 1101 0x5D
109 0110 1101 0x6D
-93 1010 0011 0xA3
-109 1001 0011 0x93
-191 1111 1111 0100 0001 0xFF41
3.二进制和八进制的转换
三位二进制对应一位八进制
十进制 二进制 八进制
0 000 0
1 001 1
2 010 2
3 011 3
4 100 4
5 101 5
6 110 6
7 111 7
93 01 011 101 0135
109 01 101 101 0155
-93
-109
-191
三、运算符与表达式
1.算数运算
1)+、-、*
2)/、%
整数相除,取整数部分。
/和%不能对整数0进行操作,否则会中断程序。但是可以对浮点0进行操作,但是得到的结果是inf,表示无穷大。
%不能对浮点数使用。
/向零取整(取更接近0的数字)。
%的结果与其左操作数的符号一致。
练习:要求用户输入一个秒数,以xx小时xx分钟xx秒的格式打印出来。
2.赋值运算
1)将赋值运算符右边的值付给左边的变量。
int a;
a = 10; // 将10赋给a
2)赋值表达式的值就是赋值表达式左操作数的值。
int a, b, c;
a = b = c = 10; // a = (b = (c = 10));
printf ("%d,%d,%d\n", a, b, c); // 10,10,10
3)赋值运算符的左操作数必须是一个左值——可被赋值的对象——变量,常量或表达式不能被赋值。
100 = 200; // error
100 = a; // error
a + b = c; // error
4)赋值运算符是“=”而不是“==”。
5)赋值运算符还可和其它运算符结合起来使用,构成复合赋值。
a += b; // a = a + b
a %= b; // a = a % b
6)初始化与赋值是不同的。
int a = 10; // 初始化
a = 20; // 赋值
3.自增减运算
1)++/--:变量自增/减1。
int a = 10;
a++; // a:11
a--; // a:10
++a; // a:11
--a; // a:10
2)不能用于常量。
100++; // error
--100; // error
3)可以用于所有的整型类变量,以及浮点类,但是多数情况下用于int。
4)前后缀自增减的区别:
前缀:先自增减,在计算表达式。
后缀:先计算表达式,再自增减。
a++表达式和++a表达式的值都是从操作数a的内存空间中得到的。二者的区别在于,一个是先取表达式的值再自增,另一个是先自增在取表达式的值。
5)忠告:自增减运算最好不要在一个表达式中使用多次。
4.关系运算
>/>=/</<=/==/!=
关系运算表达式的值是整数:1或者0。
逻辑真:1
逻辑假:0
5.逻辑运算
1)逻辑与(&&)、逻辑或(||)、逻辑非(!)
A && B:只有当A和B的值都为真(非零)时,表达式的值才为真。
A || B:只有当A和B的值都为假(零)时,表达式的值才为假。
! A:当A的值为真时,表达式的值为假,当A为假时,表达式的值为真。
2)短路运算
A && B:如果A的值为假,则B不处理。
A || B:如果A的值为真,则B不处理。
6.位运算
1)位与(&)/位或(|)/位异或(^)/位反(~)
位与:参与运算的两位都是1结果为1,否则为0。位与可以置某一位为0,也可以得到某一位的值。
10110001 A
11101111 B
&)-----------
10100001 C
^
10110001 A
00010000 B
&)----------- 若A&B==B,则A中此位为1
00010000 C
^
位或:参与运算的两位都是0结果为0,否则为1。位或可以置某一位为1,也可以得到某一位的值。
10100001 A
00010000 B
|)------------
10110001 C
^
10100001 A
11101111 B
|)------------ 若A|B==B,则A中此位为0
11101111
^
异或:参与运算的两位相异为1,相同为0。异或可以翻转某一位,想翻哪位哪位就是1,其余为0。
10101010 A
00100100 B
^)------------
10001110 C
^ ^
A^B->C
C^B->A
C^A->B
异或还可用于在不增加第三变量的前提下,交换两个变量的值。
int a = 10, b = 20;
int c = a;
a = b;
b = c;
--------------------
a : 1011
b : 0110
a = a ^ b; // a : 1101
b = a ^ b; // b : 1011
a = a ^ b; // a : 0110
位反:按位取反
01100001
~)-----------
10011110
2)左右移位
A.有符号数:左移补零,右移补符
10101010 << 1 -> 01010100
-86 84
10101010 >> 1 -> 11010101
-86 -43
B.无符号数:左移右移全补零
10101010 << 1 -> 01010100
170 84
10101010 >> 1 -> 01010101
170 85
在不发生溢出的情况下,左移一位即乘2,右移一位即除2。
00000001 << 1 -> 00000010
1 2
7.取地址和解引用(取目标)运算
取地址&:获取一个变量的地址,即其首字节的地址。
解引用*:根据地址获得变量的值。
8.类型转换
1)类型升级:由低级类型转换为高级类型。浮点高于整型,长整型高于短整型(long long > long > int > short > char)。若有符号类型能够表示无符号类型的值,则取有符号类型,否则按无符号处理。
2)强制转换:目标类型变量 = (目标类型)源类型变量。
double f = 1.23;
int n = (int)f; // n : 1
无论哪种形式的类型转换对于源变量都不会产生任何影响。
9.条件运算
条件表达式 ? 表达式1 : 表达式2
若条件表达式为真,则整个表达式的值取表达式1的值,否则整个表达式的值取表达式2的值。
#include <stdio.h>
int main (void) {
int a = 10;
printf ("%d\n", ++a); // 11
printf ("%d\n", a); // 11
a = 10;
printf ("%d\n", a++); // 10
printf ("%d\n", a); // 11
a = 10;
printf ("%d\n", a++ + ++a); //22, 11+11
printf ("%d\n", a); //12
a = 10;
printf ("%d\n", a++ + ++a + ++a);
// 34,11+11+12
printf ("%d\n", a); // 13
a = 10;
printf ("%d\n", a++ + --a - a-- * ++a); // 9+9-10*10=-82
printf ("%d\n", a); // 10
return 0;
}
#include <stdio.h>
int main (void) {
int a, b, c;
a = 100;
printf ("a=%d\n", a);
a = b = c = 200;
printf ("%d,%d,%d\n", a, b, c);
//(a = b) = 300; // 表达式不能做左值
//a + b = c;
a += b;
printf ("a=%d\n", a);
return 0;
}
#include <stdio.h>
int main (void) {
int a = 2, b = 3, c = 0;
printf ("a/b=%d\n", a / b);
printf ("a%%b=%d\n", a % b);
//printf ("a/c=%d\n", a / c);
//printf ("a%%c=%d\n", a % c);
double d = 0;
printf ("a/d=%lf\n", a / d);
//printf ("a%%d=%lf\n", a % d);
printf ("%d,%d\n", 7/3, -7/3);
printf ("%d,%d\n", -7%3, 7%-3);
return 0;
}
#include <stdio.h>
int main (void) {
printf ("请输入一个秒数:");
int sec;
scanf ("%d", &sec);
printf ("%d小时%d分钟%d秒\n", sec / 3600, sec % 3600 / 60, sec % 60);
return 0;
}
#include <stdio.h>
int main (void) {
printf ("%d\n", 5>3 && 5<8); // 1
printf ("%d\n", 5>3 && 5>8); // 0
printf ("%d\n", 5<3 && 5<8); // 0
printf ("%d\n", 5<3 && 5>8); // 0
printf ("%d\n", 10 || 0); // 1
int a = 0;
printf ("%d\n", a++ || a++); // 1
printf ("%d\n", ! (10 > 20)); // 1
printf ("%d\n", ! 10 > 20); // 0
a = 10;
printf ("%d\n", 5>3 && (a=100));
printf ("%d\n", a); // 100
printf ("%d\n", 5<3 && (a=200));
printf ("%d\n", a); // 100
printf ("%d\n", 5>3 || (a=300));
printf ("%d\n", a); // 100
int b, c;
a = b = c = 1;
++a || --b && ++c;
// 等价++a || (--b && ++c)
printf ("%d,%d,%d\n", a, b, c);
// 2,1,1
return 0;
}
#include <stdio.h>
int main (void) {
printf ("%d\n", 5 > 2);
printf ("%d\n", 3 <= 3);
printf ("%d\n", 10 == 8);
printf ("%d\n", 10 != 10);
return 0;
}
#include <stdio.h>
int main (void) {
int a = ((10 > 5) ? 10 : 5);
printf ("%d\n", a);
a = ((10 < 5) ? 10 : 5);
printf ("%d\n", a);
a = 10;
int b = 9;
int c;
c = (--a == b++) ? --a : b++;
printf ("%d,%d,%d\n", a, b, c);
// 8,10,8
return 0;
}