一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

簡(jiǎn)述C語(yǔ)言知識(shí)總結(jié):宏,枚舉,結(jié)構(gòu)體,共用體

Q4MP_gh_c472c21 ? 來(lái)源:掘金 ? 作者:Mr_Li_ ? 2021-05-20 11:25 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

1、define宏定義以#號(hào)開(kāi)頭的都是編譯預(yù)處理指令,它們不是C語(yǔ)言的成分,但是C程序離不開(kāi)它們,#define用來(lái)定義一個(gè)宏,程序在預(yù)處理階段將用define定義的來(lái)內(nèi)容進(jìn)行了替換。因此在程序運(yùn)行時(shí),常量表中并沒(méi)有用define定義的常量,系統(tǒng)不為它分配內(nèi)存。

define定義的常量,預(yù)處理時(shí)只是直接進(jìn)行了替換,它用來(lái)將一個(gè)標(biāo)識(shí)符定義為一個(gè)字符串,該標(biāo)識(shí)符被稱(chēng)為宏名,被定義的字符串稱(chēng)為替換文本。因此在編譯時(shí)它不對(duì)宏的定義進(jìn)行檢查,作用域不影響對(duì)常量的訪問(wèn) 。它的常量值只能是字符串或數(shù)字。

該命令有兩種格式:一種是簡(jiǎn)單的常量宏定義, 另一種是帶參數(shù)的宏定義。

不帶參數(shù)的宏:#define《 名字 》《 值 》

要注意,沒(méi)有結(jié)尾的分號(hào),因?yàn)椴皇荂的語(yǔ)句,名字必須是一個(gè)單詞,值可以是各種東西,宏定義是用宏名來(lái)表示一個(gè)字符串,在宏展開(kāi)時(shí)又以該字符串取代宏名,這只是一種簡(jiǎn)單的代換,字符串中可以含任何字符,可以是常數(shù),也可以是表達(dá)式,預(yù)處理程序?qū)λ蛔魅魏螜z查。如有錯(cuò)誤,只能在編譯已被宏展開(kāi)后的源程序時(shí)發(fā)現(xiàn)。

注意。宏定義不是說(shuō)明或語(yǔ)句,在行末不必加分號(hào),如加上分號(hào)則連分號(hào)也一起置換。宏定義其作用域?yàn)楹甓x命令起到源程序結(jié)束。如要終止其作用域可使用#undef命令

帶參數(shù)的宏 :

像函數(shù)的宏,一般的定義形式 :帶參宏定義的一般形式為:「#define 宏名」(形參表)字符串,也是沒(méi)有結(jié)尾的分號(hào),可以帶多個(gè)參數(shù) ,#define NB(a,b)((a)》(b)?(b):(a)), 也可以組合(嵌套)使用其他宏,注意 帶參數(shù)宏的原則 一切都要有括號(hào),參數(shù)出現(xiàn)的每個(gè)地方都要有括號(hào)。帶參數(shù)的宏在大型的程序的代碼中使用非常普遍,在#和##這兩個(gè)運(yùn)算符的幫助下可以很復(fù)雜,如“產(chǎn)生函數(shù)”,但是有些宏會(huì)被inline函數(shù)代替(C++的函數(shù))

使用宏好處:

“提高運(yùn)行效”。定義的標(biāo)識(shí)符不占內(nèi)存,只是一個(gè)臨時(shí)的符號(hào),預(yù)編譯后這個(gè)符號(hào)就不存在了。在簡(jiǎn)單的程序使用帶參數(shù)的宏定義可完成函數(shù)調(diào)用的功能,又能減少系統(tǒng)開(kāi)銷(xiāo),提高運(yùn)行效率。正如C語(yǔ)言中所講,函數(shù)的使用可以使程序更加模塊化,便于組織,而且可重復(fù)利用。

“方便程序的修改”。使用宏定義可以用宏代替一個(gè)在程序中經(jīng)常使用的常量。注意,是“經(jīng)?!笔褂玫?。這樣,當(dāng)需要改變這個(gè)常量的值時(shí),就不需要對(duì)整個(gè)程序一個(gè)一個(gè)進(jìn)行修改,只需修改宏定義中的常量即可。且當(dāng)常量比較長(zhǎng)時(shí),使用宏就可以用較短的有意義的標(biāo)識(shí)符來(lái)代替它,這樣編程的時(shí)候就會(huì)更方便,不容易出錯(cuò)。因此,宏定義的優(yōu)點(diǎn)就是方便和易于維護(hù)。

//例子:/求球的體積#include《stdio.h》#include《math.h》//對(duì)于半徑為 r 的球,其體積的計(jì)算公式為 V =4/3*Π*r^3 //這里取Π為3.14//這里給定r的值,求V#define PI 3.14int main(void) {

double r;

scanf(“%lf”, &r);

double sum = 0;

sum = (4.0 / 3.0) * PI*pow(r, 3);//這里用PI替換掉了 3.14

printf(“%f.2”, sum);

}

#include《stdio.h》//合例子:輸入數(shù)字查看是星期幾int main(void) {

enum week {Mon = 1, Tue, Wed, Thu, Fri, Sat, Sun}today;

//在這里我們給Mon賦值了一,后面Tue以后的都相應(yīng)加一賦值

scanf(“%d”, &today);

switch (today) {

case Mon: puts(“Monday”); break;

case Tue: puts(“Tuesday”); break;

case Wed: puts(“Wednesday”); break;

case Thu: puts(“Thursday”); break;

case Fri: puts(“Friday”); break;

case Sat: puts(“Saturday”); break;

case Sun: puts(“Sunday”); break;

default: puts(“no day”);

}

return 0;

}

2、enum枚舉枚舉型是一個(gè)集合,集合中的元素(枚舉成員)是一些命名的整型常量,元素之間用逗號(hào),隔開(kāi)。它是一種用戶定義的數(shù)據(jù)類(lèi)型,它用關(guān)鍵字enum以如下語(yǔ)法來(lái)聲明,:enum 枚舉類(lèi)型名字,{名字0,。。。,名字n};第一個(gè)枚舉成員的默認(rèn)值為整型的0,后續(xù)枚舉成員的值在前一個(gè)成員上加1 (當(dāng)然這個(gè)是可以自定義成員值的)

枚舉類(lèi)型名字通常并不真的使用,要用的是在它大括號(hào)里邊的名字,因?yàn)樗鼈兙褪浅A糠?hào),它們的類(lèi)型是int,值則是依次從零到n,如 enum week { Monday,Tuoesday,Wedenday}; 就創(chuàng)建了三個(gè)常量,Monday的值是0,Tuoesday是1,Wedenday是2,當(dāng)需要一些可以可以排列起來(lái)的常量值的時(shí)候,定義枚舉的意義就是給了這些常量名字。

雖然枚舉類(lèi)型可以當(dāng)類(lèi)型使用,但是實(shí)際上并不常用,但是如果是有意是排比名字,用枚舉比宏定義方便,枚舉比用好些,因?yàn)槊杜e有int類(lèi)型,在C 語(yǔ)言中,枚舉類(lèi)型是被當(dāng)做 int 或者 unsigned int 類(lèi)型來(lái)處理的,既然枚舉也是一種數(shù)據(jù)類(lèi)型,所以它和基本數(shù)據(jù)類(lèi)型一樣也可以對(duì)變量進(jìn)行聲明,枚舉也可以用typedef關(guān)鍵字將枚舉類(lèi)型定義成別名,并利用該別名進(jìn)行變量聲明

注意:

1、同一個(gè)程序中不能定義同名的枚舉類(lèi)型,不同的枚舉類(lèi)型中也不能存在同名的命名常量

2、枚舉成員)是「常量」而不是變量,這個(gè)一定要搞清楚,因?yàn)槊杜e成員的是常量,所以不能對(duì)它們賦值,只能將它們的值賦給其他的變量

3、枚舉類(lèi)型的定義和變量的聲明分開(kāi):如果對(duì)枚舉型的變量賦整數(shù)值時(shí),需要進(jìn)行類(lèi)型轉(zhuǎn)換

enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };//枚舉常量的值是可以在這里進(jìn)行自定義的 MON=1//基本數(shù)據(jù)類(lèi)型的賦值 :

int a, b, c;

a = 1;

b = 2;

c = 3;

//使用枚舉賦值 :

enum DAY yesterday, today, tomorrow;//枚舉定義變量

yesterday = MON;

today = TUE;

tomorrow = WED;

// today = (enum DAY) (yesterday + 1);//強(qiáng)制類(lèi)型轉(zhuǎn)換// tomorrow = (enum DAY) 30; //強(qiáng)制類(lèi)型轉(zhuǎn)換//tomorrow = 3; //錯(cuò)誤

枚舉在用switch-case結(jié)構(gòu)中使用非常方便。

//綜合例子:輸入數(shù)字查看是星期幾#include 《stdio.h》//枚舉是define的代替 它是一個(gè)集合 //和switch連用很方便int main() {

enum week { Mon = 1,Tues, Wed, Thurs, Fri, Sat, Sun } day; //day可放到這

//enum week day;定義

scanf(“%d”, &day);

switch (day) {

case Mon: puts(“Monday”); break;//1 puts代替printf輸出字符串

case Tues: puts(“Tuesday”); break;// 2

case Wed: puts(“Wednesday”); break;// 3

case Thurs: puts(“Thursday”); break;// 4

case Fri: puts(“Friday”); break;// 5

case Sat: puts(“Saturday”); break;// 6

case Sun: puts(“Sunday”); break;// 7

default: puts(“Error!”);

}

return 0;

}

枚舉型是預(yù)處理指令#define的替代,枚舉和宏其實(shí)非常類(lèi)似,宏在「預(yù)處理階段」將名字替換成對(duì)應(yīng)的值,枚舉在「編譯階段」將名字替換成對(duì)應(yīng)的值,其中一個(gè)枚舉常量的占的字節(jié)數(shù)為4個(gè)字節(jié),恰好和int類(lèi)型的變量占的字節(jié)數(shù)相同

3、struct 結(jié)構(gòu)體struct即結(jié)構(gòu)體,C程序中經(jīng)常需要用相關(guān)的不同類(lèi)型的數(shù)據(jù)來(lái)描述一個(gè)數(shù)據(jù)對(duì)象。例如,描述學(xué)生的綜合信息時(shí),需要使用學(xué)生的學(xué)號(hào)、姓名、性別等不同類(lèi)型的數(shù)據(jù)時(shí),像這種數(shù)據(jù)類(lèi)型總是在一起出現(xiàn),那么我們不如把這些變量裝入同一個(gè)“文件夾”中,這時(shí)用的關(guān)鍵字struct聲明的一種數(shù)據(jù)類(lèi)型就是表示這個(gè)“文件夾”的使用。

那么在說(shuō)明和使用之前必須先定義它,也就是構(gòu)造它。如同在說(shuō)明和調(diào)用函數(shù)之前要先定義一樣。結(jié)構(gòu)體是一種集合,它里面包含了多個(gè)變量或數(shù)組,它們的類(lèi)型可以相同,也可以不同,每個(gè)這樣的變量或數(shù)組都稱(chēng)為結(jié)構(gòu)體的成員,結(jié)構(gòu)體也是一種數(shù)據(jù)類(lèi)型,它由程序員自己定義,可以包含多個(gè)其他類(lèi)型的數(shù)據(jù),成員又稱(chēng)為成員變量,它是結(jié)構(gòu)體所包含的若干個(gè)基本的結(jié)構(gòu)類(lèi)型,必須用“{}”括起來(lái),并且要以分號(hào)結(jié)束,每個(gè)成員應(yīng)表明具體的數(shù)據(jù)類(lèi)型,成員一般用名字訪問(wèn)。

結(jié)構(gòu)體和數(shù)組類(lèi)似,也是一組數(shù)據(jù)的集合,整體使用沒(méi)有太大的意義。數(shù)組使用下標(biāo)[ ]獲訪問(wèn)元素,結(jié)構(gòu)體使用點(diǎn)號(hào)。訪問(wèn)單個(gè)成員。通過(guò)這種方式可以獲取成員的值,也可以給成員賦值

數(shù)組:a[0]=10; 結(jié)構(gòu)體:today.day (指針結(jié)構(gòu)體用-》訪問(wèn)) 結(jié)構(gòu)體的成員可以包含其他結(jié)構(gòu)體,也可以包含指向自己結(jié)構(gòu)體類(lèi)型的指針,而通常這種指針的應(yīng)用是為了實(shí)現(xiàn)一些更高級(jí)的數(shù)據(jù)結(jié)構(gòu)如鏈表和樹(shù)等。

聲明定義結(jié)構(gòu):

struct關(guān)鍵字+結(jié)構(gòu)體的標(biāo)志名+大括號(hào)里邊是成員+}后面的聲明此結(jié)構(gòu)變量+末尾分號(hào),一般有這些:

struct week{定義一 struct{定義二 struct week {定義三

int x; int x; int x;

char y; char y; int y;

}; }p1,p2;//在這里聲明變量 }p1,p2;

//p1和p2都是一種無(wú)名結(jié)構(gòu), //常用的一種結(jié)構(gòu)定義聲struct week p1,p2; // 里邊有X和y 訪問(wèn)一樣用。 明形式 //聲明變量p1,p2,里邊都是week的值 //里邊有x和y的值 //用。訪問(wèn) :p1.x p2.x

// p1.y, p2.y

對(duì)于第一和第三種形式,都聲明了結(jié)構(gòu)名week,但是第二種沒(méi)有聲明結(jié)構(gòu)名,只是定義了兩個(gè)結(jié)構(gòu)變量,

這種叫無(wú)名結(jié)構(gòu)

無(wú)名結(jié)構(gòu): 可以定義無(wú)名結(jié)構(gòu)體類(lèi)型的變量。編譯器對(duì)無(wú)名結(jié)構(gòu)體的處理是隨機(jī)生成一個(gè)不重復(fù)的變量名。

無(wú)名結(jié)構(gòu)的定義方式就是定義無(wú)名結(jié)構(gòu)體時(shí)必須定義該結(jié)構(gòu)體類(lèi)型的至少一個(gè)變量。

優(yōu)點(diǎn):無(wú)名結(jié)構(gòu)體的妙用就是可以避免相同類(lèi)型的結(jié)構(gòu)體的重復(fù)定義,

這樣可以對(duì)每一個(gè)具體類(lèi)型的隊(duì)列都可以定義一個(gè)結(jié)構(gòu)體來(lái)管理該隊(duì)列的頭尾指針,

即使定義多個(gè)相同具體類(lèi)型的隊(duì)列也不會(huì)引發(fā)重復(fù)定義的編譯錯(cuò)誤。這樣定義了兩個(gè)隊(duì)列,

其元素類(lèi)型均為int類(lèi)型,同時(shí)各得到了一個(gè)維護(hù)隊(duì)列頭尾指針的結(jié)構(gòu)體

缺點(diǎn):這里定義了一個(gè)無(wú)名的結(jié)構(gòu)體,同時(shí)聲明了三個(gè)此種類(lèi)型的變量。

但是,因?yàn)闆](méi)有名字,我們?cè)谶@句之后,無(wú)法內(nèi)再定義與那三種變量相同類(lèi)型的變量了。

