嵌入式C語言中結構體詳解2016

C語言允許用戶自己指定這樣一種數據結構,它由不同類型的數據組合成一個整體,以便引用,這些組合在一個整體中的數據是互相聯繫的,這樣的數據結構稱爲結構體,它相當於其它高級語言中記錄。

嵌入式C語言中結構體詳解2016

聲明一個結構休類型的一般形式如下:

struct 結構體名

{成員列表};

結構體名,用作結構體類型的標誌,它又稱 結構體標記,大括號內是該結構體中的各個成員,由它們組成一個結構體,對各成員都應進行類型聲明如:

類型名 成員名;

也可以把 成員列表稱爲 域表,第一個成員也稱爲結構體中的一個域。成員名定名規則寫變量名同。

struct student

{

int num;

char name[20];

char sex;

int age;

float score;

char addr[30];

};

  定義結構體類型變量的方法

前面只是指定了一個結構體類型,它相當於一個模型,但其中並無具體數據,系統對之也不分配實際內存單元,爲了能在程序中使用結構類型的數據,應當定義結構體類型的變量,並在其中存放具體的數據,可以採取以下3種方法定義結構體類型變量。

(1)先聲明結構體類型再定義變量名

如上面已定義了一個結構體類型 struct student,可以用它來定義變量。如:

struct student //結構體類型名

student1, student2//結構體變量名

定義了 student1, student2 爲 struct student 類型的變量。

在定義了結構體變量後,系統會爲之分配內存單元。例如 student1 和 student2在內存中各佔59個字節。

應當注意,將一個變量定義爲標準類型(基本數據類型)與定義爲結構體類型不同之處在於後者不僅要求指定變量爲結構體類型,而且要求指定爲某一特定的結構體類型(例如 struct student 類型),因爲可以定義出許多種具體的結構體類型。而在定義變量爲整形時,只需指定爲 int 型即可。

(2)在聲明類型的同時定義變量

例如:

struct student

{

int num;

char name[20];

char sex;

int age;

float score;

char addr[30];

}student1, student2;

它的作用與第一種方法相同,即定義了兩個 struct student 類型的變量 student1, student2 這種形式的定義的一般形式爲

struct 結構體名

{

成員表列

}變量名錶列;

(3)直接定義結構類型變量

其一般形式爲

struct

{

成員表列

}變量名錶列;

即不出現結構體名。

關於結構體類型,有幾點要說明:

a. 類型與變量是不同的概念,不是混同,只能對變量賦值,存取或運算,而不能對一個類型賦值,存取或運算。在編譯時,對類型是不分配空間的,只對變量分配空間。

b. 對結構體中的成員(即 域)可以單元使用,它的作用與地位相當於普通變量,

c. 成員也可以是一個結構體變量。

如:

struct date // 聲明一個結構體類型

{

int month;

int day;

int year;

}

struct student

{

int num;

char name[20];

char sex;

int age;

struct date birthday;

char addr[30];

}student1, student2;

先聲明一個 struct date 類型,它代表 日期 包括3個成員 month, day, year。然後在聲明 struct student 類型時,將成員 birthday 指定爲 struct date 類型。

d. 成員名可以與程序中的變量名相同,二者不代表同一對象。

  結構體變量的引用

(1)不能將一個結構體變量作爲一個整體進行輸入和輸出。

只能對結構體變量中的各個成員分別進行輸入輸出。引用結構體變量中的成員的方式爲

結構體變量名.成員名

例如 表示 student1 變量中的 num 成員,即 student1 的 num 項,可以對變量的成員賦值。例如:

= 10010;

"." 是成員(分量)運算符,它在所有的運算符中優先級最高,因此可以把 作爲一個整體來看待。上面的賦值語句作用是將整數 10010賦給 student1 變量中的成員 num。

(2)如果成員本身又屬一個結構體類型,則要用若干個成員運算符,一級一級地找到最低一級的成員。只能對最低的成員進行賦值或存取以及運算。

例如:結構體變量 student1 可以這樣訪問各成員:

h

注意,不能用 hday 來訪問 student1 變量中的成員 birthday,因爲 birthday 本身是一個結構體變量。

(3)對結構體變量的成員可以像普通變量一樣進行各種運算(根據其類型決定可以進行的運算)。

e = e;

sum = e + e;

++;

++ ;

由於 "." 運算符的優先級最高,因此 ++ 是對 進行自加運算。而不是先對 age 進行自加運算。

(4)可以引用結構體變量成員的地址。也可以引用結構體變量的地址。如:

scanf("%d", &);// 輸入 的值

printf("%o", &student1);// 輸出 student1 的首地址

但不能用以下語句整體讀入結構體變量如:

scanf("%d,%s,%c,%d,%f,%s", &student1);

