C語言容許用戶本身指定這樣一種數據結構,它由不一樣類型的數據組合成一個總體,以便引用,這些組合在一個總體中的數據是互相聯繫的,這樣的數據結構稱爲結構體,它至關於其它高級語言中記錄。程序員
聲明一個結構休類型的通常形式以下:編程
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 成員,即 student1 的 num 項,能夠對變量的成員賦值。例如:
student1.num = 10010;
"." 是成員(份量)運算符,它在全部的運算符中優先級最高,所以能夠把 student1.num 做爲一個總體來看待。上面的賦值語句做用是將整數 10010賦給 student1 變量中的成員 num。
(2)若是成員自己又屬一個結構體類型,則要用若干個成員運算符,一級一級地找到最低一級的成員。只能對最低的成員進行賦值或存取以及運算。
例如:結構體變量 student1 能夠這樣訪問各成員:
student1.num
student1.birthday.month
注意,不能用 student1.birthday 來訪問 student1 變量中的成員 birthday,由於 birthday 自己是一個結構體變量。
(3)對結構體變量的成員能夠像普通變量同樣進行各類運算(根據其類型決定能夠進行的運算)。
student2.score = student1.score;
sum = student1.score + student2.score;
student1.age ++;
++ student1.age;
因爲 "." 運算符的優先級最高,所以 student1.age ++ 是對 student1.age 進行自加運算。而不是先對 age 進行自加運算。
(4)能夠引用結構體變量成員的地址。也能夠引用結構體變量的地址。如:
scanf("%d", &student1.num);// 輸入 student1.num 的值
printf("%o", &student1);// 輸出 student1 的首地址
但不能用如下語句總體讀入結構體變量如:
scanf("%d,%s,%c,%d,%f,%s", &student1);
結構體變量的地址主要用於做函數參數,傳遞結構體的地址。
和其它類型變量同樣,對結構體變量能夠在定義時指定初始值。
如:
#include <stdio.h>
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. : %d\nname: %s\nsex: %c\naddress: %s\n", a.num, a.name, a.sex, a.addr);
}
一個結構體變量中能夠存放一組數據(如一個學生的學號,姓名,成績等數據)。若是有10個學生的數據須要參加運算,顯然應該用數組,這就是結構體數組。結構體數組與之前介紹過的數據值型數組不一樣之處在於每一個數組元素都一個結構體類型的數據,它們分別包括各個成員(份量)項。
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];
2 結構體數組的初始化
若是你也想成爲程序員,想要快速掌握編程,趕忙關注小編加入學習企鵝圈子吧!
裏面有資深專業軟件開發工程師,在線解答你的全部疑惑~編程語言入門「so easy」
免費學習書籍:
免費學習資料:
與其它類型數組同樣,對結構體數組能夠初始化如:
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[] = {{...},{...},{...}};
即先聲明結構體類型,而後定義數組爲該結構體類型,在定義數組時初始化。
從以上能夠看到,結構體數組初始化的通常形式是在定義數組的後面加上:
3 結構體數組應用舉例
下面例子說明結構體數組的定義和引用。
#include <stdio.h>
#include <string.h>
#include <stlib.h>
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].name) == 0)
leader[j].count ++;
}
printf("\n");
for(i=0;i<3;i++)
printf("%5s: %d\n", leader[i].name, leader[i].count);
system("pause");
}
運行結果以下:
LI
Li
Fun
Zhang
Zhang
Fun
Li
Fun
Zhang
Li
Li: 3
Zhang: 3
Fun: 3
一個結構體變量的指針就是該變量所佔據的內存段的起始地址,能夠設一個指針變量,用來指向一個結構體變量,此時該指針變量的值是結構體變量的起始地址。指針變量也能夠用來指向結構體數組中的元素。
1 指向結構體變量的指針
指向結構體變量的指針的應用:
#include <string.h>
#include <stdio.h>
#include <stdlib.b>
struct student
{
long num;
char name[20];
char sex;
float score;
};
void main()
{
struct student stu_1;
struct student *p;
p = &stu_1;
stu_1.num = 89101;
strcpy(stu_1.name, "Li Lin");
stu_1.sex = 'M';
stu_1.score = 89.5;
printf("NO. :%ld\nname: %s\nsex:%c\nscore:%f\n", stu_1.num, stu_1.name, stu_1.sex, stu_1.score);
printf("NO. :%ld\nname: %s\nsex:%c\nscore:%f\n", (*p).num, (*p).name, (*p).sex, (*p).score);
system("pause");
}
在主函數中聲明瞭 struct student 類型,而後定義了一個 struct student 類型的變量,stu_1 同時又定義一個指針變量 p ,它指向一個 struct student 類型的數據,在函數的執行部分將結構體變量 stu_1 的起始地址賦給指針變量 p ,也就是使 p 指向 stu_1 而後對 stu_1 的各成員賦值,第二個 printf 函數也是用來輸出 stu_1 各成員的值,但使用的是 (*p).num 這樣的形式, (*p) 表示 p 指向的結構體變量,(*p).num 是 p 指向的結構體變量中的成員 num 。注意 *p 兩側的括弧不可省略,由於成員運算符 '.' 優先於 '*' 運算符,*p.num 就等價於 *(p.num)
運行結果以下:
NO. :89101
name: Li Lin
sex:M
score:89.500000
NO. :89101
name: Li Lin
sex:M
score:89.500000
能夠看到兩個 printf 輸出的結果相同。
在C語言中,爲了使用方便和使之直觀,能夠把 (*p).num 改用 p->num 來代替,它表示 *p 所指向的結構體變量中的 num 成員,一樣,(*p).name 等價於 p->name。
也就是說如下三種形式等價:
a. 結構體變量.成員名
b. (*p).成員名
c. p->成員名
上面的最後一個 printf 函數輸了項能夠改寫爲
printf("NO. :%ld\nname: %s\nsex:%c\nscore:%f\n",p->num, p->name, p->sex, p->score);
其中 -> 稱爲指向運算符。
分析如下幾種運算符
p -> n 獲得 p 指向的結構體變量中的成員 n 的值
p -> n ++ 獲得 p 指向的結構體變量中的成員 n 的值,用完值後使它加1
++p -> n 獲得 p 指向的結構體變量中的成員 n 的值使之加 1 (先加)
2 指向結構體數組的指針
之前介紹過可使用指向數組或數組元素的指針和指針變量,一樣,對結構體數組及其元素也能夠用指針變量來指向。
指向結構體數組的指針的應用
#include <stdio.h>
#inlcude <stdlib.h>
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 age\n");
for(p=stu; p<stu+3;p++)
printf("%5d %-20s %2c %4d\n", 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].name
編譯時將出錯。千萬不要認爲反正 p 是存放地址的,能夠將任何地址賦給它。若是地址類型不相同,能夠用強制類型轉換。例如:
p = (struct student *)&stu[1].name;
此時,在 p 中存放 stu[1] 元素的 name 成員的起始地址。
3 用結構體變量和指向結構體的指針做函數參數
將一個結構體變量的值傳遞給另外一個函數,有3個方法:
(1)用結構體變量的成員做參數,例如:用 stu[1].num 或 stu[2].name 做函數實參,將實參值傳給形參。用法和用普通變量做實參是同樣的,屬於 值傳遞 方式。應當注意實參與形參的類型保持一致。
(2)用結構體變量做參數。老版本的C系統不容許用結構體變量做實參,ANSI C取消了這一限制。可是用結構體變量做實參時,採起的是 值傳遞 的方式,將結構體變量所佔的內存單元所有順序傳遞給形參。形參也必須是同類型的結構體變量。在函數調用期間形參也要佔用內存單元。這種傳遞方式在空間和時間上開銷較大,若是結構體的規模很大時,開銷是很可觀的,此外因爲採用值傳遞方式,若是在執行被調用函數期間改變了形參(也是結構體變量)的值,該值不能返回主調函數,這每每形成使用上的不便。所以通常較少用這種方法。
(3)用指向結構體變量(或數組)的指針做實參,將結構體變量(或數組)的地址傳給形參。
用結構體變量做函數參數。
#include <stdio.h>
#define FORMAT "%d\n%s\n%f\n%f\n%f\n"
struct student
{
int num;
char name[20];
float score[3];
};
void print(struct student stu)
{
printf(FORMAT, stu.num, stu.score[0], stu.score[1], stu.score[2]);
printf("\n");
}
void main()
{
struct student stu;
stu.num = 12345;
strcpy(stu.name, "Li Li");
stu.score[0] = 67.5;
stu.score[1] = 89;
stu.score[2] = 78.6;
printf(stu);
}
將上面改用指向結構體變量的指針做實參。
#include <stdio.h>
#define FORMAT "%d\n%s\n%f\n%f\n%f\n"
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);
}