重慶分公司,新征程啟航
為企業(yè)提供網(wǎng)站建設(shè)、域名注冊(cè)、服務(wù)器等服務(wù)
為企業(yè)提供網(wǎng)站建設(shè)、域名注冊(cè)、服務(wù)器等服務(wù)
結(jié)構(gòu)體結(jié)構(gòu)體,到底什么是結(jié)構(gòu)體?顧名思義,它是一個(gè)結(jié)構(gòu),換句話(huà)說(shuō),是一個(gè)框架,里面存放著各種各樣不同類(lèi)型的變量,而這些變量又存在著某種內(nèi)在聯(lián)系,合在一起反映了一個(gè)結(jié)構(gòu)的某種性質(zhì)。
例如:
現(xiàn)在有三個(gè)櫥柜:(把我自己說(shuō)餓了)
第一個(gè)是裝水果的櫥柜,里面放著一個(gè)蘋(píng)果,兩個(gè)橘子,三個(gè)香蕉。
第二個(gè)是裝蔬菜的櫥柜,里面放著一個(gè)白菜,兩根蔥,三根茄子,四個(gè)番茄。
第三個(gè)是裝肉的櫥柜,里面放著一塊豬肉,兩塊牛肉,三塊雞肉
其中,櫥柜——結(jié)構(gòu)體,存的東西——變量。而每一個(gè)櫥柜里的東西都有著各自的內(nèi)在聯(lián)系,合在一起就反應(yīng)了一個(gè)櫥柜的特性。
說(shuō)的官方一點(diǎn),創(chuàng)建一個(gè)結(jié)構(gòu)體,就是把多個(gè)數(shù)據(jù)按照需求進(jìn)行封裝,其中類(lèi)型和大小都可以由用戶(hù)指定。
我們現(xiàn)在知道了結(jié)構(gòu)體到底是什么,接下來(lái)就需要來(lái)使用它。很多教材都會(huì)用 “包含一個(gè)學(xué)生的信息的結(jié)構(gòu)體” 舉例子,為了普適性,我們也創(chuàng)建一個(gè)包含了學(xué)生信息的結(jié)構(gòu)體。
1. 聲明一個(gè)結(jié)構(gòu)體類(lèi)型一般來(lái)說(shuō),會(huì)在所有函數(shù)前聲明結(jié)構(gòu)體的類(lèi)型。
struct STUDENT//聲明了一個(gè)STUDENT的結(jié)構(gòu)體類(lèi)型,注意:為了規(guī)范,要用大寫(xiě)字母。
{char name[20];
int age;
char num[10];//學(xué)生的學(xué)號(hào)
} ; //分號(hào)一定不能省略
到此為止,我們只是聲明了一個(gè)結(jié)構(gòu)體類(lèi)型,并沒(méi)有聲明結(jié)構(gòu)體類(lèi)型變量!此時(shí)系統(tǒng)還沒(méi)有為他分配內(nèi)存空間??!即,此時(shí)還不能進(jìn)行初始化(落腳的地方都還沒(méi)有),類(lèi)似于int ,而不是int a.
2. 聲明結(jié)構(gòu)體變量第一步我們聲明了一個(gè)STUDENT類(lèi)型的結(jié)構(gòu)體,但是只是創(chuàng)建了一個(gè)類(lèi)型,沒(méi)有為這個(gè)類(lèi)型開(kāi)辟一個(gè)內(nèi)存空間。
前面提到過(guò),一般會(huì)在所有函數(shù)前聲明結(jié)構(gòu)體的類(lèi)型,再在某個(gè)函數(shù)中聲明他的結(jié)構(gòu)體變量。
#includestruct STUDENT
{char name[20];
int age;
char num[10];
};
int main()
{struct STUDENT stu1;//定義了一個(gè)STUDENT類(lèi)型的結(jié)構(gòu)體變量stu1,stu1具有STUDENT的結(jié)構(gòu)
}
#includestruct STUDENT
{char name[20];
int age;
char num[10];
} stu1;//聲明一個(gè)STUDENT類(lèi)型的結(jié)構(gòu)體變量stu1,注意?。?!分號(hào)不要忘了!
3. 結(jié)構(gòu)體類(lèi)型的初始化注意:
初始化的方式:
scanf(“%s,%d,%s”,stu1.name,&stu1.age,stu1.num);
int main()
{struct STUDENT stu1 = {"小明",12,k12345};
}
int main()
{struct STUDENT stu1;
strcpy(stu1.name,"小明");//如果是中文字符就必須要用strcpy!
stu1.age = 12;
stu1.num = "k12345";
}
4. 結(jié)構(gòu)體的調(diào)用首先引進(jìn)一個(gè)概念,“成員運(yùn)算符”,即目的是調(diào)用某結(jié)構(gòu)體中的成員。一般用到的是 " . “和” ->",他們的優(yōu)先級(jí)非常高,高于其他所有的運(yùn)算符。
當(dāng)我們要調(diào)用一個(gè)結(jié)構(gòu)體里的某一個(gè)成員,可以這樣做
第一種方式:
stu1.name;
第二種方式
struct STUDENT *p;
p = &stu1;
(*p).name;
第三種方式
struct STUDENT *p;
p = &stu1;
p->name;
后兩種方式需要用到指向結(jié)構(gòu)體的指針的知識(shí),后面會(huì)有詳細(xì)的介紹,這里了解即可。然而!只有當(dāng)使用指向結(jié)構(gòu)體的指針p時(shí),才可以使用->運(yùn)算符??!
下面是一個(gè)完整的例子,包含兩個(gè)結(jié)構(gòu)體的使用
#includestruct AGE
{int year;
int month;
int day;
};
struct STUDENT
{char name[20];
int age;
char num[10];
struct AGE birthday;//結(jié)構(gòu)體嵌套結(jié)構(gòu)體
//birthday是STUDENT類(lèi)型的一個(gè)成員,同時(shí)是AGE類(lèi)型的結(jié)構(gòu)體變量,因此,STUDENT類(lèi)型包含了AGE類(lèi)型的所有成員。
};
int main()
{struct STUDENT stu1={"小明",12,"k12345",{2010,6,25}};
printf("%s今年%d歲,學(xué)號(hào)是%s,生日是%d.%d.%d\n",stu1.name,stu1.age,stu1.num,stu1.birthday.year,stu1.birthday.month,stu1.birthday.day);//結(jié)構(gòu)體的調(diào)用,需要用成員運(yùn)算符“.”(他的優(yōu)先級(jí)最高)調(diào)用某一結(jié)構(gòu)體的內(nèi)部成員。
return 0;
}
(二)結(jié)構(gòu)體字節(jié)對(duì)齊”結(jié)構(gòu)體字節(jié)對(duì)齊“也可以稱(chēng)為“內(nèi)存對(duì)齊”,它不僅僅存在于結(jié)構(gòu)體當(dāng)中,更是計(jì)算機(jī)系統(tǒng)本身所具備的一種能力,存在于方方面面。
在這里,可以用來(lái)解釋不同的結(jié)構(gòu)體類(lèi)型所占的字節(jié)數(shù)。由于一個(gè)結(jié)構(gòu)體里面有不同類(lèi)型的成員,那么一個(gè)結(jié)構(gòu)體類(lèi)型究竟占多少字節(jié)呢?
根據(jù)字節(jié)對(duì)齊理論,我們以占字節(jié)最長(zhǎng)(n)的類(lèi)型為準(zhǔn)分配一個(gè)長(zhǎng)為n的內(nèi)存空間。
例如
struct this
{//先觀察全局,發(fā)現(xiàn)int占4個(gè)字節(jié),char占1個(gè)字節(jié),int所占字節(jié)數(shù)最多,于是系統(tǒng)便分配了一個(gè)長(zhǎng)度為4個(gè)字節(jié)的內(nèi)存空間。
char a;
char b;
char c;
char d;
char e;//填充后如果后面還有空位就空著,下一個(gè)int另起一行
int f;//分配一個(gè)四個(gè)字節(jié)的長(zhǎng)方形
}
為了清楚地說(shuō)明,建立了以下圖表表示內(nèi)存空間——
a | b | c | d |
---|---|---|---|
e | |||
f | f | f | f |
abcd一個(gè)一個(gè)往后填充,等 e 填充完后,由于 f 是int類(lèi)型,需要占據(jù)4個(gè)字節(jié),因此需要另起一行,那么e后面沒(méi)有能夠填充的元素,便需要空出來(lái),為 f 另起一行。
通過(guò)數(shù)格子數(shù)目,不難看出,以上定義的this類(lèi)型的結(jié)構(gòu)體所占字節(jié)為12。
那么,內(nèi)存對(duì)齊的目的是什么?
既然要節(jié)約內(nèi)存,為什么不依次按順序地把變量放進(jìn)內(nèi)存空間,而要在遇到占更多字節(jié)數(shù)的變量時(shí),要另起一行呢?是為了便于計(jì)算機(jī)尋址,提高運(yùn)行速度。
注意:
基本結(jié)構(gòu)如下:
struct STUDENT stu[10];
表示:定義了一個(gè)STUDENT類(lèi)型的結(jié)構(gòu)體數(shù)組stu,stu中有10 個(gè)元素,每一個(gè)元素都是STUDENT類(lèi)型的結(jié)構(gòu)體。
結(jié)構(gòu)體數(shù)組和普通數(shù)組其實(shí)差不多,只不過(guò)結(jié)構(gòu)體數(shù)組里面的元素是結(jié)構(gòu)體,普通數(shù)組里面的元素是數(shù)。
(四)結(jié)構(gòu)體指針之前提到過(guò),定義一個(gè)指針p,他指向某個(gè)結(jié)構(gòu)體變量,這個(gè)指針p就叫做結(jié)構(gòu)體指針。
基本結(jié)構(gòu)如下:
struct STUDENT *p;
表示:定義了一個(gè)指向STUDENT結(jié)構(gòu)體類(lèi)型的指針。注意!這里只聲明了p指向STUDENT類(lèi)型,但它并沒(méi)有明確指向哪一個(gè)變量!
于是需要對(duì)其進(jìn)行初始化
struct STUDENT *p = NULL;
調(diào)用(三個(gè)等價(jià))
(*p).name;
p->name;//非常重要?。?!
stu1.name;
如果要調(diào)用結(jié)構(gòu)體內(nèi)部成員,以下三種方式等價(jià)
注意!第三種方式只能有指針變量能用?。。?!
(->是成員運(yùn)算符,優(yōu)先級(jí)和.相同)
前面對(duì)結(jié)構(gòu)體數(shù)組、結(jié)構(gòu)體指針有所了解之后,現(xiàn)引出一個(gè)概念—— “指向結(jié)構(gòu)體數(shù)組的指針”
現(xiàn)有一結(jié)構(gòu)體數(shù)組
struct STUDENT stu[10];(有10個(gè)元素,每一個(gè)元素都是一個(gè)STUDENT類(lèi)型的結(jié)構(gòu)體)
創(chuàng)建一個(gè)指向該STUDENT類(lèi)型結(jié)構(gòu)體的指針
struct STUDENT *p=NULL;
p = stu;//(實(shí)際上指向的是該結(jié)構(gòu)體數(shù)組的第一個(gè)元素,指向數(shù)組中的第一個(gè)結(jié)構(gòu)體)
調(diào)用該指針
P是數(shù)組中第一個(gè)結(jié)構(gòu)體的首地址。
現(xiàn)在調(diào)用第一個(gè)結(jié)構(gòu)體中的第一個(gè)成員。
方式一:(*p).name;
方式二:p->name;
現(xiàn)在依次調(diào)用該數(shù)組中的每一個(gè)元素的第一個(gè)成員,直到stu+n截止(*p++).name;
(可以寫(xiě)作:p++
指針的加減,即地址位置的前后變化
答:
對(duì)于輸入函數(shù):
如果要對(duì)傳入函數(shù)的值進(jìn)行修改,就一定要傳入它的地址,從它的根本上去修改它。
如果只是要使用它的值,就只需要傳入它的值就行,相當(dāng)于復(fù)制了一個(gè)值,對(duì)原來(lái)的值沒(méi)有任何影響。
對(duì)于輸出函數(shù)
只需要對(duì)傳入的值進(jìn)行輸出,那么直接調(diào)用它的值就行。
然而,從節(jié)約內(nèi)存的角度分析,如果傳入的是一個(gè)指針變量,形參就只占據(jù)了4個(gè)字節(jié),如果傳入的是一個(gè)結(jié)構(gòu)體變量的值,那么該結(jié)構(gòu)體占多少字節(jié),形參就占多少字節(jié),這可能會(huì)使用更多的內(nèi)存空間。
然而
當(dāng)你只是想調(diào)用變量的值,卻傳入的是變量的地址,你所定義的函數(shù)就能對(duì)該變量進(jìn)行修改了?。∵@無(wú)疑是非常危險(xiǎn)的,也會(huì)成為你的程序當(dāng)中的一個(gè)漏洞。
因此
從綜合角度來(lái)分析,當(dāng)要對(duì)一個(gè)值進(jìn)行修改,傳入變量的地址。當(dāng)只是對(duì)一個(gè)變量的值進(jìn)行調(diào)用,或者單純地想要輸出它,也傳入變量的地址,但是,在前面加上一個(gè)const,這樣一來(lái),就無(wú)法修改它的值了。
舉一個(gè)小栗子來(lái)結(jié)束這篇文章
#include#includestruct STUDENT
{char name[20];
int age;
char num[10];
};
void inputstudent ( struct STUDENT *p)//定義了一個(gè)需要你輸入一個(gè)指向結(jié)構(gòu)體的指針的函數(shù),即,輸入一個(gè)地址,該函數(shù)對(duì)輸入的地址上的數(shù)據(jù)進(jìn)行操作。
{(*p).num=k123456;
strcpy((*p).name,"小明");
(*p).age=12;
return;//如果沒(méi)有返回值可以就寫(xiě)作return;
}
void outputstudent(struct STUDENT *p)//作為輸出,其實(shí)傳遞值也是可以的,但是為了節(jié)省內(nèi)存空間,常常寫(xiě)作只有4個(gè)字節(jié)的指針
{printf("名字是%s,年齡是%d,學(xué)號(hào)是%s",(*p).name,(*p).age,(*p).num);
return;
}
int main()
{struct STUDENT stu1;
inputstudent(&stu1);
outputstudent(&stu1);
return 0;
}
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