程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 我也要學C語言-第十九章:結構體的定義和初始化

我也要學C語言-第十九章:結構體的定義和初始化

編輯:關於C語言

結構體到底是什麼呀?!
  我們來思考一個問題,如果我們要保存一個年級所有學生的信息,我們該如何去做呢!我們稍微回憶下以前我學過的知識,大概能想到用數組去做,因為學號啊,姓名啊,成績啊,都是同類元素的集合,當然用數組了,如果用單個變量真的會累死人呀!但是再進一步思考發覺,學生的信息還是有不少東西的,比如學號,姓名,各科成績,電話,家庭住址,如果單單用數組,是不是得好多好多數組呀!而且這樣呢,管理起來也非常不方便啊,那怎麼辦啊。其實呢!在高級語言中,有一種類型,就是對基本類型進行重定義。把多個數據類型重新定義成一個新類型。就好比一棟房子,裡面有廁所啊,廚房,廚房裡還有幾顆白菜。如果我們想要表示你有一棟房子,你可以把房子裡面的東西全部都說一遍,你還可以把這棟房子就用一棟房子去表示。廚房裡的幾顆白菜你可以想成放在數組裡的,因為幾顆白菜是同類元素。一棟房子就相當於我們現在要學習的結構體。各種類型集合成一起,呵呵,這樣的話,你就可以用結構體去表示復雜的數據結構啦!

結構體成員變量的訪問的思考
  我們再思考一個問題,結構體是多種不同的數據類型的集合,所以每個元素的大小都是不一樣的,那麼如何訪問結構體中的成員變量呢!要是數組的話就好辦,因為是同類啊,就以前學習的數組尋址公式一下子就訪問到了(很多人質疑那個尋址公式,這個質疑很正常,因為你還沒有理解)。這確實是一個問題呀!不過,等會應該就會有答案的!

結構體的定義
  結構體定義的關鍵字是 struct. 表示一個信息結構、後面跟著的是結構體的名稱,你定義成一個新類型了,得起個名字呀!就好比,你現在造出了1個天使,天使由哪些構成呢,有天使的翅膀,還有像人一樣的天使,還有白色的耀眼的裙子。還有天使的紅色高跟鞋,還有,天使也許也有編號的吧,不只它1個天使,呵呵!還有天使的名字。現在我們先來造人,呵呵!等以後厲害了再造天使:

造人:

  

view sourceprint?struct Person 

char name[64];//定長的名字,如果這裡給的類型是char * 就可以不定長了。但是用char *尋址要尋2次。用定長的話一次就到啦! 

char sex; //性別 

int age; //int的age 應該夠啦。活得夠大啦! 

float height; 

};


  大家仔細回憶QQ的年齡設置,是不是每一年都得手動去改名字啊,QQ不會自動給你改。這樣是不是不太好啊因為每年都要去改年齡!我們是不是應該分別定義年月日啊,每次用當前年月日減去它的初始年月日,這樣的才好的啊,因為這樣無論在哪1年都知道一個人多大了的啊。比如,現在我們做的學生信息管理系統,要是每年都去改年齡,是不是設計的不太科學啊,所以,我們這裡要改1下,但是QQ比較是人才濟濟的,他們不會傻到這種地步啊,那麼它們為什麼那這樣的做呢,我想主要是考慮到大量算的壓力,因為幾億QQ使用者一上線就要請求服務器做下減法,呵呵,這樣服務器壓力就大啊,但是也可以放在客服端做的呀,那為什麼騰訊沒有這樣做呢!不知道了,慢慢地,努力的學,有一天會知道的。

結構體和INT char其實是同一級別的
  我們來看這個例子:

struct stStudent //st前綴是一種規則,你自己選擇一種,一直保持就好。{   char szName[64];    int nYear;    int nMonth;    int nDay;};
  注意1個問題啊!現在我們只是定義了一種數據類型,這裡,我們還沒有產生變量哦!它其實和int char 是一樣的哦.只不過這裡的結構體是一個符合類型。也就是這裡沒有分配內存的哦!比如我們來看下面的錯誤程序:

 正確的做法是先要聲明這種類型的變量,其實和int char聲明變量是一樣的。例如:

