结构体
为什么需要结构体
为了表示一些复杂的事物,而普通的基本类型无法满足实际要求。
什么叫结构体
把一些基本类型数据组合在一起形成的一个新的复合数据类型。
如何定义结构体
// 3种方式:
// 第一种 只是定义了一个新的数据类型,并没有定义变量 推荐采用1
struct Student
{ Int age;
Float score;
Char sex;
};
//第二种
struct Student
{ Int age;
Float score;
Char sex;
} st;
// 第三种
struct
{ Int age;
Float score;
Char sex;
} st;
怎样使用结构体变量
赋值和初始化
定义的同时可以整体赋值。
如果定义完之后,则只能单个赋初值。
如果取出结构体变量中的每一个成员{重点}
1 结构体变量名.成员名
2 指针变量名->成员名 (更常用)
它会在计算机内部转化成 (* 指针变量名).成员名 的方式来执行。
所以两者是等价的。
例子:
Struct Student {
Int age;
Float score;
Char sex;
};
Int main(void) {
Struct Student st = {80,66.6f,’F’};
//初始化定义的时候赋值 66.6在C语言中默认是double类型,如果希望一个实数是float类型,则必须在末尾加f或F, 因此66.6是double, 66.6f或66.6F是float
struct Student st2;
st2.age = 10;
st2.score = 88;
st2.sex = 'F'; // 第二种方式 单独赋值
Struct Student *pst = &st; // &st 不能写成 st
Pst->age = 88; // 通过结构体指针变量
printf("%d %f\n", st.age, pst->score);
Return 0;
}
理解:
1 pst->age 会在计算机内部转化成 (*pst).age 的方式来执行,没有为什么,这就是->的含义,这也是一种硬性规定。
2 所以 pst->age 等价于 (*pst).age 也等价于 st.age
3 pst->的含义:pst 所指向的那个结构体变量中的age这个成员。
结构体变量的大小略大于其内部成员类型所占字节数之和。试:sizeof(struct)
若想通过函数对主函数结构体变量进行修改,则主函数必须发送地址,外函数定义指针结构体变量,通过外函数内部语句完成对变量的修改。
而仅想输出、读取操作,则不用传地址,定义指针过程。
例:
/*
通过函数完成对结构体变量的输入和输出
*/
# include <stdio.h>
# include <string.h>
struct Student {
int age;
char sex;
char name[100];
}; //分号不能省
void InputStudent(struct Student *);
void OutputStudent(struct Student ss);
int main(void){
struct Student st; //15行
InputStudent(&st); //对结构体变量输入 必须发送st的地址
//printf("%d %c %s\n", st.age, st.sex, st.name); // 此行和 下行输出函数 功能相同
OutputStudent(st); //对结构体变量输出 可以发送st的地址也可以直接发送st的内容
return 0;
}
void OutputStudent(struct Student ss){
printf("%d %c %s\n", ss.age, ss.sex, ss.name);
}
void InputStudent(struct Student * pstu) //pstu只占4个字节
{
(*pstu).age = 10;
// pstu->name = "张三丰"; 或(*pstu).name = "张三丰"; 都是error,提示错误信息: cannot
convert from 'char [5]' to 'char [100]'
strcpy(pstu->name,"张三丰"); // 用字符串拷贝命令解决问题
pstu->sex = 'F';
}
/*
//本函数无法修改主函数15行st的值 所以本函数是错误的
void InputStudent(struct Student stu) {
stu.age = 10;
strcpy(stu.name, "张三"); //不能写成 stu.name = "张三";
stu.sex = 'F';
}
*/
结构体:应该发送地址还是内容
设计函数的目的:必须考虑 功能单一, 还要考虑安全因素
C++中指针前可加const 则只能读而不能修改其指向的变量。
指针的优点:
耗用内在小(4字节)
快速传递数据
执行速度快。
因此:推荐使用结构体变量作为函数参数来传递
/*
示例:
发送地址还是发送内容
目的:
指针的优点之一:
快速的传递数据,
耗用内存小
执行速度快
*/
# include <stdio.h>
# include <string.h>
struct Student{
int age;
char sex;
char name[100];
}; //分号不能省
void InputStudent(struct Student *);
void OutputStudent(struct Student *);
int main(void){
struct Student st ; //15行
//printf("%d\n", sizeof(st));
InputStudent(&st); //对结构体变量输入 必须发送st的地址
OutputStudent(&st); //对结构体变量输出 可以发送st的地址也可以直接发送st的内容 但为了减少内存的耗费,也为了提高执行速度,推荐发送地址
return 0;
}
void OutputStudent(struct Student *pst){
printf("%d %c %s\n", pst->age, pst->sex, pst->name);
}
void InputStudent(struct Student * pstu) //pstu只占4个字节
{
(*pstu).age = 10;
strcpy(pstu->name, "张三");
pstu->sex = 'F';
}
结构体变量的运算
不能加减乘除操作,只能相互赋值。
例如:
struct Student
{
Int age;
Char sex;
Char[100];
};
Struct Student str1, str2;
Str1 = str2 / str2 = str1 ; 都是正确的。
// 举例:动态构造存放学生信息的结构体数组
# include <stdio.h>
# include <malloc.h> // 必须先添加头文件 malloc
struct Student{
int age;
float score;
char name[100];
};
int main(void){
int len;
struct Student * pArr;
int i, j;
struct Student t;
//动态的构造一维数组
printf("请输入学生的个数:\n");
printf("len = ");
scanf("%d", &len);
pArr = (struct Student *)malloc(len * sizeof(struct Student));
//printf("%d\n",sizeof(struct Student)); // 108字节
//输入
for (i=0; i<len; ++i)
{
printf("请输入第%d个学生的信息:\n", i+1);
printf("age = ");
scanf("%d", &pArr[i].age);
printf("name = ");
scanf("%s", pArr[i].name); //name是数组名,本身就已经是数组首元素的地址, 所以
pArr[i].name 不能改成 &pArr[i].name
printf("score = ");
scanf("%f", &pArr[i].score);
}
//按学生成绩升序排序 冒泡算法
for (i=0; i<len-1; ++i)
{
for (j=0; j<len-1-i; ++j)
{
if (pArr[j].score > pArr[j+1].score) // >升序 <降序
{
t = pArr[j]; // 注意 t 的类型为 Struct Student
pArr[j] = pArr[j+1];
pArr[j+1] = t;
}
}
}
printf("\n\n学生的信息是:\n");
//输出
for (i=0; i<len; ++i)
{
printf("第%d个学生的信息是:\n", i+1);
printf("age = %d\n", pArr[i].age);
printf("name = %s\n", pArr[i].name);
printf("score = %f\n", pArr[i].score);
printf("\n");
}
return 0;
}
总结:
对于一个人事管理或图书管理项目,分析流程:
第一步;存储
第二步:操作
第三步:输出
前两个过程最难、最核心 是“数据结构”研究的重点,一般都屏蔽了。
数组 和 变量 虽然都可以存储,但都不完美。
比如:人事关系图、交通图等,都不好用数组保存。
从事关系结构只能用“树”还保存,而对于 两个起终点:公交线路查询,实现时间最小/ 距离最短/ 花费最低 等功能,只能用“图”来存。
而图 和 树 都必须有指针知识,它们属于较高深的思想层次的东西。因此要学好数据结构必须要 懂得指针。
若感兴趣:可以继续学习郝斌老师的《数据结构》教学视频。