C 语言数据类型

C

数据类型由编译器创建,为了更好的管理内存。

常量和变量

常量

常量,就是不会变化的数据。

  • 定义方法
    • 方法一:普通定义
      "hello"、-10、10、3.14444
      
    • 方法二:定义宏
      // #define 宏名 宏值
      // 没有分号结束标记
      #define PI 3.14
      
    • 方法三:const 关键字定义
      // 被 const 关键字修饰的变量,表示只读变量
      const int a = 10;
      
  • 示例:求圆的周长和面积
    #include 
    
    #define PI 3.1415
    
    int main(void)
    {
        //int r = 3;  // 半径
        const int r = 3;  // 只读变量
    
        float l = 2 * PI * r;  // 周长
        float s = PI * r * r;  // 面积
    
        printf("圆的周长为:%.2f\n", l);
        printf("圆的面积为:%.2f\n", s);
    
        return 0;
    }
    

变量

变量,就是会变化的数据。

  • 定义语法 (一般方法)
    // 变量三要素:类型名、变量名、变量值
    // 类型名 变量名 = 变量值
    int r = 3;  // 变量值是一个常量
    float s = PI * r * r; // 变量值是一个表达式
    
    • 变量的定义
      int a = 1;
      
      • 变量定义会开辟内存空间,变量声明不会

      • 变量想要使用必须有定义

        当编译器编译程序时,在变量使用之前,必须要看到变量定义。如果没有看到变量定义,编译器会自动寻找一个变量声明提升为定义。
        如果该变量声明前有 extern 关键字,无法提升。

      • 定义变量时,不要重名

    • 变量的声明

      没有变量值的变量定义,叫做声明。

      int a;
      extern int b;  // 添加了关键字 extern
      
  • 变量的存储
    • 变量名、地址、变量值
    • 示意图
      C
  • 变量名的本质
    • 变量名的本质,是一段连续内存空间的别名
    • 程序通过变量来申请和命名内存空间
    • 通过变量名访问内存空间
    • 不是向变量名读写数据,而是向变量所代表的内存空间中读写数据
  • 变量的修改方式
    • 直接修改

    • 间接修改 (利用指针)

      #define _CRT_SECURE_NO_WARNINGS
      #include 
      #include 
      #include 
      
      void test01()
      {
          int a = 10;
          a = 20;  // 直接修改
          printf("%d\n", a);
      
          int* p = &a;
          *p = 30;  // 间接修改
          printf("%d\n", a);
      }
      
      int main(void)
      {
          test01();
      
          system("pause");
          return 0;
      }
      

标识符

标识符是变量和常量的统称。

  • 命名规则
    • 通常常量使用大写,变量使用小写,大小写严格区分
    • 只能使用字母、数字、下划线 () 来命名标识符,且不能以数字开头,例如:a-z/A-Z/0-9/
    • 禁止使用关键字或系统函数作为标识符名称
  • 示例:变量声明
    #include 
    #define MAX 10
    
    main()
    {
        int a;
        const int b = 10;
        a = MAX;
        //a = 123;
        //b = 3;  // 常量的值不能修改
        printf("%d %d\n", a, b);
    
        return 0;
    }
    

基本类型

整型

  • 有符号整型 (signed)

    signed,有符号,但是超级不常用,通常省略。

    • short
      • %hd,2字节
    • int
      • %d,4字节
    • long
      • %ld,通常4字节

        最早期的类型,字节数区分平台。

        • windows 32/64 位 -> 都是 4 字节
        • Linux
          • 32位 -> 4字节
          • 64位 -> 8字节
    • long long
      • %lld,8字节
  • 无符号整型 (unsigned)

    unsigned,只表示数据量,没有方向 (正负),字节数和对应的 signed 类型相同。

    • unsigned short
      • %hu,2字节
    • unsigned int
      • %u,4字节
    • unsigned long
      • %lu,4字节
    • unsigned long long
      • %llu,8字节
  • 注意事项
    • 小的数据类型赋值给大的数据类型不会出错,编译器会自动转化;大的数据类型赋值给小的数据类型,可能丢失高位
  • 示例:打印整型变量
    #define _CRT_SECURE_NO_WARNING
    #include 
    #include 
    
    int main(void)
    {
        int a = 3;
        short b = 4;
        long c = 5;
        long long d = 6;
        unsigned int aa = 33;           //33u
        unsigned short bb = 44;         //44u
        unsigned long cc = 55;          //55lu
        unsigned long long dd = 66;     //66llu
    
        printf("%d\n", a);
        printf("%hd\n", b);
        printf("%ld\n", c);
        printf("%lld\n", d);
        printf("%u\n", aa);
        printf("%hu\n", bb);
        printf("%lu\n", cc);
        printf("%llu\n", dd);
    
        system("pause");
        return 0;
    }
    

