結構體-----將不一樣類型的數據成員組織到統一的名字之下,適用於對關係緊密,邏輯相關、具備相同或不一樣類型的數據進行處理html
struct 結構名(也可稱做結構標識符) 數組
{函數
類型 變量名;spa
類型 變量名;.net
······指針
};code
struct 結構名 結構變量;htm
或者blog
struct 結構名內存
{
類型 變量名;
類型 變量名;
······
}結構變量;
例:聲明結構體類型的同時定義變量名
1 struct student 2 { 3 int num; 4 }teacher;
(聲明結構體類型僅僅是聲明瞭一個類型,系統並不爲之分配內存,就如同系統不會爲類型 int 分配內存同樣。只有當使用這個類型定義了變量時,系統纔會爲變量分配內存。因此在聲明結構體類型的時候,不能夠對裏面的變量進行初始化。)
定義了一個結構名爲student的結構體和一個結構變量teacher,若是省略變量名(teacher),就變成了對結構的聲明,上述結構體聲明也可分開寫
1 struct student 2 { 3 int num; 4 }; 5
6 struct student teacher;
與上面效果相同,可理解爲struct student相似於int,而咱們用的是teacher相似於變量,若是省略結構名,則稱之爲無名結構,這種狀況經常出如今函數內部,或者說你只須要teacher這一個變量,
後面不須要再使用結構體名定義其餘變量,那麼在定義時也能夠不給出結構體名
1 struct
2 { 3 int num; 4 }teacher;
(在聲明結構體時經常與typedef函數配合使用)
訪問結構體變量的成員必須使用成員選擇運算符(也稱圓點運算符),格式爲:結構體變量名.成員名
若使用指針對結構體成員進行訪問,格式爲:指針->成員名 等價於 (*指針).成員名
爲一種數據類型定義一個新名字。這裏的數據類型包括內部數據類型(int,char等)和自定義的數據類型(struct等),
(注意與#define的區別,typedef 是用來定義一種類型的新別名的,它不一樣於宏#define,宏是簡單的字符串替換)
例:
1 typedef int INTEGER;
爲int定義了一個新的名字INTEGER,也就是說INTEGER與int是同義詞,也能夠爲結構體定義一個別名
1 typedef struct student STUDENT;
或者
1 typedef struct student 2 { 3 int num; 4 }STUDENT;
上述兩條語句是等價的,兩者都是爲struct student結構體類型定義了一個新的名字STUDENT,即STUDENT與struct student是同義詞,因此下列兩條語句等價
1 1 STUDENT stu1,stu2; 2 2 struct student stu1, stu2;
1 typedef struct tagNode 2 { 3 char *pItem; 4 pNode pNext; 5 } *pNode;
上述代碼編譯階段會報錯,緣由:
在上面的代碼中,新結構創建的過程當中遇到了 pNext 聲明,其類型是 pNode。這裏要特別注意的是,pNode 表示的是該結構體的新別名。
因而問題出現了,在結構體類型自己尚未創建完成的時候,編譯器根本就不認識 pNode,由於這個結構體類型的新別名還不存在,因此天然就會報錯。
所以,咱們要作一些適當的調整,好比將結構體中的 pNext 聲明修改爲以下方式:
1 typedef struct tagNode 2 { 3 char *pItem; 4 struct tagNode *pNext; 5 } *pNode;
或者將 struct 與 typedef 分開定義
1 typedef struct tagNode *pNode; 2 struct tagNode 3 { 4 char *pItem; 5 pNode pNext; 6 };
在上面的代碼中,咱們一樣使用 typedef 給一個還未徹底聲明的類型 tagNode 起了一個新別名。不過,雖然 C 語言編譯器徹底支持這種作法,但不推薦這樣作,建議改成
1 struct tagNode 2 { 3 char *pItem; 4 struct tagNode *pNext; 5 }; 6 typedef struct tagNode *pNode;
#define函數格式:
#define 標識符 字符串,標識符成爲宏名,宏替換時不作任何語法檢查
1 typedef char* pStr1; 2 #define pStr2 char*
3 pStr1 s1,s2; 4 pStr2 s3,s4;
在上述的變量定義中,s一、s二、s3都被定義爲char *,而s4則定義成了char,不是咱們所預期的指針變量,根本緣由就在於#define只是簡單的字符串替換而typedef則是爲一個類型起新名字。
上例中#define語句應該寫成 pStr2 s3, *s4;
就是在一個結構體內包含了另外一個結構體做爲其成員
1 typedef struct date 2 { 3 int year; 4 int month; 5 int day; 6 }DATE; 7
8 typedef struct student 9 { 10 long studentID; 11 char studentName[10]; 12 char studentSex; 13 DATE birthday; 14 int score[4]; 15 }STUDENT; 16 STUDENT pp;
上面代碼中,定義告終構體變量birthday和pp,並給struct date和struct student分別取別名爲DATE和STUDENT,
當出現結構體嵌套時,必須以級聯方式訪問結構體成員,即經過成員選擇運算符逐級找到最底層的成員時再引用
1 pp.birthday.day = 10; 2 printf("%d", pp.birthday.day);
上面是使用了typedef的結構體嵌套,也能夠不使用,代碼以下
1 struct STUDENT 2 { 3 long studentID; 4 char studentName[10]; 5 char studentSex; 6 int score[4]; 7 struct DATE 8 { 9 int year; 10 int month; 11 int day; 12 }birthday; 13 }student;
定義告終構體變量student和birthday,引用成員的的方法和上面相似
1 student.birthday.day = 100; 2 printf("%d", student.birthday.day);
C語言容許對具備相同結構體類型的變量進行總體賦值,注意:對字符數組型結構體成員進行賦值時必定要使用strcpy()
1 strcpy(stu1.studentName, 「王剛」);
而不能寫成
1 stu2.studentName = stu1.studentName
由於結構體成員studentName是一個字符型數組,studentName是該數組的名字,表明字符型數組的首地址,是一個常量,不能做爲賦值表達式的左值,
結構體所佔內存的字節數,不是簡單的相加, 由於對多數計算機而言,爲了提升內存尋址的效率,不少處理器體系結構爲特定的數據類型引入了特殊了內存對齊需求,
不一樣的系統和編譯器,內存對齊的方式有所不一樣,爲了知足處理器的對其要求,可能會在較小的成員後加入補位,例:
1 Typedef struct sample 2 { 3 Char m1; 4 Int m2; 5 Char m3; 6 }SAMPLE;
字節長度爲12而不是1+4+1=6字節長度,即sizeof(struct sample)==12;
1 typedef struct student 2 { 3 long studentID; 4 char studentName[10]; 5 char studentSex; 6 DATE birthday; 7 int score[4]; 8 }STUDENT; 9 STUDENT stu1; 10 STUDENT *pt; 11 pt = &stu1;
或者
1 STUDENT *pt = &stu1;
上面的代碼中,定義告終構體變量stu1,和結構體指針變量pt,並將stu1變量的地址賦值給了指針變量pt
假設已聲明瞭STUDENT結構體類型,而且已定義了一個有30個元素的結構體數組stu,則定義結構體指針變量pt並將其指向結構體數組stu的方法爲:
1 STUDENT *pt = stu;
等價於
1 STUDENT *pt = &stu[0];
等價於
1 STUDENT *pt; 2 pt = stu;
將結構體傳遞給函數的方式有以下3種:
1.用結構體的單個成員做爲函數參數,向函數傳遞結構體的單個成員(屬於傳值調用,不會影響相應的實參結構體的值)
2.用結構體變量作函數參數,向函數傳遞結構體完整結構(屬於傳值調用,不會影響相應的實參結構體的值)
3.用結構體指針或結構體數組做函數參數屬於模擬按引用調用,會影響相應的實參結構體的值,向函數傳遞結構體地址,由於僅複製結構體首地址一個值給被調函數,相對於第二種方式,這種傳遞效率更高
按值調用:將程序將函數調用語句中的實參的一份副本傳給函數的形參
模擬按引用調用:指針做爲函數的參數,雖然實際上也是傳值給被調用函數,可是傳給被調用函數的這個值不是變量的值,而是變量的地址,
經過向被調用函數傳遞某個變量的地址值能夠在被調函數中改變主調函數中這個變量的值,至關於模擬C++中的按引用調用所以稱爲模擬按引用調用
參考連接:
http://www.javashuo.com/article/p-gfvlhpwk-kr.html