結構體(結構體嵌套、結構體指針、結構體參數傳遞)
結構體(struct)
1、基本概念
結構體-----將不同類型的數據成員組織到統一的名字之下,適用於對關系緊密,邏輯相關、具有相同或不同類型的數據進行處理
2、結構體定義格式
struct 結構名(也可稱作結構標識符)
{
類型 變量名;
類型 變量名;
······
};
struct 結構名 結構變量;
或者
struct 結構名
{
類型 變量名;
類型 變量名;
······
}結構變量;
例:聲明結構體類型的同時定義變量名
1 struct student
2 {
3 int num;
4 }teacher;
定義了一個結構名為student的結構體和一個結構變量teacher,如果省略變量名(teacher),就變成了對結構的聲明,上述結構體聲明也可分開寫
1 struct student
2 {
3 int num;
4 };
5
6 struct student teacher;
與上面效果相同,可理解為struct student類似於int,而我們用的是teacher類似於變量,如果省略結構名,則稱之為無名結構,這種情況常常出現在函數內部
1 struct
2 {
3 int num;
4 }teacher;
(在聲明結構體時常常與typedef函數配合使用)
3、結構體成員的訪問
訪問結構體變量的成員必須使用成員選擇運算符(也稱圓點運算符),格式為:結構體變量名.成員名
若使用指針對結構體成員進行訪問,格式為:指針->成員名 等價於 (*指針).成員名
4、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;
5、typedef函數與#define函數
#define函數格式:
#define 標識符 字符串,標識符成為宏名,宏替換時不做任何語法檢查
1 typedef char* pStr1;
2 #define pStr2 char*
3 pStr1 s1,s2;
4 pStr2 s3,s4;
在上述的變量定義中,s1、s2、s3都被定義為char *,而s4則定義成了char,不是我們所預期的指針變量,根本原因就在於#define只是簡單的字符串替換而typedef則是為一個類型起新名字。
上例中#define語句應該寫成 pStr2 s3, *s4;
6、結構體嵌套
就是在一個結構體內包含了另一個結構體作為其成員
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;
當出現結構體嵌套時,必須以級聯方式訪問結構體成員,即通過成員選擇運算符逐級找到最底層的成員時再引用
1 STUDENT pp;
2 pp.birthday.day = 10;
3 printf("%d", pp.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;
7、結構體指針的定義和初始化
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;
指向結構體數組的指針,假設已聲明了STUDENT結構體類型,並且已定義了一個有30個元素的結構體數組stu,則定義結構體指針變量pt並將其指向結構體數組stu的方法為:
1 STUDENT *pt = stu;
等價於
1 STUDENT *pt = &stu[0];
等價於
1 STUDENT *pt; 2 pt = stu;
8、向函數傳遞結構體(參數傳遞)
將結構體傳遞給函數的方式有如下3種:
1.用結構體的單個成員作為函數參數,向函數傳遞結構體的單個成員(屬於傳值調用,不會影響相應的實參結構體的值)
2.用結構體變量做函數參數,向函數傳遞結構體完整結構(屬於傳值調用,不會影響相應的實參結構體的值)
3.用結構體指針或結構體數組作函數參數屬於模擬按引用調用,向函數傳遞結構體地址,因為僅復制結構體首地址一個值給被調函數,相對於第二種方式,這種傳遞效率更高
參考鏈接:
https://www.cnblogs.com/ktao/p/8578074.html
https://www.cnblogs.com/qyaizs/articles/2039101.html
http://c.biancheng.net/view/298.html
結構體(結構體嵌套、結構體指針、結構體參數傳遞)