数据类型、常量、变量,整型和浮点型数据在计算机中的存储形式

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) 指针类型

    (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
                            
 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值