結構體變量的地址主要用於作函數參數,傳遞結構體的地址。

  結構體變量的初始化

和其它類型變量一樣,對結構體變量可以在定義時指定初始值。

如:

#include

struct student

{

long int num;

char name[20];

char sex;

char addr[30];

}a = {89031, "Li Lin", 'M', "123 Beijing Road"};

void main()

{

printf("NO. : %dnname: %snsex: %cnaddress: %sn", , , , );

}

  結構體數組

一個結構體變量中可以存放一組數據(如一個學生的學號,姓名,成績等數據)。如果有10個學生的數據需要參加運算,顯然應該用數組,這就是結構體數組。結構體數組與以前介紹過的數據值型數組不同之處在於每個數組元素都一個結構體類型的數據,它們分別包括各個成員(分量)項。

5.1 定義結構體數組

和定義結構體變量的方法相仿,只需說明其爲數組即可。

struct student

{

int num;

char name[20];

char sex;

int age;

float score;

char addr[30];

};

struct student stu[3];

以上定義了一個數組 stu,其元素爲 struct student 類型數據,數組有 3 個元素。也可以直接定義一個結構體數組。如:

struct student

{

int num;

....

}stu[3];

struct

{

int num;

...

}stu[3];

5.2 結構體數組的初始化

與其它類型數組一樣,對結構體數組可以初始化如:

struct student

{

int mum;

char name[20];

char sex;

int age;

float score;

char addr[30];

}stu[3] = {{10101,"Li Lin", 'M', 18, 87.5, "103 Beijing Road"},

{10101,"Li Lin", 'M', 18, 87.5, "103 Beijing Road"},

{10101,"Li Lin", 'M', 18, 87.5, "103 Beijing Road"}};

定義數組 stu 時,元素個數可以不指定,即寫成以下形式:

stu[] = {{...},{...},{...}};

編譯時,系統會根據給出初值的結構體常量的個數來確定數組元素的個數。

當然,數組的初始化也可以用以下形式:

struct student

{

int num;

...

};

struct student stu[] = {{...},{...},{...}};

即先聲明結構體類型,然後定義數組爲該結構體類型,在定義數組時初始化。

從以上可以看到,結構體數組初始化的一般形式是在定義數組的後面加上:

5.3 結構體數組應用舉例

下面例子說明結構體數組的定義和引用。

#include

#include

#include

struct person

{

char name[20];

int count;

}leader[3] = {{"Li", 0},

{"Zhang", 0},

{"Fun", 0}};

void main()

{

int i, j;

char leader_name[20];

for(i = 1; i<= 10;i++)

{

scanf("%s", leader_name);

for(j=0;j<3;j++)

if(strcmp(leader_name, leader[j]) == 0)

leader[j]t ++;

}

printf("n");

for(i=0;i<3;i++)

printf("%5s: %dn", leader[i], leader[i]t);

system("pause");

}

運行結果如下:

LI

Li

Fun

Zhang

Zhang

Fun

Li

Fun

Zhang

Li

Li: 3

Zhang: 3

Fun: 3

  指向結構體類型數據的指針

一個結構體變量的指針就是該變量所佔據的內存段的起始地址,可以設一個指針變量,用來指向一個結構體變量,此時該指針變量的值是結構體變量的起始地址。指針變量也可以用來指向結構體數組中的元素。

6.1 指向結構體變量的指針

指向結構體變量的指針的應用:

#include

#include

#include

struct student

{

long num;

char name[20];

char sex;

float score;

};

void main()

{

struct student stu_1;

struct student *p;

p = &stu_1;

stu_ = 89101;

strcpy(stu_, "Li Lin");

stu_ = 'M';

stu_e = 89.5;

printf("NO. :%ldnname: %snsex:%cnscore:%fn", stu_, stu_, stu_, stu_e);

printf("NO. :%ldnname: %snsex:%cnscore:%fn", (*p), (*p), (*p), (*p)e);

system("pause");

}

在主函數中聲明瞭 struct student 類型,然後定義了一個 struct student 類型的變量,stu_1 同時又定義一個指針變量 p ,它指向一個 struct student 類型的數據,在函數的執行部分將結構體變量 stu_1 的起始地址賦給指針變量 p ,也就是使 p 指向 stu_1 然後對 stu_1 的各成員賦值,第二個 printf 函數也是用來輸出 stu_1 各成員的值,但使用的是 (*p) 這樣的.形式, (*p) 表示 p 指向的結構體變量,(*p) 是 p 指向的結構體變量中的成員 num 。注意 *p 兩側的括弧不可省略,因爲成員運算符 '.' 優先於 '*' 運算符,* 就等價於 *()

運行結果如下:

NO. :89101

name: Li Lin

sex:M

score:89.500000

NO. :89101

name: Li Lin

sex:M

