所有的数据都会被转换成二进制进行存储,如果想到的到正确的数据,必须使用正确的理解方式(类型),来解析二进制数据。
1.整形
占用空间:整型在 32位系统以及64位系统中都占用 4字节
整形取值范围:2^31 ~ -(2^31),如果产生溢出则最大变最小,类似环形
整数的存储方式:
原码: 正整数是直接使用补码(正整数补/反码等于原码)进行存储的,比如100这个正整数,则直接把100 转换 成二进制直接存储。
100 --> 0000 0000 0000 0000 0000 0000 0110 0100
补码:负数则是使用补码来存储,补码等于原码非符号位取反再加一
2.浮点型
对于浮点型数据来说,其二进制编码方式和整形是有很大区别的,IEEE用以下形式表示一个浮点数
以32位浮点数为例,其存储器内部情况是这样的
因此直接用整形的方式输出浮点型得到的数据并不是舍去小数部分的整数
3.字符类型
char类型定义过程
1.申请一片内存并且命名
2. 确定内存的大小为 char (1字节)
3. 把字符‘K’的ASCII码值转换为二进制,并存储到该内存中
4. 计算机中存储的所有数据都是以二进制的形式存在的, 因此字符必须映射某一个数字才能 够被存放到计算机中,这个映射的表就成为 ASCII 表,可以使用man手册来查看:
man ascii
字符实质上是一个单字节的整型,因此支持所有整型的操作,例子:
char k = 'H' ;
printf("%c\n" , k + 1 );
printf("%c\n" , k ‐ 1 );
//在其解码后会根据存入内存的数值对应ASCII表输出
4.字符串类型
字符串有两种形式:
1)数组
char s1 [] = "Hello" ; //使用一个数组来存放字符串 "Hello"
以上语句其实是把一个字符串常量 "Hello" , 复制到数组 s1 所代表的内存当中
1.申请一片内存 2.确定这片内存用于存放一个数组 3.确认该数组用于存放字符类型
数组中存放为 {‘H’,‘e’,‘l’,‘l’,‘o’,‘\0’}
2)指针
指针中存放的是指定数据的存储地址,指针占用内存的大小取决于使用什么样的系统,对指针解引用可以得到此地址存放的数据
指针运算
指针的加法:意味着地址向上移动若干个目标 (指针的类型)
指针的减法:意味着地址向下移动若干个目标 (指针的类型)
int main(int argc, char const *argv[])
{
long l;
long *p = &l;
int a;
int *pa = &a;
printf("p:%p\n",p);
printf("p+1:%p\n",p+1);
printf("pa:%p\n",pa);
printf("pa+1:%p\n",pa+1);
return 0;
}
运行结果:
p:0x7fffe4c81ad0
p+1:0x7fffe4c81ad8 //加上一个long的长度
pa:0x7fffe4c81acc
pa+1:0x7fffe4c81ad0 //加上一个int的长度
5.布尔类型
bool类型用于表示真假:非0即真
注意在使用布尔类型是需要包含他的头文件:<stdbool.h>
一般布尔类型的变量,可以用于逻辑判断比如 if / while ,或者用于函数的返回值。
布尔类型的大小:
bool a = true ;
printf("sizeof(bool):%ld \n ",sizeof(bool) );
printf("sizeof(a):%ld \n ",sizeof(a) );
printf("sizeof(true):%ld \n ",sizeof(true) );
printf("sizeof(false):%ld \n ",sizeof(false) );
printf("false:%d \n ",false );
printf("true:%d \n ",true );
//运行结果:
sizeof(bool):1
sizeof(a):1
sizeof(true):4
sizeof(false):4
false:0
true:1
6.数据类型占用内存集
16位编译器
char :1个字节
char*(即指针变量): 2个字节
short int : 2个字节
int: 2个字节
unsigned int : 2个字节
float: 4个字节
double: 8个字节
long: 4个字节
long long: 8个字节
unsigned long: 4个字节
32位编译器
char :1个字节
char*(即指针变量): 4个字节(32位的寻址空间是2^32, 即32个bit,也就是4个字节。同理64位编译器)
short int : 2个字节 int: 4个字节
unsigned int : 4个字节
float: 4个字节
double: 8个字节
long: 4个字节
long long: 8个字节
unsigned long: 4个字节
64位编译器
char :1个字节
char*(即指针变量): 8个字节
short int : 2个字节
int: 4个字节
unsigned int : 4个字节
float: 4个字节
double: 8个字节
long: 8个字节
long long: 8个字节
unsigned long: 8个字节
7.常量和变量
概念: 不可以被改变的内存,被称为常量,可以被改变的内存则成为变量
标准输入
scanf( ); // 扫描键盘 (格式化输入数据 ‐‐> 从键盘中获得指定类型的数据)
头文件:
#include <stdio.h>
函数原型:
int scanf(const char *format, ...);
参数分析:
format ‐‐> 格式化
... ‐‐> 省略号 , 根据format 所写的格式控制符,对应一个内存地址
返回值:
成功 返回具体获取到的项目数
失败 返回0
getchar( ) ; // 获取一个字符 (默认从标准输入文件中获取)
函数原型:
int getchar(void);
参数:
无
返回值:
成功 返回一个ASCII值, 代表获得的字符 (unsigned char )
失败 返回 EOF 也就是 ‐1
在scanf收到非对应的数据类型的数据时会将这些数据存入输入缓冲区,此时如果再次进行scanf操作则会对前一次放入缓冲区的数据进行判断导致连环失败,因此我们需要借用getchar函数来对输入缓冲区进行清空
实例:
int main(int argc, char const *argv[])
{
int num = 0;
char c = '0';
// & 取地址符号 , 获得 内存 num 的地址
int ret_val = scanf("%d", &num );
while(getchar() != '\n'); // 清空 由 scanf 所留在缓冲区的内容
// 如果不清空有可能会导致下一次使用标准输入缓冲区异常(有上一次的数据没有被读取)
printf("返回值:%d , 获取的数据为:%d\n" , ret_val , num );
ret_val = scanf("%c", &c );
while(getchar() != '\n'); // 清空 由 scanf 所留在缓冲区的内容
printf("返回值:%d , 获取的数据为:%c\n" , ret_val , c );
printf("EOF:%d\n" , EOF ); //EOF 实际上是一个值为‐1 的宏
return 0;
}
类型转换
不同类型但是可以兼容的类型之间,如果出现在同一表达式中会进行类型的转换
类型转换有两种模式:
隐式转换(自动):
若在表达式中未进行手动转换则会自动转换为高精度的类型
比如float+double+int会自动转换为double
强制转换(手动):
用户根据需求进行类型转换,在变量前加上‘(想要转换的数据类型)’即可,但是这种方式进行转换会影响精度
精度排序(由低到高):
char -> short -> int -> long -> float -> double -> long double
注意:不管是哪种方式的转换都只是临时的类型转换,不会对数据造成影响、
可移植数据类型
不管在多少位的系统中占用空间不变的数据类型被称为可移植数据类型
关键字:typedef 数据类型重命名