除非你再容次去定義一個(gè)這樣的相同的結(jié)構(gòu)體類(lèi)型。

還有一個(gè)重要的原因就是沒(méi)有辦法在其他位置定義我們所需要的結(jié)構(gòu)體變量,

每次需要新定義結(jié)構(gòu)體變量的時(shí)候都必須要找到最開(kāi)始結(jié)構(gòu)體代碼書(shū)寫(xiě)的位置才能定義新的結(jié)構(gòu)體

所以實(shí)際編程中無(wú)名結(jié)構(gòu)并不常用

注意:1、結(jié)構(gòu)體本身并不會(huì)被作為數(shù)據(jù)而開(kāi)辟內(nèi)存,真正作為數(shù)據(jù)而在內(nèi)存中存儲(chǔ)的是這種結(jié)構(gòu)體所定義的變量。

2、先聲明結(jié)構(gòu)體類(lèi)型,再定義該類(lèi)型的變量,聲明結(jié)構(gòu)體類(lèi)型,不分配空間定義結(jié)構(gòu)體類(lèi)型變量,就要分配內(nèi)存空間

3、量使用占為少的類(lèi)型,如,在可能的時(shí)候使用short代替int,「按數(shù)據(jù)類(lèi)型本身占用的位置從大到小排」

4、除了可以對(duì)成員進(jìn)行逐一賦值,也可以在定義時(shí)整體賦值:p1={struct week}{5,10}; 相當(dāng)于 p1.x=5,p1.y=10; p1=p2 表示 p1.x=p2.x , p1.y=p2.y; 不過(guò)整體賦值僅限于定義結(jié)構(gòu)體變量的時(shí)候,在使用過(guò)程中只能對(duì)成員逐一賦值 5、結(jié)構(gòu)體變量不能相加,相減,也不能相互乘除,但結(jié)構(gòu)體可以相互賦值,也就是說(shuō),可以將一個(gè)結(jié)構(gòu)體變量賦值給另一個(gè)結(jié)構(gòu)體變量。但是前提是這兩個(gè)結(jié)構(gòu)體變量的結(jié)構(gòu)體類(lèi)型必須相同

結(jié)構(gòu)體的運(yùn)算:要訪問(wèn)整個(gè)結(jié)構(gòu),直接用結(jié)構(gòu)變量的名字,對(duì)于整個(gè)結(jié)構(gòu),可以做賦值,取地址,也可以傳遞給函數(shù)參數(shù)

結(jié)構(gòu)體數(shù)值

嵌套的結(jié)構(gòu)體:

o4YBAGCl2D6AelhmAABF_Y8c84U422.png

結(jié)構(gòu)體相互引用:

一個(gè)結(jié)構(gòu)體A中包含一個(gè)或多個(gè)與結(jié)構(gòu)體B相關(guān)的成員, 且結(jié)構(gòu)體B中也包含一個(gè)或多個(gè)與結(jié)構(gòu)體A相關(guān)的成員稱(chēng)為結(jié)構(gòu)體的互引用。 但是要注意:如果已經(jīng)定義了兩個(gè)結(jié)構(gòu)A和B ,在定義結(jié)構(gòu)體A的成員b時(shí),結(jié)構(gòu)體B對(duì)A還未可見(jiàn),故此時(shí)編譯器會(huì)報(bào)數(shù)據(jù)類(lèi)型B未定義 解決的辦法是使用不完整聲明:

strcut A;//不完整聲明

strcut B;//不完整聲明

strcut _A{ strcut _B{

int x; int x;

int y; int y;

struct _B a; struct _A b; //在結(jié)構(gòu)B中定義了一個(gè)名為b的和A結(jié)構(gòu)一樣類(lèi)型的結(jié)構(gòu)變量

//其中可以用點(diǎn)訪問(wèn) A.a.x B.b.x

}A; }B;

//但是注意這種方式犯了一個(gè)和上面第一個(gè)嵌套結(jié)構(gòu)的錯(cuò)誤,就是結(jié)構(gòu)體A和B都是直接包含了對(duì)方,

正確的用法還是使用指針:

strcut _A{ strcut _B{

int x; int x;

int y; int y;

struct _B *a; struct _A *b; //在結(jié)構(gòu)B中定義了一個(gè)名為b的和A結(jié)構(gòu)一樣類(lèi)型的結(jié)構(gòu)指針

//其中指針要用-》訪問(wèn) A.a-》x B.b-》x

}A; }B;

//但是注意這種方式犯了一個(gè)和上面第一個(gè)嵌套結(jié)構(gòu)的錯(cuò)誤,就是結(jié)構(gòu)體A和B都是直接包含了對(duì)方,正確的用法還是使用指針:

strcut _A{ strcut _B{

int x; int x;

int y; int y;

struct _B *a; struct _A *b; //在結(jié)構(gòu)B中定義了一個(gè)名為b的和A結(jié)構(gòu)一樣類(lèi)型的結(jié)構(gòu)指針

//其中指針要用-》訪問(wèn) A.a-》x B.b-》x

}A; }B;

//所以使用互引用要注意:至少有一個(gè)結(jié)構(gòu)必須在另一個(gè)結(jié)構(gòu)體中以指針的形式被引用。

結(jié)構(gòu)體函數(shù)與函數(shù)參數(shù)

結(jié)構(gòu)體做函數(shù)形參:

整個(gè)結(jié)構(gòu)可以作為參數(shù)的值傳入函數(shù),這時(shí)候是在函數(shù)內(nèi)新建一個(gè)結(jié)構(gòu)變量,并復(fù)制調(diào)用者結(jié)構(gòu)的值,也可以返回一個(gè)值,這和數(shù)組完全不同 用結(jié)構(gòu)體變量作實(shí)參時(shí),采取的也是“值傳遞”方式,將 結(jié)構(gòu)體變量所占的內(nèi)存單元的內(nèi)容(結(jié)構(gòu)體變量成員列表) 全部順序傳遞給形參,這里形參也得是結(jié)構(gòu)體變量。

#include《stdio.h》typedef struct _node {

int n;

char a[100];

}NODE;

void add(NODE a);//這種形式只是用來(lái)做值的傳遞int main(void) {

//以傳值方式傳遞結(jié)構(gòu)需要對(duì)整個(gè)結(jié)構(gòu)做一份拷貝

NODE t;

scanf(“%d %d”, &t.a[0], &t.n);//輸入1 3

printf(“1-%d %d

”,t.a[0],t.n);//輸出 1 3

add(t);

printf(“3-%d %d

”, t.a[0], t.n);//輸出1 3//也就是說(shuō)在add函數(shù)里邊做修改根本就影響不了主函數(shù)這邊的值

}

void add(NODE a) {

a.a[0] = 100;//在這里能接受到NODE結(jié)構(gòu)里邊的成員

a.n = 666;

printf(“2-%d %d

”, a.a[0], a.n);//輸出100 666

}

****//解決辦法是用指針(也是經(jīng)常用的方式):****#include《stdio.h》typedef struct _node {

int n;

char a[100];

}NODE;

int add(NODE a);//這種形式只是用來(lái)做值的傳遞int main(void) {

//以傳值方式傳遞結(jié)構(gòu)需要對(duì)整個(gè)結(jié)構(gòu)做一份拷貝

NODE t;

scanf(“%d %d”, &t.a[0], &t.n);//輸入1 3

printf(“1-%d %d

”,t.a[0],t.n);//輸出 1 3

add(&t);//這里傳進(jìn)去的是t的地址

printf(“3-%d %d

”, t.a[0], t.n);//輸出100 666//傳進(jìn)去的是地址,所以就可以達(dá)到訪問(wèn)同一個(gè)變量的操作

}

int add(NODE *) {//定義一個(gè)結(jié)構(gòu)指針

a.a[0] = 100;//在這里能接受到NODE結(jié)構(gòu)里邊的成員

a.n = 666;

printf(“2-%d %d

”, a.a[0], a.n);//輸出100 666

return a;//這里返回的是指針 所以能達(dá)到訪問(wèn)主函數(shù)里邊調(diào)用的值

//使用指針才可以用返回值

}

//常用的方式

另一種做法

結(jié)構(gòu)體做函數(shù):

/*上面的第一個(gè)的方案,把一個(gè)結(jié)構(gòu)傳入了函數(shù),然后在函數(shù)中操作,但是沒(méi)有返回回去

問(wèn)題在于傳入函數(shù)的是外面那個(gè)結(jié)構(gòu)的克隆體,而不是指針,傳入結(jié)構(gòu)和傳入數(shù)組是不同的,

解決辦法是在這個(gè)輸入函數(shù)中,在里邊創(chuàng)建一個(gè)臨時(shí)的結(jié)構(gòu)變量,然后把這個(gè)結(jié)構(gòu)返回給調(diào)用者*/#include《stdio.h》typedef struct _node {

int x;

int y;

}NODE;

struct _node add();//定義結(jié)構(gòu)類(lèi)型的函數(shù)int main(void) {

NODE a;

a.x = 0;

a.y = 0;

printf(“1-%d %d

”, a.x, a.y);// 0 0

a = add();//函數(shù)調(diào)用 /把n的值又返回到a

printf(“3-%d %d

”, a.x, a.y);//所以在這里的時(shí)候值已經(jīng)被改變

return 0;

}

struct _node add() {

NODE n;

scanf(“%d”, &n.x);//輸入1 3

scanf(“%d”, &n.y);

printf(“2-%d %d

”, n.x, n.y);//在這里的時(shí)候賦值就成功了

//return n;//把n的值帶回出去

}

//這種方法也能達(dá)到“改變“的效果,但是往往開(kāi)銷(xiāo)內(nèi)存較大,所以一般情況都是使用指針比較方便

用結(jié)構(gòu)體變量名作參數(shù),這種傳遞方式是單向的,如果在執(zhí)行被調(diào)函數(shù)期間改變了形參(也是結(jié)構(gòu)體變量)的值,該值不能返回主調(diào)函數(shù),這往往造成使用上的不便,因此一般少用這種方法。

和本地變量一樣。在函數(shù)內(nèi)部聲明的結(jié)構(gòu)只能在函數(shù)內(nèi)部使用,所以通常在函數(shù)外部聲明一個(gè)結(jié)構(gòu)類(lèi)型的,這樣就可以被多個(gè)函數(shù)所使用

//結(jié)構(gòu)做函數(shù)參數(shù)例子 (輸入今天計(jì)算明天)#include《stdio.h》#include《stdbool.h》//利用布爾數(shù)據(jù)類(lèi)型struct date {

int year;

int month;

int day;

};

bool If(struct date p);//判斷是否是閏年int number(struct date c);//判斷是否是此月最后一天int main(void) {

struct date today,tomorrow;

printf(”年-月-日

“);

scanf(”%d %d %d“, &today.year, &today.month, &today.day);

//前面兩個(gè)判斷 是否此月最后一天 是否此年此月最后一天

if (today.day==number(today)&&today.month!=12) {//首月1號(hào)

tomorrow.day = 1;

tomorrow.month =today.month+1;

tomorrow.year = today.year;

}

else if (today.day == number(today) && today.month == 12) {//下一年

tomorrow.day = 1;

tomorrow.month = 1;

tomorrow.year =today.year+1;

}

else {

tomorrow.day =today.day+1;

tomorrow.month = today.month;

tomorrow.year = today.year;

}

printf(”明天是%d-%d-%d

“, tomorrow.year, tomorrow.month, tomorrow.day);

return 0;

}

int number(struct date c)//這里的形參接收的today結(jié)構(gòu)體數(shù)據(jù)

{

int day;

const int a[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };//這個(gè)月最大的天數(shù)

if (c.month==22&&If(c)) {//查看是否是二月并且是潤(rùn)年

day = 29;//是潤(rùn)年

}

else {

day = a[c.month - 1];

}

return day;

}

bool If(struct date p) {//這里的形參接收的today結(jié)構(gòu)體數(shù)據(jù)

//潤(rùn)年的特點(diǎn),能被4整除,但不能被100整數(shù),能被100整除,但是不能被400整除

if (p.year % 4 == 0 && p.year / 100 != 0 || p.year % 400 == 0) {

return true;

}

else {

return false;

}

}

//結(jié)構(gòu)體做函數(shù)例子 (計(jì)算下一秒)#include《stdio.h》struct time {

int hour;

int minute;

int second;

};

struct time times(struct time now);//利用結(jié)構(gòu)做函數(shù)返回值,形參也是使用結(jié)構(gòu)體做為傳值int main(void) {

struct time nows[5] = {

{11,50,20},{13,25,59},{12,59,59},{23,59,59},{00,00,00},

};

int i;

for (i = 0; i 《 5; i++) {

printf(”時(shí)間是 %d:%d:%d

“, nows[i].hour, nows[i].minute, nows[i].second);

nows[i] = times(nows[i]);

printf(”下一秒是 %d:%d:%d

“, nows[i].hour, nows[i].minute, nows[i].second);

}

return 0;

}

