结构体(c语言)

目录

                结构体设计

                结构体使用    成员访问

                结构体和数组结合

                结构体大小 

                例题练习


结构体设计

                结构体类型:  自定义数据类型 设计一个类型   int

                类型的设计不占内存  用类型定义变量时才会占内存

                struct 类型名{ 属性(变量的声明) };

 基础使用:

struct Student{
char name[10];//成员列表(属性)
int age;
int score;
};
int main() {
struct  Student stu={"qo",10,100};
struct Student*Stu=&stu;
}

指针和函数体利用typedef重命名:

struct Student{
char name[10];//成员列表(属性)
int age;
int score;
};
typedef struct Student Student;
typedef struct Student* pr;
int main() {
Student stu={"qo",10,100};
pr stu=&stu;
}

重命名的优化: 

typedef struct Student{
	const char* name;//成员列表(属性)
	int age;
	int score;
}student,*pr;
int main() {
Student stu={"qo",10,100};
 pr Stu=&stu;
}

                将strcut student 重命名为student,struct  student *重名名为pr.(该方法既适用于.c文件,也适用于.cpp文件)

结构体使用    成员访问

                1)student  s={成员列表赋值};   "s .成员 "    '.'为成员访问符

                2) student s={赋值};   PSTU   p=&s;(*p).成员   p->成员   (此处的PSTU为指向student的指针重命名)和上面的*pr相同;

                举例:1)原本结构体的使用和成员访问

typedef struct Student{
char* name;
int age;
int score;
}Student;
int main() {
Student stu1={"zs",10,100};
Student  stu2;
stu2={"ls",9,89};
printf("%s",stu1.name);
}

                           2)利用指针

typedef struct Student{
char* name;
int age;
int score;
}Student,*pr;
int main() {
Student stu1={"zs",10,100};
Student  stu2;
stu2={"ls",9,89};
printf("%s",stu1.name);
pr stu_s=&stu2
printf("%s",(*stu_s).name);//注意此处'.'的优先级高于'*',所以带括号
printf("%s",stu_s->name);'->'指向符具有解引用的作用
}

结构体和数组结合

 Student  arr[]={{成员赋值},{成员赋值},{成员赋值}};即再Student 该结构体下有几个成员,学生1,学生2,学生3……

举例:定义结构体类型数组 赋值  打印

typedef struct Student{
	const char* name;//成员列表(属性)
	int age;
	int score;
}student,*pr;
int main() {
	Student stu = { "qo", 10, 100 };
	
     //	定义结构体类型数组 赋值
	Student arr[] = { { "af", 23, 11 }, stu };//可以用已定义的变量进行赋值
	int len = sizeof(arr) / sizeof(arr[0]);//求数组长度
	for (int i = 0; i < len; i++){
		printf("第%d个学生:  姓名:%4s,年龄:%4d,成绩:%4d  \n", i, arr[i].name, arr[i].age, 
        arr[i].score);
	}
}

  结构体大小 

        内存大小的基本单位:字节 

        1.地址访问:cpu内村读写不是按照1字节1字节的读取     以 2,4,8的倍数的字节块读取内存

        2. 平台读取地址  偶数地址读取

        3.不同平台  内存对齐方式不同(VS默认8  linux默认4)

结构体内存大小的计算方法:

1.变量的首地址,必须时MIN{结构体中最大基本数据类型,指定对齐方式}所占字节数的整数倍

2.每个成员变量相对结构体首地址的偏移量,都是MIN{该成员基本数据类型,指定对齐方式}整数倍 

3.结构体总大小为MIN{结构体变量最大基本数据类型,指定对齐方式}所占字节的整数倍

   举例:

typedef struct student{
char* name;
int age;
int score;
}student,*pr;
student str={"zs",10,100};

 此处name首先占四字节(指针类型),age占4字节(int),score占四字节(int).占12个字节,我们可能看不出什么问题我们看下一段代码:

typedef struct student{
char name[10];//成员列表属性
int age;
int score;
}student,*pr;
student str={"zs",10,100};

(此处对齐方式默认8字节)数组name占10个字节,次数name的字节计算完成,接着计算age的大小4字节,然后此时结构体首地址的偏移量为10,不是这时要求变量字节和指定对齐方式最小值的的整数倍,因此向后对其两个字节(规则2),12字节,加上age的4字节,这时偏移量为16字节,16字节是接下来变量score4字节的倍数,因此不需要内存对齐,直接加上4字节,所以结果为20字节。此时20不是结构体最大基本数据类型和指定对齐方式最小值所占字节(8字节)的倍数,向后空4个字节,结果为24。

