主頁 > 軟體設計 > 結構體聯合體

結構體聯合體

2021-09-26 13:56:29 軟體設計

每天進步一點點!

什么叫結構體?結構體是由相同或者不同的資料構成的資料集合

在此之前了解一些小知識

2.1只有結構體變數才分配地址,而結構體的定義是不分配空間的,
2.2結構體中各成員的定義和之前的變數定義一樣,但在定義時也不分配空間,
2.3結構體變數的宣告需要在主函式之上或者主函式中宣告,如果在主函式之下則會報錯
2.4c語言中的結構體不能直接進行強制轉換,只有結構體指標才能進行強制轉換
2.5相同型別的成員是可以定義在同一型別下的

1.結構體的宣告與定義

1.結構體是一種自定義資料型別

struct 結構體名{

成員變數或者陣列

};

特別要注意的是末尾的分號一定不能少,表示結構體設計定義結束

結構體是一種集合,他里面包含了多個變數或者陣列,變數的型別可以相同也可以不同,每一個這樣的變數或者陣列都被稱為結構體成員,我們來看一個例子:

include<stdio.h>
struct student
{
	int age;
	char name[10];
	int score;
	char sex[10];
};

stedent為結構體名,他一共有四個成員,分別是age,name ,score,sex,結構體的定義方式和我們在前面學過的陣列十分相似,只是陣列可以初始化,而在這里是不能初始化

2.先定義結構體型別在定義結構體變數

#include<stdio.h>
struct student
{
	int age;
	char name[10];
	int score;
	char sex[10];
};
struct student s1;//s1為全域變數
int main()
{
	struct student s2;//s2為區域變數

}

3.定義結構體型別的時候同時定義結構體變數

#include<stdio.h>
struct student
{
	int age;
	char name[10];
	int score;
	char sex[10];
}s1, s2;

int main()
{
	return 0;

}

4.定義匿名結構體

#include<stdio.h>
struct
{
	int age;
	char name[10];
	int score;
	char sex[10];
}s1;

int main()
{
	return 0;

}

但是這種方式不太好,這個結構體有一種一次性的感覺,不建議這樣定義結構體

總結:

1.使用struct 關鍵字,表示他接下來是一個結構體

2.接下來是一個結構體型別名,可以自己選擇

3.花括號,括起來了結構體成員串列,使用的都是宣告的方式來描述,用;來結束描述

4.在結束花括號后的分號表示結構體設計定義的結束

5.定義的方式

1)先宣告結構體型別再定義變數名
例如:struct(型別名) student(結構體) student1(變數名),student2(變數名);
定義了student1和student2為struct student型別的變數,即他們具有struct student型別的結構

(2)在宣告型別的同時定義變數這種形式的定義的一般形式為:struct 結構體名{
成員串列
}變數名;

注意:

結構體里面的成員可以是基本資料型別也可以是自定義資料型別

5.結構體宣告的位置,及其作用

2.結構體變數的初始化

1.結構體變數和其他變數一樣可以在定義的時候指定初始值 ,結構體變數的初始化用大括號初始化

例:

#include<stdio.h>
struct student
{
	int age;
	char name[10];
	int score;
	char sex[10];
};

int main()
{
	struct student s1={20,"zhangsan",60,"男" };//初始化s1;
	printf("%d  %s  %d  %s", s1.age, s1.name, s1.score, s1.sex);//列印s1中的成員
	return 0;

}

運行結果:

結構體變數的初始化用大括號初始化

那下面這種行不行了?

#include<stdio.h>
struct student
{
	int age;
	char name[10];
	int score;
	char sex[10];
};

int main()
{
	struct student s1;
	s1={20, "zhangsan", 60, "男" };
	printf("%d  %s  %d  %s", s1.age, s1.name, s1.score, s1.sex);//列印s1中的成員
	return 0;

}

這種是不行的,s1在之前已經定義過了,下面在給他值,不是初始化了而是賦值

我們可以看到

此時編譯器報錯了,在結構體變數定義后,如果仍要對成員變數賦值,此時我們只能一一賦值

#include<stdio.h>
#include<string.h>
struct student
{
	int age;
	char name[10];
	int score;
	char sex[10];
};

int main()
{
	struct student s1;
	strcpy(s1.name, "zhangsan");
	s1.age = 40;
	s1.score = 60;
	strcpy(s1.sex, "男");
	printf("%d  %s  %d  %s", s1.age, s1.name, s1.score, s1.sex);//列印s1中的成員
	return 0;

}