score:89.500000

可以看到兩個 printf 輸出的結果相同。

在C語言中,爲了使用方便和使之直觀,可以把 (*p) 改用 p->num 來代替,它表示 *p 所指向的結構體變量中的 num 成員,同樣,(*p) 等價於 p->name。

也就是說以下三種形式等價:

a. 結構體變量.成員名

b. (*p).成員名

c. p->成員名

上面的最後一個 printf 函數輸了項可以改寫爲

printf("NO. :%ldnname: %snsex:%cnscore:%fn",p->num, p->name, p->sex, p->score);

其中 -> 稱爲指向運算符。

分析以下幾種運算符

p -> n 得到 p 指向的結構體變量中的成員 n 的值

p -> n ++ 得到 p 指向的結構體變量中的成員 n 的值,用完值後使它加1

++p -> n 得到 p 指向的結構體變量中的成員 n 的值使之加 1 (先加)

6.2 指向結構體數組的指針

以前介紹過可以使用指向數組或數組元素的指針和指針變量,同樣,對結構體數組及其元素也可以用指針變量來指向。

指向結構體數組的指針的應用

#include

#inlcude

struct student

{

int num;

char name[20];

char sex;

int age;

};

struct student stu[3] = {{10101, "Li Lin", 'M', 18},

{10102, "Zhang Fun", 'M', 19},

{10103, "Wang Min", 'F', 20}};

void main()

{

struct student *p;

printf("No.  name    sex    agen");

for(p=stu; p

printf("%5d %-20s %2c %4dn", p->num, p->name, p->sex, p->age);

system("pause");

}

運行結果如下:

No.  name    sex    age

10101 Li Lin M   18

10102 Zhang Fun M   19

10103 Wang Min F    20

注意以下兩點:

(1)如果 p 的初值爲 stu,即指向第一個元素,則 p + 1 後指向下一個元素的起始地址。例如:

(++p) -> num 先使 p 自加 1 ,然後得到它指向的元素中的 num 成員的值(即10102)。

(p++) ->num 先得到 p->num 的值(即10101),然後使 p 自加 1 ,指向 stu[1]。

注意以上二者的不同。

(2)程序已定義了指針 p 爲指向 struct student 類型數據的變量,它只能指向一個 struct student 型的數據(p 的值是 stu 數組的一個元素的起始地址),而不能指向 stu 數組元素中的某一成員,(即 p 的地址不能是成員地址)。例如,下面是不對的:

p = &stu[1]

編譯時將出錯。千萬不要認爲反正 p 是存放地址的,可以將任何地址賦給它。如果地址類型不相同,可以用強制類型轉換。例如:

p = (struct student *)&stu[1];

此時,在 p 中存放 stu[1] 元素的 name 成員的起始地址。

6.3 用結構體變量和指向結構體的指針作函數參數

將一個結構體變量的值傳遞給另一個函數,有3個方法:

(1)用結構體變量的成員作參數,例如:用 stu[1] 或 stu[2] 作函數實參,將實參值傳給形參。用法和用普通變量作實參是一樣的,屬於 值傳遞 方式。應當注意實參與形參的類型保持一致。

(2)用結構體變量作參數。老版本的C系統不允許用結構體變量作實參,ANSI C取消了這一限制。但是用結構體變量作實參時,採取的是 值傳遞 的方式,將結構體變量所佔的內存單元全部順序傳遞給形參。形參也必須是同類型的結構體變量。在函數調用期間形參也要佔用內存單元。這種傳遞方式在空間和時間上開銷較大,如果結構體的規模很大時,開銷是很可觀的,此外由於採用值傳遞方式,如果在執行被調用函數期間改變了形參(也是結構體變量)的值,該值不能返回主調函數,這往往造成使用上的不便。因此一般較少用這種方法。

(3)用指向結構體變量(或數組)的指針作實參,將結構體變量(或數組)的地址傳給形參。

用結構體變量作函數參數。

#include

#define FORMAT "%dn%sn%fn%fn%fn"

struct student

{

int num;

char name[20];

float score[3];

};

void print(struct student stu)

{

printf(FORMAT, , e[0], e[1], e[2]);

printf("n");

}

void main()

{

struct student stu;

= 12345;

strcpy(, "Li Li");

e[0] = 67.5;

e[1] = 89;

e[2] = 78.6;

printf(stu);

}

將上面改用指向結構體變量的指針作實參。

#include

#define FORMAT "%dn%sn%fn%fn%fn"

struct student

{

int num;

char name[20];

float score[3];

}stu = {12345, "Li Li", 67.5, 89, 78.6};

void print(struct student *p)

{

printf(FORMAT, p->num, p->name, p->score[0], p->score[1], p->score[2]);

printf("n");

}

void main()

{

print(&stu);

}