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