天天看点

C++之结构体、共用体、位域结构体共同体位域

C++之结构体

  • 结构体
    • 定义-day28-4
    • 初始化的三种形式-day28-6
    • 结构体引用和深浅拷贝-day28-11
    • 头文件作用和结构体声明-day28-12
    • 结构体赋值原理-day28-13
    • 结构体嵌套实现继承-day28-14
    • 结构体数组-day29-1
    • 结构体动态数组
    • 结构体大小
    • 指针和结构体
    • 函数跨数据传递数-day44-3
    • Typedef结构体和共用体
    • 共用体
    • 初始化
    • 起别名
  • 共同体
    • 共用体地址
    • 共用体size
    • 最宽字节
    • 共用体初始化
  • 位域
    • 位域,限制数据的位数,节约内存
    • 实战
    • 低位在低字节,高位在高字节

结构体

定义-day28-4

需要注意只有在初始化的时候,才可以使用大括号进行赋值运算,如果已经给定义了变量,不可以再使用大括号{}进行初始化。

struct dangdang  ddd[10][10];//每个数组是一个结构体
struct a1
{
	char email[20];
	char name[10];
	long long phone;
	double lelvel;

};

struct 
{
	char email[20];
	char name[10];
	long long phone;
	double lelvel;

}qxg;//匿名结构体,锁定变量的数量
//结构体中嵌套结构体实现继承
void main()
{
	struct a1 qxl;
	strcpy(qxl.email, "[email protected]");
	strcpy(qxl.name, "qxl");
	qxl.phone = 18810619072;

	struct a1 *p;
	p = &qxl;
	printf("%s\n%s\n%lld\n", qxl.email, qxl.name, qxl.phone);
	printf("%s\n%s\n%lld\n", p->email, p->name, p->phone);
	system("pause");

}

           
  1. 结构体类型仅仅作用于本文件,如果跨文件使用需要复制过去,因此应放置在h文件中,而不应该放置在源文件中,在工程文件中,一般是按照这种形式组织结构体头文件。
  2. 结构体定义,重名的情况下内层覆盖外层

初始化的三种形式-day28-6

struct dangdang1
{
	char name[10];
	char email[30];
	long long phone;
}d2 = { "qxl","[email protected]",18810619072 };//初始化
struct dangdang
{
	char name[10];
	char email[30];
	long long phone;
}d3 = { .name="qxl",.email="[email protected]",.phone=18810619072 };//选择性初始化
struct 
{
	char name[10];
	char email[30];
	long long phone;
}d1 = { .name = "qxl",.email = "[email protected]",.phone = 18810619072 };//匿名结构体
           

结构体引用和深浅拷贝-day28-11

结构体变量不能整体引用(打印),只能引用变量成员(逐一打印),因为结构体中并不限定数据类型,而引用(打印)成员是需要知道其数据类型的。

只有在初始化的时候才能使用大括号进行赋值。

结构体之间没有比较运算符,只能对成员变量进行运算

void main()
{
	struct str mystr1;
	mystr1.p = malloc(30);
	mystr1.num = 10;
	strcpy(mystr1.p, "hello world");
	struct str mystr2 = mystr1;//拷贝,指向同一内容
	//struct str mystr2;
	mystr2.p = malloc(30);
	strcpy(mystr2.p, mystr1.p);//深拷贝
	free(mystr1.p);
	printf("%s\n%d\n%s\n%d", mystr1.p, mystr1.num, mystr2.p, mystr2.num);
	system("pause");
}
           

对于指针都会有这个问题

头文件作用和结构体声明-day28-12

头文件的作用是放置变量、函数、结构体声明;为什么只放声明呢,是否可以将定义也包含呢?当然不可以。因为在一个工程中可能有多个c文件会include头文件,如果h文件中包含了定义,多次include导致重定义问题。

结构体赋值原理-day28-13

结构体是内存拷贝,结构体当中只有指针是浅拷贝,其他(数组等,拷贝的时候占据的 字节空间是定了的)是副本机制,深拷贝。

结构体拷贝的实现机制是memcpy

struct mystruct
{
	int a[5];
	char str[10];
	char *p;
};
void main()
{
	//memcpy是内存copy
	struct mystruct my1 = { {1,2,3,4,5},"calc",NULL };
	my1.p = malloc(30);
	strcpy(my1.p, "20200112");

	struct mystruct my2 = my1;
	my1.a[3] = 111;
	my1.str[2] = 'X';
	*(my1.p) = 'X';

	for (int i = 0; i < 5; i++)
	{
		printf("%d,%d\n", my1.a[i], my2.a[i]);
	}
	printf("%s, %s\n", my1.str, my2.str);
	printf("%s, %s\n", my1.p, my2.p);
	system("pause");
}
//输出
1,1
2,2
3,3
111,4
5,5
caXc, calc
X0200112, X0200112
           

