当前位置: 首页 > news >正文

c语言-数据类型

1.C语言的简介
    是一门面向过程的编程语言  
    1972年 贝尔实验室  丹尼斯里奇 

    ... // 百度百科 https://baike.baidu.com/item/c%E8%AF%AD%E8%A8%80/105958?fr=ge_ala


2.问题引入 

    1)我们所有要处理的这些数据文件(视频,音乐,图片等)
        都是以二进制的形式保存在内存中

    2)将8bit称为一个字节byte,并将字节作为最小的可操作单位

    我们在保存这些数据的时候,要思考这些数据的属性,比如数据的大小
        为了避免一个很大的空间保存一个很小的数据,或者一个很小的空间存放一个很大的数据

    那么 怎么让操作系统知道开辟多大的空间呢? 
            就涉及到 数据类型 


3.C语言数据类型 

    分类:
        基本类型
        构造类型
        指针类型 
        空类型(void)

    1)基本类型 
        系统分配给基本类型的变量的内存大小是固定的,C语言已经为我们定义好的类型 

        (1)整型 
            int     占4个字节  32bits       格式化输出: %d 
                (signed) int  取值范围  -2^31 ~ 2^31 - 1 
                unsigned int  取值范围  0 ~ 2^32 - 1 

            short   占2个字节  16bits       格式化输出: %hd 
                (signed) short  取值范围  -2^15 ~ 2^15 - 1 
                unsigned short  取值范围  0 ~ 2^16 - 1 

            long                            格式化输出: %ld 
                    32位机器    4个字节
                    64位机器    8个字节 


                unsigned    无符号
                    所有的位都是数值位
                signed      有符号
                    符号位(最高位)+数值位 
                      0 正数 
                      1 负数  

        (2)字符型 
            char  占1个字节 8bits           格式化输出: %c 
                (signed) char  取值范围  -128 ~ 127 
                unsigned char  取值范围  0 ~ 255 

                例子: 
                    char a = 65;        //字符型是特殊整型  ASCII码
                    printf("a = %d\n", a );
                    printf("a = %c\n", a );

                    --------------------
                        man 查看不同函数/指令的功能  
                                语法:  man 函数名/指令名 
                                        q 退出 

        (3)浮点型(实型)  

            float 单精度    占4个字节 32bits   参考图示         格式化输出: %f 
                符号位 31位(最高位)  1bit       1为负数,0为正数
                指数段 30~23位      8bits       指数加上127后,得到的二进制数
                尾数段 22~0位       23bits  

            double 双精度   占8个字节 64bits                    格式化输出: %lf 
                符号位 63位(最高位)  1bit       1为负数,0为正数
                指数段 62~52位      11bits      指数加上1023后,得到的二进制数
                尾数段 51~0位       52bits

                例子: 
                        将十六进制数 0xC1480000 转换成浮点数 

                        0xC1480000
                    --> 11000001 01001000 00000000 00000000

                    --> 1       10000010  1001000 00000000 00000000
                        符号位   指数段     尾数段

                        符号位: 1 --> 负数 

                        指数段E:  10000010 --> 130 
                                --> 130 - 127 --> 3  即实际的指数部分是 3  

                        尾数段M: 1001000 00000000 00000000 
                                这里,在尾数段的左边实际上是省略一个1, 实际的尾数为
                                    1.1001000 00000000 00000000  

                    把在三个部分的数据单独拎出来 
                        通过指数段E的值 来调整尾数段M的值 
                            方法: 
                                如果指数E为正数,则尾数段M的小数点就向右移E位 
                                如果指数E为负数,则尾数段M的小数点就向左移E位 
                    
                    此处 E==3
                    --> 1.1001000 00000000 00000000  
                    --> 1100.1000 00000000 00000000 
                    至此 上面就是这个浮点数的二进制的形式,然后再转换成十进制 
                        整数部分  1100  -->  12 
                        小数部分  1000 00000000 00000000  --> 1 * 2^(-1) --> 0.5  
                    --> 12.5 
                        由于符号位为1,因此这个浮点数为 -12.5  
                    
        注意:
            在C语言中,整数的默认类型为int, 浮点数的默认类型为double 

                sizeof() 求对象所占的字节大小 

                例子:
                        int a = 10;
                        int b = 5;
                        printf("%ld\n", sizeof(a) );    //   --> 4 
                        printf("%ld\n", sizeof(b) );    //  --> 4  
                        printf("%ld\n", sizeof(10) );    // --> 4        //10默认类型为int
                        printf("%ld\n", sizeof(3.14) );    //  -->  8    //3.14默认类型为double 


                        char c = 100;
                        printf("%ld\n", sizeof(c) );    // 1

                        long d = 1;
                        printf("%ld\n", sizeof(d) );    // 64位机器 8个字节


    2)构造类型 
        C语言允许用户自定义类型
        系统分配给构造类型的变量所占的内存大小, 取决于该类型具体是如何定义的

            数组类型
            结构体类型 
            枚举类型
            联合体类型(共用体)

    3)指针类型 

    4)空类型 void 
        void代表在内存中不占内存空间大小 
            sizeof(void) -->   理论上为0, 实际上由于编译器的优化 可能为1

        在C语言中 主要有三大作用:
            (1)void作为函数的返回值, 表示函数不返回任何数据 
            (2)void作为函数的参数, 表示该函数不带任何参数,此时void可省略
            (3)void* 表示通用指针 