struct time times(struct time now) {

now.second++;

if (now.second == 60) {//60秒

now.minute++;

now.second = 0;

if (now.minute == 60)//60分

{

now.hour++;

now.minute = 0;

now.second = 0;

if (now.hour == 24) {//零點(diǎn)

now.hour=0;

now.minute = 0;

now.second = 0;

}

}

}

return now;//返回類(lèi)型必須也函數(shù)類(lèi)型一致,換句話說(shuō)只有結(jié)構(gòu)體類(lèi)型才能返回結(jié)構(gòu)體類(lèi)型

}

結(jié)構(gòu)體數(shù)組

結(jié)構(gòu)體數(shù)組,是指數(shù)組中的每個(gè)元素都是一個(gè)結(jié)構(gòu)體。在實(shí)際應(yīng)用中,C語(yǔ)言結(jié)構(gòu)體數(shù)組常被用來(lái)表示一個(gè)擁有相同數(shù)據(jù)結(jié)構(gòu)的群體,比如一個(gè)班的學(xué)生、一個(gè)車(chē)間的職工等。結(jié)構(gòu)體可以存儲(chǔ)不同的數(shù)據(jù)類(lèi)型,將他們互相聯(lián)系起來(lái)。結(jié)構(gòu)體數(shù)組可以連續(xù)存儲(chǔ)多個(gè)結(jié)構(gòu)體,和數(shù)組作用相似。比如想定義同一個(gè)最小外接矩形的四個(gè)坐標(biāo)值,并給予這個(gè)矩形一個(gè)特征編號(hào)。當(dāng)需要存儲(chǔ)多個(gè)最小外接矩形的信息時(shí),就需要?jiǎng)討B(tài)申請(qǐng)一個(gè)結(jié)構(gòu)體數(shù)組

定義結(jié)構(gòu)體數(shù)組的方法很簡(jiǎn)單,同定義結(jié)構(gòu)體變量是一樣的,只不過(guò)將變量改成數(shù)組?;蛘哒f(shuō)同前面介紹的普通數(shù)組的定義是一模一樣的:struct student tp[10]; 這就定義了一個(gè)結(jié)構(gòu)體數(shù)組,共有 10 個(gè)元素,每個(gè)元素都是一個(gè)結(jié)構(gòu)體變量,都包含所有的結(jié)構(gòu)體成員。

結(jié)構(gòu)體數(shù)組的初始化與前面講的數(shù)值型數(shù)組的初始化也是一樣的,數(shù)值型數(shù)組初始化的方法和需要注意的問(wèn)題在結(jié)構(gòu)體數(shù)組的初始化中同樣適用,因?yàn)椴还苁菙?shù)值型數(shù)組還是結(jié)構(gòu)體數(shù)組都是數(shù)組。

//例子: //尋找學(xué)生中 學(xué)號(hào)最大的# include 《stdio.h》# include 《string.h》struct STU

{

char name[20];

int age;

char sex[20];

char num[20];

};

void OutputSTU(struct STU stu[]); //函數(shù)聲明, 該函數(shù)的功能是輸出成績(jī)最大的學(xué)生信息int main(void)

{

int i;

struct STU stu[5];

for (i = 0; i 《 2; ++i)

{

printf(”請(qǐng)按照名字、年齡、性別、學(xué)號(hào)(1-9數(shù)字)輸入第%d個(gè)學(xué)生的信息:“, i + 1);

scanf(”%s %d %s %s“, stu[i].name, &stu[i].age, stu[i].sex, stu[i].num);/*%c前面要加空格, 不然輸入時(shí)會(huì)將空格賦給%c*/

}

OutputSTU(stu);

return 0;

}

void OutputSTU(struct STU stu[])

{

struct STU stumax = stu[0];//讓臨時(shí)結(jié)構(gòu)stumax保存第一個(gè)學(xué)生的信息

int j;

for (j = 1; j 《 2; ++j)//第一個(gè)學(xué)生依次和后面的學(xué)生比較

{

if (strcmp(stumax.num, stu[j].num) 《 0) //strcmp函數(shù)的使用 s1》s2:1 s1《s2:-1

{

stumax = stu[j];//讓臨時(shí)結(jié)構(gòu)保存那個(gè)學(xué)生的信息

}

}

printf(”學(xué)生姓名:%s 學(xué)生年齡:%d 學(xué)生性別:%s 學(xué)生分?jǐn)?shù):%s

“, stumax.name, stumax.age, stumax.sex, stumax.num);

}

結(jié)構(gòu)體指針

和數(shù)組不同,結(jié)構(gòu)變量的名字并不是結(jié)構(gòu)變量的地址,必須使用&運(yùn)算符 strcut node *tp=&nb; 指針一般用-》訪問(wèn)結(jié)構(gòu)體里邊的成員

指針變量非常靈活方便,可以指向任一類(lèi)型的變量 ,若定義指針變量指向結(jié)構(gòu)體類(lèi)型變量,則可以通過(guò)指針來(lái)引用結(jié)構(gòu)體類(lèi)型變量。

pIYBAGCl2BmAV0cnAAAzQEAYTtk454.png

這里說(shuō)明:結(jié)構(gòu)體和結(jié)構(gòu)體變量是兩個(gè)不同的概念:結(jié)構(gòu)體是一種數(shù)據(jù)類(lèi)型,是一種創(chuàng)建變量的模板,編譯器不會(huì)為它分配內(nèi)存空間,就像 int、float、char 這些關(guān)鍵字本身不占用內(nèi)存一樣;結(jié)構(gòu)體變量才包含實(shí)實(shí)在在的數(shù)據(jù),才需要內(nèi)存來(lái)存儲(chǔ)。所以用一個(gè)結(jié)構(gòu)體去取一個(gè)結(jié)構(gòu)體名的地址,這種寫(xiě)法是錯(cuò)誤的,也不能將它賦值給其他變量。

#include《stdio.h》struct point {

int x;

int y;

};

struct point *gt(struct point*p);//結(jié)構(gòu)指針函數(shù)void print(const struct point *p);//結(jié)構(gòu)指針void out(struct point p);//普通的結(jié)構(gòu)體做函數(shù)參數(shù)int main(void) {

struct point y = { 0,0 };//以point結(jié)構(gòu)定義一個(gè)y的結(jié)構(gòu)變量

//以下三種調(diào)用 等價(jià)

//注意gt是一個(gè)結(jié)構(gòu)體的指針函數(shù)

gt(&y); //這是一個(gè)函數(shù)的返回結(jié)果函數(shù) //取y結(jié)構(gòu)的地址傳入函數(shù)

out(y);

out(*gt(&y)); // (里邊)的都是做為參數(shù) *gt(&y)做為指針?lè)祷刂?這個(gè)函數(shù)它的返回用指針表示

print(gt(&y)); //gt(&y)是一個(gè)返回值 這樣表示的是利用gt函數(shù)的返回值在print函數(shù)里邊操作

//*get(&y) = (struct point){ 1,2 }; //這也可以做的

}

struct point* gt(struct point*p) {// *p要的是&y的地址

scanf(”%d“, &p-》x);

scanf(”%d“, &p-》y);

printf(”a=%d,%d

“, p-》x, p-》y);//用-》來(lái)訪問(wèn)指針結(jié)構(gòu)里邊的成員

return p;// 用完指針后 返回指針

}

void out(struct point p) {

printf(”b=%d,%d

“, p.x, p.y);

}

void print(const struct point *p) {//加上const表示不再改動(dòng)參數(shù)

printf(”c=%d,%d

“, p-》x, p-》y);

}

指向結(jié)構(gòu)體數(shù)組的指針:

在之前講數(shù)值型數(shù)組的時(shí)候可以將數(shù)組名賦給一個(gè)指針變量,從而使該指針變量指向數(shù)組的首地址,然后用指針訪問(wèn)數(shù)組的元素。結(jié)構(gòu)體數(shù)組也是數(shù)組,所以同樣可以這么做。我們知道,結(jié)構(gòu)體數(shù)組的每一個(gè)元素都是一個(gè)結(jié)構(gòu)體變量。如果定義一個(gè)結(jié)構(gòu)體指針變量并把結(jié)構(gòu)體數(shù)組的數(shù)組名賦給這個(gè)指針變量的話,就意味著將結(jié)構(gòu)體數(shù)組的第一個(gè)元素,即第一個(gè)結(jié)構(gòu)體變量的地址,也即第一個(gè)結(jié)構(gòu)變量中的第一個(gè)成員的地址賦給了這個(gè)指針變量

o4YBAGCl1-SARSHjAACAnxuT9ns675.png

typedef 別名

typedef是在編程語(yǔ)言中用來(lái)為復(fù)雜的聲明定義簡(jiǎn)單的別名,新的名字是某種類(lèi)型的別名,這樣做改善了程序的可讀性,它與宏定義有些差異。它本身是一種存儲(chǔ)類(lèi)的關(guān)鍵字,與auto、extern、mutable、static、register等關(guān)鍵字不能出現(xiàn)在同一個(gè)表達(dá)式中。

typedef為C語(yǔ)言的關(guān)鍵字,功能是用來(lái)聲明一個(gè)已有的數(shù)據(jù)類(lèi)型的新名字,比如 typedef int last ; 這就使得last成為 int 類(lèi)型的別名 這樣last這個(gè)名字就可以代替int出現(xiàn)在變量定義和參數(shù)聲明的地方了

typedef也有一個(gè)特別的長(zhǎng)處:它符合范圍規(guī)則,使用typedef定義的變量類(lèi)型其作用范圍限制在所定義的函數(shù)或者文件內(nèi)(取決于此變量定義的位置),而宏定義則沒(méi)有這種特性。

o4YBAGCl18KAKjokAABnVDtAIhQ205.png

結(jié)構(gòu)體的內(nèi)存對(duì)齊方式(存儲(chǔ)空間)

結(jié)構(gòu)體內(nèi)存對(duì)齊:一個(gè)結(jié)構(gòu)體變量定義完之后,其在內(nèi)存中的存儲(chǔ)并不等于其所包含元素的寬度之和,元素是按照定義順序一個(gè)一個(gè)放到內(nèi)存中去的,但并不是緊密排列的。從結(jié)構(gòu)體存儲(chǔ)的首地址開(kāi)始,每個(gè)元素放置到內(nèi)存中時(shí),它都會(huì)認(rèn)為內(nèi)存是按照自己的大小來(lái)劃分的,因此元素放置的位置一定會(huì)在自己寬度的整數(shù)倍上開(kāi)始。

內(nèi)存對(duì)齊可以大大提升內(nèi)存訪問(wèn)速度,是一種用空間換時(shí)間的方法。內(nèi)存不對(duì)齊會(huì)導(dǎo)致每次讀取數(shù)據(jù)都會(huì)讀取兩次,使得內(nèi)存讀取速度減慢。

cpu把內(nèi)存當(dāng)成是一塊一塊的,塊的大小可以是2,4,8,16 個(gè)字節(jié),因此CPU在讀取內(nèi)存的時(shí)候是一塊一塊進(jìn)行讀取的,塊的大小稱(chēng)為內(nèi)存讀取粒度。

o4YBAGCl15KADz-1AACEa_O8BHg319.png

如果結(jié)構(gòu)體內(nèi)存在長(zhǎng)度大于處理器位數(shù)的元素,那么就以處理器的倍數(shù)為對(duì)齊單位;否則,如果結(jié)構(gòu)體內(nèi)的元素的長(zhǎng)度都小于處理器的倍數(shù)的時(shí)候,便以結(jié)構(gòu)體里面最長(zhǎng)的數(shù)據(jù)元素為對(duì)齊單位。

另外 結(jié)構(gòu)體的內(nèi)存地址就是它第一個(gè)成員變量的地址 isa永遠(yuǎn)都是結(jié)構(gòu)體中的第一個(gè)成員變量 所以結(jié)構(gòu)體的地址也就是其isa指針的地址

內(nèi)存對(duì)齊簡(jiǎn)介

由于內(nèi)存的讀取時(shí)間遠(yuǎn)遠(yuǎn)小于CPU的存儲(chǔ)速度,這里用設(shè)定數(shù)據(jù)結(jié)構(gòu)的對(duì)齊系數(shù),即犧牲空間來(lái)?yè)Q取時(shí)間的思想來(lái)提高CPU的存儲(chǔ)效率。

內(nèi)存對(duì)齊”應(yīng)該是編譯器的“管轄范圍”。編譯器為程序中的每個(gè)“數(shù)據(jù)單元”安排在適當(dāng)?shù)奈恢蒙?。但是C語(yǔ)言的一個(gè)特點(diǎn)就是太靈活,太強(qiáng)大,它允許你干預(yù)“內(nèi)存對(duì)齊”。如果你想了解更加底層的秘密,“內(nèi)存對(duì)齊”對(duì)你就不應(yīng)該再模糊了。這也是一個(gè)大小端模式的問(wèn)題

每個(gè)特定平臺(tái)上的編譯器都有自己的默認(rèn)“對(duì)齊系數(shù)”(也叫對(duì)齊模數(shù))。程序員可以通過(guò)預(yù)編譯命令#pragma pack(n)來(lái)改變這一系數(shù),其中的n就是你要指定的“對(duì)齊系數(shù)”。

規(guī)則:

1、數(shù)據(jù)成員對(duì)齊規(guī)則:結(jié)構(gòu)(struct)(或聯(lián)合(union))的數(shù)據(jù)成員,第一個(gè)數(shù)據(jù)成員放在offset為0的地方,以后每個(gè)數(shù)據(jù)成員的對(duì)齊「按照#pragma pack指定的數(shù)值和這個(gè)數(shù)據(jù)成員自身長(zhǎng)度中,比較小的那個(gè)進(jìn)行」。

2、結(jié)構(gòu)(或聯(lián)合)的整體對(duì)齊規(guī)則:在數(shù)據(jù)成員完成各自對(duì)齊之后,結(jié)構(gòu)(或聯(lián)合)本身也要進(jìn)行對(duì)齊,對(duì)齊將「按照#pragma pack 指定的數(shù)值和結(jié)構(gòu)(或聯(lián)合) 最大數(shù)據(jù)成員長(zhǎng)度中,比較小的那個(gè)進(jìn)行」對(duì)齊。

