當(dāng)前位置:首頁(yè) > 嵌入式培訓(xùn) > 嵌入式學(xué)習(xí) > 講師博文 > 【C語(yǔ)言】21-結(jié)構(gòu)體
本文目錄
• 一、什么是結(jié)構(gòu)體
• 二、結(jié)構(gòu)體的定義
• 三、結(jié)構(gòu)體變量的定義
• 四、結(jié)構(gòu)體的注意點(diǎn)
• 五、結(jié)構(gòu)體的初始化
• 六、結(jié)構(gòu)體的使用
• 七、結(jié)構(gòu)體數(shù)組
• 八、結(jié)構(gòu)體作為函數(shù)參數(shù)
• 九、指向結(jié)構(gòu)體的指針
說(shuō)明:這個(gè)C語(yǔ)言專題,是學(xué)習(xí)iOS開發(fā)的前奏。也為了讓有面向?qū)ο笳Z(yǔ)言開發(fā)經(jīng)驗(yàn)的程序員,能夠快速上手C語(yǔ)言。如果你還沒(méi)有編程經(jīng)驗(yàn),或者對(duì)C語(yǔ)言、iOS開發(fā)不感興趣,請(qǐng)忽略
C語(yǔ)言的核心部分都說(shuō)得七七八八了,相信大家已經(jīng)對(duì)C語(yǔ)言的基本數(shù)據(jù)類型(char\int\float)、數(shù)組、指針都很熟悉了,今天來(lái)學(xué)習(xí)C語(yǔ)言中另外一種數(shù)據(jù)類型:結(jié)構(gòu)體。在iOS開發(fā)中,結(jié)構(gòu)體是經(jīng)常用到的數(shù)據(jù)類型,使用頻率不亞于指針,所以需要重視,不過(guò)用法非常簡(jiǎn)單。
一、什么是結(jié)構(gòu)體
* 在第八講的時(shí)候已經(jīng)介紹了C語(yǔ)言中的數(shù)組,用法跟其他語(yǔ)言差不多。當(dāng)一個(gè)整體由多個(gè)數(shù)據(jù)構(gòu)成時(shí),我們可以用數(shù)組來(lái)表示這個(gè)整體,但是數(shù)組有個(gè)特點(diǎn):內(nèi)部的每一個(gè)元素都必須是相同類型的數(shù)據(jù)。
* 在實(shí)際應(yīng)用中,我們通常需要由不同類型的數(shù)據(jù)來(lái)構(gòu)成一個(gè)整體,比如學(xué)生這個(gè)整體可以由姓名、年齡、身高等數(shù)據(jù)構(gòu)成,這些數(shù)據(jù)都具有不同的類型,姓名可以是字符串類型,年齡可以是整型,身高可以是浮點(diǎn)型。
* 為此,C語(yǔ)言專門提供了一種構(gòu)造類型來(lái)解決上述問(wèn)題,這就是結(jié)構(gòu)體,它允許內(nèi)部的元素是不同類型的。
二、結(jié)構(gòu)體的定義
1.定義形式
結(jié)構(gòu)體內(nèi)部的元素,也就是組成成分,我們一般稱為"成員"。
結(jié)構(gòu)體的一般定義形式為:
struct 結(jié)構(gòu)體名{
類型名1 成員名1;
類型名2 成員名2;
……
類型名n 成員名n;
};
struct是關(guān)鍵字,是結(jié)構(gòu)體類型的標(biāo)志。
2.舉例
比如,我們定義一個(gè)學(xué)生
struct Student {
char *name; // 姓名
int age; // 年齡
float height; // 身高
};
上面定義了一個(gè)叫做Student的結(jié)構(gòu)體,共有name、age、height3個(gè)成員。呵呵,看到這里是否有點(diǎn)面向?qū)ο蟮奈兜滥,其?shí)這跟面向?qū)ο笸耆莾纱a事,只能說(shuō)感覺(jué)有點(diǎn)像。
三、結(jié)構(gòu)體變量的定義
前面只是定義了名字為Student的結(jié)構(gòu)體類型,并非定義了一個(gè)結(jié)構(gòu)體變量,就像int一樣,只是一種類型。
接下來(lái)定義一個(gè)結(jié)構(gòu)體變量,方式有好多種。
1.先定義結(jié)構(gòu)體類型,再定義變量
struct Student {
char *name;
int age;
};
struct Student stu;
第6行定義了一個(gè)結(jié)構(gòu)體變量,變量名為stu。struct和Student是連著使用的。
2.定義結(jié)構(gòu)體類型的同時(shí)定義變量
struct Student {
char *name;
int age;
} stu;
結(jié)構(gòu)體變量名為stu
3.直接定義結(jié)構(gòu)體類型變量,省略類型名
struct {
char *name;
int age;
} stu;
結(jié)構(gòu)體變量名為stu
四、結(jié)構(gòu)體的注意點(diǎn)
1.不允許對(duì)結(jié)構(gòu)體本身遞歸定義
如下做法是錯(cuò)誤的,注意第3行
struct Student {
int age;
struct Student stu;
};
2.結(jié)構(gòu)體內(nèi)可以包含別的結(jié)構(gòu)體
struct Date {
int year;
int month;
int day;
};
struct Student {
char *name;
struct Date birthday;
};
注意第9行
3.定義結(jié)構(gòu)體類型,只是說(shuō)明了該類型的組成情況,并沒(méi)有給它分配存儲(chǔ)空間,就像系統(tǒng)不為int類型本身分配空間一樣。只有當(dāng)定義屬于結(jié)構(gòu)體類型的變量時(shí),系統(tǒng)才會(huì)分配存儲(chǔ)空間給該變量
struct Student {
char *name;
int age;
};
struct Student stu;
第1~4行并沒(méi)有分配存儲(chǔ)空間,當(dāng)執(zhí)行到第6行時(shí),系統(tǒng)才會(huì)分配存儲(chǔ)空間給stu變量。
4.結(jié)構(gòu)體變量占用的內(nèi)存空間是其成員所占內(nèi)存之和,而且各成員在內(nèi)存中按定義的順序依次排列
比如下面的Student結(jié)構(gòu)體:
struct Student {
char *name; // 姓名
int age; // 年齡
float height; // 身高
};
在16位編譯器環(huán)境下,一個(gè)Student變量共占用內(nèi)存:2 + 2 + 4 = 8字節(jié)。
五、結(jié)構(gòu)體的初始化
將各成員的初值,按順序地放在一對(duì)大括號(hào){}中,并用逗號(hào)分隔,一一對(duì)應(yīng)賦值。
比如初始化Student結(jié)構(gòu)體變量stu
struct Student {
char *name;
int age;
};
struct Student stu = {"MJ", 27};
只能在定義變量的同時(shí)進(jìn)行初始化賦值,初始化賦值和變量的定義不能分開,下面的做法是錯(cuò)誤的:
struct Student stu;
stu = {"MJ", 27};
六、結(jié)構(gòu)體的使用
1.一般對(duì)結(jié)構(gòu)體變量的操作是以成員為單位進(jìn)行的,引用的一般形式為:結(jié)構(gòu)體變量名.成員名
struct Student {
char *name;
int age;
};
struct Student stu;
// 訪問(wèn)stu的age成員
stu.age = 27;
第9行對(duì)結(jié)構(gòu)體的age成員進(jìn)行了賦值。"."稱為成員運(yùn)算符,它在所有運(yùn)算符中優(yōu)先級(jí)高
2.如果某個(gè)成員也是結(jié)構(gòu)體變量,可以連續(xù)使用成員運(yùn)算符"."訪問(wèn)低一級(jí)成員
struct Date {
int year;
int month;
int day;
};
struct Student {
char *name;
struct Date birthday;
};
struct Student stu;
stu.birthday.year = 1986;
stu.birthday.month = 9;
stu.birthday.day = 10;
注意第14行以后的代碼
3.相同類型的結(jié)構(gòu)體變量之間可以進(jìn)行整體賦值
struct Student {
char *name;
int age;
};
struct Student stu1 = {"MJ", 27};
// 將stu1直接賦值給stu2
struct Student stu2 = stu1;
printf("age is %d", stu2.age);
注意第9行。輸出結(jié)果為:
七、結(jié)構(gòu)體數(shù)組
1.定義
跟結(jié)構(gòu)體變量一樣,結(jié)構(gòu)體數(shù)組也有3種定義方式
struct Student {
char *name;
int age;
};
struct Student stu[5]; //定義1
struct Student {
char *name;
int age;
} stu[5]; //定義2
struct {
char *name;
int age;
} stu[5]; //定義3
上面3種方式,都是定義了一個(gè)變量名為stu的結(jié)構(gòu)體數(shù)組,數(shù)組元素個(gè)數(shù)是5
2.初始化
struct {
char *name;
int age;
} stu[2] = { {"MJ", 27}, {"JJ", 30} };
也可以用數(shù)組下標(biāo)訪問(wèn)每一個(gè)結(jié)構(gòu)體元素,跟普通數(shù)組的用法是一樣的
八、結(jié)構(gòu)體作為函數(shù)參數(shù)
將結(jié)構(gòu)體變量作為函數(shù)參數(shù)進(jìn)行傳遞時(shí),其實(shí)傳遞的是全部成員的值,也就是將實(shí)參中成員的值一一賦值給對(duì)應(yīng)的形參成員。因此,形參的改變不會(huì)影響到實(shí)參。
#include <stdio.h>
// 定義一個(gè)結(jié)構(gòu)體
struct Student {
int age;
};
void test(struct Student stu) {
printf("修改前的形參:%d \n", stu.age);
// 修改實(shí)參中的age
stu.age = 10;
printf("修改后的形參:%d \n", stu.age);
}
int main(int argc, const char * argv[]) {
struct Student stu = {30};
printf("修改前的實(shí)參:%d \n", stu.age);
// 調(diào)用test函數(shù)
test(stu);
printf("修改后的實(shí)參:%d \n", stu.age);
return 0;
}
* 首先在第4行定義了一個(gè)結(jié)構(gòu)體類型Student
* 在第18行定義了一個(gè)結(jié)構(gòu)體變量stu,并在第22行將其作為實(shí)參傳入到test函數(shù)
輸出結(jié)果為: ,形參是改變了,但是實(shí)參一直沒(méi)有變過(guò)
九、指向結(jié)構(gòu)體的指針
* 每個(gè)結(jié)構(gòu)體變量都有自己的存儲(chǔ)空間和地址,因此指針也可以指向結(jié)構(gòu)體變量
* 結(jié)構(gòu)體指針變量的定義形式:struct 結(jié)構(gòu)體名稱 *指針變量名
* 有了指向結(jié)構(gòu)體的指針,那么就有3種訪問(wèn)結(jié)構(gòu)體成員的方式
• 結(jié)構(gòu)體變量名.成員名
• (*指針變量名).成員名
• 指針變量名->成員名
#include <stdio.h>
int main(int argc, const char * argv[]) {
// 定義一個(gè)結(jié)構(gòu)體類型
struct Student {
char *name;
int age;
};
// 定義一個(gè)結(jié)構(gòu)體變量
struct Student stu = {"MJ", 27};
// 定義一個(gè)指向結(jié)構(gòu)體的指針變量
struct Student *p;
// 指向結(jié)構(gòu)體變量stu
p = &stu;
/*
這時(shí)候可以用3種方式訪問(wèn)結(jié)構(gòu)體的成員
*/
// 方式1:結(jié)構(gòu)體變量名.成員名
printf("name=%s, age = %d \n", stu.name, stu.age);
// 方式2:(*指針變量名).成員名
printf("name=%s, age = %d \n", (*p).name, (*p).age);
// 方式3:指針變量名->成員名
printf("name=%s, age = %d \n", p->name, p->age);
return 0;
}