4.常量和变量  

    1)常量 
        在程序运行期间 其值不能被改变的量 叫 常量 
            比如:   
                1,2,3,4,... 100, 300, .... 

                3 = 5;  //error  3是一个常量,其值不能被改变 

        (1)整型常量 
            (1.1)二进制常量 BIN : 由0和1组成的 
                    0000 1000  ---> 等价于 十进制的8 

            (1.2)八进制常量 OCT : 以字符0开头,后面接0个或者多个 0~7的字符 
                    格式化输出 %o  
                    例子: 
                            0666 , 0777,  0123 , ... 016

            (1.3)十进制常量 DEC : 0个或者多个 0~9的字符 
                    格式化输出: %d 

            (1.4)十六进制常量 HEX : 以0x或者0X开头, 后面接0个或者多个 0-9,a-f,A-F 的字符 
                    格式化输出: %x 
                    例子: 
                        0x01 , 0xFF, 0xab 

                ==========================
                    不同进制之间的转换 
                        (a) 二进制 <--> 八进制 :  1个八进制 对应 3个二进制 
                                例子: 
                                        八进制          二进制 
                                        0               000
                                        1               001
                                        2               010 
                                        3               011
                                        ...
                                        6               110
                                        7               111

                        (b) 二进制 <--> 十六进制 : 1个十六进制 对应 4个二进制 
                                例子: 
                                        十六进制        二进制 
                                        0               0000
                                        1               0001
                                        2               0010
                                        ...
                                        9               1001
                                        a/A             1010
                                        ...
                                        f/F             1111

                        (c)二进制 转换成 十进制 
                            0111  -->  0*2^3 + 1*2^2 + 1*2^1 + 1*2^0 ==> 0 + 4 + 2 + 1 ==> 7

                        (d)八进制 转换成 十进制 
                            0765  -->  7*8^2 + 6*8^1 + 5*8^0 ==> 501
                        
                        ...
                
                结论: 
                    (1) 任何进制 转换成 十进制 
                            都是 直接乘以权值 再全部相加即可 

                    (2)十进制 转换成 其他的R进制 : 除R取余法 

                    (3)任何进制 转换成 非十进制 
                        先把该进制转换成二进制,再将该二进制数转换成对应的其他进制

                        例子: 
                            八进制 --> 十六进制 
                            0777 
                                --> 先把该进制转换成二进制 111 111 111 
                                --> 再将该二进制数转换成对应的其他进制  1 1111 1111
                                --> 0x1FF 

        (2)浮点型常量 
            单精度 float    格式化输出 %f       (默认输出6位小数)
            双精度 double   格式化输出 %lf      (默认输出6位小数) 

                例子: 
                    double pi = 1234.5678;
                    printf("%lf\n", pi );     // (默认输出6位小数) 

                    printf("%.2f\n", pi );    //小数部分保留2位

                    printf("%5.2f\n", pi );   //整个小数一共占5位(包括小数点),其中小数部分占2位 
                                                //当实际位数大于约定输出的位数,则按实际位数输出

                    printf("%9.2f\n", pi );  //向右靠齐,左边补空格
                    printf("%-9.2f\n", pi );    //向左靠齐,右边补空格
                

        (3)字符常量 
            字符常量 是以单引号'' 引起来的一个或者多个字符的序列
            格式化输出 %c  
                例如:  'a' - 'z' , '0' - '9',  'A' - 'Z'  .... 

            在计算机中,保存一个字符,保存的是它的ASCII码值,而不是这个字符本身

                查看ASCII码 
                    在终端上出入指令 man ASCII 
                        按q退出 

                    例子: 
                        '0' -- 48 
                        'A' -- 65 
                        'a' -- 97 

                        char x = 'A';
                            <==> char x = 65;
                            <==> char x = 0101;
                            <==> char x = 0x41;

            (3.1)普通字符
                一般一个字符我们称之为普通字符,可以打印出来的,有形状的字符
                    例如:  'a' - 'z' , '0' - '9',  'A' - 'Z' 

            (3.1)转义字符
                一般是不可以打印出来的,没有形状,有另外一层含义的字符 
                    例如: 
                        '\n'    换行 
                        '\t'    tab制表符 
                        '\\'    反斜杆符
                        '%%'    百分号符 
                        ... 

                        '\ddd'   ddd表示1到3位的八进制,打印效果为该数字对应的ASCII码的字符
                                    printf("\101");     // putchar('A');    //打印一个字符

                        '\xdd'   dd表示1到2位的十六进制,打印效果为该数字对应的ASCII码的字符
                                    putchar('\x41');

                    例子:
                        printf("\101"); 
                        //putchar('\777');    //超出char的范围了

                        putchar('A');    //打印一个字符
                        putchar('\x41');

                        
                        char a;
                        a = getchar();     //从键盘获取一个字符
                        putchar( a );
                

        (4)字符串常量 
            用双引号"" 引起来的一串字符   
            字符串常量在内存中保存一定会有一个'\0'结尾, 我们称之为 字符串的结束符(终止符) 
                '\0'的ASCII码值为 0  

            格式化输出 %s 

                

    2)变量 

        (1)变量 
            在程序运行期间 其值能够被改变的量 叫 变量 

                变量实质上是内存的一个具体特定属性的存储空间,它是用来存储数据的
                这块存储空间中的值,就是变量的值,而且这个值是可以改变的 
            
            变量名 
                在定义变量的时候,会在内存中分配空间(空间的大小由数据类型来决定的)
                这个变量名就会和这块空间的首地址相关联起来
                操作系统有变量名就可以访问到这个内存地址的空间 

        (2)变量的定义语法:
            数据类型 变量名; 
            数据类型 变量名 = 初始值; 

                    "数据类型": 所有C语言合法的数据类型都可以
                    "变量名": 符合C语言合法标识符的定义规则
                                由数字,字母,下划线 组成 
                                不能以数字开头, 只能以字母或者下划线开头 
                                不能与关键字冲突, 且区分大小写 
                                


                例子:   
                    int a; 

                    abc  12a  sb   usb  int  sb*  c8_9  _Sb _666 
                          x              x    x     


        (3)变量的访问 (读/写)  ☆☆☆

            (a)从变量中去读取值 
                实际上就是通过变量名找到相应的内存地址,从该地址中去取值
                这时变量一般是在 赋值符号= 的右边,表示该变量的值,我们称之为 右值 rvalue 

            (b)往变量中去写入值
                实际上就是通过变量名找到相应的内存地址,往该地址中去写入值
                这时变量一般是在 赋值符号= 的左边,表示该变量对应的存储空间,称之为 左值 lvalue 


                    例子: 
                        int a;

                        a = 10;     // a作为左值, 代表a的那块内存空间, 把10写入到这个内存空间中   

                        int c = a;  // a作为右值, 代表变量a本身的值10, 先读取a的值10 再把10写入到变量c对应的内存空间中       


            我们在定义变量时,给它赋值,称之为 初始化 
                数据类型 变量名 = 初始值; 

            如果没有给变量赋值,那么这个变量的值是 不确定的,未知的 
             


