C中結構體是另一種表示數據形式的方式,結構體中能夠表示C中的基本數據形式,如int,double....結構體可讓咱們更好的表示數據。下面來看看結構體。數組
說到結構體首先要了解的是它的申明形式,要申明一個結構體形式以下:函數
1 #include<stdio.h> 2 #define LEN 20 3 4 //申明一個結構體 5 struct name { 6 char firstname[LEN]; 7 char lastname[LEN]; 8 }; 9 10 //申明一個結構體 11 struct guy { 12 struct name handle; //結構體嵌套 13 char favfood[LEN]; 14 char job[LEN]; 15 int age; 16 }; 17 18 int main(int argc, char* argv[]) 19 { 20 ........ 21 }
在結構體中能夠有基本的數據類型例如上面的int,char數組,也能夠嵌套有其餘結構體,例如上面結構體guy中就存在另一個結構體name。值得注意的是,咱們在申明一個結構體的時候,計算機並無爲數據分配空間,而是在咱們建立結構變量的時候纔會進行分配。建立結構變量的形式以下:ui
1 struct guy new_guy; spa
在計算機執行到上面這句時,計算機會爲變量分配內存。如上guy中包含一個name結構體,name結構體中是由兩個20個char所佔字節組成,共計2*20=40字節,而favfood和job也是兩個長度爲20的char數組,age是一個int類型,因此一個guy類型的變量所佔字節數共計爲40+20+20+4=84。指針
如今咱們知道如何申明一個結構體和定義一個結構體變量了。先看看下面的代碼:code
1 struct guy new_guy1 = { //結構體的初始化 2 {"zhou","xuanyu"}, 3 "tomato", 4 "student", 5 22 6 }; 7 struct guy new_guy2 = { //結構體的初始化 8 .handle = {"zhou","xuanyu"}, 9 .job = "student", 10 };
上面一段代碼是對一個結構體進行初始化,對於new_guy1,咱們對它的每個屬性都初始化了,而對於new_guy2咱們僅僅初始化了他的handle和job。對於一個結構體咱們應該怎麼訪問結構體中的每個項呢?不錯,是使用 . 運算符。例如:對象
1 printf("%s",new_guy2.handle); ,就能夠打印出"zhouxuanyu"。再看看下面這段代碼(其中的結構體guy在上面已定義):blog
1 int main(int argc, char* argv[]) 2 { 3 struct guy new_guy[2] = { //定義一個結構體數組 4 { 5 {"zhou","xuanyu"},"tomato","student",22 //初始化數組第一項 6 }, 7 { 8 {"hu","jiannan"},"fruit","student",22 //初始化數組第二項 9 } 10 }; 11 12 struct guy * him; //指向結構體guy的指針 13 him = &new_guy[0]; //將指針指向guy數組 14 15 printf("address #1:%p, #2:%p\n",&new_guy[0],&new_guy[1]); 16 printf("pointer #1:%p, #2:%p\n",him,him+1); 17 18 printf("him->handle.firstname is %s,(*him).age is %d\n",him->handle.firstname,(*him).age); 19 him++; 20 printf("him->job is %s,(*him).handle.lastname is %s\n",him->job,(*him).handle.lastname); 21 }
在上面這段代碼中,咱們定義了一個guy類型的數組,定義一個結構體數組的形式和定義通常數組同樣。在上面代碼第12行中咱們申明瞭一個指向結構體的指針him,利用指針咱們能夠對數據的操做會更加靈活。在13行,咱們初始化了這個指針,這裏要注意的是結構體的名稱和數組名不一樣,數組名就是數組其實元素的地址,因此能夠這樣作int *p = a,假設a是一個int類型的數組,可是結構體不行,必須使用&取地址。所用上面15,16行打印出來的地址是同樣的。上面的代碼中又出現了一個新的運算符->。它的做用和剛剛說的 . 運算符同樣,只是做用的對象不同,簡單的記法就是:指針使用->訪問結構體中的項,而結構體變量使用.訪問它的項。到如今咱們已經大概瞭解告終構體的基本用法。下面來看看結構體在函數中使用的幾種方式:內存
1 #include<stdio.h> 2 #define LEN 20 3 4 struct Book { //定義結構體 5 char bookname[LEN]; 6 double price; 7 char author[LEN]; 8 }; 9 10 //三個函數都用於改變書的價格 11 double changebook1(double); //由於只改變書的價格,直接將價格做爲參數傳入函數 12 double changebook2(struct Book *); //傳入一個指向Book類型的指針 13 double changebook3(struct Book); //傳入一個結構體 14 15 16 int main(int argc, char* argv[]) 17 { 18 struct Book book = { 19 "C Primer Plus",75.0,"John" 20 }; 21 22 struct Book * p_book = &book; 23 24 printf("book's price is: %f\n",book.price); 25 printf("after changebook1(),return value is: %.2f, book's price is: %.2f\n",changebook1(book.price),book.price); 26 double new_price2 = changebook2(p_book); 27 printf("after changebook2(),return value is: %.2f, book's price is: %.2f\n",new_price2,book.price); 28 double new_price3 = changebook3(book); 29 printf("after changebook3(),return value is: %.2f, book's price is: %.2f\n",new_price3,book.price); 30 } 31 32 double changebook1(double price){ 33 return price * 2; 34 } 35 36 double changebook2(struct Book * book){ 37 book->price *= 2; 38 return book->price; 39 } 40 41 double changebook3(struct Book book){ 42 book.price *= 4; 43 return book.price; 44 }
上面的代碼中,咱們定義了三個函數用來改變book的價格,第一個是直接將double類型的pirce傳入,第二個是將一個指向結構體的指針傳入,第三個是將整個結構體傳入。最後打印出函數運行以後的結構,以下:it
從結果能夠看出,只有changebook2()函數才真正的將書的價格改變了。這是爲何呢?緣由是這樣的,方法二是將一個指針做爲參數傳入函數,指針指向的是原始數據,因此咱們所作的全部操做都是在原始數據上進行的。而方法三傳入的是一個結構體,在調用函數changebook3()的時候,會根據模板Book建立一個自動變量,而後這個變量的成員會被初始化與原始數據同樣副本。而咱們所進行的操做都是在這個副本上進行的,因此不會對原始數據有任何改變。可是這樣的作法會對內存有很大的浪費,因此咱們通常使用的第二種方式,可是第二種方式會有破壞數據的可能,該怎麼辦呢?在C中const關鍵字能夠解決這個問題。若是咱們對原始數據不須要進行修改,這時候能夠將傳入函數的指針用const修飾。