運行結果:

2.結構體中嵌套結構體的初始化

結構體中中嵌套結構體的初始化我們依然使用大括號進行初始化

#include<stdio.h>
struct techer
{
	int age;
	char name[10];
};
struct student
{
	int age;
	char name[10];
	int score;
	char sex[10];
	struct techer s2;
};

int main()
{
	struct student s1 = { 20,"zhangsan",70,"男",{20,"老師"} };//初始化s1;
	printf("%d  %s  %d  %s %s", s1.age, s1.name, s1.score, s1.sex,s1.s2.name);//列印s1中的成員
	return 0;

}

3.訪問結構體成員

訪問結構體成員主要用兩種

1.使用成員訪問運算子 ,結構體變數.成員變數

2.使用->運算子,結構體指標->成員變數名

舉個例子:

#include<stdio.h>
struct techer
{
	int age;
	char name[10];
};
struct student
{
	int age;
	char name[10];
	int score;
	char sex[10];
	struct techer s2;
};

int main()
{
	struct student s1 = { 20,"zhangsan",70,"男",{20,"老師"} };//初始化s1;
	printf("%d  %s  %d  %s %s", s1.age, s1.name, s1.score, s1.sex,s1.s2.name);//列印s1中的成員
	return 0;

}

2.結構體指標訪問成員變數

#include<stdio.h>
struct t
{
	int age;
	char name[12];
	char c;
};
int main()
{
	struct t s1 = { 20,"zhansan",'c' };//定義一個結構體變數s1并將其初始化為對應的值
	struct t* p1 = &s1;
	printf("%s %d", p1->name, p1->age);
	return 0;
}

運行結果:

#include<stdio.h>
#include<string.h>
struct t
{
	int age;
	char name[12];
	char c;
};
int main()
{
	
	struct t s1 = { 20,"zhansan",'c' };//定義一個結構體變數s1并將其初始化為對應的值
	struct t* p1 = &s1;
	printf("%s %d", p1->name, p1->age);
	return 0;
}

總結:

1.結構體整體賦值只限定于定義變數的時候并將其初始化,在使用的程序中只能對其一 一賦值,這一點和陣列是類似的,

2.結構體是一種自定義型別,是創建變數的模板,不占用空間,結構體變數才包含了實實在在的資料,需要空間來存盤

4.結構體傳參

1.可以把結構體作為函式引數,傳參的型別和其他變數或指標類似

第一種傳參方式,傳結構體用結構體來接收

#include<stdio.h>
#include<string.h>
struct t
{
	int age;
	char name[12];
	char c;
};
void print(struct t s2)
{
	printf("%d %s", s2.age, s2.name);
}
int main()
{
	
	struct t s1 = { 20,"zhansan",'c' };//定義一個結構體變數s1并將其初始化為對應的值
	print(s1);
	return 0;
}

運行結果:

方法二:

傳結構體變數的地址:

#include<stdio.h>
#include<string.h>
struct t
{
	int age;
	char name[12];
	char c;
};
void print(const struct t* s2)
{
	printf("%d %s", s2->age,s2->name);
}
int main()
{
	
	struct t s1 = { 20,"zhansan",'c' };//定義一個結構體變數s1并將其初始化為對應的值
	print(&s1);
	return 0;
}

運行結果:

兩種傳參方式都能達到目的,那哪一種傳參方式更好 了答案是第二種,原因是第一種是值傳遞,會創建一個臨時變數將實參的值拷貝給形參,如果結構體太大,傳遞的效率就會很低,空間的浪費很大,但是第二種傳遞的方式是傳地址,只需要拷貝4個或者8個位元組,如果要傳參盡量選擇第二種

5.結構體陣列

所謂的結構體陣列,指的是結構體里面的每一個元素都是結構體,在實際中常用來表示擁有相同資料結構的群體,比如一個班的學生

定義結構體陣列和定義結構體變數的方式類似定義時可以初始化

例:

#include<stdio.h>
#include<string.h>
struct student
{
	int age;
	char name[12];
	char c;
};

int main()
{
	
	struct student arr[3] = { {20,"zhangsan",'c'},{30,"lisi",'d'},{40,"wangwu",'p'} };
	printf("%d %d %d", arr[0].age, arr[1].age, arr[2].age);
}

