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

C 语言 | 结构体详解:自定义数据类型的艺术

个人主页-爱因斯晨

文章专栏-C语言

加速更新中!!

在这里插入图片描述

结构体是 C 语言中一种强大的自定义数据类型,它允许我们将不同类型的数据组合在一起,形成一个有机的整体。掌握结构体是编写复杂 C 程序的基础,也是理解面向对象编程思想的前奏。本文将系统解析结构体的方方面面,助你灵活运用这一重要特性。

一、结构体的基本概念

  1. 定义:结构体(struct)是由一系列具有相同或不同数据类型的数据构成的数据集合

  2. 核心价值

    • 将相关数据封装在一起,提高代码的可读性和维护性
    • 模拟现实世界中的实体,如学生、书籍、坐标等
    • 为复杂数据结构(如链表、树)提供基础
    • 便于组织和处理大量相关数据
  3. 声明格式

    struct 结构体名 {数据类型 成员名1;数据类型 成员名2;// ...更多成员
    };
    

二、结构体的定义与使用

  1. 基本定义与初始化

    // 定义结构体类型
    struct Student {char name[20];  // 姓名int age;        // 年龄float score;    // 成绩
    };// 声明结构体变量并初始化
    struct Student stu1 = {"张三", 18, 95.5f};
    
  2. 访问结构体成员:使用点运算符(.)

    // 访问成员
    printf("姓名: %s\n", stu1.name);
    printf("年龄: %d\n", stu1.age);// 修改成员值
    stu1.age = 19;
    stu1.score = 97.0f;
    
  3. 结构体变量的赋值

    struct Student stu2;
    stu2 = stu1;  // 整体赋值,将stu1的所有成员复制到stu2
    

三、结构体与指针

  1. 结构体指针的定义与使用

    struct Student *pStu;  // 声明结构体指针
    pStu = &stu1;          // 指向结构体变量// 通过指针访问成员:使用箭头运算符(->)
    printf("姓名: %s\n", pStu->name);
    printf("年龄: %d\n", pStu->age);// 也可以使用解引用方式
    printf("成绩: %.1f\n", (*pStu).score);
    
  2. 动态分配结构体内存

    // 动态创建结构体变量
    struct Student *p = (struct Student*)malloc(sizeof(struct Student));
    if (p != NULL) {strcpy(p->name, "李四");p->age = 20;p->score = 92.5f;// 使用完毕释放内存free(p);p = NULL;
    }
    

四、结构体数组

  1. 定义与初始化

    // 定义结构体数组
    struct Student class[3] = {{"张三", 18, 95.5f},{"李四", 19, 92.0f},{"王五", 18, 88.5f}
    };
    
  2. 访问数组元素

    // 访问第二个学生的信息
    printf("第二个学生: %s, %d岁, 成绩: %.1f\n", class[1].name, class[1].age, class[1].score);// 使用指针遍历数组
    struct Student *p;
    for (p = class; p < class + 3; p++) {printf("%s ", p->name);
    }
    

五、结构体嵌套

  1. 结构体内部包含其他结构体

    // 定义日期结构体
    struct Date {int year;int month;int day;
    };// 定义包含日期的结构体
    struct Book {char title[50];char author[30];struct Date publishDate;  // 嵌套结构体float price;
    };
    
  2. 嵌套结构体的使用

    struct Book book1 = {"C语言编程","张明",{2020, 5, 18},  // 初始化嵌套的日期结构体59.9f
    };// 访问嵌套结构体的成员
    printf("出版日期: %d年%d月%d日\n",book1.publishDate.year,book1.publishDate.month,book1.publishDate.day);
    

六、结构体与函数

  1. 结构体作为函数参数

    // 结构体传值
    void printStudent(struct Student s) {printf("姓名: %s, 年龄: %d, 成绩: %.1f\n",s.name, s.age, s.score);
    }// 调用函数
    printStudent(stu1);
    
  2. 结构体指针作为函数参数(更高效)

    // 结构体指针传参
    void updateScore(struct Student *s, float newScore) {s->score = newScore;
    }// 调用函数
    updateScore(&stu1, 98.0f);
    
  3. 函数返回结构体

    struct Student createStudent(char *name, int age, float score) {struct Student s;strcpy(s.name, name);s.age = age;s.score = score;return s;
    }// 使用
    struct Student stu3 = createStudent("赵六", 19, 94.5f);
    

七、结构体的内存对齐

  1. 内存对齐的概念:结构体成员在内存中的存放地址需要满足一定的对齐要求,并非简单连续排列

  2. 对齐规则

    • 每个成员的起始地址是该成员类型大小的整数倍
    • 结构体总大小是其最大成员类型大小的整数倍
    • 嵌套结构体的对齐以其最大成员类型大小为基准
  3. 示例分析

    struct Example {char a;    // 1字节int b;     // 4字节char c;    // 1字节
    };
    // 该结构体大小为12字节,而非6字节
    // 内存布局:a(1) + 填充(3) + b(4) + c(1) + 填充(3)
    
  4. 修改对齐方式(编译器特定):

    // GCC编译器:设置1字节对齐
    #pragma pack(1)
    struct Example {char a;int b;char c;
    };
    #pragma pack()  // 恢复默认对齐
    // 此时结构体大小为6字节
    

八、typedef 与结构体

  1. 使用 typedef 简化结构体声明

    // 方式1
    typedef struct Student {char name[20];int age;float score;
    } Student;  // 别名// 方式2
    struct _Teacher {char name[20];int id;
    };
    typedef struct _Teacher Teacher;
    
  2. 使用别名声明变量

    Student stu4;  // 无需再写struct关键字
    Teacher t1;
    

九、结构体的实际应用场景

  1. 表示复杂实体:如学生、员工、商品等包含多个属性的实体

  2. 数据集合管理:将相关数据组织在一起,方便批量处理

  3. 文件操作:读写二进制文件时,结构体可直接映射文件记录

  4. 实现数据结构:链表节点、树节点等都以结构体为基础

    // 链表节点结构体
    struct Node {int data;           // 数据域struct Node *next;  // 指针域,指向下一个节点
    };
    
  5. 硬件编程:映射硬件寄存器,方便操作硬件设备

十、结构体使用注意事项

  1. 避免结构体过大:过大的结构体传值会影响性能,建议使用指针传递

  2. 注意内存对齐:了解内存对齐规则,避免内存空间浪费

  3. 初始化所有成员:结构体变量声明后应初始化所有成员,避免使用未初始化的值

  4. 字符串处理:结构体中的字符串成员需要注意缓冲区溢出问题

  5. 动态内存管理:包含指针成员的结构体需要特别注意深拷贝和内存释放

    // 包含指针成员的结构体
    struct Data {int *numbers;int count;
    };// 深拷贝示例
    void copyData(struct Data *dest, struct Data *src) {dest->count = src->count;dest->numbers = (int*)malloc(src->count * sizeof(int));memcpy(dest->numbers, src->numbers, src->count * sizeof(int));
    }
    

结构体是 C 语言中实现数据封装的重要手段,它让我们能够以更接近现实世界的方式来组织和处理数据。掌握结构体不仅能提高代码的结构化程度,也能为学习更高级的数据结构和编程语言打下坚实基础。在实际编程中,合理设计结构体可以使代码更加清晰、高效和易于维护。

http://www.dtcms.com/a/298247.html

相关文章:

  • 【第四章:大模型(LLM)】01.神经网络中的 NLP-(1)RNN、LSTM 和 GRU 的基本原理和应用
  • MySQL常用日期函数总结
  • [1-01-01]第42节:不可变字符序列 - String类中常用的API
  • 福彩双色球篮球号码的加减法
  • 探秘抖音商城:软件采集视角下的电商生态与数据价值
  • DeepSeek DeepEP学习(四)normal combine
  • zabbix----设置告警
  • Linux 系统时间设置(date 和 ntpdate)-linux028
  • Zookeeper学习专栏(十):核心流程剖析之服务启动、请求处理与选举协议
  • 最新Amos 29下载及详细安装教程,附免激活中文版Amos安装包
  • Dart 异步编程之 Future 详解
  • 盟接之桥说制造:构建以预防为核心的供应链客诉管理体系
  • Excel——重复值处理
  • 用友ERP 反射xss漏洞复现(CVE-2025-2709)
  • Python柱状图
  • 文件被删除了怎么恢复?恢复方法总结与重点注意事项
  • 解放生产力:Amazon API Gateway 与 Amazon Lambda 的优雅组合
  • miniz:一个轻量级、高性能的开源压缩库
  • linusb + Zadig 2.x - 用户指南
  • 飞算JavaAI“删除接口信息” 功能:3 步清理冗余接口,让管理效率翻倍
  • The Magic Mask for Android:解锁无限可能的安卓自定义套件
  • “Vibe Coding”:用自然语言对话,15分钟打造Python终端速读App
  • 正交实验设计法(心血整理总结)
  • 【第四章:大模型(LLM)】01.Embedding is all you need-(6)从 Word2Vec 到推荐/广告系统,再到大语言模型(LLM)
  • Linux下提权root权限
  • Asp.net core mvc中TagHelper的GetChildContentAsync和Content区别
  • GC8871刷式直流电机驱动器深度解析:3.6A驱动与内置电流检测技术
  • 虚拟地址-物理地址
  • leetcode110:判断平衡二叉树(两种思路对比)
  • 渗透高级-----测试复现(第三次作业)