字符型 char

char 存储一个字符,本质是 ASCII 码,格式匹配符是 %c。

  • ASCII 码
    • A – 65

    • a – 97

      • 示例:大小写转换,差 32
        #define _CRT_SECURE_NO_WARNING
        #include 
        #include 
        
        int main(void)
        {
            char ch = 'M';
            printf("ch = %c\n", ch + 32);  // A - 65, a - 97,大小写之间差 32
        
            system("pause");
            return 0;
        }
        
    • 0 – 48
      • 字符 0
    • \n – 10
      • 换行符
    • \0 – 0
      • 数值 0
    • 转义字符 ()
      • 将普通字符转为特殊意,反之亦然

实型 (浮点型)

  • float
    • 单精度浮点型,保留 6 位小数
    • %f,4字节
  • double
    • 双精度浮点型 (默认)
    • %lf,8字节
  • 示例:实型 (浮点型) 格式化输出
    #define _CRT_SECURE_NO_WARNING
    #include 
    #include 
    
    int main(void)
    {
        float a = 3.14f;  //
        double b = 3.14;  //
    
        // 直接输出
        printf("a = %f\n", a);  // 自动保留6位小数
        printf("b = %lf\n", b);
    
        // 控制小数位
        printf("----------------------\n");
        printf("a = %5.2f\n", a);  // 总共5位,不够用空格补,保留2位小数
        printf("b = %08.2lf\n", b);  // 共8位,不够用0补齐,保留2位小数
    
        // 科学计数法输出
        a = 3.2e3f;   // 表示 3.2 * 10^3  -- e 可以写成 E
        b = 3.2e-3f;  // 表示 3.2 * 10^(-3)
    
        printf("----------------------\n");
        printf("a = %f\n", a);
        printf("b = %lf\n", b);
    
        system("pause");
        return 0;
    }
    

类型转换

  • atof/atoi 函数
    • 函数描述
      • 把参数 str 所指向的字符串转换为一个浮点数/整数
    • 函数原型
      #include 
      double atof(const char *str)
      int atoi(const char *str)
      long int atol(const char *str)
      
  • strtod/strtol 函数
    • 函数描述
      • 把参数 str 所指向的字符串转换为一个浮点数/长整型
    • 函数原型
      #include 
      double strtod(const char *str, char **endptr)
      long int strtol(const char *nptr, char **endptr, int base);
      
      • 参数
        • nptr
          • 要转换的字符串,必须得能够转换成对应的整型才行
        • endptr
          • 通常指定为 NULL,只有测试时才会使用,如果转换错误,会传出错误的字符串地址
        • base
          • 指定进制,可以是 8、10、16
    • 示例
      char *p = "123abc";
      char *pt = NULL;
      strtol(p, &pt, 10);  // 表示将 123abc 转换为10进制的整型
      // pt 打印结果为 abc
      

sizeof 操作符

格式匹配符是 %zd。

作用

  • 用来求变量或类型的大小,单位为字节
  • sizeof 的本质不是函数,而是操作符,所以不包含任何头文件

语法