運行結果:

6.結構體指標

顧名思義就是指向結構體的指標,方式和定義整型指標那些類似,

定義格式: struct 結構體名*+結構體指標名字

例:struct student *struct _pointer;

struct_pointer=&s1;

訪問成員時使用->運算子

struct_pointer->+成員名

#include<stdio.h>
#include<string.h>
struct student
{
	int age;
	char name[12];
	char c;
};

int main()
{
	
	struct student s1 = { 22,"zhangli",'c' };
	struct student* struct_pointer = &s1;
	printf("%d", struct_pointer->age);
}

運行結果:

注意:

結構體和結構體變數是兩個不同的概念:結構體是一種資料型別,是一種創建變數的模板,編譯器不會為它分配記憶體空間,就像 int、float、char 這些關鍵字本身不占用記憶體一樣;結構體變數才包含實實在在的資料,才需要記憶體來存盤,下面的寫法是錯誤的,不可能去取一個結構體名的地址,也不能將它賦值給其他變數:

下列寫法是錯誤的

#include<stdio.h>
#include<string.h>
struct student
{
	int age;
	char name[12];
	char c;
};

int main()
{
	
	struct student* p = &student;
	struct student* s = student;
}


7.獲取結構體成員

通過結構體指標可以獲取結構體成員,一般形式為:

(*pointer).memberName

或者:

pointer->memberName

第一種寫法中,.的優先級高于*,(*pointer)兩邊的括號不能少,如果去掉括號寫成*pointer.memberName,那么就等效于*(pointer.memberName),這樣意義就不對了,

第二種寫法中,->是一個新的運算子,習慣稱它為“箭頭”,有了它,可以通過結構體指標直接取得結構體成員,這也是->在C語言中的唯一用途,

上面兩種寫法是等效的,我們通常采用第二種寫法,這樣更加直觀,


例:

#include<stdio.h>
#include<string.h>
struct student
{
	int age;
	char name[12];
	char c;
};

int main()
{
	
	struct student s1 = { 2,"zhansan",'e' };
	struct student* pointer = &s1;
	printf("%d\n", pointer->age);
	printf("%d", (*pointer).age);
}

運行結果:

7.結構體變數的參考(輸入和輸出)

結構體變數的輸入scanf和輸出printf和其他變數的操作是一樣的

1.值得注意的是.的優先級是比較高的

2.(如果結構體的成員本身是一個結構體,則需要繼續用.運算子,直到最低一級的成員,

#include<stdio.h>
#include<string.h>
struct student
{
	int age;
	char name[12];
	char c;
	struct Date
	{
		int year;
		int month;
		int day;
	}brirthday;
}stu1;

int main()
{
	printf("%d", stu1.brirthday);//這樣寫是錯誤的,因為brirthday是一個結構體
	scanf("%d", &stu1.brirthday.month);//正確;

	
}

8.結構體記憶體對齊(重點)

結構體中的記憶體對齊是用空間換時間的一種記憶體操作,

一.結構體對齊的規則

1、 資料成員對齊規則:結構(struct)(或聯合(union))的資料成員,第一個資料成員放在offset為0的地方,以后每個資料成員的對齊按照#pragma pack指定的數值和這個資料成員自身長度中,比較小的那個進行,

2、結構(或聯合)的整體對齊規則:在資料成員完成各自對齊之后,結構(或聯合)本身也要進行對齊,對齊將按照#pragma pack指定的數值和結構(或聯合)最大資料成員長度中,比較小的那個進行,

3、結合1、2可推斷:當#pragma pack的n值等于或超過所有 資料成員長度的時候,這個n值的大小將不產生任何效果,

1) 結構體變數的首地址是其最長基本型別成員的整數倍;

備注:編譯器在給結構體開辟空間時,首先找到結構體中最寬的基本資料型別,然后尋找 記憶體地址能是該基本資料型別的整倍的位置,作為結構體的首地址,將這個最寬的基本資料型別的大小作為上面介紹的對齊模數,

2)結構體每個成員相對于結構體首地址的 偏移量(offset)都是成員大小的整數倍,如有需要編譯器會在成員之間加上填充位元組(internal adding);