3、結(jié)合1、2可推斷:當(dāng)#pragma pack的n值等于或超過(guò)所有數(shù)據(jù)成員長(zhǎng)度的時(shí)候,這個(gè)n值的大小將不產(chǎn)生任何效果。

#pragma pack(n) 設(shè)定變量以n字節(jié)為對(duì)齊方式:

「作用」:指定結(jié)構(gòu)體、聯(lián)合以及類(lèi)成員

「語(yǔ)法」:#pragma pack( [show] | [push | pop] [, identifier], n )

1,pack提供數(shù)據(jù)聲明級(jí)別的控制,對(duì)定義不起作用;

2,調(diào)用pack時(shí)不指定參數(shù),n將被設(shè)成默認(rèn)值;

n:可選參數(shù);指定packing的數(shù)值,以字節(jié)為單位;缺省數(shù)值是8,合法的數(shù)值分別是1、2、4、8、16。其他參數(shù)都是可選的可先不了解

o4YBAGCl11OAEwwFAACDgimUUxY603.png

每個(gè)成員分別對(duì)齊,即每個(gè)成員按自己的方式對(duì)齊,并最小化長(zhǎng)度;規(guī)則就是每個(gè)成員按其類(lèi)型的對(duì)齊參數(shù)(通常是這個(gè)類(lèi)型的大小)和指定對(duì)齊參數(shù)中較小的一個(gè)對(duì)齊。

大小端:

如:int 11 22 33 44

在存儲(chǔ)的時(shí)候

大端:11 22 33 44

0 1 2 3

低地址----》 高地址

小端:44 33 22 11

0 1 2 3

低地址----》 高地址

大小端的差異在于存放順序不同

常見(jiàn)的操作系統(tǒng)是小端,通訊協(xié)議是大端。

//結(jié)構(gòu)體例子:使用尾插法創(chuàng)建鏈表#include《stdio.h》//單鏈表的創(chuàng)建typedef struct _node {

int nb;//數(shù)值

struct _node *nxte;//定義一個(gè)指向下一個(gè)的節(jié)點(diǎn)的指針

}NODE;

typedef struct _link{//利用這個(gè)結(jié)構(gòu)體 封裝 首尾節(jié)點(diǎn)

NODE *head;

NODE *qt;

}link;

void add(link *phead, link *qt, int n);//定義函數(shù)將 首尾指針傳入int main(void) {

link head, q;//定義一個(gè)結(jié)構(gòu),連指針都不是的

head.head = q.qt = NULL;//初始化

int n;

for (scanf(”%d“, &n); n != -1; scanf(”%d“, &n)) {

add(&head, &q, n);//將地址 值傳入

}

NODE *t;

t = head.head;//利用臨時(shí)結(jié)構(gòu)將鏈表輸出

for (; t; t = t-》nxte) {

printf(”%d “, t-》nb);

}

return 0;

}

//尾插法void add(link *phead, link *qt, int n) {

NODE *p = (NODE*)malloc(sizeof(NODE));//為新結(jié)點(diǎn)開(kāi)辟空間

p-》nb = n;

p-》nxte = NULL;

if (phead-》head == NULL) {//判斷首結(jié)點(diǎn)是否為空

phead-》head = p;//是空的就讓首結(jié)點(diǎn)等于新結(jié)點(diǎn)

}

else {//不為空時(shí),讓尾結(jié)點(diǎn)依次跑到后面去

qt-》qt-》nxte = p;

}

qt-》qt = p;

}

4、union 共用體(聯(lián)合體)在進(jìn)行某些算法的C語(yǔ)言編程的時(shí)候,需要使幾種不同類(lèi)型的變量存放到同一段內(nèi)存單元中。也就是使用覆蓋技術(shù),幾個(gè)變量互相覆蓋。這種幾個(gè)不同的變量共同占用一段內(nèi)存的結(jié)構(gòu),在C語(yǔ)言中 以關(guān)鍵字union聲明的一種數(shù)據(jù)結(jié)構(gòu),這種被稱(chēng)作“共用體”類(lèi)型結(jié)構(gòu),也叫聯(lián)合體。

“聯(lián)合”與“結(jié)構(gòu)”有一些相似之處。但兩者有本質(zhì)上的不同。在結(jié)構(gòu)中各成員有各自的內(nèi)存空間,一個(gè)結(jié)構(gòu)體變量的總長(zhǎng)度大于等于各成員長(zhǎng)度之和。而在“聯(lián)合”中,各成員共享一段內(nèi)存空間,一個(gè)聯(lián)合變量的長(zhǎng)度等于各成員中最長(zhǎng)的長(zhǎng)度。注意這里所謂的共享不是指把多個(gè)成員同時(shí)裝入一個(gè)聯(lián)合變量?jī)?nèi),而是指該聯(lián)合變量可被賦予任一成員值,但每次只能賦一種值,賦入新值則沖去舊值,共用體變量中起作用的成員是最后一次存放的成員,在存入一個(gè)新成員后,原有成員就失去作用,共用體變量的地址和它的各成員的地址都是同一地址

一個(gè)聯(lián)合類(lèi)型必須經(jīng)過(guò)定義之后,才能把變量說(shuō)明為該聯(lián)合類(lèi)型:

o4YBAGCl1xiAWJLgAABKhAO0aYY218.png

注意:1、不能把共用體變量作為函數(shù)參數(shù),也不能是函數(shù)帶回共用體變量,但可以使專(zhuān)用指向共用體變量的指針

2、所有成員占用同一段內(nèi)存,修改一制個(gè)成員會(huì)影響其余所有成員。

共用體的訪問(wèn):共用體訪問(wèn)成員的值時(shí)一般使用。運(yùn)算符,指針時(shí)用-》運(yùn)算符(和結(jié)構(gòu)體是一樣的)

typedef union _node {

int a;

double b;

char c;

union _node *p;

}NODE;

int main(void) {

NODE a;//定義變量

NODE t;

a.b;//用。訪問(wèn)

t.p-》a;//指針用-》訪問(wèn)

}

聯(lián)合的使用規(guī)則幾乎和結(jié)構(gòu)體strtct的規(guī)則用法一樣,只不過(guò)是內(nèi)部表示的不同。

補(bǔ)充:

還有一個(gè)是無(wú)名聯(lián)合體,它是和無(wú)名結(jié)構(gòu)體的工作原理是相同的

#include《stdio.h》//簡(jiǎn)單的例子#include《string.h》typedef union _node{

int a;

double b;

char c[20];

}NODE;

int main(void) {

NODE a;//這里只定義一個(gè)變量

a.a = 666;

printf(”%d

“, a.a);

a.b = 9.99;

printf(”%f

“, a.b);

strcpy(a.c, ”hello world!“);

printf(”%s

“, a.c);

//我們看到,三個(gè)都被完整的輸出了,因?yàn)樵谕粫r(shí)刻,只有一個(gè)成員是有效的

}

輸出:

6669.990000

hellow world!

共用體的作用:

1、節(jié)省內(nèi)存,有兩個(gè)很長(zhǎng)的數(shù)據(jù)結(jié)構(gòu),不會(huì)同時(shí)使用,比如一個(gè)表示老師,一個(gè)表示學(xué)生,如果要統(tǒng)計(jì)教師和學(xué)生的情況用結(jié)構(gòu)體的話就有點(diǎn)浪費(fèi)了!用結(jié)構(gòu)體的話,只占用最長(zhǎng)的那個(gè)數(shù)據(jù)結(jié)構(gòu)所占用的空間,就足夠了!

2、實(shí)現(xiàn)不同類(lèi)型數(shù)據(jù)之間的類(lèi)型轉(zhuǎn)換,遇到各種類(lèi)型的數(shù)據(jù)共用存儲(chǔ)空間,很方便的實(shí)現(xiàn)了不同數(shù)據(jù)類(lèi)型之間的轉(zhuǎn)換,不需要顯示的強(qiáng)制類(lèi)型轉(zhuǎn)換。

其他:1、確定CPU的模式:大端、小端模式確定

大小端不同,則存儲(chǔ)的方式也存在差別,比如int需要4個(gè)字節(jié),而char只需要1個(gè)字節(jié),根據(jù)1個(gè)字節(jié)所在的具體位置即可判定CPU的模式

2、寄存器的定義,實(shí)現(xiàn)整體的訪問(wèn)和單項(xiàng)的訪問(wèn)//共用體綜合例子:根據(jù)輸入的數(shù)據(jù)類(lèi)型輸出需要的相應(yīng)的數(shù)據(jù)#include《stdio.h》#include《string.h》//數(shù)據(jù)類(lèi)型輸出 5*4 m n n的第幾個(gè)x union node {

int a;

double b;

char c[30];

}add[10000];

char p[10000][30]; //保存的字符串?dāng)?shù)組int main(void) {

int n, m;

scanf(”%d %d“, &n, &m);

int x;

double y;

char t[50];

int i, j;

for (i = 0; i 《 n; i++) {//輸入

scanf(”%s“, &p[i]);//作為字符串?dāng)?shù)組,需要取地址

if (strcmp(”INT“, p[i]) == 0) {//整形

scanf(”%d“, &x);

add[i].a = x;

}

else if(strcmp(”DOUBLE“,p[i])==0){//浮點(diǎn)

scanf(”%lf“, &y);

add[i].b = y;

}

else if (strcmp(”STRCING“, p[i]) == 0) {//字符串

scanf(”%s“, t);

strcpy(add[i].c, t);

}

}

for (i = 0; i 《 m; i++) {//輸出

scanf(”%d“, &j);

if (strcmp(”INT“, p[j]) == 0) {

printf(”%d

“, add[j].a);

}

else if (strcmp(”DOUBLE“, p[j]) == 0)

{

printf(”%f

“, add[j].b);

}else if(strcmp(”STRING“,p[j])==0)

{

printf(”%s

“, add[j].c);

}

}

return 0;

}

//輸入:/*

5 4

INT 456

DOUBLE 123.56

DOUBLE 0.476

STRING welcomeToC

STRING LemonTree

0

1

2

4

*///輸出:/*

456

123.56

0.48

LemonTree

*/

編輯:jq1、define宏定義以#號(hào)開(kāi)頭的都是編譯預(yù)處理指令,它們不是C語(yǔ)言的成分,但是C程序離不開(kāi)它們,#define用來(lái)定義一個(gè)宏,程序在預(yù)處理階段將用define定義的來(lái)內(nèi)容進(jìn)行了替換。因此在程序運(yùn)行時(shí),常量表中并沒(méi)有用define定義的常量,系統(tǒng)不為它分配內(nèi)存。

define定義的常量,預(yù)處理時(shí)只是直接進(jìn)行了替換,它用來(lái)將一個(gè)標(biāo)識(shí)符定義為一個(gè)字符串,該標(biāo)識(shí)符被稱(chēng)為宏名,被定義的字符串稱(chēng)為替換文本。因此在編譯時(shí)它不對(duì)宏的定義進(jìn)行檢查,作用域不影響對(duì)常量的訪問(wèn) 。它的常量值只能是字符串或數(shù)字。

該命令有兩種格式:一種是簡(jiǎn)單的常量宏定義, 另一種是帶參數(shù)的宏定義。

不帶參數(shù)的宏:#define《 名字 》《 值 》

要注意,沒(méi)有結(jié)尾的分號(hào),因?yàn)椴皇荂的語(yǔ)句,名字必須是一個(gè)單詞,值可以是各種東西,宏定義是用宏名來(lái)表示一個(gè)字符串,在宏展開(kāi)時(shí)又以該字符串取代宏名,這只是一種簡(jiǎn)單的代換,字符串中可以含任何字符,可以是常數(shù),也可以是表達(dá)式,預(yù)處理程序?qū)λ蛔魅魏螜z查。如有錯(cuò)誤,只能在編譯已被宏展開(kāi)后的源程序時(shí)發(fā)現(xiàn)。

注意。宏定義不是說(shuō)明或語(yǔ)句,在行末不必加分號(hào),如加上分號(hào)則連分號(hào)也一起置換。宏定義其作用域?yàn)楹甓x命令起到源程序結(jié)束。如要終止其作用域可使用#undef命令

帶參數(shù)的宏 :

像函數(shù)的宏,一般的定義形式 :帶參宏定義的一般形式為:「#define 宏名」(形參表)字符串,也是沒(méi)有結(jié)尾的分號(hào),可以帶多個(gè)參數(shù) ,#define NB(a,b)((a)》(b)?(b):(a)), 也可以組合(嵌套)使用其他宏,注意 帶參數(shù)宏的原則 一切都要有括號(hào),參數(shù)出現(xiàn)的每個(gè)地方都要有括號(hào)。帶參數(shù)的宏在大型的程序的代碼中使用非常普遍,在#和##這兩個(gè)運(yùn)算符的幫助下可以很復(fù)雜,如“產(chǎn)生函數(shù)”,但是有些宏會(huì)被inline函數(shù)代替(C++的函數(shù))

使用宏好處:

“提高運(yùn)行效”。定義的標(biāo)識(shí)符不占內(nèi)存,只是一個(gè)臨時(shí)的符號(hào),預(yù)編譯后這個(gè)符號(hào)就不存在了。在簡(jiǎn)單的程序使用帶參數(shù)的宏定義可完成函數(shù)調(diào)用的功能,又能減少系統(tǒng)開(kāi)銷(xiāo),提高運(yùn)行效率。正如C語(yǔ)言中所講,函數(shù)的使用可以使程序更加模塊化,便于組織,而且可重復(fù)利用。

“方便程序的修改”。使用宏定義可以用宏代替一個(gè)在程序中經(jīng)常使用的常量。注意,是“經(jīng)?!笔褂玫摹_@樣,當(dāng)需要改變這個(gè)常量的值時(shí),就不需要對(duì)整個(gè)程序一個(gè)一個(gè)進(jìn)行修改,只需修改宏定義中的常量即可。且當(dāng)常量比較長(zhǎng)時(shí),使用宏就可以用較短的有意義的標(biāo)識(shí)符來(lái)代替它,這樣編程的時(shí)候就會(huì)更方便,不容易出錯(cuò)。因此,宏定義的優(yōu)點(diǎn)就是方便和易于維護(hù)。

