首页 > 其他分享 >C语言自定义类型

C语言自定义类型

时间:2024-12-30 09:28:38浏览次数:3  
标签:struct 自定义 int name 定义 C语言 char 类型 结构

构造类型

数据类型

  1. 基本类型/基础类型
    • 整数类型
      • 短整型:short/short int(2字节)
      • 整型:int(4字节)
      • 长整型:long/long int(8字节(64位系统))
      • 长长整型:long long /long long int(16字节)
    • 浮点型
      • 单精度:float(4字节)
      • 双精度:double(8字节)
      • 长双精度:long double(16字节(64位系统))
    • 字符型:char(1字节)
  2. 指针类型
    • 数据类型*:*int、char*、float*(8字节)
    • void*:任意数据类型的指针(万能指针)(8字节)
  3. 空类型
    • void:没有返回值/没有形参(不能定义变量)
  4. 自定义类型/构造类型
    • 结构体类型:struct
    • 共用体/联合体类型:union
    • 枚举类型:enum

结构体

结构体的定义
  • 定义:自定义数据类型的一种,关键字struct,结构体类型的变量可以存储多个不同数据类型的数据。
  • 定义格式:
struct 结构体名
{
	数据类型1 成员名称1;	//结构体中的变量叫做成员
	数据类型2 成员名称2;
	....
}

注意:结构体中定义的变量,我们称之为成员变量

  • 格式说明
    • 结构体名,合法的标识符,建议单词的首字母大写(所谓的结构体名,就是自定义类型的类型名称)
    • 数据类型n:C语言支持的所有类型(包括函数,函数在这里用函数指针表示)
    • 成员的名称:合法的标识符,就是变量的命名标准
    • 数据类型n成员名称n:类似于定义变量,定义了结构体中的成员

标识符:

说明:变量名、数组名、函数名、常量名、结构体名、共用体名、枚举名等都是标识符

命名规则:

  1. 只能包含字母、数字、下划线
  2. 不能以数字开头
  • 注意:

    • 结构体在定义时,成员不能赋值

      举例:

      struct cat
      {
      	int age = 5;	//错误,定义时不能赋值
      	double hight;	//正确
      	void (*run)(void);//正确
      }
      
  • 常见的定义格式

    • 方式一:常规定义(命名结构体,只定义类型)推荐
    struct Student
    {
    	int num;
    	char name[20];
    	char sex;
    	int age;
    	char address[100];
    	void (*info)(void);
    }
    
    • 方式二:定义匿名结构体(常用于作为其他结构体的成员使用)
    struct Dog
    {
    	char *name;
    	int age;
    	struct	//结构体中嵌套的结构体不能有名字,故被称作匿名结构体
    	{
    		int year;
    		int month;
    		int day;
    	}
    }
    

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

    总结:

    • 结构体可以定义在局部位置,也可以定义在全局位置(用的比较多)
    • 全局位置的结构体名和局部位置的结构体名可以相同,就近原则
  • 结构体类型的使用:

    利用结构体类型定义变量,定义数组;结构体类型的使用与基本数据类型的使用类似。

结构体变量的定义
  • 三种形式定义结构体变量

    结构体变量也成为结构体的实例。

    • 第一种

      1. 先定义结构体(自定义数据类型)
      2. 然后使用
      struct 结构体名 变量名 (实例);
      
      //先定义结构体(自定义数据类型)
      struct A
      {
          int a;
          char b;
      }
      //后定义结构体变量(使用自定义数据类型)
      struct A x;
      struct A y;
      
    • 第二种

      1. 在定义结构体的同时,定义结构体变量
      struct 结构体名
      {
      	数据类型1 数据成员1;
      	...
      }变量列表;
          
          
      struct A
      {
          int a;
          char b;
      }x,y;
      
      struct A z;
      
    • 第三种(不推荐)

      1. 在定义匿名结构体的同时,定义结构体变量
      struct
      {
          int a;
          char b;
      }x,y;
      
      struct
      {
          int a;
          char b;
      }z;
      

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

  • 匿名结构体:弊大于利

    • 优点:少些一个结构体名称
    • 缺点:只能使用一次,定义结构体类型的同时必须定义变量。
    • 应用场景:
      • 当结构体的类型只需要使用一次,并且定义类型的同时定义变量
      • 作为其他结构体的成员
  • 定义结构的同时,定义结构体变量初始化

