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個位元組
實戰