5.整数的存储问题

    整数的存储 是以 二进制的补码形式 存放的 

    1)正数 
        正数的补码 就是其原码本身 

            例子: 
                char a = 13;
                    a  -->  0000 1101   -->  13的原码(二进制序列),也是它的补码

                int b = 9;  
                    b  -->  00000000 00000000 00000000 00001001     --> 9的原码,也是9的补码


    2)负数 
        负数的补码 是 其绝对值的原码,取反,+1 得到的 

            例子: 
                char a = -13;

                    |-13| --> 13 -->    0000 1101     绝对值的原码 
                                        1111 0010       取反(0->1, 1->0)
                                        1111 0011       +1 
                                            (-13的补码, -13在计算机中的存储形式)

            已知一个负整数的补码,如何去求这个负整数的十进制数? 
                    补码还原: (逆运算)
                        负整数的补码 -->  -1  -->  取反  -->  绝对值的原码  -->  得到负数 

                例子: 
                    求 1111 1110 所表示的负整数是多少? 

                        补码还原:  
                                    1111 1110
                            -1      1111 1101   
                            取反     0000 0010  绝对值的原码  --> 2 
                            --->    -2 

                        -2在计算机中的存储形式  1111 1110 
                        254在计算机中的存储形式 1111 1110
                        
                        -3在计算机中的存储形式  1111 1101 
                        253在计算机中的存储形式 1111 1101 

                        -4 
                        242 

                        .... 
                
                结论: 
                    一个负整数(-X) 会 和一个正整数(2^N - X )的存储形式是一样的 
                        (N代表用多少bit为来存储这个数)


                计算机怎么知道这个数到底代表的是正数还是负数?
                    %d : 以有符号的(32位)整数形式进行输出
                    %u : 以无符号的(32位)整数形式进行输出 

            总结: 
                (1)当编译器以有符号的整数输出时%d,是以补码还原的方式去解读 
                (2)当编译器以无符号的整数输出时%u,就没有符号位的概念了
                    直接把所有位都当作是数值位进行输出 
                (3)当CPU进行数据运算时,直接是以内存中的存放形式进行运算的,即补码形式 

            例子: 
                1)
                    int a = -2;
                    printf("a = %d\n", a );
                    printf("a = %u\n", a );

                        a在内存中的存放形式 
                            |-2|    00000000 00000000 00000000 00000010     绝对值的原码 2 
                                    11111111 11111111 11111111 11111101     取反 
                                    11111111 11111111 11111111 11111110     +1 (a在内存中的存放形式)

                            %d  : -2 
                                    补码还原 
                                        -1 --> 取反 --> 绝对值 --> 负数 

                            %u  : 2^32 - 2 

                2) 
                    unsigned int b = -1;
                    printf("b = %d\n", b );
                    printf("b = %u\n", b );

                        b       00000000 00000000 00000000 00000001     
                                11111111 11111111 11111111 11111110
                                11111111 11111111 11111111 11111111     b在内存中的存放形式 

                            %d :  -1 

                            %u :  2^32 - 1 

                3)
                    char c = -56;
                    printf("c = %d\n", c );         // -56
                    printf("c = %u\n", c );         // 2^32 - 56

                        c   |-56|   0011 1000 
                                    1100 0111  
                                    1100 1000  c的存放形式 

                            char  -->  int   (无符号数直接补0, 有符号数补符号位)

                                1100 1000    
                        -->     11111111 11111111 11111111 1100 1000

                            %d (有符号的32位整数形式) 
                                补码还原 
                                    11111111 11111111 11111111 1100 1000 
                                    11111111 11111111 11111111 1100 0111    -1 
                                    00000000 00000000 00000000 0011 1000    绝对值的原码 56 
                                --> -56 

                            %u (无符号的32位整数形式)
                                    11111111 11111111 11111111 1100 1000
                                -->  2^32 - 56 

                4) 
                    unsigned char d = -56;
                    printf("d = %d\n", d );     // 200
                    printf("d = %u\n", d );        // 200

                        d   |-56|   0011 1000 
                                    1100 0111  
                                    1100 1000  的存放形式  

                                char --> int   (无符号数直接补0, 有符号数补符号位)
                                    1100 1000 
                                --> 00000000 00000000 00000000 1100 1000

                            %d  : 200 

                            %u  : 200 


                        