结构体嵌套实现继承-day28-14

#include<stdlib.h>
#include<stdio.h>

struct life
{
	int canmove;
};
struct animal
{
	struct life life1;
	int canrun;
};
struct man
{
	struct animal animal1;
	int canthink;
};
struct triger
{
	struct animal animal1;
	int tooth;
	int ismao;
};
//预习链表,使用链表解决内存不连续的问题
struct listnode
{
	int num;
	struct listnode *pleftlist;
	struct listnode *prightlist;
};
struct file
{
	int size;
	int isbin;
	int isexe;
	int time;
};
struct filesnode
{
	struct file *pfile;//多个文件
	int pfiles;//指针数组
	struct filesnode *pfielsnode;//多个文件夹
	int ppfiles;
};
struct array//数组实现
{
	int *p;
	int length;
}
//链表嵌套可以实现继承,可以描述事物的复杂属性,c语言数组结构都是结构体
           

结构体数组-day29-1

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct //匿名结构体
{
	int num;//c要求一个结构或者联合至少有一个成员变量
	double db;
}*p,x[10],z;//定义结构体指针数组变量
//匿名结构体如果有指针,指针可以开辟内存,所以无法锁定数量
struct Mystruct
{
	int data;
	int id;
}my[10];//第二种定义
struct csdn
{
	char name[100];
	char pass[100];
	char email[100];
}csdndata[3] = 
{
	{"qxl","111","[email protected]"},
	{ "lh","222","[email protected]" },
	{ "lrr","333","[email protected]" }
}, *csdnp;
void main()
{
	//struct Mystruct my[10];//第一种定义
	//struct Mystruct *p = (struct Mystruct[10]) { 0 };//栈区,数组
	//struct Mystruct my[2] = { {10,20},{10,20} };//结构体数组初始的一般形式
	//struct Mystruct *p = (struct Mystruct[2]) { 10, 20, 10, 20 };//一定要遵循顺序
	//以上两种数组都属于是栈上的数组
	struct Mystruct my[] = { {0},{0} };//初始化为空,设定为0
	csdnp = (struct csdn[]) {//指针赋值之后如何调用
		{"qxl", "111", "[email protected]"},
		{ "lh","222","[email protected]" },
		{ "lrr","333","[email protected]" }
	};
	for (int i = 0; i < sizeof(csdndata) / sizeof(csdndata[0]); i++)
	{
		//a.b   &a->b  p->b   (*p).b
		//char *p = strstr(csdndata[i].email, "[email protected]");
		//char *p = strstr(csdnp[i].email, "[email protected]");//[]表示是变量了
		//char *p = strstr((csdnp+i)->email, "[email protected]");//(csdnp+i)还是地址的形式
		char *p = strstr((*(csdnp + i)).email, "[email protected]");//(csdnp+i)还是地址的形式
		//printf("%d\n", csdndata[i].email);
		if (p != NULL)
		{
			puts(csdndata[i].pass);
		}
	
	}
	
	system("pause");
}
           

结构体动态数组

#define _CRT_SECURE_NO_WARNINGS
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<malloc.h>

struct csdn
{
	int num;
	int id;
};
void main1()
{
	int num;
	scanf("%d", &num);
	struct csdn *csdn1 = malloc(sizeof(struct csdn)*num);//堆
	struct csdn *csdn2 = alloca(sizeof(struct csdn)*num);//栈
	//以上不会全都初始化?使用memset进行初始化
	memset(csdn1, 0, sizeof(struct csdn)*num);
	memset(csdn2, 0, sizeof(struct csdn)*num);
	for (int i = 0; i < num; i++)
	{
		printf("%d,%d,%d,%d\n", csdn1[i].num, csdn1[i].id, csdn2[i].num, csdn2[i].id);
	}
	system("pause");
}
void main()
{
	struct csdn *p2 = (struct csdn[]) {1,2,3,4};//指向数组
	printf("\n%d",p2[1].id);
	printf("\n%d",(&p2[1])->id);
	printf("\n%d", (p2+1)->id);
	printf("\n%d",(*(p2+1)).id);
	
	system("pause");
}
           