備注:為結構體的一個成員開辟空間之前,編譯器首先檢查預開辟空間的首地址相對于結構體首地址的偏移是否是本成員的整數倍,若是,則存放本成員,反之,則在本成員和上一個成員之間填充一定的位元組,以達到整數倍的要求,也就是將預開辟空間的首地址后移幾個位元組,

3) 結構體的總大小為結構體最寬基本型別成員大小的整數倍,如有需要, 編譯器會在最末一個成員之后加上填充位元組(trailing padding),

備注:結構體總大小是包括填充位元組,最后一個成員滿足上面兩條以外,還必須滿足第三條,否則就必須在最后填充幾個位元組以達到本條要求,

4) 結構體內型別相同的連續元素將在連續的空間內,和 陣列一樣,

5) 如果結構體記憶體在長度大于處理器位數的元素,那么就以處理器的倍數為對齊單位;否則,如果結構體內的元素的長度都小于處理器的倍數的時候,便以結構體里面最長的 資料元素為對齊單位,

2.為什么要設定結構體記憶體對齊?

一、硬體原因:加快CPU訪問的速度
我們大多數人在沒有搞清楚CPU是如何讀取資料的時候,基本都會認為CPU是一位元組一位元組讀取的,但實際上它是按照塊來讀取的,塊的大小可以為2,4,8,16,塊的大小也稱為記憶體讀取粒度,
假設CPU沒有記憶體對齊,要讀取一個4位元組的資料到一個暫存器中,(假設讀取粒度為4),則會出現兩種情況
1、資料的開始在CPU讀取的0位元組處,這剛CPU一次就你能夠讀取完畢
2、資料的開始沒在0位元組處,假設在1位元組處吧,CPU要先將0~3位元組讀取出來,在讀取4~7位元組的內容,然后將0~3位元組里的0位元組丟棄,將4~7位元組里的5,6,7位元組的資料丟棄,然后組合1,2,3,4的資料,
由此可以看出,CPU讀取的效率不是很高,可以說比較繁瑣,
但如果有記憶體對齊的話:
由于每一個資料都是對齊好的,CPU可以一次就能夠將資料讀取完成,雖然會有一些記憶體碎片,但從整個記憶體的大小來說,都不算什么,可以說是用空間換取時間的做法,
二、平臺原因:
不是所有的硬體平臺都可以訪問任意地址上的任意資料,某些硬體平臺只能在某些地址處取某些型別的資料,否則拋出硬體例外,

3.結構體大小的計算

計算結構體的大小需要按照上面的規則:

在次說明一下:

第一個成員在結構體變數偏移量為0 的地址處,

其他成員變數要對齊到某個數字(對齊數)的整數倍的地址處,對齊數 = 編譯器默認的一個對齊數與該成員大小中的較小值,vs中默認值是8 Linux默認值為4.

結構體總大小為最大對齊數的整數倍,(每個成員變數都有自己的對齊數)

如果嵌套結構體,嵌套的結構體對齊到自己的最大對齊數的整數倍處,結構體的整體大小就是所有最大對齊數(包含嵌套結構體的對齊數)的整數倍,

下面我們來實踐一下,光說不練,假把式

#include<stdio.h>
#include<string.h>
struct student
{
	int age;
	char a;
}stu1;

int main()
{
	printf("%d", sizeof(stu1));
	return 0;
}


上面這個結構體的大小是多少了?

首先按照上面的規則第一個元數放到偏移量為0的地方,第一個元素的型別是整型,大小為4個位元組,而第二個元素的a的型別是char,大小是1個位元組,而編譯器默認的最大對對齊數是8,兩者取最小值為1,那么a就要放到1的倍數下,此時a和age一共占用了5個位元組,但所有成員里面最大對齊數為4也就是age,5并不是4的倍數,所以編譯器會浪費3個位元組的空間對齊,所以這個結構體的大小為8

運行結果:

下面我們再來看一道題

#include<stdio.h>
#include<string.h>
struct student
{
	char c1;
	char c2;
	int i;
}stu1;

int main()
{
	printf("%d", sizeof(stu1));
	return 0;
}

運行結果:

結果是8,我們來分析一下為什么結果是 8??
c1是char型,占一個位元組,第一個成員即 c1 在結構體變數偏移量為0 的地址處,
c2是char型,占一個位元組,要對齊到對齊數的整數倍的位置,對齊數 = 編譯器默認的一個對齊數與該成員大小中的較小值,vs中默認值是8,取較小值1,char型別的對齊數是1,所以對齊到1 的整數倍,那就是偏移量為1開始的地址空間,
i是int型別,占四個位元組,要對齊到對齊數的整數倍的位置,int型別的對齊數就是 4,所以對齊到4 的整數倍,
我們來看一下記憶體分布圖:

