12、C 语言结构体基础总结

发布于:2025-08-15 ⋅ 阅读:(14) ⋅ 点赞:(0)

结构体的定义、初始化、引用,到结构体指针和数组等方面

C 语言结构体基础核心知识点总结

一、结构体的基本概念与定义

结构体是 C 语言中用于组合不同数据类型的自定义类型,能够将多个相关联的变量封装为一个整体,以表示现实世界中的复杂对象(如学生、商品等)。

1. 结构体的定义语法

结构体的定义由关键字struct、结构体标签、成员列表组成,语法如下:

struct 结构体标签 {

    数据类型 成员1;  // 结构体内部的变量,可为任意数据类型

    数据类型 成员2;

    // ... 更多成员

};

  • 结构体标签:用于区分不同结构体的标识符(如studentdata_node)。
  • 成员:结构体内部的变量,可包含基本类型(int、float 等)、数组、指针,甚至其他结构体。

2. 常见定义方式

(1)普通定义(带标签)

// 定义学生结构体

struct student {

    char name[128];  // 姓名(字符串)

    int id;          // 学号(整型)

    float score;     // 成绩(浮点型)

};

  • 特点:定义变量时需带struct关键字(如struct student stu;)。
(2)使用typedef取别名

通过typedef为结构体定义别名,简化变量声明:

// 为结构体取别名stu_t(普通变量)和stu_p(指针变量)

typedef struct {

    char name[128];

    int id;

    float score;

} stu_t, *stu_p;

  • 特点:定义变量时可直接使用别名(如stu_t stu;stu_p p;),无需重复struct
(3)带标签 +typedef(二合一)

兼顾标签和别名的灵活性,便于结构体内部引用自身(如链表节点):

typedef struct data_node {

    int num;

    struct data_node *next;  // 引用自身结构体指针

} node_t, *node_p;

二、结构体的初始化

结构体的初始化需为其成员赋值,支持两种方式:普通初始化(按顺序)和指定成员初始化(按名称)。

1. 普通初始化(按顺序)

按成员在结构体中的定义顺序依次赋值,适用于成员较少且顺序固定的场景:

struct student stu1 = {"张三", 1001, 90.5};  // 依次为name、id、score赋值

  • 局限性:
    • 必须按成员顺序赋值,遗漏或顺序错误会导致初始化错误。
    • 若结构体新增成员,初始化语句需同步修改,否则可能报错。

2. 指定成员初始化(推荐)

通过成员名显式赋值,不依赖顺序,支持部分初始化,便于结构体升级迭代:

struct student stu2 = {

    .id = 1002,          // 学号

    .name = "李四",      // 姓名(顺序可任意调整)

    .score = 88.0        // 成绩

};

  • 优势:
    • 成员初始化顺序可任意调整。
    • 可只初始化部分成员(未初始化成员默认值为 0)。
    • 结构体新增成员后,原有初始化语句仍可正常使用。

三、结构体成员的引用

结构体成员需通过特定符号访问,根据结构体变量类型(普通变量或指针)使用不同的引用符。

1. 普通结构体变量

使用点运算符(.) 访问成员:

struct student stu;

stu.id = 1003;                // 为学号赋值

strcpy(stu.name, "王五");      // 为姓名赋值(字符串需用strcpy)

stu.score = 95.5;             // 为成绩赋值

  • 注意:字符串成员(如name)不能直接用=赋值(数组名不可修改),需用strcpy函数复制。

2. 结构体指针变量

使用箭头运算符(->) 访问成员(指针指向结构体变量或堆内存):

struct student *p = &stu;  // 指针指向栈区结构体变量

p->id = 1004;             // 等价于 (*p).id = 1004

strcpy(p->name, "赵六");   // 等价于 strcpy((*p).name, "赵六")

四、结构体数组与结构体指针

结构体支持数组和指针两种扩展形式,用于批量管理结构体对象或动态分配内存。

1. 结构体数组

由多个相同结构体类型的元素组成,适用于存储多个同类型对象(如多个学生):

// 定义包含5个学生的数组

struct student stu_arr[5] = {0};  // 初始化为0

// 为第一个元素赋值

stu_arr[0].id = 1005;

strcpy(stu_arr[0].name, "孙七");

stu_arr[0].score = 92.0;

  • 访问方式:通过数组下标 + 成员引用符(如stu_arr[i].name)。

2. 结构体指针

指向结构体变量或动态分配的结构体内存,灵活管理结构体对象的生命周期:

(1)指向栈区结构体

struct student stu;

struct student *p = &stu;  // 指针指向栈区变量

p->id = 1006;

(2)指向堆区结构体(动态内存)

通过malloc申请堆内存,需手动释放(避免内存泄漏):

// 函数:创建堆区结构体并返回指针

struct student* create_stu() {

    struct student *p = malloc(sizeof(struct student));  // 申请内存

    if (p != NULL) {

        p->id = 1007;

        strcpy(p->name, "周八");

        p->score = 85.5;

    }

    return p;

}

// 使用堆区结构体

struct student *p = create_stu();

printf("学号:%d,姓名:%s\n", p->id, p->name);

free(p);  // 释放堆内存,避免泄漏

p = NULL; // 避免野指针

五、核心注意事项

  1. 结构体大小与内存对齐

结构体总大小并非成员大小的简单相加,编译器会自动进行内存对齐(按最大成员对齐数),可通过#pragma pack调整对齐方式(进阶内容)。

  1. 字符串成员赋值

结构体中的字符数组(如name[128])不能直接用=赋值,必须使用strcpystrncpy等函数复制字符串。

  1. 堆区结构体管理

动态分配的结构体内存(malloc)必须用free释放,且释放后需将指针置为NULL,避免野指针访问。

  1. 结构体作为函数参数

结构体传参时默认按值传递(复制整个结构体),效率较低,推荐传递结构体指针(仅复制地址)。

总结

结构体是 C 语言实现数据封装的核心机制,通过组合不同类型的成员描述复杂对象。掌握结构体的定义(带标签 / 别名)、初始化(指定成员优先)、成员引用(. 与 ->)及扩展形式(数组 / 指针),能有效处理现实世界中的复杂数据。实际开发中,需注意内存管理(尤其是堆区结构体)和字符串成员的正确赋值,确保代码的安全性和可维护性。


网站公告

今日签到

点亮在社区的每一天
去签到