C语言:构造类型

构造类型

数据类型

  1. 基本类型/基础类型/简单类型

    • 整型

      • 短整型:short -- 2字节

      • 基本整型:int -- 4字节

      • 长整型:long -- 32位系统4字节/ 64位系统8字节

      • 长长整型:long long 8字节(大多数现代机器,旧机器可能超过8字节),C99新增

      • 注意:以上类型又分为signed(默认) 和 unsigned

    • 浮点型

      • 单精度型:float --4字节

      • 双精度型:double --8字节

      • 长双精度型:long double -- 16字节(视平台而定),C99新增

    • 字符型: char --1字节

  2. 指针类型

    • 数据类型*:32位系统4字节,64位系统8字节

    • void*:通用指针类型(万能指针)32位系统4字节,64位系统8字节

  3. 空值类型

    • void:无返回值,无形参(不能修饰变量)

  4. 构造类型(自定义类型)

    • 结构体类型:struct

    • 共用体/联合体类型:union

    • 枚举类型:enum

结构体

结构体定义【定义类型】
  • 定义:自定义数据类型的一种,关键字struct。

  • 语法:

struct 结构体名 // 结构体名:自定义的数据类型名字  类似于int,double之类的
{
  	数据类型1 成员名称1;  // 结构体中的变量叫做成员
    数据类型2 成员名称2;
    ...
};
  • 注意:结构体中定义的变量,称之为成员变量(成员属性)

  • 格式说明:

    • 结构体名:合法的标识符,建议首字母大写(所谓的结构体名,就是自定义类型的类型名称)

    • 数据类型n:C语言支持的所有类型(包括函数,函数在这里用函数指针表示)

    • 成员名称n:合法的表示,就是变量的命名标准

    • 数据类型n 成员名称n:类似于定义变量,定义了结构体中的成员

  • 注意:

    • 结构体在定义的时候,成员不能赋值,示例:

struct Cat
{
  	int age = 5;      // 错误,结构体定义的时候,并未在内存中申请空间,因此无法进行赋值
    double height;    // 正确
    void (*run)(void);// 正确
};
  • 常见的定义格式:

    • 方式1:常规定义(命名结构体,只定义数据类型)

      struct Student
      {
          int num;           // 学号
          char name[20];     // 姓名
          char sex;          // 性别
          int age;           // 年龄
          char address[100]; // 籍贯
          void (*info)(void);// 信息输出(函数指针)
      };
    • 方式2:匿名结构体(常用于作为其他结构体的成员使用)

      struct Dog // 命名结构体
      {
        	char *name;        // 姓名
          int age;           // 年龄
          struct // 匿名结构体
          {
              // 定义结构体时不能省略成员,否则编译报错
              int year; // 年
              int month;// 月
              int day;  // 日
          } bithday;         // 年龄,匿名结构体一定要提供成员名称,否则无法访问
      };

    • 注意:定义匿名结构体的同时必须定义结构体成员,否则编译报错;结构体可以作为另一个结构体的成员。

      总结:

      • 结构体可以定义在局部位置(函数作用域、块作用域),也可以定义在全局位置(推荐,可以复用)

      • 全局位置的结构体名和局部位置的结构体名可以相同,遵循就近原则(和变量的定义同理)

    • 结构体类型的使用:

      利用结构体类型定义变量、数组,也可以作为函数的返回值和参数;结构体类型的使用与基本数据类型的使用类似。

结构体变量定义【定义变量】
三种形式定义结构体变量

