C语言学习第七章——结构体

结构体的基础知识与使用

课前引入

随着大家对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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值