结构体大小

  1. 结构体大小等于所有成员的大小之和
  2. Char int float double是基本类型 double是最宽基本成员,数组和结构体不是最宽基本成员
  3. 设定于当前最宽 ,二者取最短的为最宽
  4. 结构体成元的地址-结构体的首地址=偏移量,必须是当前成员的整数倍
  5. 结构体尾部不足的部分,就会被填充
  6. 结构体对齐,注意节省内存
  7. 在实际工作中使用较少,在架构设计中考虑较多。
  8. 以上是默认的对齐方式,通过设置修改对齐方式
char num2;	
	char num3;
	int num1;//占据8个字节

	char num2;
	int num1;
	char num3;//占据12个字节
           

指针和结构体

  1. 结构体有副本机制,如果结构体中有数组,对数组也生效。
  2. 结构体返回值也有副本机制
  3. 函数返回数组C语言不支持
  4. 内存分配及赋值
  5. 结构体存储以8字节为最小单位,如果不足8,补位
#include<stdio.h>
struct
{
	char num1;
	double num2;
	int num3;
	char ch1;
	char ch2;//int char char 累加为8个字节
	long long num4;
}s1;//存储以8字节为最小单位,如果不足8,补位,所以占用的size为32;
void main()
{
	printf("%d", sizeof(s1));//输出32

	getchar();
}



struct data
{
	int num;
};
void main3()
{
	//struct data *pnew = malloc(sizeof(struct data) * 10);
	struct data *pnew = alloca(sizeof(struct data) * 10);//分配在栈,不需要手动free释放内存
	int i = 0;
	for (struct data *p = pnew; p < pnew + 10; p++)
	{
		printf("%p, %d\n",p,((*p).num) = i++);
	}
	system("pause");
}
           

函数跨数据传递数-day44-3

Return数据变量为什么合法?因为是副本机制,局部函数中的变量已经释放。

动态分配内存(malloc)能否跨函数使用?动态分配内存是在堆区完成的,返回指针后不会释放内存。但函数返回时,栈区的内容会被释放,因此不能返回指向栈区的指针。

是否可以返回只读存储区的指针?

Char *p = “hello”;

Return p;//返回局部指针是ok的,只能用于输出,不能用于输入。

Typedef结构体和共用体

#include<stdio.h>
#include<stdlib.h>

struct Mystruct
{
	int num;
	double score;
};
union Myunion
{
	int num;
	double score;
};
typedef struct Mystruct m1;
typedef union Myunion u1;

void main1()
{
	m1 mm1 = { mm1.num = 1, 1.0 };
	u1 uu1 = { 1 };
}
           

共用体

共用体变量任何时刻只有一个变量存在

初始化

共用体只能对一个变量初始化

起别名

typedef struct/union Mystruct  mys;
typedef struct Mystruct
{
	int num;
	float f1;
}mys;
           

共同体

共用体地址

对于共用体而言,所有成员地址都是一样的

共用体size

共用体宽度是最长的那个,但是必须整除最宽

Union Mynion
{
		char str[13];
		double num;//size为16,因为要整除
}
           

共用体变量定义分配内存,长度等于最长成员所占字节数

最宽字节

字节对齐属性设置和成员中的最宽,取较小的为最宽

结构体嵌套的情况下,最宽基本成员不局限于当前结构体。

共用体初始化

#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>

union pc
{
	int num;
	char price[10];//字符串数组
	char *p;//指针
};

void main()
{
	union pc p1 = { 1000 };
	union pc p2[2] = { {1000},{1000} };
	//union pc *p = (union pc[]){ {1000}, { 1000 }, {1000} };
	system("pause");
}
           

位域

位域,限制数据的位数,节约内存

struct Mystruct
{
	unsigned int a:5;//位域,限制数据的位数,节约内存
	unsigned int b:4;//需要注意符号位
	unsigned int c:16;
}//输出size大小是4个字节
2.	多个数据进行重合,按照类型进行重合。
3.	如果类型不一致,遵顼结构体的对齐规则,通过设置对齐方式可以进行内存优化
Struct data
{
	unsigned char a:1;//位域,限制数据的位数,节约内存
	unsigned char b:1;
}//输出size大小是1个字节
与
Struct data
{
	unsigned short a:1;//位域,限制数据的位数,节约内存
	unsigned short b:1;
}//输出size大小是2个字节
           

实战

C++之结构体、共用体、位域结构体共同体位域

低位在低字节,高位在高字节

C++之结构体、共用体、位域结构体共同体位域