6.整数之间的赋值问题 

    在C语言中,允许各个类型的整数之间的相互赋值 

        char --> int 
        short --> int 
        unsigned int --> int 
        int --> char 
        ... 

    赋值规则: 
        1)长的数据类型 --> 短的数据类型 
            int --> char 
            int --> short 

            低字节直接拷贝,高字节全部舍弃 
                
                比如: 
                    260 --->  00000000 00000000 00000001 00000100 
                        ---> char  -->   00000100 

        2)短的数据类型 --> 长的数据类型 
            低字节直接拷贝,高字节要分情况: 
                如果短的数据是无符号的,那么高字节就直接全部补0
                如果短的数据是有符号的,那么高字节就直接全部补符号位
                    

                char --> int 
                            1100 1000    
                        --> 11111111 11111111 11111111 1100 1000

                            0011 1110 
                        --> 00000000 00000000 00000000 0011 1110

                unsigned char --> int 
                            1100 1000    
                        --> 00000000 00000000 00000000 1100 1000


            ===========================
                当CPU把数据进行运算时,不能把变量的数据进行计算的
                    需要把数据拷贝到CPU内部的寄存器(32bits)
                    再对寄存器的值进行运算 

                        当变量的数据小于32bits时 
                            无符号的数据拷贝到寄存器高位补0
                            有符号的数据拷贝到寄存器高位补符号位

            练习: 
                1) 
                    char a = 250;
                    char d;
                    d = a + 8;
                    printf("d = %d\n", d );
                    printf("d = %u\n", d ); 

                        a   1111 1010                               (char)
                        8   00000000 00000000 00000000 00001000    (int) 

                            a   char --> int 
                                11111111 11111111 11111111 11111010 
                            +8  00000000 00000000 00000000 00001000  
                            ---------------------------------------------
                              1 00000000 00000000 00000000 00000010    
                          -->   00000000 00000000 00000000 00000010   (int)

                                int --> char 
                            -->  d  :  00000010 

                        %d : 2 

                        %u : 2 
        2) 
            unsigned char a = 250;
            int d = a + 8;
            printf("d = %d\n", d );
            printf("d = %u\n", d );

                a在内存中的存放形式 
                    250     11111010 

                        unsigned char  --> int 
                        00000000 00000000 00000000 11111010

                    8   00000000 00000000 00000000 00001000
                    +   ---------------------------------------
                        00000000 00000000 00000001 00000010       258 

                d在内存中的存放形式 
                        00000000 00000000 00000001 00000010 

                    %d : 符号位为0,为正数,直接输出 --> 258 
                    %u : 直接输出 --> 258 

        3) 
            short a = 32767;
            a = a + 1;
            printf("%d\n", a );
            printf("%u\n", a );

                a在内存中的存放形式 
                    32767   --> 01111111 11111111       (short)

                        short  -->  int     (符号位为0)
                        00000000 00000000 01111111 11111111

                    1   00000000 00000000 00000000 00000001
                    + -------------------------------------------
                        00000000 00000000 10000000 00000000

                    再存入a中 
                        int -> short 
                        10000000 00000000

                    %d : 有符号的32位整数形式  
                            short -> int      (此时 符号位为1)
                            11111111 11111111 10000000 00000000 
                            补码还原: 
                                11111111 11111111 01111111 11111111    -1 
                                00000000 00000000 10000000 00000000     取反  绝对值的原码 32768 
                            --->  -32768 

                    %u :    short -> int     
                            11111111 11111111 10000000 00000000 
                        --> 直接输出 2^32 - 32768 


        4) 
            unsigned int a = 10;
            int b = -30;
            int w = a + b;

            if( a+b > 5 )
            {
                printf("YES \n");
            }
            else 
            {
                 printf("NO \n");
            }

            if( w > 5 )
            {
                printf("YES \n");
            }
            else 
            {
                 printf("NO \n");
            }

            a   --> 00000000 00000000 00000000 00001010      unsigned int 

            b   --> |-30|
                --> 00000000 00000000 00000000 00011110 
                ~   11111111 11111111 11111111 11100001
                +1  11111111 11111111 11111111 11100010     b在内存中的存放形式

            a+b   unsigned int  +  int  ===>  unsigned int  

                    a 00000000 00000000 00000000 00001010   (unsigned int)
                    b 11111111 11111111 11111111 11100010   (int)
                    + --------------------------------------
                      11111111 11111111 11111111 11101100   (unsigned int)
                      a+b的结果是无符号数

                (1) a+b > 5  ===>  YES 

            w   int 

                a+b的结果 再存入到w中 
                    11111111 11111111 11111111 11101100
                    w是一个有符号的整数,此时的符号位为1,表示是一个负数 

                (2) w < 5   ==>  NO 


http://www.mrgr.cn/news/33387.html

相关文章:

  • C++:数组与字符串
  • Git从了解到操作
  • 【homebrew安装】踩坑爬坑教程
  • Renesas R7FA8D1BH (Cortex®-M85) 生成4路PWM
  • 【ArcGIS微课1000例】0123:数据库中要素类批量转为shapefile
  • 数据结构之堆(优先级队列)
  • 2024/9/22周报
  • 【面经】查找中常见的树数据结构
  • 8. Data Member的绑定
  • 国产游戏技术能否引领全球【终稿】
  • CompletableFuture如何优雅处理异步任务超时!妙就完了
  • 国人卖家可折叠无线充电器发起TRO专利维权,功能相同可能侵权
  • 【深入学习Redis丨第六篇】Redis哨兵模式与操作详解
  • 图神经网络的新篇章:通用、强大、可扩展的图变换器
  • WebGL基础知识快速入门
  • 空栈压数 - 华为OD统一考试(E卷)
  • thinkphp 做分布式服务+读写分离+分库分表(分区)(后续接着写)
  • 【shell脚本4】Shell脚本学习--字符串和数组
  • 掌控历史:如何通过Git版本管理工具提升你的开发效率
  • 2024华为杯E题成品文章已出!