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");
}
- 结构体类型仅仅作用于本文件,如果跨文件使用需要复制过去,因此应放置在h文件中,而不应该放置在源文件中,在工程文件中,一般是按照这种形式组织结构体头文件。
- 结构体定义,重名的情况下内层覆盖外层
初始化的三种形式-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");
}
结构体大小
- 结构体大小等于所有成员的大小之和
- Char int float double是基本类型 double是最宽基本成员,数组和结构体不是最宽基本成员
- 设定于当前最宽 ,二者取最短的为最宽
- 结构体成元的地址-结构体的首地址=偏移量,必须是当前成员的整数倍
- 结构体尾部不足的部分,就会被填充
- 结构体对齐,注意节省内存
- 在实际工作中使用较少,在架构设计中考虑较多。
- 以上是默认的对齐方式,通过设置修改对齐方式
char num2;
char num3;
int num1;//占据8个字节
char num2;
int num1;
char num3;//占据12个字节
指针和结构体
- 结构体有副本机制,如果结构体中有数组,对数组也生效。
- 结构体返回值也有副本机制
- 函数返回数组C语言不支持
- 内存分配及赋值
- 结构体存储以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个字节
实战
