1. 程式人生 > >結構體(結構體嵌套、結構體指針、結構體參數傳遞)

結構體(結構體嵌套、結構體指針、結構體參數傳遞)

birt char* 別名 不同的 logs under 情況 計算 調用

結構體(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

結構體(結構體嵌套、結構體指針、結構體參數傳遞)