0,引入
程序运行时需要把程序文件/可执行文件加载到内存中,期间产生的一些数据和结果都会保存在内存中(内存分配的基本单位是 字节 byte)
c语言提出了数据类型的概念,不同的数据归于不同的类型,如:整数,小数,字符 .....
不同的数据类型有不同的属性,比如:需要的内存大小不一样,存储方式不一样,数据计算的方式也不一样....
1,c语言的数据类型
有4大类数据类型
(1)基本类型
就是c语言中已经定义好了,我们可以直接使用
1.1 整型数据(整数)
short (int) //短整型
int //整型
long (int) //长整型
long long (int) //长长整型
区别在于能够表示的数据大小的范围不一样 -》 占用的内存大小不一样 short 占2字节(16bit) int 占4字节 long 4或者8字节 在32位机器上占4字节,在64位机器上占8字节 long long 8字节 如果记不住怎么办? sizeof(int) -> 求int占几个字节
unsigned / signed -》用来修饰整型数据的 表示无符号和有符号数据 如: int <-> signed int //有符号整型,int其实就是 signed int,但是一般省略这个 signed unsigned int //无符号整型 无符号整型:这个数据的所有 bit都是数据位 有符号整型:最高bit位为符号位,剩下的才是数据位 符号位为0 表示这个数是正数 符号位为1 表示这个数为负数 1.2 字符型数据:用来保存字符 char 占1字节 1.3 浮点型 :用来保存小数 float 占4字节 double 占8字节 long double 占16字节 (2) 构造类型:需要我们程序员自己去定义 数组 结构体 共用体 枚举 (3) 指针类型 占8字节 (4) 空类型 void ,一般用于函数返回值位置,表示该函数没有返回值
c语言程序中的数据按照是否可以被修改(是否可写)分为两种: 常量(不可修改/ 不可写) 变量(可以修改/可写)
2,常量
在程序的运行过程中不能被修改的数据
常量也有多种数据类型
(1)整型常量
以0开头的:是八进制,在代码中由一段数字组成 [0-7]
如: 0231
0654
0768 //error
以0x/0X 开头的是十六进制,是由 数字 [0-9]+[a/A-f/F]这16个组成 如: 0xab 0x12f 0x78d .... 以0b/0B开头的是二进制 (不是所有平台都支持) 如: 0b1010100 其它的就是十进制 123 默认是int类型 123 l 后缀为l的是 long 类型 123 u unsigned int 类型 ....
换算规则: 十进制换算成二进制 除二取余法:一直除2,直到商为0,然后再反过来取每一次的余数 25 -》 0b11001 十进制换算成八进制 除八取余法 25 -》 031 十进制换算成十六进制 除16取余法 25 -》0x19 二进制换算成十进制 假设从右到左依次为 n0 n1 n2 n3 .... n0*2^0 + n1*2^1 + n2*2^2 + ....... 如: 0b011100 1*2^2 + 1*2^3 + 1*2^4 = 28 在这里用^表示次方,但是c语言并没有次方这个符号,^也不次方 0b0011011 = 27 八进制换算十进制 0123 3*8^0 + 2*8^1 + 1*8^2 = 3+2*8+1*64 = 3+16+64 = 83 十六进制换算成十进制 0x123 3*16^0 + 2*16^1 + 1*16^2 = 3+32+256 = 291 二进制换算成八进制 常规方法:先换算成10进制,再换算成八进制 0b100110 = 38 = 046 二进制的每3位对应八进制的一位,注意要从低位开始 0b 001 001 100 = 0114 1 1 4 二进制换算成十六进制 0b0 0100 1100 = 0x4c 八进制换算成二进制 023 = 0b010011 十六进制换算成二进制 0x23 = 0b00100011
(2)字符常量 字符常量是用单引号 '' 引起来的一个字符 如: '1' 'x' '%' .... 在计算机中怎么保存一个字符呢? 不是保存这个字符的形状,而是保存这个字符的 编码 :ascii码 编码:一个字符对应一个数字 除了 ascii码之外还有很多其它编码,课后可以去了解一下 '0' 48 'a' 97 'A' 65 字符有两种: 普通字符:有形状,可以显示出来 特殊字符:没有形状,但是有特殊含义 '\n' 换行 '\t' tab '\0' 字符串结束标志 ascii 为 0 ... 字符可以有多种表示方式 如: 'A' 65 '\***' :由\开头,后面接一个八进制数字 这个八进制数字就是该字符的 ascii码的八进制值 '\101' <-> 'A' '\x**' :由 \x 开头,后面接一个十六进制数字 这个16进制数字就是该字符的 ascii码的16进制值 '\x41' <-> 'A' (3) 浮点型常量 :小数 可以有后缀 f/F l/L l/L long double f/F float 没有后缀默认是double 1.5 -> double 1.5f -> float 1.5l -> long double 科学计数法: 123.456 -> 1.23456 * 10^2 由整数部分,小数点,小数部分,一个 e/E ,一个可选的带符号的整型指数,一个可选的 后缀 123.456 -> 1.23456e2 0.0001234 -> 1.234e-4 (4)符号常量(宏定义) #define X 123 #define PI 3.1415926
3,变量
变量是指在程序的运行期间,其值可以被修改
int a = 10; a = 20; a = 19; ....
变量是用来保存数据的,那么肯定需要合适大小的内存空间,需要多大的空间呢? 由这个变量/数据的类型决定 所以我们在定义变量的时候,必须指定它的数据类型 定义变量的语法格式如下: 数据类型 变量名; 或者 数据类型 变量名 = 初始值; 如:我想定义一个变量用来保存整数,那么就得定义一个整型变量 int a; int b = 60; 注意:变量名不能随便取,要遵循一定的规则:只能由字母、数字、下划线组成,并且不能以数字开头 并且不能是c语言的关键字 int a; 当程序运行到这行代码的时候,会分配内存空间(4字节),并且记录了这个变量名 a 和这4个字节的对应关系 a = 10; 当程序运行到这行代码的时候,会把数据10写入变量a对应的4字节内存中去 printf("a=%d\n",a); 从a对应的4字节中读取数据并打印输出 ----------------------------------------- int b = 20; 当程序运行到这行代码的时候,会分配内存空间(4字节),并且记录了这个变量名 b 和这4个字节的对应关系, 并把20这个数据写入到这4字节内存中 最终效果和 int b ; b=20 ;//赋值语句 这两行代码一样,但是有不同说法: int b = 20; //初始化 int b;//定义变量 b = 20;//赋值 ------------------------------------------- 变量名到底怎么理解? int a ,b; a = 20; (1) printf("a=%d\n",a); (2) b = a; (3) a = b; (4) 请问前面4行代码中的a怎么理解? 在c语言中,对变量的访问,本质上都是两种形式 读 就是从变量对应的内存中读取数据 (2) (3) 写 就是把数据存储到变量对应的内存中 (1) (4) 在c语言中变量名,也有两种含义 1,代表变量的值 -》 右值 对应 (2) (3) 2,代表变量的地址(内存单元编号) -》左值 对应 (1) (4)
4,整型数据在内存中存储形式 (包括 char)
因为 char 的本质是存储 字符的 ascii码, ascii码本身就是一个整数
所以 -》 char 也可以归纳到整型中
整型数据在计算机是以二进制补码的形式存储的
一个整数 原码:把它换算成二进制 如: 100 0 00..0000 0110 0100 -100 1 00..000 0110 0100 反码:把数据位全部取反 补码:正数的补码是原码本身 负数的补码是绝对值的原码取反加1 如: 100 绝对值原码 000..0000 0110 0100 《- 100的补码 -100 绝对值原码 000..0000 0110 0100 取反 111..1111 1001 1011 加一 111..1111 1001 1100 《- -100的补码
练习: int a = 50; 00..000 110010 int b = -6; 请计算a,b的补码 绝对值原码 00..00 0110 取反 11..11 1001 加一 11..11 1010
10 + (-5) = 5 如果存储的是原码: 00..000 1010 10..000 0101 ------------------- 10..000 1111 -> -15 结果错误 现在存储的补码 00..000 1010 11..111 1011 ------------------ 1 00..000 0101 最高位的1保存不了,丢弃。 所以最终的结果 00..000 0101 -> 5 结果正确
练习: 求 unsigned int a = 4294967290 的补码 1111111111111111111111111111 1010 int b = -6 的补码也是 1111111111111111111111111111 1010 int b = -6;//分配了4字节的内存(32bit) 依次存储 11111111111111111111111111111010 //我们又知道, unsigend int 类型的 4294967290 也是这么存储的 //那么这4字节内存里面的值到底是多少? 取决于你怎么解析它 //如果你把它当作 unsigned int 来解析,那就意味着32bit全部都是数据位,没有符号 //通过这个补码直接可以算出值(二进制换算成10进制): 4294967290 //如果你把它当作 int 来解析,那就意味着最高位位符号位,其余才是数据 //先看符号位,发现是1,说明是负数,然后按照负数求补码的过程反过来计算 //先减一 11111111111111111111111111111001 //再取反 00000000000000000000000000000110 // 所以它的绝对值为 6 -》这个值本身是 -6
内存中有4个字节存储的是整数,二进制补码为 1111111111111111111111111101 1010 请问这个值可能是多少?? 如果是无符号数据,直接换算 4294967258 如果是有符号数据,先看符号位,符号位是1,说明是负数 ..... -38
内存中有4个字节存储的是整数,二进制补码为 0111111111111111111111111101 1010 请问这个值可能是多少?? 如果是无符号数据,直接换算 2147483610 如果是有符号数据,先看符号位,符号位是0,说明是正数,直接换算 2147483610
printf();函数 %d 打印 int %u 打印 unsigned int %hd 打印 short %hu 打印 unsigned short %ld 打印 long %lu 打印 unsigned long %c 打印 char %s 打印字符串 %f 打印 float %lf 打印 double
一个 unsigned int 和 int相加减,结果默认是 unsigned int short + int -> int int + double -> double ... unsigned int a = 6; int b = -20; if(a+b > 6) { printf("a+b>6\n"); } else { printf("a+b<=6\n"); }
字符的存储: char c = 'A'; 'A' 的 ascii是65,二进制补码是 01000001 printf("%c\n",c);//输出 A printf("%d\n",c);//输出 65
5,浮点型存储形式
先换算成二进制,再用科学计数法表示
如:
8.25
换算成二进制的方法是: 整数部分除二取余,小数部分乘二取整(直到小数部分为0,取整的时候 顺着取)
8 -> 1000
0.25 -> 01
-》 1000.01 -> 1.00001*2^3 13.75 1101.11 -> 1.10111*2^3 任何小数都可以用 1.xxx * 2^n表示 1和小数点和2都是一样的,不一样的 符号位 和 xxx(尾数部分) 和 n(指数部分)
只需要存不同的东西: 符号位 指数部分 尾数部分 符号位 指数部分 尾数部分 float 1bit 8bit 23bit double 1bit 11bit 52bit 符号位 : 为0表示正数,为1表示负数 指数部分存储: 指数部分+127 再换算成2进制 尾数部分: 把尾数部分换算成二进制,然后低位补0(补满23bit或者52bit)
8.25 1.00001*2^3 符号位 指数部分 尾数部分 0 3+127 (10000010) 00001 补18个0 -> 8.25占4字节在内存中存储形式是: 0 10000010 00001000000000000000000 13.75 0 10000010 10111000000000000000000
6,整数之间的赋值问题
int a = -6; // 11111111111111111111111111111010
short b = 100;
(1) 长的赋值给短的(溢出) b = a; //b 变量16bit 分别是 1111 1111 1111 1010 高位丢弃,保留低位 printf("%hd\n",b);//输出 -6 printf("%hu\n",b);//输出 65530
练习: short a = 0x4142; char c = a; printf("%c\n",c);//请问输出什么? B (2) 短的赋值给长的 a = b; 短的直接赋值给长的的低位 高位补什么? 如果短的是无符号数据,长的高位全部补0 如果短的是有符号数据,长的高位全部补短的的符号位 int a = -6; short b = 100;// 0000 0000 0110 0100 a = b; // 高位补b的符号位0 00..0000 0000 0000 0110 0100
int a = -6; short b = -100;// 1111 1111 1001 1100 a = b;// 高位补b的符号位 1 11..1111 1111 1111 1001 1100 int a = -6; unsigned short b = 100; a = b; // 高位直接补0 00..0000 0000 0000 0110 0100 int a = -6; unsigned short b = -100;// 1111 1111 1001 1100 a = b;// 高位直接补0 00..0000 1111 1111 1001 1100
练习: 1, short int a = -6; //1111 1111 1111 1010 int b = a;//11..111 1111 1111 1111 1010 printf("%d\n",b);// -6 printf("%u\n",b);// 429496.... 2, unsigned short int a = -6;//1111 1111 1111 1010 int b = a;//00..000 1111 1111 1111 1010 printf("%d\n",b);//65530 printf("%u\n",b);//65530 3, short int a = -6; //1111 1111 1111 1010 printf("%d\n",a);// %d是当作 int打印,会先把 a赋值给/转换为 int类型,再进行打印 //效果和第一种情况一样 printf("%u\n",a);// 也和第一种情况一样 4, char c = 358; 358是一个int类型的常量,00..0000 0001 0110 0110 c是char类型, -》长的赋值给短的 ,高位丢弃,保留低8位 c : 0110 0110 102 printf("%c\n",c);// f printf("%d\n",c);//c是 char类型,当作 int 来打印,意味着短的赋值给长的 //高位补符号位 0 00..000 0110 0110 -》 102
测试代码:
#include<stdio.h>//包含头文件,标准输入输出头文件,需要用到输入或者输出函数的时候必须要包含它
//测试不同进制数据的表示方法
void test1()
{
int data = 200;//十进制
printf("data=%d\n",data);//%d是以10进制形式打印 int类型的数据
data = 0x123;//十六进制
printf("data=%d\n",data);
data = 0123;//八进制
printf("data=%d\n",data);
//data = 0b1100;//十六进制
//printf("data=%d\n",data);
}
//字符的不同表示形式
void test2()
{
printf("%c\n",'A');
printf("%c\n",65);
printf("%c\n",'\101');
printf("%c\n",'\x41');
}
//整数的存储形式
void test3()
{
int b = -6;//分配了4字节的内存(32bit) 依次存储 11111111111111111111111111111010
//我们又知道, unsigend int 类型的 4294967290 也是这么存储的
//那么这4字节内存里面的值到底是多少? 取决于你怎么解析它
//如果你把它当作 unsigned int 来解析,那就意味着32bit全部都是数据位,没有符号
//通过这个补码直接可以算出值(二进制换算成10进制): 4294967290
//如果你把它当作 int 来解析,那就意味着最高位位符号位,其余才是数据
//先看符号位,发现是1,说明是负数,然后按照负数求补码的过程反过来计算
//先减一 11111111111111111111111111111001
//再取反 00000000000000000000000000000110
// 所以它的绝对值为 6 -》这个值本身是 -6
printf("%d\n",b);//输出什么? -6
printf("%u\n",b);//输出什么? 4294967290
int c = 2147483610;
printf("%d\n",c);//输出什么? 2147483610
printf("%u\n",c);//输出什么? 2147483610
char d = 'A';
//'A' 的 ascii是65,二进制补码是 01000001
printf("%c\n",d);//输出 A
printf("%d\n",d);//输出 65
}
int main()//主函数,程序的入口,一个程序有且仅有一个 main函数
{
//test1();
//test2();
test3();
return 0;//表示返回0,并结束这个函数,main函数结束就是整个程序结束
}