1 计算机中的数据和存储
1.1 数据的表示
所有的数据(包含音频、图像、视频、文本数据)都需要在计算机中存储和表示,具体的方式采用的二进制形式表示,其实质将数据以零(0)和一(1)的有效序列来存储。
1.二进制数据表示形式
计算机思维:
数据只有两种状态(0和1)构成,在数据存储和运算的过程中,逢2进1;
特点:方便于表示计算机中数据某位的状态(1 = 高电平、0 = 低电平);数据存储是由若干位构成,不便于人来阅读。
2.十进制数据表示形式
人思维:
数据有多种状态(0-9)构成,在数据存储和运算的过程中,逢10进1;
特点:方便于人来阅读数据;在计算机中数据的某位状态表示不方便;
换位思考:
对于一个十进制数,表示某位的状态,可以将其转换为二进制编码形式:
整数:循环对2取余,在取整;当取整数为0结束循环;
小数:循环乘2取整,在取小数,当小数为0结束循环;
对于一个二进制数,读方便,可以将其转换为十进制编码形式:
位编码*2的n(位数)次方并累加
由于在使用十进制和二进制的情况下存在问题,为了能够更好的同时从人的思维和计算机思维分析数据(数据能够同时方便人取阅读某一位的状态),可以采用十六进制和八进制来表示:
3.十六进制
数据有多种状态(0-9,a-f)构成,在以0x为起始标识, 在数据存储和运算的过程中,逢16进1;
数据的每4个位的值(0-15)只需要1个符号存储,读某一位的时候利用(8421编码)将其转换为二进制。
4.八进制
数据有多种状态(0-7)构成,在以0为起始标识,在数据存储的运算的过程中,逢8进1;
1.2 数据的存储
所有数据的存储都是以二进制形式存储;在存储分析的时候需要将数据转换位二进制编码形式。
1.正数
内存中的编码形式是数据的源码:其实质是数据的二进制编码
123存储编码也就是数据123的源码:
0111 1011
2.负数
内存中的编码形式是数据的补码:其实质是数据的正数部分的源码取反+1;
-123存储编码:
源码:正数的二进制编码: 0111 1011
反码:将源码的所有位取反,包括符号位 1000 0100
补码:反码+1 1000 0101
2 C语言关键字
C语言中一共有32个关键字
2.1 数据类型关键字
一共有12个数据类型关键字
2.1.1 基本数据类型
1.整型数据
char 空间大小1字节
值域范围:
unsigned char 无符号char类型数据 数据位8位 值域: 0 ~ 255
signed char 有符号char类型数据 符号位1位+7位的数据位
符号位:1表示的负数,0表示的正数。 值域范围: -128 ~ 127
short 空间大小2字节
值域范围:
unsigned short 值域: 0 ~ 65535
signed short 值域: -32768 ~ 32767
int 空间大小(16位系统2字节,32位系统4字节)
long 空间大小(32位系统4字节,64位系统8字节)
2.浮点型数据
float 单精度浮点型数据
int main() { float f = 13.625; printf("0x%x\n", *(int *)&f); # 运行后的输出结果是:0x415a0000 }
注意:由于底数位只有23位来存储,所以最多只能保留小数点后6位
double 双精度浮点型数据
double数据存储:数据存储空间大小8字节(64位) 符号位(1位) + 指数位(11位) + 底数位(52位)
指数:移位数+1023
2.1.2 构造数据类型
struct 结构体数据类型,需要边数一个对象的多个属性的时候,将多个数据类型属性成员封装称为一个新的(结构体)数据类型;
union 共用体数据类型,实现数据封装,成员不能同时去访问,空间大小由最大成员空间决定;
enum 枚举
2.1.3 特殊数据类型
void 不是一个具体的数据类型,不能用于定义变量,可以用来定义指针(可以指向任意数据类型的指针),还可以作为函数的返回数据类型。
2.2 存储类型关键字
1.auto关键字
自动存储类型关键字
1) auto只能用来修饰局部变量,不能修饰全局变量;
2) auto修饰的变量存储在栈区;
3) 所有的局部在定义的时候如果省略了存储类型则默认为auto修饰的自动存储类型变量。
#include <stdio.h>
int a;
//auto int b; /* error,auto关键字只能修饰局部变量,不能修饰全局变量 */
int main()
{
int c; /* 变量c的存储类型是auto类型,所有局部变量在默认情况下都是auto类型 */
auto int d; /* 变量d的存储类型是auto类型 */
}
2.register关键字
register用来修饰寄存器变量
1) register只能用来修饰局部变量,不能修饰全局变量;
2) register修饰的变量存储在寄存器中而不是存储在内存中,不能对寄存器变量取地址运算
3) register修饰的变量存储在寄存器中访问效率高,但是寄存器数量有限,所以不能将所有的变量都定义为寄存器变量,在定义寄存器变量的时候可能会因为寄存器数量有限而失败,失败的时候默认为auto类型变量。
4) 寄存器变量只能用于定义整型数据变量。
#include <stdio.h>
int a;
//register int b; /* error:register不能修饰全局变量,只能修饰局部变量 */
int main()
{
int c;
register int d; /* 只能修饰局部变量 */
printf("&c:%p\n", &c);
// printf("&d:%p\n", &d); /* error:register修饰的变量存储在寄存器中,不存在内存中(不能取地址运算) */
}
3.extern关键字
外部声明引用,主要用于程序中其它文件中的全局变量和函数声明引用当前文件中访问
test.c文件中来定义函数和全局变量
#include <stdio.h>
/* 定义全局变量 */
int a = 34;
/* 定义函数 */
void prt_a(void)
{
printf("a = %d\n", a);
}
主函数文件app.c
#include <stdio.h>
extern void prt_a(void); /* extern 修饰函数 外部声明引用 */
extern int a; /* extern 修饰全局变量 */
int main()
{
prt_a(); /* 访问其它文件中所定义的函数 */
a = 1234; /* 访问其它文件中定义的全局变量 */
prt_a();
}
4.static关键
静态存储变量:主要修饰局部变量、全局变量和函数
修饰局部变量
改变变量的存储位置和生命周期:
1) 存储位置的改变:未被static修饰的局部变量存储位置为栈区,被static修饰的局部变量存储位置为静态存储区;
2) 生命周期的改变:未被static修饰的局部变量生命周期为语句执行到模块结束,被static修饰生命周期为语句执行到程序结束。
#include <stdio.h>
#include <unistd.h>
int main()
{
while(1) {
int i = 0; /* 生命周期是程序执行到模块结束,在每次循环都需要重新开辟空间 */
static int j = 0; /* 生命周期是程序执行到程序结束:在模块结束的时候不会释放j的空间,下一次循环使用上次修改的值 */
printf("i = %d, j = %d\n", i++, j++); /* 输出结果,i每次输出都是0,j输出为 0、1、2、3 …… */
sleep(1);
}
}
饰全局变量和函数
改变变量的作用域或者链接属性
对于未被static修饰的全局变量和函数作用域为整个程序域,在程序中来全局访问链接;被static修饰的全局变量和函数作用域为文件域,只能在所定义的文件中访问链接。
2.3 控制语句关键字
if、else、switch、case、break、default、for、while、do、goto、continue、return
2.4 特殊的关键字
sizeof 计算数据(常量、变量、数据类型、指针、函数)所占空间的大小;
typedef 类型定义(重定义数据类型的名称);
volatile 易变的、可变的。用来修饰的变量防止编译器优化
优化:在变量访问的时候,内存到寄存器在到内存,效率较低,编译器为了提高效率,编译器会优化代码(在多次访问内存数据的时候,只会对内存进行1次读,多次数据操作,在1回写)。防止优化:每次数据运算都需要对内存进行读和写访问。
const 修饰的只读变量,变量只能读,不能写。