可能还不是很清楚,我们再举一例:

#include<stdio.h>
#pragma pack(4)//指定对齐方式4字节
typedef struct people{
int a;
long long b;
short c;
char d;
}people;
pragma pack()//必须存在该语句(结束)

首先计算a所占字节(4),紧接着计算b长整型(8)字节,偏移量4字节是(该变量和对齐方式最小值)4的倍数,这是偏移量为12(4+8)字节,紧接着short类型(2字节),这时 12是2(该变量和对齐方式最小值)的整数倍,所以此时直接加上2(14),14是1字节(该变量和对齐方式最小值)的整数倍,直接加上去(15),15不是结构体中最大基本类型所占字节(long long 8字节和对齐方式4字节最小值)4的倍数,因此继续对齐(16-15)1字节,(此处16是4的最小整数(4)倍)所以总共所占字节为16字节.

结构体镶嵌情况下的大小计算

struct add{
int a;
long long b;
char* c;
}
struct AD{
char* A;
int B;
struct add C;
int D;
}

 计算AD结构体的大小(此处默认对齐方式8字节):首先A(char*)4字节,B为4字节,偏移量4字节是(该变量字节数4和对齐方式8字节最小值)4的整数倍,因此不需要向后空出字节,此时是8字节,然后C,此处是add结构体的字节大小,{a字节数是4不是8(下一个变量和对齐方式最小值)的整数倍,向后空出4字节,加上该变量的8字节,偏移量是16字节是4(c字节大小和对齐方式最小值)的整数倍,直接加上4字节是20字节,20不是8(最大基本数据类型和对齐方式最小值)的整数倍,向后对齐4字节,}C变量大小为24字节,8是8(对齐方式和该变量字节数最小值)的整数倍,直接加上C的字节数32,32是4(D大小和对齐方式最小值)的整数倍,因此直接相加是36字节,最后36不是8(该结构体最大基本数据类型long long 8字节和对齐方式8字节最小值)的整数倍,向后空出4字节,所以AD结构体大小为40字节。

例题练习 

 建立一个学生结构体,成员属性:姓名     成绩

利用冒泡排序将其按成绩升序进行排序,若成绩相同则按姓名的降序进行排序。

冒泡排序的方法参考以前的博客进行学习,此处不说明。具体讲函数体的用法

代码:

typedef struct student{//定义结构体
	const char* name;
	int score;
}student, *stu;//此处对结构体和指针进行重命名
void swap(stu stu_s, int i,int j){
/*交换函数,将stu_s函数的第i个成员和第j个成员进行交换,此时成员内部的属性均交换*/
	student temp=stu_s[i];
	stu_s[i] = stu_s[j];
	stu_s[j] = temp;
}
void point(stu stu_s,int len){
	int flag = 0;//标记
    for (int i = 0; i < len; i++){
	flag = 0;
		for (int j = 0; j<len - i - 1; j++){
			if (stu_s[j].score>stu_s[j+1].score) {//成绩比较大小(成员属性的调用)
				swap(stu_s, j, j+1);
				flag = 1;
		     }
			if (stu_s[j].score == stu_s[j+1].score)  {//成绩相同
				if (strcmp(stu_s[j].name, stu_s[j+1].name)){//姓名比较大小,成员的姓名属性调用
					flag = 1;swap(stu_s, j+1, j);
				}    
			}
		}
	if (flag == 0) break;

     }
}

上面代码用指针重命名,此处直接对结构体进行重新命名。(可用性更强)

typedef struct student{
	const char* name;
	int score;
}student;
typedef student ET;//对student这一结构体做一重命名
void swap(ET *i, ET*j){
	ET temp = *i;
	*i = *j;
	*j = temp;
}
void point(ET* stu_s, int len){
	int flag = 0;
	for (int i = 0; i < len; i++){
		flag = 0;
		for (int j = 0; j<len - i - 1; j++){
			if (stu_s[j].score>stu_s[j + 1].score) {
				swap(&stu_s[j], &stu_s[j+1]);
				flag = 1;
			}
			if (stu_s[j].score == stu_s[j + 1].score)  {
				if (strcmp(stu_s[j].name, stu_s[j + 1].name)){
					flag = 1; swap(&stu_s[j + 1], &stu_s[j]);
				}
			}
		}
		if (flag == 0) break;

	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

*闲鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值