C语言结构体介绍

一,前言

以下是我在学习结构体过程中对结构的相关总结。

二,结构体简述

1.结构体

具有相同或不同类型元素的集合叫做结构体。结构体本质是一种类型。结构体通常用关键字 struct 定义。如定义一个学生类型结构体。

struct Student
{
	char name[50];
	int Chinese;
	int Math;
	int English;
};

2.结构体全局变量声明

//此代码主要用于说明如何重命名定义
struct Student
{
    char name[50];
    int Chinese;
    int Math;
    int English;
};
//全局变量声明 ,用typedef实现
//如typedef int char 此时的char不再是基本数据类型char,而是代表着int类型
//在如:typedef unsigned long long unit64
//     ① unsigned long long val=0;
//     ②uniit64 val=0;  ①与②所代表的相同

此时可以将typedef与结构体定义结合,实现重命名,简化后续代码,如上述的学生类型结构体

typedef struct Student
{
	char name[50];
	int Chinese;
	int Math;
	int English;
}Student;

此后可以用Student代替struct Student.

3.结构体赋值

以下为结构体赋值

#include <string.h>//此头文件为strcpy 与 memcpy 与strncpy的头文件
#include <stdio.h>
struct Student
{
	char name[50];
	int age;
};

int main()
{
	struct Student s = { "yxb", 18 };//初始化变量

	strcpy(s.name, "ls");//对变量进行赋值改变 strcpy为关键字拷贝字符串

	memcpy(s.name, "ls", 3);//也是拷贝关键字,意义为将ls中的3个字符赋值给s.name
	//注意memcpy中要赋值的3个字符包括'\0'

	strncpy(s.name, "ls", 2);//拷贝关键字, 意义为将ls中的个字符赋值给s.name
	//注意strncpy中要赋值的2个字符不包括'\0'

	s.age = 24;

	return 0;
}

4.结构体访问

#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <stdio.h>
typedef struct Student
{
	char name[50];
	int age;
}stu;

int main()
{
	// 通过'.'访问结构体成员
	stu s;
	strcpy(s.name, "yxb");
	s.age = 20;

	// 通过指针'->'访问结构体成员
	stu * p = &s;
	printf("%s\n", p->name);
	printf("%d\n", p->age);
	//通过不同的方式访问
	printf("%s\n", (*p).name);
	printf("%d\n", (*p).age);
	return 0;
}

打印结果:

在函数传参时,会生成临时变量,若采用传值方式,传输的结构体较大则占用空间大,顾建议采用传值方式。

5.结构体数组

结构体数组:是指数组中的每一个元素都是结构体。结构体数组在定义的同时也可以初始化,同时可以定义不同的数值。

typedef struct stu
{
	char name[20];  //姓名
	int num;  //号码
	int age;  //年龄
}stu;
int main()
{
	stu s[2] =
	{
		{"zs", 18,14},
		{"yxb", 4,13},
	};
	return 0;
}

6.结构体简述代码示例

银行卡类型:卡号,密码,钱,银行名,持卡人{姓名,身份证号,电话号码},是否被锁,记录[10]{时间,事件,金额}       写出结构体

​//以下代码仅供参考,具体细节不在补充
#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
typedef struct BankCard
{
	int _id;
	int _passwd;
	float _money;
	char _bankname[10];
	bool _islocked;
	User user;
	Record record[10];
}BankCard;
typedef struct User
{
	char _name[10];
	char _idcord[20];
	char iphhone[10];
}User;
typedef struct Record
{
	char _time[50];
	char _typr[10];
	float _rmoney[10];
}Record;
int main()
{
	BankCard card = { 123,123,0.0,"建行",false,{"zs","610481200312270019","110"},{"2024....","存款",200.0}};
return 0;
}
​

若要改变结构体内已经赋值的数如:改变记录里面的金额

card.record[1]._rmoney=-800;

三, 结构体大小的计算

1.单个结构体计算方法

struct A
{
	char c;//1+3
	int a;//4
	short s;//2
};
sizeof(A);10+2=12B

下面我将对上述代码进行解释:

已知char类型占1个字节,int类型占据4个字节,由于内存对齐前方偏移量之和要为后方的整数倍,顾对char类型原有1字节加上3,进行内存填充(后面会说到内存填充),相同的道理,Short类型为2个字节,前方偏移量之和为8,是2的整数倍,故不用进行内存填充。

当计算结构体整体大小时,将算上的所有字节大小相加相加之和若为结构体内最大字节数的整数倍,则得出来的值为结构体的大小,若相加之和不为结构体内最大字节的整数倍,则要进行内存填充,将其扩大到最大字节的整数倍。

2.多个结构体计算方法

struct A
{
	char c;//1+1
	short s;//2
};//4B
struct B
{
	char c;//1+1
	A a;//4
	short s;//2
};
sizeof(B)----->8B

下面我将对上述代码进行解释:

相信结构体A已经没有什么问题了,估计问题主要集中在结构体B中为什么char c 内存填充只加1。

因为在多个结构体计算时,若遇到像结构体B里面的情况,char c 的内存偏移量只算结构体A里面的最大字节及结构体A里面的short,占据两个字节,故内存填充值只加1。

3.指定对齐方式

VS 中的默认对齐数为 8,不是所有编译器都有默认对齐数,当编译器没有默认对齐数的时候,成员变量的大小就是该成员的对齐数。

要是需要修改默认对齐方式则用:#pragam pack() ------->括号里面填写需要设置的默认对齐值

#pragma pack(2)
struct A
{
	char c;//1+1
	short s;//2--->min{short,2}
	int a;//4----->min{int ,2}
};//8B---->min{4,2}

下面我将对上述代码进行解释:

将VS原有的默认对齐值8改为对齐值为2,及对结构体A里面的每一个不同的部分,将他们本身的字节大小与2进行对比只需要选最小的对比,若当前字节为最小的数的整数倍即可若不为整数倍进行内存填充。

4.内存对齐


1)内存大小的基本单位是字节(byte),理论上来讲,可以从任意地址访问变量,但是实际上,cup并非读写内存,而是以2,4,或8的倍数的字节块来读写内存,因此就会对基本数据类型的地址作出一些限制,即它须是 2,4或8的倍数。那么就要求各种数据类型按照一定的规则在空间上排列,这就是对齐。
2)有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结身字节进行拼凑才能得到该32bit数据。显然在读取效率上下降很多。
3)由于不同平台对齐方式可能不同,如此一来,同样的结构在不同的平台其大小可能不同,在无意识的情互相发送的数据可能出现错乱,甚至引发严重的问题。

5.位段设计

#include <stdio.h>
typedef struct room
{
	unsigned short _homeid : 10;//2个字节中的10个位
	unsigned short _num : 3;//2个字节中的3个位
	unsigned short _isused : 1;//2个字节中的1个位
}rom;//一共占据10+3+1=14bit  --->2B
int main()
{
	printf("%d",sizeof(rom));
	return 0;
}

运行结果:

四,小代码练习

设计学生结构体{姓名,语文成绩,数学成绩,英语成绩}
//5个学生
//1.求语文平均成绩
//2.英语成绩最高分?获取最高分学生信息

#include <stdio.h>
typedef struct Student
{
	char name[50];
	int Chinese;
	int Math;
	int English;
}Student;
int main()
{
	Student student[5] = { { "yang",40,50,30 }, { "zhao",30,40,50 }, { "sun",30,40,50 }, { "qian",30,40,50 },{"zhang",30,40,80} };
	int i=0;
	int allchinese = 0;
	for (i; i < 5; i++)
	{
		allchinese += student[i].Chinese;
	}
	int AVGchinese = allchinese /5 ;
	printf("语文平均:%d\n", AVGchinese);
	int j = 1;
	int maxenglish = student[0].English;
	Student message = student[0];
	for (j; j < 5; j++)
	{
		if (student[j].English > maxenglish)
		{
			maxenglish = student[j].English;
			message = student[j];
		}
	}
	printf("英语最高:%d\n", maxenglish);
	printf("姓名:%s\n英语成绩:%d\n数学成绩:%d\n语文成绩:%d\n", message.name,message.English, message.Math, message.Chinese);
	return 0;
}

结果:

也可以使用函数书写,这里不再过多叙述。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值