//例子:/求球的體積#include《stdio.h》#include《math.h》//對(duì)于半徑為 r 的球,其體積的計(jì)算公式為 V =4/3*Π*r^3 //這里取Π為3.14//這里給定r的值,求V#define PI 3.14int main(void) {

double r;

scanf(“%lf”, &r);

double sum = 0;

sum = (4.0 / 3.0) * PI*pow(r, 3);//這里用PI替換掉了 3.14

printf(“%f.2”, sum);

}

#include《stdio.h》//合例子:輸入數(shù)字查看是星期幾int main(void) {

enum week {Mon = 1, Tue, Wed, Thu, Fri, Sat, Sun}today;

//在這里我們給Mon賦值了一,后面Tue以后的都相應(yīng)加一賦值

scanf(“%d”, &today);

switch (today) {

case Mon: puts(“Monday”); break;

case Tue: puts(“Tuesday”); break;

case Wed: puts(“Wednesday”); break;

case Thu: puts(“Thursday”); break;

case Fri: puts(“Friday”); break;

case Sat: puts(“Saturday”); break;

case Sun: puts(“Sunday”); break;

default: puts(“no day”);

}

return 0;

}

2、enum枚舉枚舉型是一個(gè)集合,集合中的元素(枚舉成員)是一些命名的整型常量,元素之間用逗號(hào),隔開(kāi)。它是一種用戶定義的數(shù)據(jù)類(lèi)型,它用關(guān)鍵字enum以如下語(yǔ)法來(lái)聲明,:enum 枚舉類(lèi)型名字,{名字0,。。。,名字n};第一個(gè)枚舉成員的默認(rèn)值為整型的0,后續(xù)枚舉成員的值在前一個(gè)成員上加1 (當(dāng)然這個(gè)是可以自定義成員值的)

枚舉類(lèi)型名字通常并不真的使用,要用的是在它大括號(hào)里邊的名字,因?yàn)樗鼈兙褪浅A糠?hào),它們的類(lèi)型是int,值則是依次從零到n,如 enum week { Monday,Tuoesday,Wedenday}; 就創(chuàng)建了三個(gè)常量,Monday的值是0,Tuoesday是1,Wedenday是2,當(dāng)需要一些可以可以排列起來(lái)的常量值的時(shí)候,定義枚舉的意義就是給了這些常量名字。

雖然枚舉類(lèi)型可以當(dāng)類(lèi)型使用,但是實(shí)際上并不常用,但是如果是有意是排比名字,用枚舉比宏定義方便,枚舉比用好些,因?yàn)槊杜e有int類(lèi)型,在C 語(yǔ)言中,枚舉類(lèi)型是被當(dāng)做 int 或者 unsigned int 類(lèi)型來(lái)處理的,既然枚舉也是一種數(shù)據(jù)類(lèi)型,所以它和基本數(shù)據(jù)類(lèi)型一樣也可以對(duì)變量進(jìn)行聲明,枚舉也可以用typedef關(guān)鍵字將枚舉類(lèi)型定義成別名,并利用該別名進(jìn)行變量聲明

注意:

1、同一個(gè)程序中不能定義同名的枚舉類(lèi)型,不同的枚舉類(lèi)型中也不能存在同名的命名常量

2、枚舉成員)是「常量」而不是變量,這個(gè)一定要搞清楚,因?yàn)槊杜e成員的是常量,所以不能對(duì)它們賦值,只能將它們的值賦給其他的變量

3、枚舉類(lèi)型的定義和變量的聲明分開(kāi):如果對(duì)枚舉型的變量賦整數(shù)值時(shí),需要進(jìn)行類(lèi)型轉(zhuǎn)換

enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };//枚舉常量的值是可以在這里進(jìn)行自定義的 MON=1//基本數(shù)據(jù)類(lèi)型的賦值 :

int a, b, c;

a = 1;

b = 2;

c = 3;

//使用枚舉賦值 :

enum DAY yesterday, today, tomorrow;//枚舉定義變量

yesterday = MON;

today = TUE;

tomorrow = WED;

// today = (enum DAY) (yesterday + 1);//強(qiáng)制類(lèi)型轉(zhuǎn)換// tomorrow = (enum DAY) 30; //強(qiáng)制類(lèi)型轉(zhuǎn)換//tomorrow = 3; //錯(cuò)誤

枚舉在用switch-case結(jié)構(gòu)中使用非常方便。

//綜合例子:輸入數(shù)字查看是星期幾#include 《stdio.h》//枚舉是define的代替 它是一個(gè)集合 //和switch連用很方便int main() {

enum week { Mon = 1,Tues, Wed, Thurs, Fri, Sat, Sun } day; //day可放到這

//enum week day;定義

scanf(“%d”, &day);

switch (day) {

case Mon: puts(“Monday”); break;//1 puts代替printf輸出字符串

case Tues: puts(“Tuesday”); break;// 2

case Wed: puts(“Wednesday”); break;// 3

case Thurs: puts(“Thursday”); break;// 4

case Fri: puts(“Friday”); break;// 5

case Sat: puts(“Saturday”); break;// 6

case Sun: puts(“Sunday”); break;// 7

default: puts(“Error!”);

}

return 0;

}

枚舉型是預(yù)處理指令#define的替代,枚舉和宏其實(shí)非常類(lèi)似,宏在「預(yù)處理階段」將名字替換成對(duì)應(yīng)的值,枚舉在「編譯階段」將名字替換成對(duì)應(yīng)的值,其中一個(gè)枚舉常量的占的字節(jié)數(shù)為4個(gè)字節(jié),恰好和int類(lèi)型的變量占的字節(jié)數(shù)相同

3、struct 結(jié)構(gòu)體struct即結(jié)構(gòu)體,C程序中經(jīng)常需要用相關(guān)的不同類(lèi)型的數(shù)據(jù)來(lái)描述一個(gè)數(shù)據(jù)對(duì)象。例如,描述學(xué)生的綜合信息時(shí),需要使用學(xué)生的學(xué)號(hào)、姓名、性別等不同類(lèi)型的數(shù)據(jù)時(shí),像這種數(shù)據(jù)類(lèi)型總是在一起出現(xiàn),那么我們不如把這些變量裝入同一個(gè)“文件夾”中,這時(shí)用的關(guān)鍵字struct聲明的一種數(shù)據(jù)類(lèi)型就是表示這個(gè)“文件夾”的使用。

那么在說(shuō)明和使用之前必須先定義它,也就是構(gòu)造它。如同在說(shuō)明和調(diào)用函數(shù)之前要先定義一樣。結(jié)構(gòu)體是一種集合,它里面包含了多個(gè)變量或數(shù)組,它們的類(lèi)型可以相同,也可以不同,每個(gè)這樣的變量或數(shù)組都稱(chēng)為結(jié)構(gòu)體的成員,結(jié)構(gòu)體也是一種數(shù)據(jù)類(lèi)型,它由程序員自己定義,可以包含多個(gè)其他類(lèi)型的數(shù)據(jù),成員又稱(chēng)為成員變量,它是結(jié)構(gòu)體所包含的若干個(gè)基本的結(jié)構(gòu)類(lèi)型,必須用“{}”括起來(lái),并且要以分號(hào)結(jié)束,每個(gè)成員應(yīng)表明具體的數(shù)據(jù)類(lèi)型,成員一般用名字訪問(wèn)。

結(jié)構(gòu)體和數(shù)組類(lèi)似,也是一組數(shù)據(jù)的集合,整體使用沒(méi)有太大的意義。數(shù)組使用下標(biāo)[ ]獲訪問(wèn)元素,結(jié)構(gòu)體使用點(diǎn)號(hào)。訪問(wèn)單個(gè)成員。通過(guò)這種方式可以獲取成員的值,也可以給成員賦值

數(shù)組:a[0]=10; 結(jié)構(gòu)體:today.day (指針結(jié)構(gòu)體用-》訪問(wèn)) 結(jié)構(gòu)體的成員可以包含其他結(jié)構(gòu)體,也可以包含指向自己結(jié)構(gòu)體類(lèi)型的指針,而通常這種指針的應(yīng)用是為了實(shí)現(xiàn)一些更高級(jí)的數(shù)據(jù)結(jié)構(gòu)如鏈表和樹(shù)等。

聲明定義結(jié)構(gòu):

struct關(guān)鍵字+結(jié)構(gòu)體的標(biāo)志名+大括號(hào)里邊是成員+}后面的聲明此結(jié)構(gòu)變量+末尾分號(hào),一般有這些:

struct week{定義一 struct{定義二 struct week {定義三

int x; int x; int x;

char y; char y; int y;

}; }p1,p2;//在這里聲明變量 }p1,p2;

//p1和p2都是一種無(wú)名結(jié)構(gòu), //常用的一種結(jié)構(gòu)定義聲struct week p1,p2; // 里邊有X和y 訪問(wèn)一樣用。 明形式 //聲明變量p1,p2,里邊都是week的值 //里邊有x和y的值 //用。訪問(wèn) :p1.x p2.x

// p1.y, p2.y

對(duì)于第一和第三種形式,都聲明了結(jié)構(gòu)名week,但是第二種沒(méi)有聲明結(jié)構(gòu)名,只是定義了兩個(gè)結(jié)構(gòu)變量,

這種叫無(wú)名結(jié)構(gòu)

無(wú)名結(jié)構(gòu): 可以定義無(wú)名結(jié)構(gòu)體類(lèi)型的變量。編譯器對(duì)無(wú)名結(jié)構(gòu)體的處理是隨機(jī)生成一個(gè)不重復(fù)的變量名。

無(wú)名結(jié)構(gòu)的定義方式就是定義無(wú)名結(jié)構(gòu)體時(shí)必須定義該結(jié)構(gòu)體類(lèi)型的至少一個(gè)變量。

優(yōu)點(diǎn):無(wú)名結(jié)構(gòu)體的妙用就是可以避免相同類(lèi)型的結(jié)構(gòu)體的重復(fù)定義,

這樣可以對(duì)每一個(gè)具體類(lèi)型的隊(duì)列都可以定義一個(gè)結(jié)構(gòu)體來(lái)管理該隊(duì)列的頭尾指針,

即使定義多個(gè)相同具體類(lèi)型的隊(duì)列也不會(huì)引發(fā)重復(fù)定義的編譯錯(cuò)誤。這樣定義了兩個(gè)隊(duì)列,

其元素類(lèi)型均為int類(lèi)型,同時(shí)各得到了一個(gè)維護(hù)隊(duì)列頭尾指針的結(jié)構(gòu)體

缺點(diǎn):這里定義了一個(gè)無(wú)名的結(jié)構(gòu)體,同時(shí)聲明了三個(gè)此種類(lèi)型的變量。

但是,因?yàn)闆](méi)有名字,我們?cè)谶@句之后,無(wú)法內(nèi)再定義與那三種變量相同類(lèi)型的變量了。

除非你再容次去定義一個(gè)這樣的相同的結(jié)構(gòu)體類(lèi)型。

還有一個(gè)重要的原因就是沒(méi)有辦法在其他位置定義我們所需要的結(jié)構(gòu)體變量,

每次需要新定義結(jié)構(gòu)體變量的時(shí)候都必須要找到最開(kāi)始結(jié)構(gòu)體代碼書(shū)寫(xiě)的位置才能定義新的結(jié)構(gòu)體

所以實(shí)際編程中無(wú)名結(jié)構(gòu)并不常用

注意:1、結(jié)構(gòu)體本身并不會(huì)被作為數(shù)據(jù)而開(kāi)辟內(nèi)存,真正作為數(shù)據(jù)而在內(nèi)存中存儲(chǔ)的是這種結(jié)構(gòu)體所定義的變量。

2、先聲明結(jié)構(gòu)體類(lèi)型,再定義該類(lèi)型的變量,聲明結(jié)構(gòu)體類(lèi)型,不分配空間定義結(jié)構(gòu)體類(lèi)型變量,就要分配內(nèi)存空間

3、量使用占為少的類(lèi)型,如,在可能的時(shí)候使用short代替int,「按數(shù)據(jù)類(lèi)型本身占用的位置從大到小排」

4、除了可以對(duì)成員進(jìn)行逐一賦值,也可以在定義時(shí)整體賦值:p1={struct week}{5,10}; 相當(dāng)于 p1.x=5,p1.y=10; p1=p2 表示 p1.x=p2.x , p1.y=p2.y; 不過(guò)整體賦值僅限于定義結(jié)構(gòu)體變量的時(shí)候,在使用過(guò)程中只能對(duì)成員逐一賦值 5、結(jié)構(gòu)體變量不能相加,相減,也不能相互乘除,但結(jié)構(gòu)體可以相互賦值,也就是說(shuō),可以將一個(gè)結(jié)構(gòu)體變量賦值給另一個(gè)結(jié)構(gòu)體變量。但是前提是這兩個(gè)結(jié)構(gòu)體變量的結(jié)構(gòu)體類(lèi)型必須相同

結(jié)構(gòu)體的運(yùn)算:要訪問(wèn)整個(gè)結(jié)構(gòu),直接用結(jié)構(gòu)變量的名字,對(duì)于整個(gè)結(jié)構(gòu),可以做賦值,取地址,也可以傳遞給函數(shù)參數(shù)

結(jié)構(gòu)體數(shù)值

嵌套的結(jié)構(gòu)體:

o4YBAGCl2D6AelhmAABF_Y8c84U422.png

結(jié)構(gòu)體相互引用:

一個(gè)結(jié)構(gòu)體A中包含一個(gè)或多個(gè)與結(jié)構(gòu)體B相關(guān)的成員, 且結(jié)構(gòu)體B中也包含一個(gè)或多個(gè)與結(jié)構(gòu)體A相關(guān)的成員稱(chēng)為結(jié)構(gòu)體的互引用。 但是要注意:如果已經(jīng)定義了兩個(gè)結(jié)構(gòu)A和B ,在定義結(jié)構(gòu)體A的成員b時(shí),結(jié)構(gòu)體B對(duì)A還未可見(jiàn),故此時(shí)編譯器會(huì)報(bào)數(shù)據(jù)類(lèi)型B未定義 解決的辦法是使用不完整聲明:

strcut A;//不完整聲明

strcut B;//不完整聲明

strcut _A{ strcut _B{

int x; int x;

int y; int y;

struct _B a; struct _A b; //在結(jié)構(gòu)B中定義了一個(gè)名為b的和A結(jié)構(gòu)一樣類(lèi)型的結(jié)構(gòu)變量

//其中可以用點(diǎn)訪問(wèn) A.a.x B.b.x

}A; }B;

//但是注意這種方式犯了一個(gè)和上面第一個(gè)嵌套結(jié)構(gòu)的錯(cuò)誤,就是結(jié)構(gòu)體A和B都是直接包含了對(duì)方,

正確的用法還是使用指針:

strcut _A{ strcut _B{

int x; int x;

int y; int y;

struct _B *a; struct _A *b; //在結(jié)構(gòu)B中定義了一個(gè)名為b的和A結(jié)構(gòu)一樣類(lèi)型的結(jié)構(gòu)指針

//其中指針要用-》訪問(wèn) A.a-》x B.b-》x

}A; }B;

//但是注意這種方式犯了一個(gè)和上面第一個(gè)嵌套結(jié)構(gòu)的錯(cuò)誤,就是結(jié)構(gòu)體A和B都是直接包含了對(duì)方,正確的用法還是使用指針:

strcut _A{ strcut _B{

int x; int x;

int y; int y;

struct _B *a; struct _A *b; //在結(jié)構(gòu)B中定義了一個(gè)名為b的和A結(jié)構(gòu)一樣類(lèi)型的結(jié)構(gòu)指針

//其中指針要用-》訪問(wèn) A.a-》x B.b-》x

}A; }B;

//所以使用互引用要注意:至少有一個(gè)結(jié)構(gòu)必須在另一個(gè)結(jié)構(gòu)體中以指針的形式被引用。

結(jié)構(gòu)體函數(shù)與函數(shù)參數(shù)

結(jié)構(gòu)體做函數(shù)形參:

整個(gè)結(jié)構(gòu)可以作為參數(shù)的值傳入函數(shù),這時(shí)候是在函數(shù)內(nèi)新建一個(gè)結(jié)構(gòu)變量,并復(fù)制調(diào)用者結(jié)構(gòu)的值,也可以返回一個(gè)值,這和數(shù)組完全不同 用結(jié)構(gòu)體變量作實(shí)參時(shí),采取的也是“值傳遞”方式,將 結(jié)構(gòu)體變量所占的內(nèi)存單元的內(nèi)容(結(jié)構(gòu)體變量成員列表) 全部順序傳遞給形參,這里形參也得是結(jié)構(gòu)體變量。

#include《stdio.h》typedef struct _node {

int n;

char a[100];

}NODE;

void add(NODE a);//這種形式只是用來(lái)做值的傳遞int main(void) {

//以傳值方式傳遞結(jié)構(gòu)需要對(duì)整個(gè)結(jié)構(gòu)做一份拷貝

NODE t;

scanf(“%d %d”, &t.a[0], &t.n);//輸入1 3

printf(“1-%d %d

”,t.a[0],t.n);//輸出 1 3

add(t);

printf(“3-%d %d

”, t.a[0], t.n);//輸出1 3//也就是說(shuō)在add函數(shù)里邊做修改根本就影響不了主函數(shù)這邊的值

}

void add(NODE a) {

a.a[0] = 100;//在這里能接受到NODE結(jié)構(gòu)里邊的成員

a.n = 666;

printf(“2-%d %d

”, a.a[0], a.n);//輸出100 666

}

****//解決辦法是用指針(也是經(jīng)常用的方式):****#include《stdio.h》typedef struct _node {

int n;

char a[100];

}NODE;

int add(NODE a);//這種形式只是用來(lái)做值的傳遞int main(void) {

//以傳值方式傳遞結(jié)構(gòu)需要對(duì)整個(gè)結(jié)構(gòu)做一份拷貝

NODE t;

scanf(“%d %d”, &t.a[0], &t.n);//輸入1 3

printf(“1-%d %d

”,t.a[0],t.n);//輸出 1 3

add(&t);//這里傳進(jìn)去的是t的地址

printf(“3-%d %d

”, t.a[0], t.n);//輸出100 666//傳進(jìn)去的是地址,所以就可以達(dá)到訪問(wèn)同一個(gè)變量的操作

}

int add(NODE *) {//定義一個(gè)結(jié)構(gòu)指針

a.a[0] = 100;//在這里能接受到NODE結(jié)構(gòu)里邊的成員

a.n = 666;

printf(“2-%d %d

”, a.a[0], a.n);//輸出100 666

return a;//這里返回的是指針 所以能達(dá)到訪問(wèn)主函數(shù)里邊調(diào)用的值

//使用指針才可以用返回值

}

//常用的方式

另一種做法

結(jié)構(gòu)體做函數(shù):

/*上面的第一個(gè)的方案,把一個(gè)結(jié)構(gòu)傳入了函數(shù),然后在函數(shù)中操作,但是沒(méi)有返回回去

問(wèn)題在于傳入函數(shù)的是外面那個(gè)結(jié)構(gòu)的克隆體,而不是指針,傳入結(jié)構(gòu)和傳入數(shù)組是不同的,

解決辦法是在這個(gè)輸入函數(shù)中,在里邊創(chuàng)建一個(gè)臨時(shí)的結(jié)構(gòu)變量,然后把這個(gè)結(jié)構(gòu)返回給調(diào)用者*/#include《stdio.h》typedef struct _node {

int x;

int y;

}NODE;

struct _node add();//定義結(jié)構(gòu)類(lèi)型的函數(shù)int main(void) {

NODE a;

a.x = 0;

a.y = 0;

printf(“1-%d %d

”, a.x, a.y);// 0 0

a = add();//函數(shù)調(diào)用 /把n的值又返回到a

printf(“3-%d %d

”, a.x, a.y);//所以在這里的時(shí)候值已經(jīng)被改變

return 0;

}

struct _node add() {

NODE n;

scanf(“%d”, &n.x);//輸入1 3

scanf(“%d”, &n.y);

printf(“2-%d %d

”, n.x, n.y);//在這里的時(shí)候賦值就成功了

//return n;//把n的值帶回出去

}

//這種方法也能達(dá)到“改變“的效果,但是往往開(kāi)銷(xiāo)內(nèi)存較大,所以一般情況都是使用指針比較方便

用結(jié)構(gòu)體變量名作參數(shù),這種傳遞方式是單向的,如果在執(zhí)行被調(diào)函數(shù)期間改變了形參(也是結(jié)構(gòu)體變量)的值,該值不能返回主調(diào)函數(shù),這往往造成使用上的不便,因此一般少用這種方法。

和本地變量一樣。在函數(shù)內(nèi)部聲明的結(jié)構(gòu)只能在函數(shù)內(nèi)部使用,所以通常在函數(shù)外部聲明一個(gè)結(jié)構(gòu)類(lèi)型的,這樣就可以被多個(gè)函數(shù)所使用

//結(jié)構(gòu)做函數(shù)參數(shù)例子 (輸入今天計(jì)算明天)#include《stdio.h》#include《stdbool.h》//利用布爾數(shù)據(jù)類(lèi)型struct date {

int year;

int month;

int day;

};

bool If(struct date p);//判斷是否是閏年int number(struct date c);//判斷是否是此月最后一天int main(void) {

struct date today,tomorrow;

printf(”年-月-日

“);

scanf(”%d %d %d“, &today.year, &today.month, &today.day);

//前面兩個(gè)判斷 是否此月最后一天 是否此年此月最后一天

if (today.day==number(today)&&today.month!=12) {//首月1號(hào)

tomorrow.day = 1;

tomorrow.month =today.month+1;

tomorrow.year = today.year;

}

else if (today.day == number(today) && today.month == 12) {//下一年

tomorrow.day = 1;

tomorrow.month = 1;

tomorrow.year =today.year+1;

}

else {

tomorrow.day =today.day+1;

tomorrow.month = today.month;

tomorrow.year = today.year;

}

printf(”明天是%d-%d-%d

“, tomorrow.year, tomorrow.month, tomorrow.day);

return 0;

}

int number(struct date c)//這里的形參接收的today結(jié)構(gòu)體數(shù)據(jù)

{

int day;

const int a[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };//這個(gè)月最大的天數(shù)

if (c.month==22&&If(c)) {//查看是否是二月并且是潤(rùn)年

day = 29;//是潤(rùn)年

}

else {

day = a[c.month - 1];

}

return day;

}

bool If(struct date p) {//這里的形參接收的today結(jié)構(gòu)體數(shù)據(jù)

//潤(rùn)年的特點(diǎn),能被4整除,但不能被100整數(shù),能被100整除,但是不能被400整除

if (p.year % 4 == 0 && p.year / 100 != 0 || p.year % 400 == 0) {

return true;

}

else {

return false;

}

}

//結(jié)構(gòu)體做函數(shù)例子 (計(jì)算下一秒)#include《stdio.h》struct time {

int hour;

int minute;

int second;

};

struct time times(struct time now);//利用結(jié)構(gòu)做函數(shù)返回值,形參也是使用結(jié)構(gòu)體做為傳值int main(void) {

struct time nows[5] = {

{11,50,20},{13,25,59},{12,59,59},{23,59,59},{00,00,00},

};

int i;

for (i = 0; i 《 5; i++) {

printf(”時(shí)間是 %d:%d:%d

“, nows[i].hour, nows[i].minute, nows[i].second);

nows[i] = times(nows[i]);

printf(”下一秒是 %d:%d:%d

“, nows[i].hour, nows[i].minute, nows[i].second);

}

return 0;

}

struct time times(struct time now) {

now.second++;

if (now.second == 60) {//60秒

now.minute++;

now.second = 0;

if (now.minute == 60)//60分

{

now.hour++;

now.minute = 0;

now.second = 0;

if (now.hour == 24) {//零點(diǎn)

now.hour=0;

now.minute = 0;

now.second = 0;

}

}

}

return now;//返回類(lèi)型必須也函數(shù)類(lèi)型一致,換句話說(shuō)只有結(jié)構(gòu)體類(lèi)型才能返回結(jié)構(gòu)體類(lèi)型

}

結(jié)構(gòu)體數(shù)組

結(jié)構(gòu)體數(shù)組,是指數(shù)組中的每個(gè)元素都是一個(gè)結(jié)構(gòu)體。在實(shí)際應(yīng)用中,C語(yǔ)言結(jié)構(gòu)體數(shù)組常被用來(lái)表示一個(gè)擁有相同數(shù)據(jù)結(jié)構(gòu)的群體,比如一個(gè)班的學(xué)生、一個(gè)車(chē)間的職工等。結(jié)構(gòu)體可以存儲(chǔ)不同的數(shù)據(jù)類(lèi)型,將他們互相聯(lián)系起來(lái)。結(jié)構(gòu)體數(shù)組可以連續(xù)存儲(chǔ)多個(gè)結(jié)構(gòu)體,和數(shù)組作用相似。比如想定義同一個(gè)最小外接矩形的四個(gè)坐標(biāo)值,并給予這個(gè)矩形一個(gè)特征編號(hào)。當(dāng)需要存儲(chǔ)多個(gè)最小外接矩形的信息時(shí),就需要?jiǎng)討B(tài)申請(qǐng)一個(gè)結(jié)構(gòu)體數(shù)組

定義結(jié)構(gòu)體數(shù)組的方法很簡(jiǎn)單,同定義結(jié)構(gòu)體變量是一樣的,只不過(guò)將變量改成數(shù)組?;蛘哒f(shuō)同前面介紹的普通數(shù)組的定義是一模一樣的:struct student tp[10]; 這就定義了一個(gè)結(jié)構(gòu)體數(shù)組,共有 10 個(gè)元素,每個(gè)元素都是一個(gè)結(jié)構(gòu)體變量,都包含所有的結(jié)構(gòu)體成員。

結(jié)構(gòu)體數(shù)組的初始化與前面講的數(shù)值型數(shù)組的初始化也是一樣的,數(shù)值型數(shù)組初始化的方法和需要注意的問(wèn)題在結(jié)構(gòu)體數(shù)組的初始化中同樣適用,因?yàn)椴还苁菙?shù)值型數(shù)組還是結(jié)構(gòu)體數(shù)組都是數(shù)組。

//例子: //尋找學(xué)生中 學(xué)號(hào)最大的# include 《stdio.h》# include 《string.h》struct STU

{

char name[20];

int age;

char sex[20];

char num[20];

};

void OutputSTU(struct STU stu[]); //函數(shù)聲明, 該函數(shù)的功能是輸出成績(jī)最大的學(xué)生信息int main(void)

{

int i;

struct STU stu[5];

for (i = 0; i 《 2; ++i)

{

printf(”請(qǐng)按照名字、年齡、性別、學(xué)號(hào)(1-9數(shù)字)輸入第%d個(gè)學(xué)生的信息:“, i + 1);

scanf(”%s %d %s %s“, stu[i].name, &stu[i].age, stu[i].sex, stu[i].num);/*%c前面要加空格, 不然輸入時(shí)會(huì)將空格賦給%c*/

}

OutputSTU(stu);

return 0;

}

void OutputSTU(struct STU stu[])

{

struct STU stumax = stu[0];//讓臨時(shí)結(jié)構(gòu)stumax保存第一個(gè)學(xué)生的信息

int j;

for (j = 1; j 《 2; ++j)//第一個(gè)學(xué)生依次和后面的學(xué)生比較

{

if (strcmp(stumax.num, stu[j].num) 《 0) //strcmp函數(shù)的使用 s1》s2:1 s1《s2:-1

{

stumax = stu[j];//讓臨時(shí)結(jié)構(gòu)保存那個(gè)學(xué)生的信息

}

}

printf(”學(xué)生姓名:%s 學(xué)生年齡:%d 學(xué)生性別:%s 學(xué)生分?jǐn)?shù):%s