说明:结构体变量也被称作结构体对象或者结构体实例。

  • 第一种方式:

    ① 先定义结构体(定义数据类型)

    ② 然后定义结构体变量(定义变量)

    示例:

    // 定义结构体(定义数据类型)
    struct A
    {
        int a;
        char b;
    };
    
    // 定义结构体实例/变量(定义变量)
    struct A x;   // A就是数据类型,x就是变量名
    struct A y;   // A就是数据类型,y就是变量名
    • 第二种方式:

      ① 在定义结构体的同时,定义结构体变量(同时定义数据类型和变量)

      语法:

      struct 结构体名
      {
      	数据类型1 数据成员1;
          ...
      } 变量列表;

      示例:

      struct A
      {
      	int a;
          char b;
      } x, y; // A就是数据类型,x,y就是变量名

    • 第三种方式:

      ① 在定义匿名结构体的同时,定义结构体变量。

      示例:

      struct
      {
          int a;
          char b;
      } x, y;

      此时定义了一个没有名字的结构体(匿名结构体),x,y是这个结构体类型的变量。

    匿名结构体

    • 优点:少写一个结构体名称

    • 缺点:只能使用一次,定义结构体类型的同时必须定义变量。

    • 应用场景:

      • 当结构体的类型只需要使用一次,并且定义类型的同时定义了变量。

      • 作为其他结构体的成员使用。

        struct Cat
        {
            int age;
            char color[20];
        } cat;

    • 结构体成员部分初始化,大括号不能省略

    • 结构体成员,没有默认值,是随机值,和局部作用域的变量一致。

    案例:

    #include <stdio.h>
    
    /**
     * 先定义结构体,再定义结构体变量(实例)
     */ 
    void fun1()
    {
        // 定义结构体
        struct A
        {
            int a;
            char b;
        };
    
        // 定义结构体变量
        struct A x;
        struct A y;
        struct A x1,y1;
        
    }
    
    /**
     * 定义结构体的同时定义结构体变量
     */ 
    void fun2()
    {
        struct A
        {
            int a;
            char b;
        } x,y;
    
        struct A z;
        struct A x1,y1;
    }
    
    /**
     * 定义匿名结构体的同时定义结构体变量
     */ 
    void fun3()
    {
        struct
        {
            int a;
            char b;
        } x,y;
    
        struct
        {
            int a;
            char b;
        } z;
    }
    
    int main(int argc,char *argv[])
    {
        fun1();
        fun2();
        fun3();
    
        return 0;
    }
    

     

    结构体变量的使用【变量使用】
    结构体变量访问成员

    语法:

    结构体变量名(实例名).成员名;

    ① 可以通过访问成员进行赋值(存数据)

    ② 可以通过访问成员进行取值(取数据)

    • 结构体变量未初始化,结构体成员的值是随机的(和局部作用域的变量和数组同理)

    • 建议用大括号{}标明数据的范围。

      #include <stdio.h>
      
      /** 定义全局的结构体,方便被多个函数访问*/
      struct Dog
      {
      	char *name;        // 名字
      	int    age;        // 年龄
      	char   sex;        // 性别 M:公,W:母
      	void (*eat)(void); // 吃狗粮
      };
      
      void eat()
      {
      	printf("狗狗正在吃狗粮!\n");
      }
      
      /**
       * 方式1:先定义,再初始化   ---> 结构体变量访问成员
       */
      void fun1()
      {
      	// 定义结构体变量
      	struct Dog dog;
      	
      	// 结构体变量成员赋值
      	dog.name = "旺财";
      	dog.age = 5;
      	dog.sex = 'M';
      	dog.eat = eat;
      	
      	// 结构体变量成员访问
      	printf("%s,%d,%c\n", dog.name, dog.age, dog.sex);
      	// 访问成员方法(函数)
      	dog.eat();
      }
      
      /**
       * 方式2:定义的同时初始化,给变量成员初始化
       */
      void fun2()
      {
      	// 定义结构体变量的同时,给变量成员初始化
      	struct Dog d1 = {"旺财", 5, 'M', eat}; // 完整初始化,按照顺序赋值
      	struct Dog d2 = {.name = "莱德", .sex = 'M'}; // C99之后,支持部分成员初始化,未初始化的成员自动填充0
      	struct Dog d3 = {"旺财"}; // C99之后,可以默认初始化第一个成员,其他成员用0填充
      	
      	// 结构体变量成员访问
      	printf("%s,%d,%c\n", d1.name, d1.age, d1.sex);
      	printf("%s,%d,%c\n", d2.name, d2.age, d2.sex);
      	printf("%s,%d,%c\n", d3.name, d3.age, d3.sex);
      	
      }
      
      int main(int argc, char *argv[])
      {
      	fun1();
      	printf("\n------------\n");
      	fun2();
      	return 0;
      }
      结构体数组的定义【数组定义】
      什么时候需要结构体数组

      比如:我们需要管理一个学生对象,只需要定义一个struct Student yifanjiao;

      假如:我们需要管理一个班的学生对象,此时就需要定义一个结构体数组struct Student stus[50];

      定义

      存放结构体实例的数组,称之为结构体数组。

      四种形式定义结构体数组
    • 第一种方式:

    // 第一步:定义一个结构体数组
    struct Student
    {
      	char      *name;     // 姓名
        int         age;     // 年龄
        float scores[3];     // 三门课程的成绩
    } stus[3];
    
    // 第二步:赋值
    stus[0].name = "张三";
    stus[0].age = 21;
    stus[0].scores[0] = 89;
    stus[0].scores[1] = 99;
    stus[0].scores[2] = 87;
    
    stus[1].name = "李四";
    stus[1].age = 22;
    stus[1].scores[0] = 66;
    stus[1].scores[1] = 77;
    stus[1].scores[2] = 88;
    • 第二种方式:
      // 第一步:定义一个学生结构体(定义数据类型)
      struct Student
      {
        	char      *name;     // 姓名
          int         age;     // 年龄
          float scores[3];     // 三门课程的成绩
      };
      
      // 第二步:定义结构体实例(定义结构体实例)
      struct Student zhangsan = {"张三", 21, {89,99,87}};
      struct Student lisi     = {"李四", 22, {66,77,88}};
      
      // 第三步:定义结构体数组
      struct Student stus[] = {zhangsan, lisi};

    • 第三种方式:

      // 第一步:定义一个学生结构体(定义数据类型)
      struct Student
      {
        	char      *name;     // 姓名
          int         age;     // 年龄
          float scores[3];     // 三门课程的成绩
      };
      
      // 第二步:定义结构体数组并初始化成员
      struct Student stus[] = {
          {"张三", 21, {89,99,87}},
          {"李四", 22, {66,77,88}}
      };

    • 第四种方式:

      // 第一步:定义一个结构体数组,并初始化
      struct Student
      {
        	char      *name;     // 姓名
          int         age;     // 年龄
          float scores[3];     // 三门课程的成绩   
      } stus[] = {
          {"张三", 21, {89,99,87}},
          {"李四", 22, {66,77,88}}
      };
      结构体数组的访问【数组访问】

      语法:

      结构体成员.成员名
      结构体指针 -> 成员名     // -> 结构体指针成员访问符

      举例:

      // 方式1:结构体成员访问
      (*p).成员名
      // 方式2:结构体指针访问
      p -> 成员名

      案例:

      #include <stdio.h>
      
      /* 定义全局的Student结构体 */
      struct Student
      {
      	int          id;         // 编号
      	char      *name;         // 姓名
      	int         age;         // 年龄
      	float scores[3];         // 三门课成绩
      	void (*info)(char*,int); // 信息输出
      };
      
      void info(char* name, int age)
      {
      	printf("大家好,我是%s,今年%d岁!\n", name, age);
      }
      
      int main(int argc, char *argv[])
      {
      	// 定义结构体实例并初始化
      	struct Student zhangsan = {1, "张三", 21, {78,88,98}, info};
      	struct Student lisi     = {2, "李四", 22, {90,98,91}, info};
      	
      	// lisi.info = info
      	
      	// 定义结构体数组并初始化
      	struct Student stus[] = {zhangsan, lisi};
      	
      	// 计算数组的大小
      	int len = sizeof(stus) / sizeof(stus[0]);
      	
      	// 用一个指针进行遍历
      	struct Student *p = stus;
      	
      	// 表格-表头
      	printf("序号\t姓名\t年龄\t语文\t数学\t英语\n");
      	for (; p < stus + len; p++)
      	{
      		// 结构体成员访问,不推荐
      		// printf("%d\t%s\t%d\t%.2f\t%.2f\t%.2f\t\n",(*p).id, (*p).name, (*p).age, (*p).scores[0], (*p).scores[1], (*p).scores[2]);
      		// (*p).info((*p).name, (*p).age);
      		
      		// 结构体指针访问,推荐
      		printf("%d\t%s\t%d\t%.2f\t%.2f\t%.2f\t\n",p->id, p->name, p->age, p->scores[0], p->scores[1], p->scores[2]);
      		// 函数调用
      		p->info(p->name, p->age);
      	}
      	
      	printf("\n");
      	
      	return 0;
      }

      结构体类型

      结构体数组

      案例

    • 需求:对候选人得票进行统计,设有三个候选人,每次输入一个得票的候选人名字,最后输出个人得票的结果。

      #include <stdio.h>
      #include <string.h>
      
      #define LEN 3
      
      struct Person
      {
        char name[20];
        int count;
      
      };
      
      /*
      *定义候选人数组并初始化
      */
      struct Person persons[] = {
        {"小帅",0},
        {"小张",0},
        {"小黄",0}
      };
      
      
      int main(int argc,char *argv[])
      {
          //定义循环变量
          register int i,j;
      
          //创建数组用来接收控制台录入的候选人名字
          char leader_name[20];
      
          //使用一个for循环,模拟10个人参与投票
          printf("投票系统\n");
          for ( i = 0; i < 10; i++)
          {
            printf("请输入目标投票人的名字:\n");
            scanf("%s",leader_name);
      
            //从候选人列表中匹配被投票的人 count++
            for (j = 0; j < LEN; j++)
            {
              //判断两个字符串是否相等
              if (strcmp(leader_name, persons[j].name) == 0)
              {
                persons[j].count++; //票数+1
              }
              
            }
            
          }
          printf("\n");
          printf("\n投票结果:\n");
          struct Person *p = persons;  //指针p指向数组persons的第一个元素
      
          //遍历数组:使用指针变量
          for ( ; p < persons + LEN; p++)
          {
            printf("%s:%d\n",p ->name, p ->count);
          }
          printf("\n");
      
          //遍历数组:使用指针
          for ( i = 0; i < LEN; i++)
          {
            printf("%s:%d",(persons + i)->name,(persons + i) ->count);
          }
          
          //遍历数组:使用下标
          for ( i = 0; i < LEN; i++)
          {
            printf("%s:%d",persons[i].name,persons[i].count);
          }
          
          return 0;
      }
      

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值