015__结构体基础

发布于:2025-02-11 ⋅ 阅读:(27) ⋅ 点赞:(0)

[ 基本难度系数 ]:★★☆☆☆

一、结构体基本概念和定义

C语言提供了众多的基本类型,但现实生活中的对象一般都不是单纯的整型、浮点型或字符串,而是这些基本类型的综合体。比如一个学生,典型地应该拥有学号(整型)、姓名(字符串)、分数(浮点型)、性别(枚举)等不同侧面的属性,这些所有的属性都不应该被拆分开来,而是应该组成一个整体,代表一个完整的学生。

在C语言中,可以使用结构体来将多种不同的数据类型组装起来,形成某种现实意义的自定义的变量类型。结构体本质上是一种自定义类型。

  • 结构体的语法:
结构体标签: 用来区分各个不同的结构体。
成员:       是包含在结构体内部的数据,可以是任意的数据类型。
  • 结构体的定义:
struct 结构体标签
{
    成员1;
    成员2;
    ...
}; // 此处有;号
  • 示例代码:
#include <stdio.h>
// 自定义结构体类型
// (1)、普通的结构体定义
// 1、学生结构体
struct student          // 结构体标签:用来区分各个不同的结构体的
{
    char name[128];     // 成员:包含在结构体内存的数据,可以是任意的类型(包括结构体本身、函数指针等)
    char phone[12];
    int  id;
    int gender;
    int class;
    int score;
    int height;
    int weight;
    int age;
};                      // 此处一定要加;号


// 2、数据节点结构体
struct data_node        // 结构体标签:用来区分各个不同的结构体的
{
    int a;
    int b;
    double c;
};

// (2)、使用typedef给结构体取别名
typedef struct  
{
    char name[128];    
    char phone[12];
    int  id;
    int gender;
    int class;
    int score;
    int height;
    int weight;
    int age;

}stu, *stu_p;       // 你可以在此处写这个结构体的别名,没有结构体标签,意味着你只能够使用此处提供的结构体变量


// (3)、二合一法
typedef struct data_node2 
{
    char name[128];    
    char phone[12];
    int  id;
    int gender;
    int class;
    int score;
    int height;
    int weight;
    int age;

}node, *node_p;     

// 主函数
int main(int argc, char const *argv[])
{
    // (1)、普通结构体的定义
    struct student    fzetc;       // 1、信息不够集中(类似于这种写法:int num) 2、数据类型名字固定死了,含义有局限
    struct data_node  data;

    // (2)、使用typedef给结构体取别名
    stu    qingge;                 // 普通变量?√  指针变量?
    stu_p  fanggong_p;             // 普通变量? 指针变量?√       


    // (3)、二合一法
    struct data_node2 n1;          // 普通变量,普通结构体定义
           node       n2;          // 普通变量,typedef表达
           node_p     n3_p;        // 指针变量,typedef表达
 
    return 0;
}

二、结构体初始化和应用

(1)、初始化

结构体跟普通变量一样,涉及定义、初始化、赋值、取址、传值等等操作,这些操作绝大部分都跟普通变量别无二致,只有少数操作有些特殊性。这其实也是结构体这种组合类型的设计初衷,就是让开发者用起来比较顺手,不跟普通变量产生太多差异。

  • 结构体的定义和初始化。
    • 由于结构体内部拥有多个不同类型的成员,因此初始化采用与数组类似的列表方式。
    • 结构体的初始化有两种方式:①普通初始化;②指定成员初始化。
    • 为了能适应结构体类型的升级迭代,一般建议采用指定成员初始化。
  • 指定成员初始化的好处:
    • 成员初始化的次序可以改变。
    • 可以初始化一部分成员。
    • 结构体新增了成员之后初始化语句仍然可用。
  • 示例代码:
#include <stdio.h>

// 学生结构体
typedef struct student 
{
    // int class;      // 加了一个成员变量
    char name[128];    
    char phone[12];
    int  id;
    int gender;  
    int score;
    int height;
    int weight;
    int age;

}stu, *stu_p;  

