C语言数据类型

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函数结束就是整个程序结束
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值