天天看點

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++之結構體、共用體、位域結構體共同體位域