“, stumax.name, stumax.age, stumax.sex, stumax.num);

}

結(jié)構(gòu)體指針

和數(shù)組不同,結(jié)構(gòu)變量的名字并不是結(jié)構(gòu)變量的地址,必須使用&運(yùn)算符 strcut node *tp=&nb; 指針一般用-》訪問(wèn)結(jié)構(gòu)體里邊的成員

指針變量非常靈活方便,可以指向任一類(lèi)型的變量 ,若定義指針變量指向結(jié)構(gòu)體類(lèi)型變量,則可以通過(guò)指針來(lái)引用結(jié)構(gòu)體類(lèi)型變量。

pIYBAGCl2BmAV0cnAAAzQEAYTtk454.png

這里說(shuō)明:結(jié)構(gòu)體和結(jié)構(gòu)體變量是兩個(gè)不同的概念:結(jié)構(gòu)體是一種數(shù)據(jù)類(lèi)型,是一種創(chuàng)建變量的模板,編譯器不會(huì)為它分配內(nèi)存空間,就像 int、float、char 這些關(guān)鍵字本身不占用內(nèi)存一樣;結(jié)構(gòu)體變量才包含實(shí)實(shí)在在的數(shù)據(jù),才需要內(nèi)存來(lái)存儲(chǔ)。所以用一個(gè)結(jié)構(gòu)體去取一個(gè)結(jié)構(gòu)體名的地址,這種寫(xiě)法是錯(cuò)誤的,也不能將它賦值給其他變量。

#include《stdio.h》struct point {

int x;

int y;

};

struct point *gt(struct point*p);//結(jié)構(gòu)指針函數(shù)void print(const struct point *p);//結(jié)構(gòu)指針void out(struct point p);//普通的結(jié)構(gòu)體做函數(shù)參數(shù)int main(void) {

struct point y = { 0,0 };//以point結(jié)構(gòu)定義一個(gè)y的結(jié)構(gòu)變量

//以下三種調(diào)用 等價(jià)

//注意gt是一個(gè)結(jié)構(gòu)體的指針函數(shù)

gt(&y); //這是一個(gè)函數(shù)的返回結(jié)果函數(shù) //取y結(jié)構(gòu)的地址傳入函數(shù)

out(y);

out(*gt(&y)); // (里邊)的都是做為參數(shù) *gt(&y)做為指針?lè)祷刂?這個(gè)函數(shù)它的返回用指針表示

print(gt(&y)); //gt(&y)是一個(gè)返回值 這樣表示的是利用gt函數(shù)的返回值在print函數(shù)里邊操作

//*get(&y) = (struct point){ 1,2 }; //這也可以做的

}

struct point* gt(struct point*p) {// *p要的是&y的地址

scanf(”%d“, &p-》x);

scanf(”%d“, &p-》y);

printf(”a=%d,%d

“, p-》x, p-》y);//用-》來(lái)訪問(wèn)指針結(jié)構(gòu)里邊的成員

return p;// 用完指針后 返回指針

}

void out(struct point p) {

printf(”b=%d,%d

“, p.x, p.y);

}

void print(const struct point *p) {//加上const表示不再改動(dòng)參數(shù)

printf(”c=%d,%d

“, p-》x, p-》y);

}

指向結(jié)構(gòu)體數(shù)組的指針:

在之前講數(shù)值型數(shù)組的時(shí)候可以將數(shù)組名賦給一個(gè)指針變量,從而使該指針變量指向數(shù)組的首地址,然后用指針訪問(wèn)數(shù)組的元素。結(jié)構(gòu)體數(shù)組也是數(shù)組,所以同樣可以這么做。我們知道,結(jié)構(gòu)體數(shù)組的每一個(gè)元素都是一個(gè)結(jié)構(gòu)體變量。如果定義一個(gè)結(jié)構(gòu)體指針變量并把結(jié)構(gòu)體數(shù)組的數(shù)組名賦給這個(gè)指針變量的話,就意味著將結(jié)構(gòu)體數(shù)組的第一個(gè)元素,即第一個(gè)結(jié)構(gòu)體變量的地址,也即第一個(gè)結(jié)構(gòu)變量中的第一個(gè)成員的地址賦給了這個(gè)指針變量

o4YBAGCl1-SARSHjAACAnxuT9ns675.png

typedef 別名

typedef是在編程語(yǔ)言中用來(lái)為復(fù)雜的聲明定義簡(jiǎn)單的別名,新的名字是某種類(lèi)型的別名,這樣做改善了程序的可讀性,它與宏定義有些差異。它本身是一種存儲(chǔ)類(lèi)的關(guān)鍵字,與auto、extern、mutable、static、register等關(guān)鍵字不能出現(xiàn)在同一個(gè)表達(dá)式中。

typedef為C語(yǔ)言的關(guān)鍵字,功能是用來(lái)聲明一個(gè)已有的數(shù)據(jù)類(lèi)型的新名字,比如 typedef int last ; 這就使得last成為 int 類(lèi)型的別名 這樣last這個(gè)名字就可以代替int出現(xiàn)在變量定義和參數(shù)聲明的地方了

typedef也有一個(gè)特別的長(zhǎng)處:它符合范圍規(guī)則,使用typedef定義的變量類(lèi)型其作用范圍限制在所定義的函數(shù)或者文件內(nèi)(取決于此變量定義的位置),而宏定義則沒(méi)有這種特性。

o4YBAGCl18KAKjokAABnVDtAIhQ205.png

結(jié)構(gòu)體的內(nèi)存對(duì)齊方式(存儲(chǔ)空間)

結(jié)構(gòu)體內(nèi)存對(duì)齊:一個(gè)結(jié)構(gòu)體變量定義完之后,其在內(nèi)存中的存儲(chǔ)并不等于其所包含元素的寬度之和,元素是按照定義順序一個(gè)一個(gè)放到內(nèi)存中去的,但并不是緊密排列的。從結(jié)構(gòu)體存儲(chǔ)的首地址開(kāi)始,每個(gè)元素放置到內(nèi)存中時(shí),它都會(huì)認(rèn)為內(nèi)存是按照自己的大小來(lái)劃分的,因此元素放置的位置一定會(huì)在自己寬度的整數(shù)倍上開(kāi)始。

內(nèi)存對(duì)齊可以大大提升內(nèi)存訪問(wèn)速度,是一種用空間換時(shí)間的方法。內(nèi)存不對(duì)齊會(huì)導(dǎo)致每次讀取數(shù)據(jù)都會(huì)讀取兩次,使得內(nèi)存讀取速度減慢。

cpu把內(nèi)存當(dāng)成是一塊一塊的,塊的大小可以是2,4,8,16 個(gè)字節(jié),因此CPU在讀取內(nèi)存的時(shí)候是一塊一塊進(jìn)行讀取的,塊的大小稱(chēng)為內(nèi)存讀取粒度。

o4YBAGCl15KADz-1AACEa_O8BHg319.png

如果結(jié)構(gòu)體內(nèi)存在長(zhǎng)度大于處理器位數(shù)的元素,那么就以處理器的倍數(shù)為對(duì)齊單位;否則,如果結(jié)構(gòu)體內(nèi)的元素的長(zhǎng)度都小于處理器的倍數(shù)的時(shí)候,便以結(jié)構(gòu)體里面最長(zhǎng)的數(shù)據(jù)元素為對(duì)齊單位。

另外 結(jié)構(gòu)體的內(nèi)存地址就是它第一個(gè)成員變量的地址 isa永遠(yuǎn)都是結(jié)構(gòu)體中的第一個(gè)成員變量 所以結(jié)構(gòu)體的地址也就是其isa指針的地址

內(nèi)存對(duì)齊簡(jiǎn)介

由于內(nèi)存的讀取時(shí)間遠(yuǎn)遠(yuǎn)小于CPU的存儲(chǔ)速度,這里用設(shè)定數(shù)據(jù)結(jié)構(gòu)的對(duì)齊系數(shù),即犧牲空間來(lái)?yè)Q取時(shí)間的思想來(lái)提高CPU的存儲(chǔ)效率。

內(nèi)存對(duì)齊”應(yīng)該是編譯器的“管轄范圍”。編譯器為程序中的每個(gè)“數(shù)據(jù)單元”安排在適當(dāng)?shù)奈恢蒙?。但是C語(yǔ)言的一個(gè)特點(diǎn)就是太靈活,太強(qiáng)大,它允許你干預(yù)“內(nèi)存對(duì)齊”。如果你想了解更加底層的秘密,“內(nèi)存對(duì)齊”對(duì)你就不應(yīng)該再模糊了。這也是一個(gè)大小端模式的問(wèn)題

每個(gè)特定平臺(tái)上的編譯器都有自己的默認(rèn)“對(duì)齊系數(shù)”(也叫對(duì)齊模數(shù))。程序員可以通過(guò)預(yù)編譯命令#pragma pack(n)來(lái)改變這一系數(shù),其中的n就是你要指定的“對(duì)齊系數(shù)”。

規(guī)則:

1、數(shù)據(jù)成員對(duì)齊規(guī)則:結(jié)構(gòu)(struct)(或聯(lián)合(union))的數(shù)據(jù)成員,第一個(gè)數(shù)據(jù)成員放在offset為0的地方,以后每個(gè)數(shù)據(jù)成員的對(duì)齊「按照#pragma pack指定的數(shù)值和這個(gè)數(shù)據(jù)成員自身長(zhǎng)度中,比較小的那個(gè)進(jìn)行」。

2、結(jié)構(gòu)(或聯(lián)合)的整體對(duì)齊規(guī)則:在數(shù)據(jù)成員完成各自對(duì)齊之后,結(jié)構(gòu)(或聯(lián)合)本身也要進(jìn)行對(duì)齊,對(duì)齊將「按照#pragma pack 指定的數(shù)值和結(jié)構(gòu)(或聯(lián)合) 最大數(shù)據(jù)成員長(zhǎng)度中,比較小的那個(gè)進(jìn)行」對(duì)齊。

3、結(jié)合1、2可推斷:當(dāng)#pragma pack的n值等于或超過(guò)所有數(shù)據(jù)成員長(zhǎng)度的時(shí)候,這個(gè)n值的大小將不產(chǎn)生任何效果。

#pragma pack(n) 設(shè)定變量以n字節(jié)為對(duì)齊方式:

「作用」:指定結(jié)構(gòu)體、聯(lián)合以及類(lèi)成員

「語(yǔ)法」:#pragma pack( [show] | [push | pop] [, identifier], n )

1,pack提供數(shù)據(jù)聲明級(jí)別的控制,對(duì)定義不起作用;

2,調(diào)用pack時(shí)不指定參數(shù),n將被設(shè)成默認(rèn)值;

n:可選參數(shù);指定packing的數(shù)值,以字節(jié)為單位;缺省數(shù)值是8,合法的數(shù)值分別是1、2、4、8、16。其他參數(shù)都是可選的可先不了解

o4YBAGCl11OAEwwFAACDgimUUxY603.png

每個(gè)成員分別對(duì)齊,即每個(gè)成員按自己的方式對(duì)齊,并最小化長(zhǎng)度;規(guī)則就是每個(gè)成員按其類(lèi)型的對(duì)齊參數(shù)(通常是這個(gè)類(lèi)型的大?。┖椭付▽?duì)齊參數(shù)中較小的一個(gè)對(duì)齊。

大小端:

如:int 11 22 33 44

在存儲(chǔ)的時(shí)候

大端:11 22 33 44

0 1 2 3

低地址----》 高地址

小端:44 33 22 11

0 1 2 3

低地址----》 高地址

大小端的差異在于存放順序不同

常見(jiàn)的操作系統(tǒng)是小端,通訊協(xié)議是大端。

//結(jié)構(gòu)體例子:使用尾插法創(chuàng)建鏈表#include《stdio.h》//單鏈表的創(chuàng)建typedef struct _node {

int nb;//數(shù)值

struct _node *nxte;//定義一個(gè)指向下一個(gè)的節(jié)點(diǎn)的指針

}NODE;

typedef struct _link{//利用這個(gè)結(jié)構(gòu)體 封裝 首尾節(jié)點(diǎn)

NODE *head;

NODE *qt;

}link;

void add(link *phead, link *qt, int n);//定義函數(shù)將 首尾指針傳入int main(void) {

link head, q;//定義一個(gè)結(jié)構(gòu),連指針都不是的

head.head = q.qt = NULL;//初始化

int n;

for (scanf(”%d“, &n); n != -1; scanf(”%d“, &n)) {

add(&head, &q, n);//將地址 值傳入

}

NODE *t;

t = head.head;//利用臨時(shí)結(jié)構(gòu)將鏈表輸出

for (; t; t = t-》nxte) {

printf(”%d “, t-》nb);

}

return 0;

}

//尾插法void add(link *phead, link *qt, int n) {

NODE *p = (NODE*)malloc(sizeof(NODE));//為新結(jié)點(diǎn)開(kāi)辟空間

p-》nb = n;

p-》nxte = NULL;

if (phead-》head == NULL) {//判斷首結(jié)點(diǎn)是否為空

phead-》head = p;//是空的就讓首結(jié)點(diǎn)等于新結(jié)點(diǎn)

}

else {//不為空時(shí),讓尾結(jié)點(diǎn)依次跑到后面去

qt-》qt-》nxte = p;

}

qt-》qt = p;

}

4、union 共用體(聯(lián)合體)在進(jìn)行某些算法的C語(yǔ)言編程的時(shí)候,需要使幾種不同類(lèi)型的變量存放到同一段內(nèi)存單元中。也就是使用覆蓋技術(shù),幾個(gè)變量互相覆蓋。這種幾個(gè)不同的變量共同占用一段內(nèi)存的結(jié)構(gòu),在C語(yǔ)言中 以關(guān)鍵字union聲明的一種數(shù)據(jù)結(jié)構(gòu),這種被稱(chēng)作“共用體”類(lèi)型結(jié)構(gòu),也叫聯(lián)合體。

