进制是一种计数的表现方式。
我们日常生活中用十进制,即每满10个,前一位加1,当前位清零;
而计算机只能读懂0和1,所以计算机是二进制,每满2个,前一位加1,当前位清零;
内存地址用十六进制计数,每满16个,前一位加1,当前位清零,十六进制中数字10到15用ABCDEF这六个字母表示;
当然,还有八进制,如果你愿意,三进制、四进制、五进制你都可以用,鉴于大多数人都不用这些进制,我猜它们可能不太好用,这里就不研究了。
我们来感受一下二进制、八进制、十六进制是如何使用的,数一下下面有多少个笑脸,分别用各种进制计数。
十进制:12
二进制:1100
八进制:14
十六进制:C
试着判断一下下面的数字写法是否合理?
00011 0x0011 0x7H4 10.98 0986 .089 -109
+178 0b325 0b0010 0xFFdc 96f 96.0f 96.0F
-.003 15.4e6 10e8.7 7.6e-6
上面标黄的写法是不合理的。
.089的写法是正确的 .089 == 0.089
+178的写法是正确的 +178 == 178
-.003的写法是正确的 -.003 == -0.003
15.4e6的写法是正确的 15.4e6 == 15.4 * 10的6次方
7.6e-6的写法是正确的 7.6e-6 == 7.6 * 10的-6次方
不同类型的数据占用的字节是不一样的,一个整型变量占用4字节(Byte),1字节(Byte)=8比特位(bit)
1>所占用字节数跟类型有关,也跟编译器环境有关
//一个int类型数据占用4个字节,即32bit
//0000 0000 0000 0000 0000 0000 0000 1100
int num1 = 12;
//0000 0000 0000 0000 0000 0000 0000 1101
int num2 = 13;
为变量分配内存地址时是从大往小分配的,下图中得内存地址是我虚构的,但不影响举例。
首先,由于num1和num2都是int类型,所以他们都占用4个字节。
1>最高位(比特位)为1,表示负数,最高位为0,表示正数
2>负数的表示形式:反码、补码
假设我们现在有1个字节的空间,这个空间内存储的数的取值范围是多少?
1字节等于8比特,1个比特储存的数有两种可能,0和1,8比特就有2的8次方种可能。
内存中第一位默认标识数组的正负,所以就只剩下2的7次方种可能。
所以1字节能存的数的取值范围为 负2的七次方~正2的七次方-1。
5.练习题
写出下列变量在内存中的存储情况
int a = 134;
int b = 0;
int c = -10;
下面是各种类型的占位符格式:
int %d
short %d
long %ld
long long %lld
char %c
float / double %f %.nf(显示小数点后n位)
signed: 内存比特位中最高位作为符号位(0正1负) 取值范围 -2^31~2^31-
unsigned: 内存比特位中最高位不作为符号位 取值范围 0~2^32
unsigned输出 %u
unsigned long %lu
1)功能:只有对应的两个二进制位均为1时,结果位才为1,否则为0。
2)举例:
计算 9 & 5;
9转换成二进制为: 1001
5转换成二进制为: 0101
每一位按位与后的结果: 0001
0001转换为的十进制结果为: 1
3)规律: 二进制中,与1相&就保持原位,与0相&就为0。
1) 功能
只要对应的二个二进位至少有一个为1时,结果位就为1,两个二进制位都不为1,结果位就为0。
2)举例:
比如 9 | 5,其实就是1001 | 101 = 1101,因此 9 | 5 = 13
计算 9 | 5
9转换成二进制 1001
5转换成二进制 0101
每一位按位与或的结果 1101
1101转换为的十进制结果为:13
1) 功能
当对应的二进位相异(不相同)时,结果为1,否则为0。
2)举例:
比如9^5,其实就是1001^101=1100,因此9^5=12
计算 9 ^ 5;
9转换成二进制 1001
5转换成二进制 0101
每一位按位与或的结果 1100
1100转换为的十进制结果为:12
3)规律
1>相同整数相^的结果是0。比如5^5=0
2>任何数值跟0进行异或,结果还是原来的数值 9 ^ 0 == 9
3>多个整数相^的结果跟顺序无关。比如5^6^7=5^7^6
4.>因此得出结论:a^b^a = b
1) 功能
对整数a的各二进位进行取反,符号位也取反(0变1,1变0)
2)举例:
比如9按位取反 ~9
计算 ~9 ;
9转换成二进制 0000 0000 0000 0000 0000 0000 0000 1001
按位取反后的结果 1111 1111 1111 1111 1111 1111 1111 0110
~9 == -10
想了解负数的内存占用,需要复习原码、反码、补码
1) 功能
a<
计算 9<<2 ;
这一行0用来做参照物 0000 0000 0000 0000
1) 功能
把整数a的各二进位全部右移n位,保持符号位不变。右移n位其实就是除以2的n次方
2) 举例
计算 8>>2 ;
这一行0用来做参照物 0000 0000 0000 0000 0000 0000 0000 0000
8符号位不动,右移两位 0000 00 0000 0000 0000 0000 0000 0000 1000
最高位补的值与符号位保持一致,所以补两次0,最后结果为2
3) 规律
1>为正数时, 符号位为0,最高位补0
2>为负数时,符号位为1,最高位是补0或是补1 取决于编译系统的规定
3>当计算a/2的n次方时,可以用a>>n来代替,右移的运算效率比除法高。
#include
int main()
{
int a = 7, b = 8;
a = a^b;
b = a^b; // 相当于b= a^b^b == a
a = a^b; // 相当于 a = a^b^a== b
printf("a=%d, b=%d\n", a, b);
return 0;
}
#include
int main()
{
int a = -4;
int b = a & 1; // 取出a的二进制的最后一位
if(b ==1)
printf("a是奇数\n");
else
printf("a是偶数\n");
return 0;
}
// 下面4句的写法都是错误的
char a = A;
char b = "A";
char c = 'ABCD';
char d = '男';
// 正确的写法:
char a = 'A';
char b = 'z';
char c = '+';
输出字符对应的ASC码数值 printf(“%d”, ‘A’);
输出ASC码数值对应的字符 printf(“%c”, 68);
转义字符 |
意义 |
ASCII码值 |
\n |
将当前位置移到下一行开头(回车换行) |
10 |
\t |
跳到下一个TAB位置 |
9 |
\\ |
代表一个反斜线字符 |
92 |
\' |
代表一个单引号字符 |
39 |
\" |
代表一个双引号字符 |
34 |
\0 |
空字符 |
0 |
一个 int 类型的变量能保存一个人的年龄,如果想保存整个班的年龄呢?
数组,从字面上看,就是一组数据的意思,没错,数组就是用来存储一组数据的
数组的特点:
1)只能存放一种类型的数据 ,比如 int 类型的数组、 float 类型的数组
2) 里面存放的数据称为“元素”
2>数组的定义格式:int ages[5];
6)遍历数组
#include
void printArray(int ages[]) //定义函数
{
for(int i=0; i<5; i++)
{
printf("ages[%d]的值是%d\n", i, ages[i]);
}
}
int main()
{
int ages1[5] = {1,2,3,4,5};
printArray(ages1); //调用函数,将数组ages1[]的地址传给形参ages[]
return 0;
}
#include
int maxOfArray(int array[], int length)
{
int max = array[0];
for(int i=1; i max) max = array[i];
}
return max;
}
int main()
{
int ages[] = {11, 90, 67, 100, 78, 60, 70, 89, 120};
//引用函数,并将数组实参、数组长度实参传入函数maxOfArray
int max = maxOfArray(ages, sizeof(ages)/sizeof(int));
printf("%d\n", max);
return 0;
}
一个数组能表示一个班人的年龄,如果想表示很多班呢?
什么是二维数组?int ages[3][10]; 三个班,每个班10个人,相当于3行10列,相当于装着3个一维数组
二维数组是一个特殊的一维数组:它的元素是一维数组。
例如int a[2][3]可以看作由一维数组a[0]和一维数组a[1]组成,这两个一维数组都包含了3个int类型的元素
存储大小 int ages[3][10]; ages[3][10]占用储存空间是 3*10*4=120字节
存储结构和顺序:二维数组内部的每个一维数组都是按从前往后的顺序排列地址的,一维数组内部个元素也是从前往后
存储地址问题:二维数组的地址是它首个一维数组的首元素的地址。
int a[3][4] = {1,2,3,4,5,6};
int a[3][4] = {{1,2,3,4},{1,2,3,4},{1,2,3,4}};
数组元素简单访问
int a[][5] = {3,21,31,2,32,1};
注意错误:
int a[3][4];
a[3] = {}; // 不能对二维数组中的某一个一维数组整体赋值,只能给每个元素单独赋值。
遍历所有的元素:在一维数组遍历基础上嵌套一个for循环。
遍历地址:%p
1.注意不同进制的书写格式
二进制 0b 八进制 0 十六进制 0x
2.假如有n个字节的内存,可储存数字的取值范围就是:
-2的(n-1)次方 ~ +2的(n-1)次方-1
2.数组内部元素的地址分配是正序的,从前向后的。
3.二维数组中的一维数组排序也是正序的。
4.相位异或:两个二进制位 相异=1,相同=0
a^b^a == b^0 == b
5.左移、右移n位,相当于与乘以或除以2的n次方
左移、右移的计算效率比乘方高。
6.字符可以当做整型来使用(ASC码的值)0~128
7.数组作为函数参数时,相当于指针。会影响外面实参的值。
To be continue……