struct Cat
{
	int age;
}cat;
  • 结构体成员部分初始化时,大括号{}不能省略
  • 结构体成员,没有默认值,是不确定的数

结构体变量的使用

  • 结构体变量访问结构体成员

    • 格式:
    结构体变量名.成员名;
    

    可以通过访问给这个成员赋值(存数据)

    可以通过访问获取成员的值(取数据)

    • 结构体变量未初始化,结构体的成员值随机(不确定)
  • 结构体变量在定义是,可以初始化

    • 建议用大括号表明数据的范围
    • 结构体成员初始化,可以部分初始化,部分初始化时一定带大括号标明数据的范围
  • 案例:

#include <stdio.h>

/*
    全局结构体(数据类型)
*/
struct Dog
{
    char *name;        // 姓名
    int age;           // 年龄
    char sex;          // M:公,W:母
    void (*eat)(void); // 吃饭
};

void eat()
{
    printf("狗在吃狗粮\n");
}

/*
    先定义在初始化
*/
void fun1()
{
    // 定义结构体变量
    struct Dog dog;

    // 给结构体变量赋值,其实就是给成员赋值
    dog.name = "旺财";
    dog.age = 5;
    dog.eat = eat;
    // 访问结构体变量,其实就是访问其成员
    printf("%s%d%c\n", dog.name, dog.age, dog.sex);
    //访问函数
    dog.eat();
}

void fun2()
{
    // 定义结构体变量并初始化
    struct Dog dog = {"招财", 23, 'M'};
    // 修改成员的值
    dog.name = "金宝";
    printf("%s%d%c\n", dog.name, dog.age, dog.sex);
}

