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

C语言基础—构造类型

数据类型

1.基本类型/基础类型

  • 整型

    • 短整型:short[int] --2字节

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

    • 长整型:long[int] --32位4字节/64位8字节

    • 长长整型:long long [int] (C99)

      注意:以上类型又都分为signed(有符号)和unsigned(无符号)

  • 浮点型

    • 单精度:float --4字节

    • 双精度:double --8字节

    • 长双精度: long double --(C99新增)

  • 字符型

    • 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成员名称n:类似于定义变量,定义了结构体中的成员

  • 注意:结构体在定义的时候,成员不能赋值
struct Cat
{
    int age = 5;    //错误
    double height;  //正确
}

常见的定义格式

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

  • 方式2:定义匿名结构体(常用于作为其他结构体的成员使用)

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

    总结:

    • 结构体可以定义在局部位置,也可以定义在全局位置(用的比较多,因为可以实现复用)

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

  • 结构体类型的使用:

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

结构体变量的定义(定义变量)

三种形式定义结构体变量

结构体变量也称之为结构体实例

  • 第一种:

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

    ②然后使用(使用数据类型定义变量)

  • 第2种

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

    举例:

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

    此时定义了一个结构体A,x和y是这个结构体类型的变量。

  • 第3种(不推荐)

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

struct A
{

    int a;
    char b;
    struct
    {
        int a1;
        char b1;
    }c,d;
}e;

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

  • 匿名结构体

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

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

    • 应用场景:

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

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

  • 定义结构体的同时,定义结构体变量初始化

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

    • 结构体成员,没有默认值,是随机值。

结构体变量的使用

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

    • 语法:

       结构体变量名.成员名;

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

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

    • 结构体变量未初始化,结构体的成员是随机值(和普通的变量、数组同理)

  • 结构体变量在定义时,可以初始化

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

    • 结构体成员初始化,可以部分初始化(和数组类以),部分初始化时一定要带大括号标明数据的范围。

结构体数组的定义

  • 什么时候需要结构体数组

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

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

    • 第1种:结构体→结构体变量→结构体数组

    • 第2种:结构体→结构体数组,

    • 第3种:结构体、结构体数组一体化(含初始化)

    • 第4种:结构体、结构体数组一体化(不含初始化)

结构体数组的访问

语法:

结构体 -> 成员名

举例:

(*p).成员名
p -> 成员名

注意:

->[]共存的时候,它们的优先级关系:[] >  ->

构造体类型

构造体数组

举例:

#include <stdio.h>

#pragma pack(1)
struct Student
{
    char *name;
    int age;
    float score[3];
};
#pragma pack()

void stu_print(struct Student *stu)
{
    printf("学生的名字是:%s\n",stu -> name);
    printf("学生的年龄是:%d\n",stu -> age);
    printf("语文成绩是:%.2f\n",stu -> score[0]);
    printf("数学成绩是:%.2f\n",stu -> score[1]);
    printf("英语成绩是:%.2f\n",stu -> score[2]);
}

int get_avg(struct Student *stu)
{
    struct Student *p = stu;
    for(; p < stu + 2; p++)
    {
        float sum = 0;
        for(int i = 0; i < 3; i ++)
        {
            sum += p -> score[i];
        }
        float avg = sum / 3;
        printf("%s的平均分为:%.2f\n",p -> name, avg);
    }
}
int main(int argc,char *argv[])
{
    struct Student stu = {"张三",20,{90,88,75}};
    stu_print(&stu);
    struct Student stus[] = {
        {"李四",21,{67,87,68}},
        {"王五",22,{76,92,70}}
    };
    get_avg(stus);
    return 0;
}

构造体指针

  • 定义:结构体类型的指针变量指向结构体变量或者数组的起始地址。

  • 语法:

struct 结构体名 *指针变量列表;
  • 举例
#include <stdio.h>

struct Product
{
    char *name;
    int id;
    int or_price;
    int now_price;
    char *production_deta;
    char *due_deta;
};