struct stStudent //st前綴是一種規則,你自己選擇一種,一直保持就好。{  char szName[64];  int nYear;  int nMonth;  int nDay;  float fScore[3];};int main(){       stStudent.szName[0] = ‘J’;//這樣是錯誤的哦,這裡就好比 int = 123;相當於是對類型在賦值。}   

 

struct stStudent //st前綴是一種規則,你自己選擇一種,一直保持就好。{   char szName[64];    int nYear;    int nMonth;    int nDay;    float fScore[3];};int main(){       stStudent stu;   stu.szName[0] = ‘J’;}   


結構體變量的初始化
和數組的初始化差不多: stStudent stu = {    "beyond",     1989,     2,                11,    {        99.9        87.3        100        }    }
其實呢,還可以不要中間嵌套的那個括號,為什麼呢,我們先來看看內存:

哈哈!0012fef0,CCCCCCCCCCCC!!!為什麼會這樣呢!嘿嘿!我們當然知道啦,通過以前的學習,我已經條件反射啦!全C是因為是局部變量,就算不看全C,0012fef0也可以知道這是1個局部變量,因為這個地址是棧地址呀!然後我們單步下去,內存地址就依次被賦值啦!所以呢!那個括號是可以不用給的,因為是連續依次排列的啊,但是鑒於代碼的清晰,最好還是給括號啦!

  唉!剛才我的szName給得太大啦,調試的時候不好截圖呀!下面的代碼,我把它修改下,修改為16好了。下面我們再來看1個問題,代碼修改如下:

那麼現在我們思考一個問題,這個結構體一共占多大的內存呢,我們先來算算:這樣吧!我們用printf把它給顯示出來(偷偷懶!呵呵!)首先我們先看看沒有char Sex的時候的大小:

程序打印出40.為什麼是40呢?!因為16+4+4+4+12=40呀!

那麼現在我們加上這個Sex後,會打印什麼結果呢!你可能想啊,char啊!當時是1的啊,40+1=41啊!嗯,我覺得也是這樣的,那麼我們去看看結果!!!

郁悶呀!結果竟然是44.哦!驚奇啊!怎麼會這樣呢!其實啊!這裡的這個問題到底會打印多少還得看編譯環境,到底看哪個編譯環境呢,看這個:

哈哈!大家看到了嗎?!這裡有個結構體成員對齊呀!哦,原來是這樣啊!那麼我們先來選擇1字節對齊再來看打印出什麼結果,哇!打印出來了41了呢!其實!VC6.0默認是模4字節對齊的!剛才打印出41就是用的模1地址對齊,也就是不對齊啦!這個真好玩,原來還可以自己去安排一些規則的呀!

VC關於對齊的預編譯指令

#pragma pack(n)

#pragma pack(push | pop)

其實這些指令就是微控對齊的控制。具體做法非常簡單,MSDN上有詳細解釋,這裡就不示范啦!

為什麼要學習地址對齊呢
  因為後面用結構體的時候,大多數時候要用到數據包的發送和解析。數據包是有一定格式的,這時候就需要考慮是否考慮對齊問題。否則對齊錯了,解析出來的東西就全亂啦!所以一定要注意這點的理解和學習哦!

結構體的嵌套極其注意問題
  前面我們的程序,關於日期的定義,我們是不是可以定義一個stDate數據類型啊,這麼看起來好像更好看點啊!例如:

#include <stdio.h>struct stDate{   int nYear;   int nMonth;   int nDay;};struct stStudent{   char szName[64];   struct stDate WoW;   float fScore[3];};int main(){   struct stStudent stu={      "dodolook",      {      1981,      7,      7},      {         100,         99,         60      }   };   return 0;}
嘿嘿!挺好玩吧!嵌套的時候一定要注意1個原則,無論如何去嵌套!只要能sizeof求出大小的,隨便你怎麼去嵌套,不能sizeof求出大小的就不能嵌套!原因是如果不能sizeof求出大小的結構體,編譯器無法給其大小!

  現在我們再思考一個問題!如果要把結構體初始化為全0,怎麼辦呢!其實很簡單了,就是給結構體1個0就可以了啊。注意不要什麼都不給哦,什麼都不給的時候,是一個不確定的值。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved