C语言结构体:从入门到精通

1.回顾:

描述数值的数据类型:

  • short int long
  • float double

描述字符类型:char

构造数据类型:数组,而且是在一片连续性空间可以存储多个相同数据类型

但是后续开发过程中,会遇到一个目标需要多个属性来描述,例如学生:身高(float),体重(float),年龄(int),性别(char),名字(char [ ])。用单一的数据类型无法进行准确描述。所以,此时需要一个构造数据类型:结构体

个人理解:结构体,是一个融合了多个基本数据类型的一个复合数据类型


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 = {"孙鑫",'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 = {"国祥",'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结构体的赋值方法

方法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 = {"孙鑫",'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;
        }

方法2:单一复制,尤其注意name

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, "孙鑫");
    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:键盘输入赋值

    STU stu2;
    printf("请你依次输入name   gender   id   以及score,中间用空格隔开\n");
    scanf("%s %c %d %f", stu2.name, &stu2.gender, &stu2.id, &stu2.score); 

    // 可以用 结构体变量名 + . 的方式取出对应的成员属性
    printf("NAME:%s  GENDER:%c  ID:%d  SCORE:%0.1f\n",
           stu2.name, stu2.gender, stu2.id, stu2.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结构体成员动态内存分配

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结构体动态内存分配

#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;
}

7.结构体所占空间大小问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值