結(jié)構(gòu)體概述
1 在C語(yǔ)言中,結(jié)構(gòu)體(struct)指的是一種數(shù)據(jù)結(jié)構(gòu),是C語(yǔ)
言中構(gòu)造類型的其中之一。
2 在實(shí)際應(yīng)用中,我們通常需要由不同類型的數(shù)據(jù)來(lái)構(gòu)成一
個(gè)整體,比如學(xué)生這個(gè)整體可以由姓名、年齡、身高等數(shù)
據(jù)構(gòu)成,這些數(shù)據(jù)都具有不同的類型,姓名可以是字符串
類型,年齡可以是整型,身高可以是浮點(diǎn)型。
3 C語(yǔ)言便提供了結(jié)構(gòu)體來(lái)解決我們的這種需求,它允許內(nèi)
部的元素是不同類型的
4.結(jié)構(gòu)體是一種自定義的數(shù)據(jù)類型。
結(jié)構(gòu)體
結(jié)構(gòu)體的定義:
struct 結(jié)構(gòu)體名 {
類型說明符 成員名;
類型說明符 成員名;
類型說明符 成員名;
… …
類型說明符 成員名;
?}
舉例,定義如下結(jié)構(gòu)體:
struct teacher {
char name[20];
int age;
float height;
};
三、結(jié)構(gòu)體變量的定義
結(jié)構(gòu)體變量
第一種方式: 先定義結(jié)構(gòu)體類型,再定義變量
? 此定義方式與普通數(shù)據(jù)類型變量的定義方式相同;
? struct 結(jié)構(gòu)體名 變量名;
注意: 其中struct 結(jié)構(gòu)名才為數(shù)據(jù)類型, 單純的結(jié)構(gòu)名不
算作數(shù)據(jù)類型。
結(jié)構(gòu)體變量
struct teacher {
char name[20];
int age;
float height;
};
struct teacher englishTeacher;
結(jié)構(gòu)體變量
第二種方式: 定義結(jié)構(gòu)體類型的同時(shí)定義變量:
struct teacher {
char name[20];
int age;
float height;
} mathTeacher;
其中mathTeacher為變量名。
結(jié)構(gòu)體變量
第三種方式: 直接定義結(jié)構(gòu)體類型變量,省略類型名:
struct {
char name[20];
int age;
float height;
} chineseTeacher;
? 其中chineseTeacher為變量名, 此結(jié)構(gòu)體我們稱為匿名結(jié)構(gòu)體
結(jié)構(gòu)體的重定義
結(jié)構(gòu)體的重定義方式分為兩種:
1. 對(duì)已有結(jié)構(gòu)體進(jìn)行重定義:
typedef struct teacher Teacher;
2. 在創(chuàng)建結(jié)構(gòu)體時(shí), 進(jìn)行重定義:
typedef struct teacher {
char name[20];
int age;
float height;
} Teacher;
結(jié)構(gòu)體變量的成員
結(jié)構(gòu)體變量成員的賦值:
englishTeacher = {“老王”, 23, 1.70f};
注意:賦值時(shí), 需按照成員的順序依次賦值。
結(jié)構(gòu)體變量的成員
? 引入新的操作符?
? 先找到結(jié)構(gòu)體變量,再通過 . 操作符訪問變量的成員;
? 簡(jiǎn)單數(shù)據(jù)類型的age可以直接賦值;
? englishTeacher.age = 30
? 字符數(shù)組區(qū)別于簡(jiǎn)單數(shù)據(jù)類型, 如下直接賦值是不可以的:
? englishTeacher.name = “老張” ? ? (不可以的)
? 字符串成員賦值需要使用字符串拷貝函數(shù)。
結(jié)構(gòu)體變量的成員
? 結(jié)構(gòu)體成員的訪問 .語(yǔ)法既可以賦值也可以取值:
? printf(“englishTeacher.age = %d”, englishTeacher.age);
結(jié)構(gòu)體變量的注意事項(xiàng)
? 結(jié)構(gòu)體與結(jié)構(gòu)體可以直接賦值:
? 例如:
englishTeacher = mathTeacher;
注意:數(shù)組是不可以直接賦值的
小技巧: 可以通過把數(shù)組作為結(jié)構(gòu)體的成員實(shí)現(xiàn)直接賦值。
六、結(jié)構(gòu)體的內(nèi)存分配
分配方式以最大成員類型所占空間為分配單位
按結(jié)構(gòu)體成員自上而下分配。
各成員變量在存放的時(shí)候根據(jù)在結(jié)構(gòu)體中出現(xiàn)的順序依次
申請(qǐng)空間,同時(shí)按照上面的對(duì)齊方式調(diào)整位置。
結(jié)構(gòu)體的內(nèi)存分配
? 內(nèi)存分配
struct s1 {
char a; // 為a 分配1 個(gè)字節(jié)
char name[20]; // 20個(gè)字節(jié)
char c; // 1個(gè)字節(jié)
};
? s1的大小為22 = 1+20+1
結(jié)構(gòu)體的內(nèi)存分配
字節(jié)對(duì)齊的細(xì)節(jié)和編譯器實(shí)現(xiàn)相關(guān),但一般而言,滿足
三個(gè)準(zhǔn)則:
1) 結(jié)構(gòu)體變量的首地址能夠被其最寬基本類型成員的大小所
整除;
2) 結(jié)構(gòu)體每個(gè)成員相對(duì)于結(jié)構(gòu)體首地址的偏移量(offset)
都是成員大小的整數(shù)倍,如有需要編譯器會(huì)在成員之間加上
填充字節(jié)(internal adding);
3) 結(jié)構(gòu)體的總大小為結(jié)構(gòu)體最寬基本類型成員大小的整數(shù)倍,
如有需要編譯器會(huì)在最末一個(gè)成員之后加上填充字節(jié)
(trailing padding)。
七、結(jié)構(gòu)體嵌套
? 結(jié)構(gòu)體與結(jié)構(gòu)體是可以嵌套使用的,如下:
struct car {
char carName[20];
int carNum;
};
typedef struct car Car;
struct person {
char name[20];
Car car;
};
? 結(jié)構(gòu)體與結(jié)構(gòu)體是可以嵌套使用的,如下:
struct car {
char carName[20];
int carNum;
};
typedef struct car Car;
struct person {
char name[20];
Car car;
};
? 結(jié)構(gòu)體嵌套時(shí),應(yīng)注意避免使用結(jié)構(gòu)體本身, 如下寫法是
錯(cuò)誤的:
struct person {
char name[20];
struct person per;
};
八、結(jié)構(gòu)體數(shù)組
結(jié)構(gòu)體數(shù)組的定義
? 定義一個(gè)結(jié)構(gòu)體數(shù)組的方式與定義普通類型數(shù)組一樣
? 數(shù)據(jù)類型 數(shù)組名[數(shù)組長(zhǎng)度] = {初值};
Teacher tea[20] = {englishTeacher,
chineseTeacher, mathTeacher};
結(jié)構(gòu)體數(shù)組元素的訪問
? 通過.語(yǔ)法可直接訪問元素的成員
注意:結(jié)構(gòu)體數(shù)組中存放的是相同結(jié)構(gòu)體類型的結(jié)構(gòu)體。
總結(jié)
1. 結(jié)構(gòu)體是一種比較靈活的 數(shù)據(jù)類型,并且與OC要學(xué)的類很
相似。
2. 結(jié)構(gòu)體與數(shù)組都是構(gòu)造類型。
3. 結(jié)構(gòu)體與數(shù)組相互嵌套,可以實(shí)現(xiàn)較為復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。