// 主函数
int main(int argc, char const *argv[])
{
    // (1)、结构体的初始化
    // 1、普通初始化
    struct student stu1 = {"qingge", "13430343954", 9127, 1, 99, 185, 160, 18};
    /*
        局限性:增加一个新成员时,有可能会报以下错误
            warning: initialization makes integer from pointer without a cast [-Wint-conversion]
            warning: overflow in implicit constant conversion [-Woverflow]

            不能够指定成员初始化,只能够顺序初始化,初始化的值一定要和类型匹配,所以后续增加结构体成员的
            时候,会出现错误,不方便升级     cf手游(屎山代码,不敢动) ==》 前面的开发,对后面的开发造成影响和损坏
    */

    // 2、指定成员初始化
    struct student stu2 = 
    {
        .id     = 9527,              // 初始化次序可以改变
        .gender = 1,                 // 小圆点 ==> "当前结构体里面的" 什么什么成员
        .score  = 100,
        .name   = "fanggong",
        .phone  = "13430343958",

        .height = 186,
        .weight = 161,
        // .age = 19                 // 可以只初始化一部分成员
    };

    return 0;
}

(2)、引用

结构体相当于一个集合,内部包含了众多成员,每个成员实际上都是独立的变量,都可以被独立地引用。引用结构体成员非常简单,只需要使用一个成员引用符即可:

  • 语法:
结构体.成员
  • 示例代码:
#include <stdio.h>

// 学生结构体
typedef struct student 
{
    // int class;      // 加了一个成员变量
    char name[128];    
    char phone[12];
    int  id;
    int gender;  
    int score;
    int height;
    int weight;
    int age;

}stu, *stu_p;  

// 主函数
int main(int argc, char const *argv[])
{
    // (2)、结构体的引用
    struct student stu1 = {0};
    
    // 非字符串赋值
    stu1.age   = 20;
    stu1.score = 101;

    // 字符串赋值
    // stu1.phone = "13430343959";      // 错误,这句话的意思是将地址赋值给结构体的phone数组成员,而数组名相当于一个常量指针,不能更改其地址
    strcpy(stu1.phone, "13430343959");  // 正确,通过strcpy这个字符串函数,将字符串的内容赋值给结构体里面的phone数组

    return 0;
}

三、结构体指针与数组

跟普通变量别无二致,可以定义指向结构体的指针,也可以定义结构体数组。

  • 结构体数组(示例代码):
// 自定义结构体类型
typedef struct student 
{
    char name[128];    
    char phone[12];
    int  id;
    int gender;
    int class;
    int score;
    int height;
    int weight;
    int age;

}stu, *stu_p;

 // 主函数
int main(int argc, char const *argv[])
{
    struct student qingge[5] = {0};     // 因为是结构体数组,数量成员太多,建议初始化为0 
    
    // 为结构体数组第一个成员初始化
    qingge[0].age   = 18;
    qingge[0].class = 306;
    strcpy(qingge[0].name, "xiaoqing");
    
    return 0;
}
  • 结构体指针(示例代码):
// 自定义结构体类型
typedef struct student 
{
    char name[128];    
    char phone[12];
    int  id;
    int gender;
    int class;
    int score;
    int height;
    int weight;
    int age;

}stu, *stu_p;


// 初始化结构体函数(申请一个结构体的堆空间内存)
// 方法1:struct student*  STU_Init(void) 
// 方法2:stu*             STU_Init(void) 
stu_p STU_Init(void)             // 返回值为stu_p类型(是一个结构体指针类型)    
{
    // 1、给结构体申请堆空间
    stu_p p = malloc(sizeof(struct student ));  
    if (p != NULL)              // 申请堆空间成功
    {
        strcpy(p->name,  "qingge");
        strcpy(p->phone, "13430343954");   
        p->id     = 9127;
        p->gender = 1;
        p->age    = 18;

        // .....不写了
    }
    else
    {
        free(p);               // 申请堆空间失败,释放内存(释放资源)
        return NULL;           
    }

    // 2、成功,返回指向这个结构体堆空间的内存的地址
    return p;
}

 // 主函数
int main(int argc, char const *argv[])
{
   // 1、这个指针指向的内存在栈空间
    stu  fanggong  = {0};
    stu* fangong_p = &fanggong; 

    // 2、这个指针指向的内存在堆空间
    stu_p p = STU_Init();
    p->age = 18;
    strcpy(p->name, "xiaofang");
    
    return 0;
}
  • 解析

[ 课堂课后实验 ]:

【1】、实验1:(结构体基本概念)

思考以下问题:

  1. 结构体初始化的基本语法是怎样的?
  2. 什么叫做指定成员初始化?这样做有什么好处?

【2】、实验2:(结构体基本语法)

指出以下代码片段的不妥之处。

structure node
(
    char itable,
    int num[5],
    char * togs
)

【3】、实验3:(结构体基本语法)

定义一个结构体来存储日期(含年、月、日)。并设计一个函数,计算传入的结构体存储的日期是一年中的第几天。(不考虑大小月、闰年)


网站公告

今日签到

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