“聯(lián)合”與“結(jié)構(gòu)”有一些相似之處。但兩者有本質(zhì)上的不同。在結(jié)構(gòu)中各成員有各自的內(nèi)存空間,一個(gè)結(jié)構(gòu)體變量的總長(zhǎng)度大于等于各成員長(zhǎng)度之和。而在“聯(lián)合”中,各成員共享一段內(nèi)存空間,一個(gè)聯(lián)合變量的長(zhǎng)度等于各成員中最長(zhǎng)的長(zhǎng)度。注意這里所謂的共享不是指把多個(gè)成員同時(shí)裝入一個(gè)聯(lián)合變量?jī)?nèi),而是指該聯(lián)合變量可被賦予任一成員值,但每次只能賦一種值,賦入新值則沖去舊值,共用體變量中起作用的成員是最后一次存放的成員,在存入一個(gè)新成員后,原有成員就失去作用,共用體變量的地址和它的各成員的地址都是同一地址

一個(gè)聯(lián)合類(lèi)型必須經(jīng)過(guò)定義之后,才能把變量說(shuō)明為該聯(lián)合類(lèi)型:

o4YBAGCl1xiAWJLgAABKhAO0aYY218.png

注意:1、不能把共用體變量作為函數(shù)參數(shù),也不能是函數(shù)帶回共用體變量,但可以使專(zhuān)用指向共用體變量的指針

2、所有成員占用同一段內(nèi)存,修改一制個(gè)成員會(huì)影響其余所有成員。

共用體的訪問(wèn):共用體訪問(wèn)成員的值時(shí)一般使用。運(yùn)算符,指針時(shí)用-》運(yùn)算符(和結(jié)構(gòu)體是一樣的)

typedef union _node {

int a;

double b;

char c;

union _node *p;

}NODE;

int main(void) {

NODE a;//定義變量

NODE t;

a.b;//用。訪問(wèn)

t.p-》a;//指針用-》訪問(wèn)

}

聯(lián)合的使用規(guī)則幾乎和結(jié)構(gòu)體strtct的規(guī)則用法一樣,只不過(guò)是內(nèi)部表示的不同。

補(bǔ)充:

還有一個(gè)是無(wú)名聯(lián)合體,它是和無(wú)名結(jié)構(gòu)體的工作原理是相同的

#include《stdio.h》//簡(jiǎn)單的例子#include《string.h》typedef union _node{

int a;

double b;

char c[20];

}NODE;

int main(void) {

NODE a;//這里只定義一個(gè)變量

a.a = 666;

printf(”%d

“, a.a);

a.b = 9.99;

printf(”%f

“, a.b);

strcpy(a.c, ”hello world!“);

printf(”%s

“, a.c);

//我們看到,三個(gè)都被完整的輸出了,因?yàn)樵谕粫r(shí)刻,只有一個(gè)成員是有效的

}

輸出:

6669.990000

hellow world!

共用體的作用:

1、節(jié)省內(nèi)存,有兩個(gè)很長(zhǎng)的數(shù)據(jù)結(jié)構(gòu),不會(huì)同時(shí)使用,比如一個(gè)表示老師,一個(gè)表示學(xué)生,如果要統(tǒng)計(jì)教師和學(xué)生的情況用結(jié)構(gòu)體的話就有點(diǎn)浪費(fèi)了!用結(jié)構(gòu)體的話,只占用最長(zhǎng)的那個(gè)數(shù)據(jù)結(jié)構(gòu)所占用的空間,就足夠了!

2、實(shí)現(xiàn)不同類(lèi)型數(shù)據(jù)之間的類(lèi)型轉(zhuǎn)換,遇到各種類(lèi)型的數(shù)據(jù)共用存儲(chǔ)空間,很方便的實(shí)現(xiàn)了不同數(shù)據(jù)類(lèi)型之間的轉(zhuǎn)換,不需要顯示的強(qiáng)制類(lèi)型轉(zhuǎn)換。

其他:1、確定CPU的模式:大端、小端模式確定

大小端不同,則存儲(chǔ)的方式也存在差別,比如int需要4個(gè)字節(jié),而char只需要1個(gè)字節(jié),根據(jù)1個(gè)字節(jié)所在的具體位置即可判定CPU的模式

2、寄存器的定義,實(shí)現(xiàn)整體的訪問(wèn)和單項(xiàng)的訪問(wèn)//共用體綜合例子:根據(jù)輸入的數(shù)據(jù)類(lèi)型輸出需要的相應(yīng)的數(shù)據(jù)#include《stdio.h》#include《string.h》//數(shù)據(jù)類(lèi)型輸出 5*4 m n n的第幾個(gè)x union node {

int a;

double b;

char c[30];

}add[10000];

char p[10000][30]; //保存的字符串?dāng)?shù)組int main(void) {

int n, m;

scanf(”%d %d“, &n, &m);

int x;

double y;

char t[50];

int i, j;

for (i = 0; i 《 n; i++) {//輸入

scanf(”%s“, &p[i]);//作為字符串?dāng)?shù)組,需要取地址

if (strcmp(”INT“, p[i]) == 0) {//整形

scanf(”%d“, &x);

add[i].a = x;

}

else if(strcmp(”DOUBLE“,p[i])==0){//浮點(diǎn)

scanf(”%lf“, &y);

add[i].b = y;

}

else if (strcmp(”STRCING“, p[i]) == 0) {//字符串

scanf(”%s“, t);

strcpy(add[i].c, t);

}

}

for (i = 0; i 《 m; i++) {//輸出

scanf(”%d“, &j);

if (strcmp(”INT“, p[j]) == 0) {

printf(”%d

“, add[j].a);

}

else if (strcmp(”DOUBLE“, p[j]) == 0)

{

printf(”%f

“, add[j].b);

}else if(strcmp(”STRING“,p[j])==0)

{

printf(”%s

“, add[j].c);

}

}

return 0;

}

//輸入:/*

5 4

INT 456

DOUBLE 123.56

DOUBLE 0.476

STRING welcomeToC

STRING LemonTree

0

1

2

4

*///輸出:/*

456

123.56

0.48

LemonTree

*/

編輯:jq

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    11080

    瀏覽量

    217159
  • 數(shù)據(jù)
    +關(guān)注

    關(guān)注

    8

    文章

    7256

    瀏覽量

    91925
  • C語(yǔ)言
    +關(guān)注

    關(guān)注

    180

    文章

    7632

    瀏覽量

    141836

原文標(biāo)題:C語(yǔ)言知識(shí)總結(jié):宏,枚舉,結(jié)構(gòu)體,共用體

文章出處:【微信號(hào):gh_c472c2199c88,微信公眾號(hào):嵌入式微處理器】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    定義IO初始化結(jié)構(gòu)

    由上述IOPORT相關(guān)功能的枚舉類(lèi)型我們可以知道,在對(duì)IOPORT模塊進(jìn)行初始化時(shí)需要根據(jù)情況配置它們。因此我們定義一個(gè)IOPORT初始化的結(jié)構(gòu)類(lèi)型IOPORT_Init_t,它的成員包括了由上述所有
    的頭像 發(fā)表于 07-16 16:26 ?568次閱讀

    滲壓計(jì)在混凝土結(jié)構(gòu)中的安裝指南

    在現(xiàn)代土木工程和巖土工程中,滲壓計(jì)是監(jiān)測(cè)混凝土結(jié)構(gòu)體內(nèi)孔隙水壓力變化的重要工具。南京峟思公司生產(chǎn)的滲壓計(jì)因其高精度和可靠性而被廣泛應(yīng)用于各種工程監(jiān)測(cè)項(xiàng)目中。一、滲壓計(jì)在混凝土結(jié)構(gòu)中的應(yīng)用價(jià)值滲壓計(jì)
    的頭像 發(fā)表于 05-28 10:55 ?166次閱讀
    滲壓計(jì)在混凝土<b class='flag-5'>結(jié)構(gòu)</b><b class='flag-5'>體</b>中的安裝指南

    【「零基礎(chǔ)開(kāi)發(fā)AI Agent」閱讀體驗(yàn)】操作實(shí)戰(zhàn),開(kāi)發(fā)一個(gè)編程助手智能

    .總結(jié) 非常有幸能夠閱讀本書(shū),讓我快速掌握了開(kāi)發(fā)智能的相關(guān)技能和基礎(chǔ)知識(shí).希望以后相關(guān)活動(dòng)還能多多參加.
    發(fā)表于 05-27 11:16

    GLAD應(yīng)用:全息光柵模擬

    用于模擬全息記錄介質(zhì)中形成的梯度折射率分布。全息結(jié)構(gòu)一旦形成,就可以在傳輸過(guò)程中將一束入射光波逐漸轉(zhuǎn)換成形成體全息結(jié)構(gòu)的另一束光波。兩束光波之間的能量傳遞轉(zhuǎn)換效率與全息
    發(fā)表于 05-15 09:32

    程序設(shè)計(jì)與數(shù)據(jù)結(jié)構(gòu)

    《程序設(shè)計(jì)與數(shù)據(jù)結(jié)構(gòu)》重點(diǎn)闡述了三大方向內(nèi)容: 1. C語(yǔ)言學(xué)習(xí)中的痛點(diǎn):針對(duì)當(dāng)前工程師在C語(yǔ)言學(xué)習(xí)中的痛點(diǎn),如指針函數(shù)與函數(shù)指針,如何靈
    發(fā)表于 05-13 16:45

    C語(yǔ)言結(jié)構(gòu)與聯(lián)合體的深度解析:內(nèi)存布局與應(yīng)用場(chǎng)景

    一、基礎(chǔ)概念與核心差異 1.1 結(jié)構(gòu)(Struct)的本質(zhì) **結(jié)構(gòu)C語(yǔ)言中實(shí)現(xiàn)數(shù)據(jù)封裝的
    發(fā)表于 04-08 09:18

    全套C語(yǔ)言培訓(xùn)資料—PPT課件

    共用、位運(yùn)算、文件 全套C語(yǔ)言培訓(xùn)資料,共427頁(yè),13個(gè)章節(jié):C語(yǔ)言概述、程序的靈魂—算
    發(fā)表于 03-12 14:50

    等離子的一些基礎(chǔ)知識(shí)

    等離子(Plasma)是一種電離氣體,通過(guò)向氣體提供足夠的能量,使電子從原子或分子中掙脫束縛、釋放出來(lái),成為自由電子而獲得,通常含有自由和隨機(jī)移動(dòng)的帶電粒子(如電子、離子)和未電離的中性粒子。由于
    的頭像 發(fā)表于 01-20 10:07 ?3544次閱讀
    等離子<b class='flag-5'>體</b>的一些基礎(chǔ)<b class='flag-5'>知識(shí)</b>

    結(jié)構(gòu)成員的順序會(huì)影響結(jié)構(gòu)的大小嗎

    相同的結(jié)構(gòu)成員,如果把順序調(diào)整一下,會(huì)不會(huì)影響結(jié)構(gòu)的大??? 答案是會(huì)的,這主要跟字節(jié)對(duì)齊有關(guān)。 比如這樣的結(jié)構(gòu)
    的頭像 發(fā)表于 11-25 16:24 ?566次閱讀

    《DNESP32S3使用指南-IDF版_V1.6》第二章 常用的C語(yǔ)言知識(shí)點(diǎn)

    5.4 extern外部申明5.5 typedef類(lèi)型別名5.6 struct結(jié)構(gòu)5.7 指針 5.1 位操作位操作是直接在整數(shù)的二進(jìn)制位上進(jìn)行操作的一種技術(shù)。C語(yǔ)言提供了多種位操
    發(fā)表于 11-21 09:26

    C語(yǔ)言C++中結(jié)構(gòu)的區(qū)別

    同樣是結(jié)構(gòu),看看在C語(yǔ)言C++中有什么區(qū)別?
    的頭像 發(fā)表于 10-30 15:11 ?778次閱讀

    C語(yǔ)言中最常見(jiàn)的定義寫(xiě)法

    如果讓你用C語(yǔ)言寫(xiě)個(gè)定義,我相信大部分同學(xué)順手就能寫(xiě)出define。
    的頭像 發(fā)表于 10-28 11:12 ?837次閱讀

    《嵌入式機(jī)電一化系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)》讀后感

    和方法,還通過(guò)大量的案例分析和實(shí)踐操作,讓讀者能夠更好地理解和掌握這些知識(shí)。這種理論與實(shí)踐相結(jié)合的教學(xué)方式,讓我受益匪淺。 此外,本書(shū)的語(yǔ)言風(fēng)格平實(shí)易懂,邏輯清晰嚴(yán)謹(jǐn),非常適合初學(xué)者和有一定基礎(chǔ)的讀者閱讀
    發(fā)表于 08-21 08:45

    帶你認(rèn)識(shí)貼片一成型電感的材料結(jié)構(gòu)

    貼片一成型電感(也被稱(chēng)為模壓電感)是一種具有特殊結(jié)構(gòu)和材料組成的電子元件。其材料結(jié)構(gòu)主要包括以下幾個(gè)方面: 一、主要材料 1. 金屬粉末 核心材料:一成型電感的主要材料是金屬粉末,
    的頭像 發(fā)表于 08-07 16:01 ?1094次閱讀
    帶你認(rèn)識(shí)貼片一<b class='flag-5'>體</b>成型電感的材料<b class='flag-5'>結(jié)構(gòu)</b>

    技術(shù)干貨驛站 ▏深入理解C語(yǔ)言:掌握程序結(jié)構(gòu)知識(shí)

    在計(jì)算機(jī)編程的世界中,C語(yǔ)言被廣泛認(rèn)可為一門(mén)強(qiáng)大而高效的編程語(yǔ)言,其簡(jiǎn)潔的語(yǔ)法和直接的指令使得它成為了許多程序員的首選。了解C語(yǔ)言的程序
    的頭像 發(fā)表于 07-27 08:45 ?1861次閱讀
    技術(shù)干貨驛站 ▏深入理解<b class='flag-5'>C</b><b class='flag-5'>語(yǔ)言</b>:掌握程序<b class='flag-5'>結(jié)構(gòu)</b><b class='flag-5'>知識(shí)</b>