typedef struct Product Pro;
//打印商品信息
void product_print(Pro *p)
{
    Pro *t_p = p;
    printf("名字是:%s\n",t_p -> name);
    printf("商品ID为:%d\n",t_p -> id);
    printf("原价为:%d\n",t_p -> or_price);
    printf("现价为:%d\n",t_p -> now_price);
    printf("生产日期:%s\n",t_p -> production_deta);
    printf("到期时间是:%s\n",t_p ->due_deta);
}
int main(int argc,char *argv[])
{
    //typedef struct Product Pro;
    Pro p1 = {"麻辣公主",10001,100,10,"2025,1,10","2025,2,10"};
    product_print(&p1);
    return 0;
}

构造体成员的访问

结构体成员访问

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

    • 语法

结构体数组名 -> 成员名;
(*结构体数组名).成员名;
  • 结构体成员访问符

    • .左侧是结构体变量,也可以叫做结构体对象访问成员访问符,右侧是结构体成员。

    • ->左侧是结构体指针,也可以叫做结构体指针访问成员符右侧是结构体成员

    • 举例

struct Person *p = persons; // p就是结构体指针
for(; p < persons + 3; p++)
    printf("%s:%d\n",p -> name, p -> count);
结构体是自定义数据类型,它是数据类型,用法类似于基本类型的 int
结构体数组它是存放结构体对象的数组,类似于 int 数组存放 int 数据;
基本类型数组怎么用,结构体数组就怎么用 ---> 可以遍历,可以作为形式参数,也可
以做指针等;

结构体类型求大小 

字节对齐

  • 字节对齐的原因:
       1. 硬件要求 某些硬件平台(如 ARM x86 )要求特定类型的数据必须对齐到特定地址,否则会 引发性能下降或硬件异常。
        2. 优化性能 对齐的数据访问速度更快。例如, CPU 访问对齐的 int 数据只需一次内存操作, 而未对齐的数据可能需要多次操作。
  • 字节对齐规则
        1. 默认对齐规则
 结构体的每个成员按其类型大小和编译器默认对齐数(通常是类型的自然对齐数)对
 齐。 结构体的总大小必须是最大对齐数的整数倍。
        2. 对齐细节
基本类型的对齐数 char 1 字节)、 short 2 字节)、 int 4 字节)、 double (8字节)。
结构体成员的对齐 :每个成员的起始地址必须是对齐数的整数倍。
结构体总大小的对齐 :结构体的总大小必须是其最大对齐数的整数倍
        3. #pragma pack(n) 的影响 使用 #pragma pack(n) 可以强制指定对齐数为 n n 1 、 2、 4 8 16 )。此时:
每个成员的对齐数取 n 和其类型大小的较小值。
结构体的总大小必须是 n 和最大对齐数中的较小值的整数倍。

共用体

定义:使几个不同变量占用同一段内存的结构。共用体按定义中需要存储空间最大的成员来分
配存储单元,其他成员也是使用该空间,它们的首地址是相同。
定义格式:
union 共用体名称
{
    数据类型 成员名;
    数据类型 成员名;
    ...
}
共用体的定义和结构体类似。
1.可以有名字,也可以匿名
2.共用体在定义时也可以定义共用体变量
3.共用体在定义时也可以初始化成员
4.共用体也可以作为形参和返回值类型使用
5.共用体也可以定义共用体变量
...
         也就是说,结构体的语法,共用体都支持
注意:
        共用体弊大于利,尽量少用,一般很少用;
        共用体变量在某一时刻只能存储一个数据,并且也只能取出一个数
        共用体所有成员共享同一内存空间,同一时间只能存储一个值,可能导致数据覆盖
        共用体和结构体都是自定义数据类型,用法类似于基本数据类型
         共用体可以是共用体的成员,也可以是结构体的成员
        结构体可以是结构体的成员,也可以是共用体的成员

枚举类型