int main()
{
    fun1();
    fun2();

    return 0;
}
结构体数组的定义
  • 什么时候需要结构体数组

    需要管理一个学生对象,只需要定义一个struct Student A;

    若管理多个学生对象,此时需要一个结构体数组struct Student student[29];

  • 四种形式定义结构体数组

    1. 先定义结构体类型,然后定义结构体变量,最后将变量储存到结构体数组

      //定义一个学生类型的结构体
      struct Student
      {
      	char* name;
      	int age;
      	floar scores[3];
      }
      
      //定义结构体对象
      struct Student zhangsan = {"张三",21,{80,85,72}};
      struct Student zhangsan = {"李四",21,{82,75,92}};
      
      //定义结构体数组
      struct Student student[3] = {zhangsan,lisi};
      
    2. 定义结构体类型,然后定义结构体数组并初始化

      //定义一个学生类型的结构体
      struct Student
      {
      	int id;
      	char* name;
      	int age;
      	float scores[3];
      }
      
      //定义结构体数组并初始化
      struct Student students[3] = {
          {1,"张三",21,{89,85,68}},
          {2,"李四",20,{85,76,90}}
      };
      
    3. 定义结构体类型的同时定义结构体并完成初始化

      //定义一个学生类型的结构体
      struct Student
      {
      	int id;
      	char* name;
      	int age;
      	float scores[3];
      } students[3] = {
          {1,"张三",21,{89,85,68}},
          {2,"李四",20,{85,76,90}}
      };
      
    4. 定义结构体类型的同时定义结构体数组,然后通过索引给结构体成员赋值

    //定义一个学生类型的结构体
    struct Student
    {
    	int id;
    	char* name;
    	int age;
    	float scores[3];
    } stus[3];
    
    //赋值
    stus[0].id = 1;
    stus[0].name = "张三";
    stus[0].age = 19;
    stus[0].scores[0] = 89;
    

    小贴士

    结构体数组名访问结构体成员:

    格式:结构体数组名->成员名

    #include <stdio.h>
    
    void print_(char *str)
    {
        printf("%s", str);
    }
    
    void fun3()
    {
        // 定义学生类型的结构体
        struct Student
        {
            int id;
            char *name;
            int age;
            float scores[3];
            void (*print_)(char *)
        };
    
        struct Student stu1 = {1, "张三", 21, {89, 20, 65}};
        struct Student stu2 = {2, "李四", 21, {89, 20, 65}};
        stu1.print_ = print_;
        stu2.print_ = print_;
    
        struct Student stus[] = {stu1, stu2};
    
        int len = sizeof(stus) / sizeof(stus[0]);
    
        for (int i = 0; i < len; i++)
        {
            // printf("%-3d", stus->id);
            printf("%d,%s,%d,%.2f\n", stus[i].id, stus[i].name, stus[i].age, stus[i].scores[i]);
            stus->print_(stus->name);
        }
    }
    
    int main()
    {
        fun3();
        return 0;
    }
    
    //指针写法
    #include <stdio.h>
    
    void print_(char *str)
    {
        printf("%s", str);
    }
    
    void fun3()
    {
        // 定义学生类型的结构体
        struct Student
        {
            int id;
            char *name;
            int age;
            float scores[3];
            void (*print_)(char *);
        };
    
        struct Student stu1 = {1, "张三", 21, {89, 20, 65}};
        struct Student stu2 = {2, "李四", 21, {89, 20, 65}};
        stu1.print_ = print_;
        stu2.print_ = print_;
    
        struct Student stus[] = {stu1, stu2};
    
        int len = sizeof(stus) / sizeof(stus[0]);
    
        struct Student *p = stus;
        for (; p < stus + len; p++)
        {
            printf("%d,%s,%d", p->id, p->name, p->age);
            float *q = p->scores;
            int len_ = sizeof(p->scores) / sizeof(p->scores[0]);
            for (; q < p->scores + len_; q++)
            {
                printf(" %-6.2f", *q);
            }
            printf("\n");
        }
    
    int main()
    {
        fun3();
        return 0;
    }
    

构造体类型

构造体数组

案例

需求:对候选人得票的统计程序。设有3个候选人,每次输入一个的票的候选人名字,要求最后输出各人的票的结果

#include <stdio.h>
#include <string.h>

/*
    需求:对候选人得票的统计程序。
    设有3个候选人,每次输入一个的票的候选人名字,
    要求最后输出各人的票的结果
    定义一个候选人的构造体(对象)
*/

struct Person
{
    char name[20];
    int temp;
};

/*定义候选人数组*/
struct Person persons[3] = {
    {"张三", 0},
    {"李四", 0},
    {"王五", 0}};

int main()
{
    char leader_name[20];
    // 使用循坏完成十次投票
    for (int i = 0; i < 10; i++)
    {
        printf("请输入您要投票的候选人姓名:\n");
        scanf("%s", leader_name);

        // 给被投票的候选人加一票
        for (int j = 0; j < 3; j++)
        {
            // 判断两个字符串结构是否相同
            if (strcmp(leader_name, persons[j].name) == 0)
            {
                persons[j].temp++;
            }
        }
    }

    printf("投票的结果:\n");
    // 下标法
    // for (int i = 0; i < 3; i++)
    // {
    //     printf("%s:%d\n", persons[i].name, persons->temp);
    // }

    struct Person *p = persons;
    for (; p < persons + 3; p++)
    {
        printf("%s:%d\n", p->name, p->temp);
    }

    return 0;
}
构造体指针
  • 定义:结构体类型的指针变量指向结构体变量或数组的起始地址

  • 语法:

    struct 结构体名 *指针变量列表;
    
    struct Dog
    {
        char name[20];
        int age;
    };
    
    struct Dog dog = {"富贵",5};
    struct Dog *p = &dog;
    
构造体成员访问
  • 结构体成员访问

    • 结构体数组名访问结构体成员

      • 格式:结构体数组名->成员名;
      • 举例
      for (; p < persons + 3; p++)
      {
          printf("%s:%d\n", persons->name, persons->temp);
      }
      
    • 结构体成员访问符

      • ==.==左侧是结构体变量(结构体对象/结构体实例),也可以叫做结构体对象访问成员符,右侧是结构体成员
      • ==->==左侧是指针,也叫做结构体指针访问成员符,右侧是结构体成员
    • 访问结构体成员的两种类型,三种方式

      1. 通过结构体对象访问成员

        struct Stu
        {
            int age;
            char name[20];
        }stu;
        
        stu.name;
        
      2. 通过结构体指针访问成员

        • 指针引用访问成员

          struct Stu
          {
              int age;
              char name[20];
          }stu;
          
          struct Stu *p = &stu;
          
          p->name;
          
        • 指针解引用间接访问成员

          struct Stu
          {
              int age;
              char name[20];
          }stu;
          
          struct Stu *p = &stu;
          
          (*p)->name;
          
    • 结构体数组中元素的访问

      struct Stu
      {
          int id;
          char name[20];
          float scores[3];
      } stu[3] = {
          {1,"张三",{75,85,95}},
          {2,"李四",{85,84,95}},
          {3,"王五",{88,97,77}}
      }
      
      printf("%s,%.2f",stu[1].name,stus[1].scores[1]);李四84
      
      printf("%s,%.2f",stu->name,stus->scores[1]);张三85
          
      printf("%s,%.2f",(stu+2)->name,(stus+2)->scores[2]);王五77   
          
      printf("%s,%.2f",(*(stu+2)).name,(*(stus+2)).scores[2]);王五77   
      

      小贴士

    • 结构体类型的使用案例

      结构体可以作为函数的返回类型、形式参数

构造体类型大小
  • 规则:字节对齐(默认,数据在内存中存储在其类型大小的整数倍)

    1. 首先保证结构体中的成员储存在自身的对齐边界(类型大小的整数倍)
    2. 在满足条件1下,最终大小要满足最大成员所占存储单元的整数倍
  • 为什么要字节对齐

    节省内存,提高访问效率

  • 在GNU标准中,可以在定义结构体时,指定对齐规则:

    __attribute__((packed));//结构体所占内存大小时所哟成员所占内存大小之和
    
    __attribute__((aligned(n)));//设置结构体占n个字节,若n比默认值小,n不起作用;n必须是2的次方
    

    案例

    #include <stdio.h>
    
    int main()
    {
        struct Cat
        {
            int id;
            char *name;
            char sex __attribute((aligned(2)));//设置结构体占n个字节
        } __attribute__((packed));//结构体所占内存大小时所哟成员所占内存大小之和
    
        printf("%ld\n", sizeof(struct Cat)); // 默认字节对齐24,使用packed后13,设置大小后14
    
        return 0;
    }
    
  • 柔性数组:

    struct St
    {
        ...
        char arr[0];
    }
    

    柔性数组不占有结构体的大小

    案例

    #include <stdio.h>
    
    int main()
    {
        struct Cat
        {
            int id;
            char *name;
            char arr[0];//柔性数组不占用结构体大小
            char sex __attribute((aligned(2)));//设置结构体占n个字节
        } __attribute__((packed));
    
        printf("%ld\n", sizeof(struct Cat)); // 默认字节对齐24
    
        return 0;
    }
    

共用体/联合体类型

  • 定义:使几个不同的变量占用同一段内存的结构。共用体按定义中需要存储空间最大的成员来分配存储单元,其他成员也是用该空间,其首地址相同。

  • 语法

    union 共用体名称
    {
        数据类型 变量名;
        ....
    };
    
  • 共用体的定义和结构体类似

    • 可以有名字,也可以匿名

    • 共用体在定义时也可以定义共用体变量

    • 共用体在定义时也可以初始化成员

    • 共用体也可以作为形参和返回值类型使用

    • 共用体也可以定义共用体变量

    结构体的语法,共用体都支持

  • 注意:

    • 共用体弊大于利,尽量少用,一般少用;
    • 共用体变量在某一时刻只能存一个数据,也只能取一个数
    • 共用体和结构体都是自定义数据类型,用法类似于基本数据类型
      • 共用体可以使共用体的成员,也可以是结构体的成员
      • 结构体可以是结构体的成员,也可以是共用体的成员

标签:struct,自定义,int,name,定义,C语言,char,类型,结构
From: https://blog.csdn.net/weixin_64487558/article/details/144815749

相关文章

  • C语言自定义类型与文件操作
    构造类型枚举类型若定义不相关的常量使用宏定义;若定义一组相关的常量使用枚举。switch中case后访问的就是枚举。定义:我们一般情况下定义常量使用宏定义(#define),宏定义适合没有关联关系的常量;但有时需要对一组有关联关系的量进行定义,例如:星期、月份、方向(上下左右中)......
  • C语言中整型数组
    一.数组数组也是一种数据类型,属于构造类型数组:一组相同类型的数据(变量)的集合定义数组:C语言中,只研究一维数组,二维数组。定义方式:类型说明符数组名[常量表达式];(1)数据类型(2)数组名:数组类型(3)[]整型常量表达式:代表该数组中同类型变量的个数eg:intscore[40];//批......
  • C语言结构体简介:“结”在一起,“构”成一“体”
    一、什么是结构体如果要一下子记录很多条数据,咱们一般都会想到用数组,比如记录一个班的学生的成绩。但是数组有个限制:元素必须是同一数据类型。如果我们想同时记录一个人的姓名(字符串)、年龄(整型)、身高(浮点型)等信息时,数组就派不上用场了,这时候就要用到结构体。结构体(struct)内......
  • 数据类型
    数据类型WXS语言目前共有以下几种数据类型:number:数值string:字符串boolean:布尔值object:对象function:函数array:数组date:日期regexp:正则number语法number包括两种数值:整数,小数。vara=10;varPI=3.141592653589793;属性constructor:返回字符串"Numbe......
  • 【C语言】多进程/多线程
    多进程/多线程多进程服务器步骤代码多线程一、线程创建和回收二、线程属性三、线程分离多进程服务器步骤  服务器使用父进程fork创建子进程来和客户端进行通信,父进程负责取出连接请求。并且父进程接收子进程退出信号,通过信号处理函数回收子进程步骤:1.首先屏......
  • 【C语言】线程同步
    【C语言】线程同步线程同步1.互斥锁2.读写锁3.条件变量4.信号量线程同步  线程同步是指在多线程的情况下,如果多个线程去访问共享资源,需要按照一定规则顺序依次去访问,保证共享资源的数据一致性。1.互斥锁互斥相关函数//互斥量pthread_mutex_tmutex;//p......
  • C语言二维数组
    在C语言中,二维数组是一种常用的数据结构,用于存储和处理具有行和列结构的数据。以下是关于C语言二维数组的详细介绍: 1.二维数组的定义 二维数组本质上是数组的数组。其定义语法如下: c数据类型数组名[行数][列数];  例如,定义一个3行4列的整数二维数组: cint......
  • C语言函数的参数
    在C语言中,函数参数是用于向函数传递数据的重要元素。 函数参数分为形式参数(形参)和实际参数(实参)。 形式参数 -定义在函数声明或定义中的参数。例如在函数 intadd(inta,intb) 中, a 和 b 就是形参。它们像是函数内部的变量,在函数被调用时才会被分配内存空间,用......
  • 学习012-02-04 Customize Controllers and Actions(自定义控制器和操作)
    CustomizeControllersandActions(自定义控制器和操作)ToimplementanewfeatureintheXAF,createanewController.Ifthefeaturerequiresend-userinteraction,addActionstoit.Atthesametime,youmayneedtocustomizeaControllerorActionprovi......
  • C语言学习笔记(基础语法篇)
    C语言学习笔记(基础语法篇)序言首先事先说明一下,这是我从各处整理的,当初刚接触CS,甚至连标注意识都没有,再次感谢写这些文章的人.当然这里不是说全部都是别人写的了,也有一点我自己的思考.首先是几个注意点:结构化,模块化,分而治之多写注释,多调试指针也有不同类型......