结构体的使用:
为什么使用结构体:
为了比表示一些复杂的数据结构,而满足用户需求的
什么叫做结构体
把一些基本的数据组合在一起形成一个新的复合数据类型,这个叫做结构体
1、如何定义一个结构体:
//(1)
#include<stdio.h>
//第一种定义结构的体即只定义了一个新的数据类型,并没有定义结构体变量(建议用此方法)
struct Student
{
int age;
float score;
char sex;
};//分好不能忘
//(2)第二种定义结构的方法定义结构体的同时定义结构体变量的命(不建议用此方法)
struct Student
{
int age;
float score;
char sex;
}stu2;
//第三种定义结构体的方式(这样也不好)这样没有结构体的名字
struct
{
int age;
float score;
char sex;
}stu3;
int main(void)
{
struct Student st ={80,66.6,'F'};
return 0;
}
2、怎样使用结构体变量
赋值和初始化
(1)初始化 定义的同时初始化附初始值
(2)定义完成后没有赋值只能一个一个的赋值
如何取出结构体中的每一个成员
(1) 结构体变量名.成员名
(2)指针变量名->成员名(常用)
指针变量名->成员名 在计算机内部会被转化成 (*指针变量名).成员名 的方式来执行
#include<stdio.h>
struct Student
{
int age;
float score;
char sex;
};
int main(void)
{
struct Student st ={80,66.6f,'F'};//初始化 定义的同时初始化附初始值
struct Student st2;//定义完成后没有赋值只能一个一个的赋值
struct Student * pst = &st;
st2.age = 15;
st2.score = 3.1f;//C语言重66.6默认为double类型,如果希望是float类型则必须在末尾加f或者F
st2.sex = 'F';
pst->age = 99;//pst->age 在计算机内部会被转化成(*pst).age 也等价于st.age来执行
printf("普通.运算符对结构体成员的操作结果: %d %f %c\n",st2.age,st2.score,st2.sex);//取值 结构体变量名.成员名
printf("普通.运算符对结构体成员的操作结果: %d %f %c\n",st.age,st.score,st.sex);
printf("%d\n",pst->age);
return 0;
}
注意:1、pst->age 在计算机内部会被转化成 (*pst).age
2、所以 pst->age 等价于 (*pst).age 也等价于st.age
3、我们知道 pst->age 等价于 (*pst).age ,是因为pst->age 是被转化成了(*pst).age 来执行的
4、pst->age 的含义: pst所指向那个结构体变量中age这个成员
结构体变量和结构体指针作为函数参数传递的问题
推荐用结构体指针变量作为函数的参数来传递
结构体重的变量的运算
结构体变量不能相加,不能相减,也不能相互乘除,但可以相互赋值
结构体成员变量可以加减乘除运算
struct Student
{
int age;
char sex;
char name;
};//分号不能少
struct Student st1,st2;
st1 + st2; st1*st2;st1/st2; //这些都是错的
st1 = st2;//这是对的
1、要想通过函数对结构体成员变量进行操作(即修改结构体成员变量时)必须用结构体指针,形参为结构体变量的地址,否则访问不到结构体成员变量,
#include<stdio.h>
#include<string.h>
struct Student
{
int age;//4个字节
char sex;//1个字节
char name[100];//100字节
};
void InpoutStudentInfo(struct Student stu);//前置声明
int main(void)
{
struct Student st;
//pritnf("%d",sizeof(st));
InpoutStudentInfo(st);//对结构体变量的输入
printf("%d %c %s\n",st.age,st.sex,st.name);
return 0;
}
void InpoutStudentInfo(struct Student stu)
{
stu.age = 10;
strcpy(stu.name,"张三");//不能写成stu.name="张三";不行
stu.sex ='F';
}
输出结果为乱码:
原因是当我们用函数操作时,其实是开辟了一段临时空间,当把结构体变量当做实参传进函数时,实际上是把结构体变量中的结构体成员在函数中复制了一份,函数运行时操作的只不过是函数临时开辟空间中存放的结构体成员变量,并没有操作到原来的结构体中的结构体成员变量。当函数运行结束后,开辟的临时空间将会销毁,在函数中对结构体成员变量的操作结果也被销毁,此时传进的结构体变量st并没有用到,那么他输出的是没有赋初值的结构体变量,里面是内存中的一些垃圾数据。
InpoutStudentInfo(st);//对结构体变量的输入
2、要想对结构体成员变量进行操作需实参要穿进结构体变量的首地址,形参为结构体变量的指针用于接收实参传进来的结构体变量的首地址,通过地址我们可以找到结构体成员变量然后进行修改
#include<stdio.h>
#include<string.h>
struct Student
{
int age;//4个字节
char sex;//1个字节
char name[100];//100字节
};
void InpoutStudentInfo(struct Student * pstu);//前置声明
int main(void)
{
struct Student st;
//pritnf("%d",sizeof(st));
InpoutStudentInfo(&st);//对结构体变量的输入
printf("分数: %d 性别: %c 姓名: %s\n",st.age,st.sex,st.name);
return 0;
}
void InpoutStudentInfo(struct Student * pstu)//pstu占4个字节
{
pstu->age = 10;
strcpy(pstu->name,"张三");//不能写成stu.name="张三";不行
pstu->sex ='F';
}
运行结果:
3、当我们用函数仅用来输出结构体成员变量此时可以用结构体变量做实参,缺点是相当消耗空间,因为函数临时开辟的空间需要存的下传进来的结构体变量
#include<stdio.h>
#include<string.h>
struct Student
{
int age;//4个字节
char sex;//1个字节
char name[100];//100字节
};
void InpoutStudentInfo(struct Student * pstu);//前置声明
void OutpoutStudentInfo(struct Student stu);//对结构体变量的输出
int main(void)
{
struct Student st;
//pritnf("%d",sizeof(st));
InpoutStudentInfo(&st);//对结构体变量的输入
OutpoutStudentInfo(st);//对结构体变量的输出不建议用因为传进的参数太占空间了参数st总共占了105个字节
//机器对齐填充数据组成原理中的知识导致108个字节
return 0;
}
void InpoutStudentInfo(struct Student * pstu)//pstu占4个字节
{
pstu->age = 10;
strcpy(pstu->name,"张三");//不能写成stu.name="张三";不行
pstu->sex ='F';
}
void OutpoutStudentInfo(struct Student st)
{
printf("函数临时开辟的空间大小为%d个字节\n",sizeof(st));
printf("分数: %d 性别: %c 姓名: %s\n",st.age,st.sex,st.name);
}
运行结果:
此时发现输出结构体的函数需要开辟一个能存放结构体中所有的成员的内存空间,这样想到耗内存,而且运行慢
4、为了减小内存开销,使运行更快我们输出结构体成员变量时实参为结构体的变量,形参为结构体变量的指针接收结构体变量的地址。优点是内存开销较小,运行快,缺点:不安全,因为在输出函数中可以对结构体的成员变量进行修改(但是我们可以用const来修饰形参避免对结构体的成员变量的修改)
#include<stdio.h>
#include<string.h>
struct Student
{
int age;//4个字节
char sex;//1个字节
char name[100];//100字节
};
void InpoutStudentInfo(struct Student * pstu);//前置声明
void OutpoutStudentInfo(struct Student * stu);//对结构体变量的输出
int main(void)
{
struct Student st;
//pritnf("%d",sizeof(st));
InpoutStudentInfo(&st);//对结构体变量的输入
OutpoutStudentInfo(&st);//对结构体变量的输出建议用因为参数只传进一个结构体变量的首地址
return 0;
}
void InpoutStudentInfo(struct Student * pstu)//pstu占4个字节
{
pstu->age = 10;
strcpy(pstu->name,"张三");//不能写成stu.name="张三";不行
pstu->sex ='F';
}
void OutpoutStudentInfo(struct Student * st)
{
printf("函数临时开辟的空间大小为%d个字节\n",sizeof(&st));
printf("函数临时开辟的空间大小为%d个字节\n",sizeof(st));
printf("分数: %d 性别: %c 姓名: %s\n",st->age,(*st).sex,st->name);
}
运行结果:
5、指针变量存放的是变量的首地址的详解
任何类型的指针变量系统只分配四个字节,指针变量存放的是变量的首地值,例如数组的首地值,结构体变量的首地值,double类型数据的首地值,任何类型数据的首地地址;首地值即是数据第一个字节的地址编号,每一个字节的地址编号都是32位的二进制,这32位的地址编号占四个字节,所以系统为指针变量分配四个字节来存储首地值。然后系统会根据不同类型数据的首地址用不同的寻址方式找到数据。