建议:如果定义不相干的常量,使用宏定义(符号常量);如果需要定义一组相关的常量,如月份0~11,星期0-6,方向0-3等,使用枚举,进行统一管理。以后正式开发中,switch的case后访问的就是枚举中的常量。

  • 定义

    我们一般情况下,定义常量使用宏定义(#define 宏名称 值),宏定义非常适合没有关联关系的常量;但是有时候我们可能需要对一组拥有关联关系的量进行定义,如月份0~11,星期0-6,方向0-3等,那么使用宏定义,就不是很清晰,也不方便统一管理,这个时候就需要用到枚举。

    枚举的存在就是将多个拥有关联关系的常量组合到一起,提高代码的可读性。

  • 说明

    枚举类型定义了一组常量,我们在开发中直接使用这些常量。(常用)

    当然枚举类型也可以类似于结构体一样定义变量等操作。(不常用)

    枚举常量有默认值,从0开始依次+1我们可以在定义时指定它的默认值,如果个别没有斌值,可以根据赋值依次+1推导。

  • 特点

    定义了一组常量,类似于定义了多个符号常量(宏定义)。

    提高了代码的可读性。

  • 语法:

  • 定义枚举类型名以后就可以定义该枚举类型的变量。(枚举的成员是常量)

enum 枚举类型名 变量列表;

       在定义枚举类型的同时定义该枚举类型的变量。

enum 枚举类型名(枚举元素列表) 变量列表;

      直接定义枚举变量(变量)。

enum(枚举元素列表) 变量列表;

typedef

  • 说明:给类型重命名,不会影响到类型本身。

  • 作用:给己有的类型起别名

  • 格式:

typedaef 已有类型名 新类型名;
  • 举例:
#include <stdio.h>

struct Product
{
    char *name;
    int id;
    int or_price;
    int now_price;
    char *production_deta;
    char *due_deta;
};

typedef struct Product Pro;
//打印商品信息
void product_print(Pro *p)
{
    Pro *t_p = p;
    printf("名字是:%s\n",t_p -> name);
    printf("商品ID为:%d\n",t_p -> id);
    printf("原价为:%d\n",t_p -> or_price);
    printf("现价为:%d\n",t_p -> now_price);
    printf("生产日期:%s\n",t_p -> production_deta);
    printf("到期时间是:%s\n",t_p ->due_deta);
}
int main(int argc,char *argv[])
{
    //typedef struct Product Pro;
    Pro p1 = {"麻辣公主",10001,100,10,"2025,1,10","2025,2,10"};
    product_print(&p1);
    return 0;
}
  • 应用场景:

    • 数据类型复杂(结构体、共用体、枚举、结构体指针、无符号的长整型)时使用

    • 为了跨平台的兼容性,例如:

    1. size_t:类型重名后的数据类型:typedef unsigned long size_t;

    2. unit16:类型重命名后的数据类型。

相关文章:

  • ubuntu 安装 g++
  • QT6使用Mysql全流程
  • StarRocks 证书SRCA和SRCP
  • 内容中台的数字化管理价值是什么?
  • UniApp开发多端应用——流式语音交互场景优化
  • uvm configuration
  • 线程同步——条件变量
  • supabase新增用户的完整流程和注册
  • Pycharm(七):几个简单案例
  • 从排泄危机到数字免疫:解码餐饮业“全息食安大脑“的进化逻辑
  • SQL 链接服务器的查询提示“不允许使用远程表值函数调用”(NOLOCK)
  • 【Deepseek】Deepseek学习
  • vscode连接服务器失败问题解决
  • JavaScript中闭包的使用
  • 【vLLM 学习】快速入门
  • React19源码系列之Hooks(useRef)
  • SQL中累计求和与滑动求和函数sum() over()的用法
  • WebRTC简介及应用
  • 惠购供应链 SAAS 系统正式上线,构建数字商业生态版图
  • InfluxDB OSS v2的数据写入与查询——以C#为例操作
  • 沂源网站开发/互动营销案例
  • 自己如何做独立网站/广告外链平台
  • 购物网站建设流程/专业的网页制作公司
  • 网站顶部小图标怎么做/qq引流推广软件哪个好
  • 重庆市官网首页/杭州最好的seo公司
  • asp.net怎么做网站/深圳网络优化seo