sizeof(变量)
sizeof(类型)
sizeof 变量  // 可以不加小括号 ()
  • 示例 1
    #define _CRT_SECURE_NO_WARNING
    #include 
    #include 
    
    int main(void)
    {
        int a = 3;
        short b = 4;
        long c = 5;
        long long d = 6;
    
        size_t e = sizeof(d);
    
        printf("int %zd\n", sizeof(int));
        printf("short %zd\n", sizeof(short));
        printf("long %zd\n", sizeof(long));
        printf("long long %zd\n", sizeof(long long));
    
        printf("int %zd\n", sizeof(a));
        printf("short %zd\n", sizeof(b));
        printf("long %zd\n", sizeof(c));
        printf("long long %zd\n", sizeof(d));
    
        printf("long long %zu\n", e);
    
        system("pause");
        return 0;
    }
    
  • 示例 2

    “`c

    define _CRT_SECURE_NO_WARNINGS

    include

    // 1.sizeof 基本用法
    void test01()
    {
    int a = 10;
    printf(“len = %u, %u, %u\n”, sizeof(a), sizeof(int), sizeof a); // 4, 4, 4
    }

    // 2.sizeof 返回值类型
    void test02()
    {
    unsigned int a = 10;
    printf(“10 – 11 = %u\n”, a – 11); // 4294967295
    printf(“10 – 11 = %d\n”, a – 11); // -1
    if (a – 11 111000
    C

  • 二进制转十进制

    • 2^10 以下要记下来
      C

八进制

八进制数字,以0开头,每位小于8。

  • 八进制转二进制
    • 按 421 码将每个八进制位展开
    • 示例:056 和 05326 转二进制
      C
  • 八进制转十进制
    • 示例:056 -> 46
      C
  • 二进制转八进制
    • 421 码,3 个一组,从右往前,高位不足补 0
    • 示例:1 010 111 010 110 -> 012726
      C

十六进制

十六进制数字,以 0x 开头,每位取 0-9/A-F/a-f。

  • 语法
    • 十六进制和十进制数字对照
      C
  • 十六进制转十进制
    • 示例:0x1A -> 26,0x13F -> 319
      C
  • 十六进制转二进制
    • 示例:0x1A 和 0x13F 转为二进制
      C
  • 二进制转十六进制
    • 8421 码
    • 示例:0001 0011 1111 转为十六进制
      C

赋值

  • 格式匹配符
    • 十进制显示:%d
    • 八进制显示:%o
    • 十六进制显示:%x
  • 注意事项
    • 不能直接赋值二进制
  • 示例:进制转换
    #define _CRT_SECURE_NO_WARNING
    #include 
    #include 
    
    int main(void)
    {
        int a = 0x2c;  // 不能直接赋值二进制数
    
        printf("a 的16进制数为:%x\n", a);
        printf("a 的10进制数为:%d\n", a);
        printf("a 的8进制数为:%o\n", a);
    
        system("pause");
        return 0;
    }
    

计算机内存数值存储方式 (原码、反码和补码)

存储知识

  • 1 bit
    • 就是一个二进制位
  • 1 个字节 1B = 8 bit

  • 1KB = 1024B
  • 1MB = 1024KB
  • 1GB = 1024MB
  • 1TB = 1024GB

原码 (已淘汰)

不便于加减运算。

  • 43 -> 00 101011
    • 正数以0开头,不足8位的补0
  • -43 -> 10 101011
    • 负数以1开头,不足8位补0

反码 (已淘汰)

  • 43 -> 00 101011
    • 正数与原码相同:00 101011
  • -43 -> 10 101011
    • 负数是符号位不变,其他位原码取反:11 010100

补码 (现今计算机采用的存储形式)

  • 人为规定
    • 000 0000 -> 0
    • 1000 0000 -> -128
  • 43 -> 00 101011
    • 正数与原码相同:00 101011
  • -43 -> 10 101011
    • 负数是符号位不变,其他位原码取反 + 1:11 010101
  • 43 – 27 = 43 + (-27)
    • 43 的补码
      • 00 101011
    • -27
      • 原码
        • 100 11011
      • 反码
        • 111 00100
      • 补码
        • 111 00101
    • 43 – 27 = 00 101011 + 111 00101 = 10000 10000
      • 超出8位的丢弃 -> 000 10000 -> 16

原码、反码和补码总结

  • 对于正数
    • 原码、反码、补码相同
  • 对于负数
    • 补码 = 反码 + 1
    • 补码的符号位不动,其他位求反,最后整个数加1,得到原码

数值范围

  • char 类型
    • 1 字节,8 个 bit,相当于数值位有 7 个
    • 有符号 char
      • -2^(8-1) ~ 2^(8-1)-1
        • 最后 -1 是因为有一个 0 值
        • -128 ~ 127
    • 无符号 char
      • 0 ~ 2^8-1
        • 0 ~ 255
  • int 类型
    • 有符号
      • -2^(48-1) ~ 2^(48-1)-1
        • -2147483648 ~ 2147483647
    • 无符号
      • 0 ~ 2^(4*8)-1
        • 0 ~ 4294967295
  • long 类型
    • 同 int
  • long long 类型
    • 有符号
      • -2^(88-1) ~ 2^(88-1)-1
    • 无符号
      • 0 ~ 2^(8*8)-1

类型限定符

extern

美 /ˈekstɜːrn/

  • 表示声明,没有内存空间,不能提升

const

  • 限定变量为只读变量

volatile

  • 防止编译器优化代码

register

  • 定义一个寄存器变量 (寄存器变量没有地址,变量地址在内存中),提高效率
  • register 是建议型的指令,而不是命令型的指令,如果 CPU 有空闲寄存器,那么 register 就生效,如果没有空闲寄存器,就无效

字符串的格式化输入和输出

字符串常量

  • 字符串一定有一个结束标记 ‘\0’
  • 字符串使用双引号引起来
  • 字符串常量和字符常量的不同
    • ‘a’ 不等价 “a”:一个是字符,一个是字符串

格式匹配符

  • %%
    • 用来转义 %,\ 转义无效
  • %Ns
    • 显示 N 个字符的字符串,不足 N 用空格向左填充
      %015.2f  //左侧填充0
      
  • %-Ns
    • 显示 N 个字符的字符串,不足 N 用空格向右填充
      %-015.2f  // 向右填充0
      

格式化输出

  • printf 函数
    • 从字符串第一个字符开始打印,直到 ‘\0’ 结束
  • putchar 函数

    输出单个字符到屏幕 (也可以直接使用 ASCII 码)。
    常用 putchar('\n'); 来打印换行。

    • 函数描述
      • 输出单个字符
      • 不能输出字符串 (‘abc’ 既不是有效字符,也不是有效字符串)
    • 示例
      putchar(97);
      putchar('\n');
      

格式化输入

  • scanf()
    • 函数描述
      • 从键盘接收用户输入。
      • 接收字符串
        • 变量名要取地址传递给 scanf,数组名本身包含地址,不用取地址
        • 申请了 10 个字节,超出的部分不受保护,但是不出错
    • 注意事项
      • scanf 具有安全隐患,如果存储空间不足,数据能存储到内存中,但是不受保护
      • scanf 函数在接收字符串时,碰到空格和换行终止,所以不能使用 scanf 接收带有空格的字符串
    • 示例
      // 接收整数 %d
      int a, b, c;
      scanf("%d %d %d", &a, &b, &c);  // &:取出变量的地址
      
      // 接收字符 %c
      int a, b, c;
      scanf("%c %c %c", &a, &b, &c);
      
      // 接收字符串 %s
      char str[10];
      scanf("%s", str);
      
  • getchar()
    • 函数描述
      • 从键盘获取用户输入的一个字符,返回该字符的 ASCII 码。
    • 示例
      #define _CRT_SECURE_NO_WARNINGS
      #include 
      
      // 接收字符
      void test01()
      {
          char c1 = getchar();
          printf("%c\n", c1);
      }
      
      int main()
      {
          test01();
      
          return 0;
      }
      

运行时报错:scanf 不安全

  • 解决方法
    • 在源文件第一行添加:#define _CRT_SECURE_NO_WARNINGS
    • 设置VS:VS 项目-属性-C/C++-预处理器-预处理器定义-编辑,添加 _CRT_SECURE_NO_WARNINGS
      C
英仔
版权声明:本站原创文章,由 英仔 2022-08-04发表,共计6228字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)