015结构体基础

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

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

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

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

// 2、数据节点结构体
struct data_node1
{
    int num;
    struct data_node1 *p;    
};

// (2)、使用typedef给结构体取别名
typedef   unsigned long   size_t;
typedef struct
{
    char name[128];     
    char phone[128];
    int id;
    int gender;
    int class;
    int score;
    int height;
    int weight;
    int age;
}stu_t, *stu_p;    // 你可以在此处写这个结构体的别名,没有结构体标签,意味着你只能够使用此处的给它的别名

// (3)、二合一法
typedef struct data_node2
{
    int num;
    struct data_node2 *p;    

}node_t, *node_p;


// 主函数
int main(int argc, char const *argv[])
{
    
    // (1)、普通结构体的定义
    struct  student   qingge;        // 信息不够集中(类似于这种写法:int num才好点) 2、数据类型名字固定死了,含义有局限性  3、而且有时会出现歧义
    struct  data_node1 n1;       

    // (2)、使用typedef给结构体取别名
    stu_t fanggong;                  // 普通变量                 
    stu_p fzetc;                     // 指针变量

    // (3)、二合一法:
    struct  data_node2  n2;           // 普通变量,普通结构体定义
    struct  data_node2* n3;           // 指针变量,普通结构体定义
            node_t      n4;           // 普通变量,typedef表达
            node_p      n5;           // 指针变量,typedef表达

    return 0;
}

二、结构体初始化和应用

(1)、初始化

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

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

(2)、引用

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

  • 语法:
结构体.成员

示例代码:

#include 

// 自定义结构体类型(学生结构体)
typedef struct stu
{
    // int hoppy;
    char name[128];     
    char phone[128];
    int id;
    int gender;
    int class;
    int score;
    int height;
    int weight;
    int age;


}stu_t, *stu_p;    


// 主函数
int main(int argc, char const *argv[])
{
    // (1)、结构体的初始化
    // 1、普通初始化
    struct stu stu1 = {"qingge", "13430343954", 9127, 1, 2503, 99, 185, 160, 18};
    /*
        局限性:
            结构体增加一个新成员时,有可能会报以下警告
            warning: initialization makes integer from pointer without a cast [-Wint-conversion]
            overflow in implicit constant conversion [-Woverflow]
            ....
        原因:
            不能够指定成员初始化,只能够顺序初始化,初始化的值一定要和类型相匹配,所以后续增加结构体成员
            的时候,就会出现错误,不方便后面程序的升级 cfm手游(屎山代码,为什么不重构??)前面的开发,对后面的开发造成了影响
    */

    // 2、指定成员初始化
    struct stu stu2 = 
    {
        .age    = 18,          // 初始化的次序可以改变
        .class  = 2503,        // 小圆点 ==》 "当前结构体里面的"什么什么成员
        .gender = 1,
        .height = 180, 
        //.id     = 9127,      // 可以只初始化一部分成员
        .name   = "fanggogn",
        .phone  = "110",
        .score  = 99,
        .weight = 150
    };

    // (2)、结构体的引用
    // 1、非字符串的赋值
    stu1.age   = 20;
    stu1.score = 100;

    // 2、字符串的赋值
    // stu1.phone = "12345678";         // 错误,这句话的意思是,将字符串"12345678"的首字符的地址,赋值给数组(但是数组名不可被赋值)
    strcpy(stu1.phone, "12345678");     // 正确,通过strcpy函数,将字符串数据复制到数组的内存空间中


    
    return 0;
}

三、结构体指针与数组

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

  • 图解:

015结构体基础_第1张图片

  • 示例代码:(结构体指针和数组)
#include 
#include 
#include 

// 自定义结构体类型(学生结构体)
typedef struct student
{
    char name[128];     
    char phone[128];
    int id;
    int gender;
    int class;
    int score;
    int height;
    int weight;
    int age;
}stu_t, *stu_p;    


// 初始化结构体函数
// 方法一: struct student *STU_Init(void)
// 方法二: stu_t *STU_Init(void)
// 方法三: stu_p STU_Init(void)
stu_p STU_Init(void)    // 返回值为stu_p结构体类型(是一个结构体指针类型)
{
    // 1、给结构体申请堆空间
    stu_p p = malloc(sizeof(struct student));
    if ( p != NULL)     // 申请堆空间成功
    {
        strcpy(p->name, "a");
        strcpy(p->phone, "0");
        p->id     = 0;
        p->gender = 0;
        p->age    = 0;
        // ....剩下不写了
    }
    else
    {
        free(p);        // 申请堆空间失败,释放掉内存(释放资源)
        return NULL;
    }

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

// 主函数
int main(int argc, char const *argv[])
{
    // (1)、结构体数组
    struct student stu[5] = {0};    // 因为是结构体数组,成员数量太多,建议都初始化为0先

    // 为结构体数组的第一个成员进行赋值操作
    stu[0].age   = 18;
    stu[0].class = 2503;
    strcpy(stu[0].name, "qingge");

    // (2)、结构体指针
    // 1、这个结构体指针指向的内存空间在栈区
    stu_t fanggong = {0};
    fanggong.age = 18;

    stu_p fzetc  = &fanggong;
    fzetc->age   = 20;
    /*
        解析:
            一般获取结构体成员的时候,使用小圆点(.),则一般这个结构体内存属于这个变量的
            一般获取结构体成员的时候,使用箭头(->),则一般这个结构体内存属于这个变量指向的

    */
    
    // 2、这个结构体指针指向的内存空间在堆区
    stu_p p = STU_Init();
    p->age = 20;
    strcpy(p->name, "fanggong");
    printf("p->age  == %d\n", p->age);
    printf("p->name == %s\n", p->name);


    return 0;
}

至此,希望看完这篇文章的你有所收获,我是Bardb,译音八分贝,道友,下期见!

你可能感兴趣的:(C语言,vscode,c语言)