结构体的基础知识与使用
课前引入
随着大家对C语言数据类型与数据结构的了解,大家学习的主线从单一类型的变量到单一类型的多个变量结构(数组)。那么大家有没有思考过一个问题,现实生活中我们常常遇到考试报告单的问题(狗头),成绩报告单里面有学号,姓名,成绩,性别等。显然这些数据的数据类型是不一样的,那么在C语言当中如何实现将这些类型封装在同一个框架下呢?这就是这一章结构体要学习的内容了。
结构体基础知识
结构体的使用步骤:
1.声明,即确定结构体的大体框架长什么样
2.定义 定义一个结构体,此时告诉编译器结构体的名字,也可以在这时候告诉编译器结构体里面装的数据内容
3.调用 可以对结构体里面的内容进行调用,调用包括写入,修改和输出
要注意的有几点:
1.C语言中,在结构体进行声明的时候,其实并没有在内存中分配对应的村粗空间,而是在定义的时候,编译器才在内存中分配对应的存储空间
2.C语言中,结构体里面所封装的叫做成员变量。对于成员变量的访问我们采取.运算,没错就是点运算。对于这一点我们要抓住继承的概念,.的左边是父代,右边是子代,子代从左边而来。这里面涉及到结构体的嵌套,如下:
#include<stdio.h>
struct Person{
char name[10];
char sex;
int age;
struct Birthday{ //Birthday这里可写可不写
int year;
int month;
int day;
}birthday;
};
int main()
{
char *p[2]={"男人","女人"};
printf("这个程序只是一个例子哈\n");
struct Person p1;
printf("请输入姓名:");
scanf("%s",p1.name);
printf("请输入性别:");
scanf("%s",&p1.sex);
printf("请输入年龄:");
scanf("%d",&p1.age);
printf("请输入生日的年份:");
scanf("%d",&p1.birthday.year);
printf("请输入生日的月份:");
scanf("%d",&p1.birthday.month);
printf("请输入生日的日期:");
scanf("%d",&p1.birthday.day);
if(p1.sex=='f')
printf("姓名:%s性别:%s 年龄:%d 生日:%d-%d-%d\n",p1.name,p[1],p1.age,p1.birthday.year,p1.birthday.month,p1.birthday.day);
else printf("姓名:%s性别:%s 年龄:%d 生日:%d-%d-%d\n",p1.name,p[0],p1.age,p1.birthday.year,p1.birthday.month,p1.birthday.day);
return 0;
}
当然这里要注意,如果在大结构体内部直接书-写嵌套结构体的声明加定义的话,该嵌套结构体作用域只限于大结构体内部。离开{}就什么都没有了。
#include<stdio.h>
/*结构体 结构体可以实现多种数据的封装*/
/*结构体的声明,此时并不在内存中分配空间,只有在定义结构体类型变量的时候才会在内存中分配一个储存空间*/
struct Book{
char title [128];// 成员名称
char author[40];
float price;
unsigned int date;
char publisher[40];
}; // 一定要注意分号!!! }book; 在声明的时候定义,这样子就定义了一个全局变量
int main()
{
struct Book book; // Book 为框架的名称,book为变量名
/*如何访问结构体内容*/
printf("请输入书名:");
scanf("%s",book.title);
printf("请输入作者:");
scanf("%s",book.author);
printf("请输入售价:");
scanf("%f",&book.price);//非数组要注意&
printf("请输入出版日期:");
scanf("%d",&book.date);//非数组要注意&
printf("请输入出版社:");
scanf("%s",book.publisher);
printf("书名:%s 作者:%s 售价:%.2f 出版日期 :%d 出版社:%s",book.title,book.author,book.price,book.date,book.publisher);
/*也可以指定成员变量进行初始化
struct Book book2{.price=48.8};
*/
return 0;
}
结构体中内存对齐
#include<stdio.h>
int main()
{
struct A{
char a;//一个字节
int b;// 四个字节
char c;// 一个字节
} a={'x',520,'0'};
printf("size of a=%d\n",sizeof(a)); // 答案是十二而不是六,原因是编译器对内存进行对齐,方便CPU进行访问.
/*
为什么要发生内存对齐呢,主要有两个原因,一个的cpu内存的读取方式,另一个是平台的原因。
1.CPU 32位机子位访问的时候,是以4个字节4个字节访问的,而64位机子是以8个字节8个字节进行访问的。在这里通过内存对齐可以方便CPU进行访问,即以空间换时间
2.平台的原因。操作系统分配给编译器平台的存储空间是有限的。而当一个平台要取一个整型数据的时候,只能在地址为4的倍数的位置取得,否则CPU无法访问到该整型数据
*/
printf("%p\n",&a.a);
printf("%p\n",&a.b);
printf("%p\n",&a.c);
struct B{
char a;
char c;
int b;
} b={'x','0',520};
printf("size of b=%d\n",sizeof(b));
/*通过对结构体的合理配置,可以起到节约内存空间的目的*/
return 0;
}
如果想要更加了解这方面的知识,推荐下面这个博主的文章结构体内存对齐(如何计算结构体的大小)
版权声明:本文为CSDN博主「2021dragon」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/chenlong_cxy/article/details/114332324
如果要了解如何优化结构体,节省内存空间。这里推荐小甲鱼推荐的一篇文章
结构体内存空间优化的问题即内存对齐
结构体数组和结构体指针
继承上面刚才讲的学生的例子,可以发现学习结构体基础知识后,每一个结构体只能存放一个学生的个人信息,如果要储存多个学生的信息,那就得使用到数组(这里也可以理解为,数据类型都为结构体的数据(已经封装为一个结构体的数据)构成的数组就叫做结构体数组。
#include<stdio.h>
struct Book{
char title [128];// 成员名称
char author[40];
float price;
unsigned int date;
char publisher[40];
};
int main()
{
struct Book *pt; // 结构体指针
struct Book *pg;
struct Book book1={
"如何学习Python","佚名",38.5,2021,"夕阳无限好出版社"
};
/********************************************************/
/*结构体数组*/
struct Book book[3]={
{"如何学习Java","佚名",38.5,2021,"夕阳无限好出版社" },
{"青春不散场","佚名",39.5,2020,"青春正奋斗出版社"},
{"我爱你,再见","青春",15.9,2019,"芙蓉出版社"}
};
struct Test{
int x;
int y;
}t1,t2;
t1.x=3;
t1.y=4;
t2=t1; //两个结构体变量可以相互赋值的条件是,两个结构体的框架是相同的,即结构体里面的数据类型是相同的
printf("%d,%d\n",t2.x,t2.y);
pt =book; // 由于结构体数组是数组,所以可以不使用取值运算符
pg=&book1;
printf("%s\n",(*pg).title); // 括号是因为优先级的原因 .的优先级大于*所以为了保证可以访问到该结构体的成员,得先进行解引用
printf("%s\n",pg->title);
return 0;
}
结构体变量与函数
结构体作为函数的参数和返回值进行传递
#include<stdio.h>
/*结构体变量与函数的关系*/
struct Classmates{
long num;
char name[10];
float goals;
};
void printIm(struct Classmates c1);
struct Classmates getInput(struct Classmates c );
/*************************************************/
struct Classmates getInput(struct Classmates c )
{
printf("请输入姓名:");
scanf("%s",c.name);
printf("请输入学号:");
scanf("%ld",&c.num);
printf("请输入成绩:");
scanf("%f",&c.goals);
return c;
}
void printIm(struct Classmates c1)
{
printf("姓名:%s 学号:%ld 成绩:%f",c1.name,c1.num,c1.goals);
}
int main(void)
{
struct Classmates c1,c2;
printf("请录入第一个同学的信息....\n");
c1=getInput(c1);
printIm(c1);
return 0;
}
结构体指针作为函数参数和返回值进行传递
结构体指针作用:减少函数参数和返回值传递是对内存空间的占用
#include<stdio.h>
/*结构体指针作用:减少函数参数和返回值传递是对内存空间的占用*/
struct Classmates{
long num;
char name[10];
float goals;
};
void printIm(struct Classmates *c1);
void getInput(struct Classmates *c );
/*************************************************/
void getInput(struct Classmates *c )
{
printf("请输入姓名:");
scanf("%s",c->name);
printf("请输入学号:");
scanf("%ld",&c->num);
printf("请输入成绩:");
scanf("%f",&c->goals);
}
void printIm(struct Classmates *c1)
{
printf("姓名:%s 学号:%ld 成绩:%f",c1->name,c1->num,c1->goals);
}
int main(void)
{
struct Classmates c1,c2;
printf("请录入第一个同学的信息....\n");
getInput(&c1);
printIm(&c1);
return 0;
}
结构体的动态内存分配
#include<stdio.h>
#include<stdlib.h>
/*结构体指针作用:减少函数参数和返回值传递是对内存空间的占用*/
struct Classmates{
long num;
char name[10];
float goals;
};
void printIm(struct Classmates *c1);
void getInput(struct Classmates *c );
/*************************************************/
void getInput(struct Classmates *c )
{
printf("请输入姓名:");
scanf("%s",c->name);
printf("请输入学号:");
scanf("%ld",&c->num);
printf("请输入成绩:");
scanf("%f",&c->goals);
}
void printIm(struct Classmates *c1)
{
printf("姓名:%s 学号:%ld 成绩:%f",c1->name,c1->num,c1->goals);
}
int main(void)
{
struct Classmates *c1,*c2;
c1=(struct Classmates *)malloc(sizeof(struct Classmates)); //在堆中申请空间,返回值为无类型的指针,要进行强制类型转化
if(c1==NULL)
{
printf("内存分布失败");
exit(1);//退出 需要stdlib头文件
}
printf("请录入第一个同学的信息....\n");
getInput(c1);
printIm(c1);
free(c1); //有申请就有释放
return 0;
}
学无止境,我爱编程
欢迎大家私信交流
内存对齐的实例
#include<stdio.h>
#include <stddef.h>
int main()
{
struct A{
char a; //1
int b; //4
char c;//1
double d;//8
} a={'x',520,'0',52.0};
struct B{
double d; //8
int b; //4
char c;//1
char a;//1
} b={52.0,520,'x','0'};
printf("size of a=%d\n",sizeof(a));
printf("char a:%d,int b:%d,char c:%d double d:%d\n",&a.a,&a.b,&a.c,&a.d);
printf("%p\n",&a.d);
printf("%d\n",sizeof(double));
printf("size of b=%d\n",sizeof(b));
printf("******************************\n");
printf("a的偏移值:%d\n",offsetof(struct A,a));
printf("b的偏移值:%d\n",offsetof(struct A,b));
printf("c的偏移值:%d\n",offsetof(struct A,c));
printf("d的偏移值:%d\n",offsetof(struct A,d));
/*
size of a=24
size of b=16
*/
return 0;
}