DAY10-结构体

这个结构体不难理解,难理解的是后面结构体指针数组。多多观看,主包也在学习,可能解释的并不是特别明了,想要多多了解的可以多看看相关教学视频。

1.基本认识

在我们之前的开发中,会遇到一个目标需要多个属性来描述,例如学生:名字,性别,身高,体重等等。用单一的数据类型无法进行准确描述。所以此时就需要构造数据类型:结构体。

结构体就我个人理解而言:是一个融合了多种基本数据类型的复合数据类型。

2.结构体数据类型的格式

结构体声明   一般是在main函数前面

结构体声明有两种格式,一种是匿名声明方法,没有小名/别称。另一种是起了一个别称,可以叫别名声明法(主包自己想的后续可以使用这个别称来创造结构体。

格式1:

struct  student
{
    char name[32];
    char gender;
    int  id;
    float score;
};   //匿名声明方法    没有小名

格式2:

typedef struct student2
{
    char name[32];
    char gender;
    int  id;
    float score;
}STU;  //给struct student2   起起了个别名  叫STU

3.结构体变量

3.1结构体:是一种复合数据的数据类型

变量的声明: 数据类型    变量名  =  初始化赋值;

结构体变量的声明:

结构体类型    变量名   =  {初始化赋值};

#include<stdio.h>

struct  student
{
    char name[32];
    char gender;
    int  id;
    float score;
};

typedef struct student2
{
    char name[32];
    char gender;
    int  id;
    float score;
}STU;

int main(int argc, char const *argv[])
{
    //匿名,没有小名  所以用struct student 直接声明变量
    struct student stu1 = {"xxx",'M',10086,99.3F};   //要与成员一一对应

    //可以用 结构体变量名 + . 的方式取出对应的成员属性
    printf("NAME:%s  GENDER:%c  ID:%d  SCORE:%0.1f\n",
        stu1.name,stu1.gender,stu1.id,stu1.score);


    //用别名 STU声明一个stu2     等价于 struct student2 stu2;
    STU stu2 = {"yyy",'M',10010,99.1F};
    printf("NAME:%s  GENDER:%c  ID:%d  SCORE:%0.1f\n",
        stu2.name,stu2.gender,stu2.id,stu2.score);

    return 0;
}

3.2结构体的赋值方法

方法一:

通过像是对数组赋值一样,对结构体进行赋值,赋值时要根据不同的数据类型赋值。

#include<stdio.h>

struct  student
{
    char name[32];
    char gender;
    int  id;
    float score;
};

typedef struct student2
{
    char name[32];
    char gender;
    int  id;
    float score;
}STU;

int main(int argc, char const *argv[])
{
    //匿名,没有小名  所以用struct student 直接声明变量
    struct student stu1 = {"xxx",'M',10086,99.3F};   //要与成员一一对应

    //可以用 结构体变量名 + . 的方式取出对应的成员属性
    printf("NAME:%s  GENDER:%c  ID:%d  SCORE:%0.1f\n",
        stu1.name,stu1.gender,stu1.id,stu1.score);
        return 0;
        }

方法二:单一赋值,尤其是name;strcpy是一个字符串复制函数。在linux中可以使用 man 命令查看不同函数的使用方法。eg:man strcpy。

typedef struct student2
{
    char name[32];
    char gender;
    int id;
    float score;
} STU;

int main(int argc, char const *argv[])
{
    STU stu1;

    strcpy(stu1.name, "xxx");
    stu1.gender = 'M';
    stu1.id = 10000;
    stu1.score = 99.8F;

    // 可以用 结构体变量名 + . 的方式取出对应的成员属性
    printf("NAME:%s  GENDER:%c  ID:%d  SCORE:%0.1f\n",
           stu1.name, stu1.gender, stu1.id, stu1.score);
}

3.3结构体指针变量

回顾:

指针变量的声明:

数据类型   *指针变量名 = 初始化地址;

int  *p  =  NULL;

结构体指针变量:

结构体类型   *结构体变量名    =    初始化地址;

结构体指针变量的一个例子:

#include <stdio.h>
#include <string.h>

typedef struct student2
{
    char name[32];
    char gender;
    int id;
    float score;
} STU;

int main(int argc, char const *argv[])
{
    STU stu1 = {"lucy", 'F', 99999, 100.0F};
    STU *p = &stu1; // p指向 stu1的首地址

    printf("NAME:%s  GENDER:%c  ID:%d  SCORE:%0.1f\n",
           (*p).name, (*p).gender, (*p).id, (*p).score); //*p ==>stu1

    printf("NAME:%s  GENDER:%c  ID:%d  SCORE:%0.1f\n",
           stu1.name, stu1.gender, stu1.id, stu1.score);

    // 可以通过 指针+ ->  取出对应的属性
    printf("NAME:%s  GENDER:%c  ID:%d  SCORE:%0.1f\n",
           p->name, p->gender, p->id, p->score);

    printf("NAME:%s  GENDER:%c  ID:%d  SCORE:%0.1f\n",
           (&stu1)->name, (&stu1)->gender, (&stu1)->id, (&stu1)->score);

    return 0;
}

4.结构体动态内存开辟

4.1结构体成员动态内存分配

这里我们来name进行动态内存分配

将name定义为指针变量,用来承接动态内存分配出来的地址

typedef struct student2
{
    char *name;  //指针,用来承接动态内存分配出来的地址
    char gender;
    int id;
    float score;
} STU;
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct student2
{
    char *name;
    char gender;
    int id;
    float score;
} STU;

int main(int argc, char const *argv[])
{
    STU stu1;
    stu1.gender = 'M';
    stu1.id = 99999;
    stu1.score = 100.0F;
    stu1.name  = (char *)malloc(sizeof("漫夜"));
    strcpy(stu1.name,"漫夜");

    printf("NAME:%s  GENDER:%c  ID:%d  SCORE:%0.1f\n",
        stu1.name, stu1.gender, stu1.id, stu1.score);
    if (stu1.name != NULL )   //防御性代码,避免操作到无权限的指针
    {
        free(stu1.name);   
        stu1.name = NULL;
    }            
    return 0;
}

4.2结构体动态内存分配

将结构体动态内存分配之后,再将name动态内存开辟;

通俗的理解就是:开辟一个结构体空间之后,再将结构体中的name开辟出内存空间。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct student2
{
    char *name;
    char gender;
    int id;
    float score;
} STU;

int main(int argc, char const *argv[])
{
    STU *stu = NULL;
    stu = (STU *)malloc(sizeof(STU));  //先开辟结构体空间
    stu->name = (char *)malloc(sizeof("漫夜"));   //再开辟成员空间
    stu->gender = 'M';
    stu->id = 10001;
    stu->score = 99.9F;

    strcpy(stu->name, "漫夜");

    printf("NAME:%s  GENDER:%c  ID:%d  SCORE:%0.1f\n",
           stu->name, stu->gender, stu->id, stu->score);


    if (stu->name != NULL)    //先释放结构体成员指针
    {
        free(stu->name);
        stu->name = NULL;
    }

    if (stu != NULL)  // 再释放结构体指针。如果先释放结构体指针,那么结构体成员指针将没有操作权限
    {
        free(stu);
        stu = NULL;
    }

    return 0;
}

5.结构体数组

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct student2
{
    char name[32];
    char gender;
    int id;
    float score;
} STU;


int main(int argc, char const *argv[])
{
    STU stu[3];
    for (int i = 0; i < 3; i++)
    {
        printf("请依次输入第 %d个学生的信息,姓名  性别 id 成绩,空格隔开\n",i);
        scanf("%s %c %d %f",stu[i].name,&stu[i].gender,&stu[i].id,&stu[i].score);
    }

    for (int i = 0; i < 3; i++)
    {
        printf("NAME:%s  GENDER:%c  ID:%d  SCORE:%0.1f\n",
        stu[i].name, stu[i].gender, stu[i].id, stu[i].score);
    }
    
    return 0;
}

6.结构体指针 数组

定义一个数组,里面存放的都是结构指针

6.1数组全在栈区,结构体在堆区(重要!)

一个一级指针,指向数组第一个元素地址

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct student2
{
    char name[32];
    char gender;
    int id;
    float score;
} STU;

int main(int argc, char const *argv[])
{
    STU *stu[3] = {NULL}; // 初始化赋值,都指向NULL    数组在栈区

    for (int i = 0; i < 3; i++)
    {
        stu[i] = (STU *)malloc(sizeof(STU)); // 数组中每个成员在堆区
    }

    for (int i = 0; i < 3; i++)
    {
        printf("请依次输入第 %d个学生的信息,姓名  性别 id 成绩,空格隔开\n", i);
        scanf("%s %c %d %f", stu[i]->name, &stu[i]->gender, &stu[i]->id, &stu[i]->score);
    }

    for (int i = 0; i < 3; i++)
    {
        printf("NAME:%s  GENDER:%c  ID:%d  SCORE:%0.1f\n",
               stu[i]->name, stu[i]->gender, stu[i]->id, stu[i]->score);
    }

    for (int i = 0; i < 3; i++)
    {
        if (stu[i] != NULL)
        {
            free(stu[i]);
            stu[i] = NULL;
        }
    }
    return 0;
}

6.2数组在堆区,结构体在堆区(难点,但不是重点,理解为主)

一个二级指针,指向数组地址的地址,有点难理解。

就是一个数组中存放着地址,这个数组中的地址指向一级指针的地址。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct student2
{
    char name[32];
    char gender;
    int id;
    float score;
} STU;

int main(int argc, char const *argv[])
{
    int capacity = 3;
    STU ** stu = (STU**)malloc(capacity*sizeof(STU*));

    for (int i = 0; i < 3; i++)
    {
        stu[i] = (STU *)malloc(sizeof(STU)); // 数组中每个成员在堆区
    }

    for (int i = 0; i < 3; i++)
    {
        printf("请依次输入第 %d个学生的信息,姓名  性别 id 成绩,空格隔开\n", i);
        scanf("%s %c %d %f", stu[i]->name, &stu[i]->gender, &stu[i]->id, &stu[i]->score);
    }

    for (int i = 0; i < 3; i++)
    {
        printf("NAME:%s  GENDER:%c  ID:%d  SCORE:%0.1f\n",
               stu[i]->name, stu[i]->gender, stu[i]->id, stu[i]->score);
    }

    for (int i = 0; i < 3; i++)
    {
        if (stu[i] != NULL)
        {
            free(stu[i]);
            stu[i] = NULL;
        }
    }

    if (stu !=NULL)
    {
        free(stu);
        stu = NULL;
    }
    
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值