記憶體分布圖:

那么這一個結果又是多少了?

#include<stdio.h>
#include<string.h>
struct student
{
	char c1;
	
	int i;
	char c2;
}stu1;

int main()
{
	printf("%d", sizeof(stu1));
	return 0;
}

運行結果:

結果是12,來看一下程序?
c1是char型,占一個位元組,對應到結構體變數偏移量為0 的地址處,
i是int型,占四個位元組,對齊數就是4,對齊到4的整數倍位置處,即偏移量為4開始的地址空間,
c2是char型,占一個位元組,對齊到1 的整數倍,那就是下一個地址空間,對齊到偏移量為8的地址空間,
結構體總大小為最大對齊數的整數倍,所以為對齊數4的整數倍,現在已經用了9個位元組的空間,那么總大小就是12個位元組空間,所以輸出結果是12,

記憶體圖:

下面我們在來看一個例子結構體嵌套結構體的大小又應該如何計算

例:

#include<stdio.h>
struct s3
{
	double d;
	char c;
	int i;
};
struct s4
{
	char c1;
	struct s3 s;
	double d;
};
int main()
{
	struct s4 t;
	printf("%d ", sizeof(t));
}

運行結果:

結果是32,我們來看一下分析:
容易得出struct S3占16個位元組,請讀者自行分析,如果不會的話可以問我哦,
那我們來看一下struct S4的大小,struct S4中有三個成員變數,第一個char型,占一個位元組,對齊到偏移量為0的地址處,第二個成員是結構體嵌套使用,結構體S3變數s3,剛才已經得出占16個位元組,所以第二個成員對齊數是16,又因為對齊數是編譯器默認數與成員對齊數中的較小值,vs默認對齊數是8,取較小值8,所以對齊到偏移量為8的地址空間,處,第三個成員是double型,占8個位元組,對應到8的整數倍即偏移量24的地址處,
結構體總大小是最大對齊數8的整數倍,所以是32,
來看一下記憶體分布圖:

#pragma pack()修改默認對齊數

簡單理解#pragma
作為較為復雜的預處理指令之一,它的作用為更改編譯器的編譯狀態以及為特定的編譯器提供特定的編譯指示,這些指示是具體針對某一種(或某一些)編譯器的,其他編譯器可能不知道該指示的含義又或者對該指示有不同的理解,也即是說,#pragma的實作是與具體平臺相關的,可以簡單將其理解為該預處理指令是開發者和編譯器互動的一個工具,

#pragma pack指令說明
由于記憶體的讀取時間遠遠小于CPU的存盤速度,這里用設定資料結構的對齊系數,即犧牲空間來換取時間的思想來提高CPU的存盤效率,

這里先說編譯器的對齊配置,以vc6為例,vc6中的編譯選項有 /Zp[1|2|4|8|16] ,/Zp1表示以1位元組邊界對齊,相應的,/Zpn表示以n位元組邊界對齊,n位元組邊界對齊的意思是說,一個成員的地址必須安排在成員的尺寸的整數倍地址上或者是n的整數倍地址上,取它們中的最小值,也就是:
min ( sizeof ( member ), n)
實際上,1位元組邊界對齊也就表示了結構成員之間沒有空洞,
/Zpn選項是應用于整個工程的,影響所有的參與編譯的結構,

例子:

#include<stdio.h>
#pragma pack(1)
struct s4
{
	char c1;
	double d;
};
int main()
{
	struct s4 t;
	printf("%d ", sizeof(t));
	
}

運行結果:

答案為9,我們通過#pragma修改了默認對齊數,修改為1,所有成員的大小和1取最小值,那么所有成員的對齊數為1,也就是挨著放的,9所以大小為9

offfsetof及其實作

offsetof是一個庫函式在<stddef.h>中,其作用是計算成員變數在結構體中的偏移量·

函式原型:

如何使用了:

#include<stdio.h>

#include<stddef.h>
struct s4
{
	char c1;
	double d;
};

int main()
{
	struct s4 t;
	printf("%d ", offsetof(struct s4, d));
	
}

運行結果:

原理已經在上面說過了在這里就不過多贅述

實作offsetof,他實際是一個宏

代碼實作:

#include<stdio.h>
#include<stddef.h>
#define OFFSETOFF(struct_type ,member)(int)&((struct_type*)0)->member
struct s4
{
	char c1;
	int a;
	double d;
};

int main()
{
	printf("%d ", OFFSETOFF(struct s4, a));
	
}

第一個引數是結構體的名字,第二個引數是結構體成員的名字,回傳的是該成員在結構體中的偏移量

這個宏的實作巧妙之處在于,將起始的物件的地址強制賦為0, 即是(struct_type*)0這里.那么回傳的(struct_type*)0->member即是成員的偏移量了.


注意:這個結構并沒有申請記憶體空間,卻要去訪問其成員,按常理不是會出錯,因為訪問了未申請的記憶體空間.

但是,在這里我們實際并沒有訪問結構成員的記憶體空間,只是回傳其地址值,我們用的是取址運算子.而這里的值是編繹器在編繹階段便已經計算好的,hs

聯合體

什么是聯合體?在C語言中,變數的定義是分配存盤空間的程序,一般的,每個變數都具有其獨有的存盤空間,那么可不可以在同一個記憶體空間中存盤不同的資料型別(不是同事存盤)呢?

答案是可以的,使用聯合體就可以達到這樣的目的,聯合體也叫共用體,在C語言中定義聯合體的關鍵字是union,

1.定義一個聯合體的格式和結構體類似

union 聯合體名{

成員串列

};

成員串列中有若干成員,成員形式一般為:型別說明符 成員名,

與結構體,列舉一樣,聯合體也是一種構造型別

2.聯合體定義的方法

方法一:先創建模板后定義變數

#include<stdio.h>
union student{
	int a;
	char c;
};
int main()
{
	union student s1;
	return 0;
}

方法二:創建模板和變數

#include<stdio.h>
union student
{
	int a;
	char c;
}s1;
int main()
{
	
	return 0;
}

方法三:省略聯合體名,也就是匿名聯合體

#include<stdio.h>
union 
{
	int a;
	char c;
}s1;
int main()
{
	
	return 0;
}

聯合體的初始化和結構體基本一樣,在這里就不過多贅述

2.聯合體的大小計算

當沒有定義#pragma pack()這種指定value位元組對齊時,他的計算規則時聯合體中最大成員所占的記憶體的大小,并且必須為最大型別所占位元組的倍數

下面我們來看一個例子:

#include<stdio.h>
union 
{
	char s[10];
	int a;
}s1;
int main()
{
	printf("%d", sizeof(s1));
	return 0;
}

運行結果:

在這個聯合體中最大的成員的大小為10也就是那個陣列,但是最大型別所占位元組數的大小為4.并不是4的整數倍所以編譯器會浪費2個位元組,所以大小為12個位元組

3.使用聯合體判斷大小端:

聯合體的概念和特征:union維護足夠的空間來存放多個資料成員中的“一種”,而不為每一個資料成員都配置空間,在union中所有的成員共用同一個空間,同一時間只存盤一個資料成員,最大的特征就是所有的資料成員具有相同的起始地址即聯合體的基地址,

2)計算機中位元組存盤主要有兩種:大端模式(Big_endian)和小端模式(Little_endian),從英文名字上可以明白,大端模式是從低地址開始,高位結束,(即高地址存地位,低地址存高位);小端模式是從高地址開始,低地址結束(與大端相反,),

3)利用union中所有資料成員具有同樣的起始地址的特點,通過一個int成員存盤1,然后通過char成員來讀取,即可巧妙地得出資料存放的方式,若通過char成員(即讀取起始位置上的第一個位元組)讀取,若得出值為1,則說明是小端模式,

代碼如下:

#include<stdio.h>
union stu
{
	int a;
	char c;
};
int main()
{
	union stu s;
	s.a = 1;
	if (s.c == 1)
	{
		printf("小端");
	}
	else
	{
		printf("大端");
	}
	return 0;
}

博主實力有限如有錯誤請在評論區留言,如果覺得寫的不錯可以點個贊,謝謝!

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/303085.html

標籤:其他

上一篇:【Java】認識Sring、String的常見操作和StringBuffer 和StringBuilder的區別【字串詳解】

下一篇:學透CSS-如何組織你的CSS代碼 [學]

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more