定義和使用結構體變量
1、定義結構體
1)結構體:用戶自己建立由不同類型數據組成的組合型的數據結構。
一般形式:
struct 結構體名
{
成員列表
};
struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; };
大括號內的是結構體子項,成為結構體成員 ,成員列表也稱為“域表”。
2)成員可以是另外一個結構體的變量
struct date { int month; int day; int year; } struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; struct date birthday; };
2、定義結構體類型變量
1)先聲明結構體類型,再定義該類型的變量
struct student student1,student2 // student1和student2是結構體變量名
2)在聲明類型的同時定義變量
一般形式:
struct 結構體名
{
成員列表
}變量名表項;
struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }student1,student2;
3)不指定類項名而直接定義結構體類型變量(即無名結構體)
一般形式:
struct
{
成員列表
}變量名列表;
補充: ① 結構體類型和結構體變量區別:只能對變量賦值,存取或運算,類型則不行。編譯時,只對變量分配空間,類型不分配;
② 結構體類型的成員名可以與程序變量名同名,互不相干;
③ 結構體變量中的成員(稱為“域”),可以單獨使用。
3、結構體變量的初始化和引用:
例1:把一個學生的信息放在一個結構體變量中,然后輸出這個學生的信息。
struct student { int num; char name[20]; char sex; char addr[30]; }student1={10101,"Li Lin",'M',"Beijing Road"}; printf("NO:%d\nname:%s\nsex:%c\naddress:%s\n",student1.num,student1.name,student1.sex,student1.addr); return 0;
1)引用結構體變量中的成員的值,引用方式:
結構體變量名.成員名
“.”是“成員運算符”在所有運算符中優先級最高.
2)如果成員本身又屬於一個結構體類型,則要用若干個成員運算符,一級一級的地找到最低的一級的成員:
student1.num student1.birthday.month // 結構體變量中student1中的成員birthday中的成員month
3)結構體變量的成員像普通變量一樣,可以進行各種運算(例如:賦值、自加、自減):
student2.score=student1.score; sum=student1.score+student2.score; student1.age++;
4)同類型的結構體變量可以相互賦值:
student1=student2;
5)可以應用結構變量成員的地址和結構體變量的地址:
scanf("%d",student1.num); // 輸入student1.num的值
printf("%0",&student1); // 輸出結構體變量student1的首地址
例子1:輸入兩個學生的學號、姓名和成績,輸出成績較高的學生的學號、姓名和成績:

#include<stdio.h> int main() { struct student { int num; char name[20]; float score; }student1,student2; scanf("%d%s%f",&student1.num,&student1.name,&student1.score); scanf("%d%s%f",&student2.num,&student2.name,&student2.score); printf("The higher score is:\n"); if(student1.score>student2.score) { printf("%d %s %6.2f\n",student1.num,student1.name,student1.score); } else if(student1.score<student2.score) { printf("%d %s %6.2f\n",student2.num,student2.name,student2.score); } else { printf("%d %s %6.2f\n",student1.num,student1.name,student1.score); printf("%d %s %6.2f\n",student2.num,student2.name,student2.score); } return 0; }
結構體數組
例子1:有3個候選人,每個選民只能投票選一人,要求編寫一個統計選票的程序,先后輸人被選人的名字,最后輸出各人得票結果。

#include <stdio.h> #include <string.h> #define N 5 struct person { char name[20]; int count; }leader[3]={"Li",0,"Zhang",0,"Liang",0}; // 定義結構體數組並初始化 int main() { int i,j; char leader_name[20]; for(i=0;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("\nResult:\n"); for(i=0;i<3;i++) { printf("%5s:%d\n",leader[i].name,leader[i].count); } return 0; }
1、結構體數組的定義和使用
1)定義結構體數組的一般形式:
struct 結構體名
{成員列表}數組名[數組長度]
2)先聲明一個結構體類型,再用此類型定義結構體數組:
結構體類型 數組名 [數組長度];
struct person leader[3];
3)初始化形式:
struct person leader[3]={"Li",0,"Zhang",0,"Liang",0};
例子2:有N個學生的信息(包括學號、姓名、成績),要求按照成績的高低順序輸出各學生的信息。

#include <stdio.h> #define N 5 struct student { int num; char name[20]; float score; }; int main() { struct student stu[N]={ 101,"Zhang",99, 103,"Liang",80, 104,"Dai",77, 102,"Chen",98, 105,"Li",87}; // 定義結構體數組並初始化 struct student temp; // 臨時結構體變量,用於交換 int i,j,k; char leader_name[20]; for(i=0;i<N-1;i++) // 這里用選擇排序 { k=i; for(j=i+1;j<N;j++) { if(stu[j].score>stu[i].score) { k=j; } temp=stu[k];stu[k]=stu[i];stu[i]=temp; } } printf("\nResult:\n"); for(i=0;i<N;i++) { printf("%6d %8s %6.2f\n",stu[i].num,stu[i].name,stu[i].score); } printf("\n"); return 0; }
結構體指針
1、定義:
- 指向結構體數據的指針,一個結構體變量的起始地址 就是這個結構體變量的指針;
- 把一個結構體變量的起始地址存放在一個指針變量 中,那么,這個指針變量就指向該結構體變量;
- 指針變量既可以指向結構體變量,也可以用來指向結構體數組 中的 元素;
- 指針變量的基類型 必須與結構體變量的類型 相同
例子1:通過指向結構體變量的指針變量輸出結構體變量中成員的信息

#include <stdio.h> #include <string.h> int main() { struct student { long num; char name[20]; char sex; float score; }; struct student stu_1; // 定義struct student類型的變量stu_1 struct student *p; // 定義指向struct student類型數據的指針變量p p=&stu_1; // p指向結構體變量stu_1 stu_1.num=10101; // 對結構體變量的num成員賦值 strcpy(stu_1.name,"Li Lin");// 對結構體變量的name成員賦值 stu_1.sex='M'; // 對結構體變量的sex成員賦值 stu_1.score=89.5; // 對結構體變量的score成員賦值 printf("No.:%ld\nname:%s\nsex:%c\nscore:%5.1lf",stu_1.num,stu_1.name,stu_1.sex,stu_1.score); // 正常輸出結構體變量stu_1各成員的值 printf("\nNo.:%ld\nname:%s\nsex:%c\nscore:%5.1lf",(*p).num,(*p).name,(*p).sex,(*p).score); // 用指針輸出 printf("\n"); return 0; }
第二個printf 是通過指向結構體變量的指針變量訪問它的成員,輸出stu_1各成員的值,使用的是( * p).num這樣的形式。( * p)表示p指向的結構體變量,( * p).num是p指向的結構體變量中的成員num。注意* p兩側的括號不可省,因為成員運算符“ . ”優先於“ * ”運算符,* p.num就等價於* (p.num)了。
2、指向運算符
- C語言允許把 p->num 代替 (*p).num ,它表示p所指向的結構體變量中的num成員;
- p一> name等價於(*p).name;
- “->”稱為指向運算符 。
如果p指向一個結構體變量,以下3種形式等價:
① 結構體變量.成員名
② ( *p).成員名
③ p->成員名
指向結構體變量的指針變量,也可以用來指向結構體數組元素。
例子1:有3個學生的信息,放在結構體數組中,要求輸出全部學生的信息。

#include <stdio.h> struct student // 聲明結構體類型 struct student { int num; char name[20]; char sex; float score; char addr[20]; }; struct student stu[4]={ {101,"Li",'M',90,"Beijing"}, {102,"Zhang",'M',89,"Nanjing"}, {103,"Chen",'F',87,"Guangdong"}, {104,"Dai",'M',95,"Hebei"}}; // 定義結構體數組並初始化 int main() { struct student *p; // 定義指向struct student結構體變量的指針 printf("No name sex score addr\n"); for(p=stu;p<stu+4;p++) // 指針指向結構體數組元素 { printf("%d%15s%15c%20f%15s\n",p->num,p->name,p->sex,p->score,p->addr); // 指向各結構體變量的成員 } return 0; }
程序分析過程:p是指向struct student結構體類型數據的指針變量。在for語句中先使p的初值為stu, 也就是數組stu第一個元素的起始地址。在第一次循環中輸出stu[0]的各個成員值。然后執行p++,使p自加1。p加1意味着p所增加的值為結構體數組stu的一個元素所占的字節數(4+20+1+4+20=49)。執行p++后p的值等於stu+1,p指向stu[1],在第二次循環中輸出stu[1]的各成員值。在執行p++后,p的值等於stu+2,再輸出stu[2]的各成員值。直到p的值變為stu+4,已不再小於stu+3了,不再執行循環。
值得注意的點:
(1)如果p的初值為stu,即p指向stu的第一個元素,p加1后,p就指向下一個(結構體數組中的)元素。例如:
(++p)-> num //先使p自加1,然后得到p指向的元素中的num成員值(即102)
(p++)-> num //先求得p->num的值(即101),然后再使p自加1,指向stu[1]
(2)指向結構體類型數據的指針變量,只能用來指向結構體變量或者結構體數組中的元素,而不能用來指向結構體數組中元素的某一成員,例如下面做法是錯誤的:
p=stu[1].name; // 編譯時將出現“警告”,表示地址類型不匹配
p雖然是存放地址的,但不是啥都放。如果要指向結構體數組中的元素的成員,必須要進行強制轉換才可以,如:
p=(struct student *)stu[0].name;
此時,p的值是stu[0]元素name成員的起始地址,即stu[0].name的純地址,但是已經把原來指向結構體數組的指針改為了指向一個student類型的數據,此時的p+1是指向stu[1]中的name。
總結:把指向結構體數組元素(一個元素包含多個成員)的指針和指向結構體數組中元素的成員的指針區分開來,一個是指向元素,一個是指向元素的成員。
用結構體變量和結構體變量的指針作函數參數
例子2:有 N個結構體變量stu,內含學生學號、姓名和3門課程的成績。要求輸出平均成績最高的學生的信息(包括學號、姓名、3門課程成績和平均成績)。

#include <stdio.h> #define N 3 struct student { int num; char name[20]; float score[3]; float aver; }; int main() { struct student stu[N],*p=stu; // 定義結構體數組和結構體指針p,p指向stu數組的首元素stu[0] void input(struct student stu[]); // 聲明函數,形參是結構體student類型的數組,即stu是stu[N]地址 struct student max(struct student stu[]); // 聲明函數(帶返回值,是一個結構體變量) void print (struct student stu); // 聲明函數,形參是結構體student類型的結構體變量(用max中選出來的一個結構體變量) input (p); // p作為input函數的實參 print(max(p)); return 0; } void input(struct student stu[]) // 形參是struct student類型的數組,stu和p具有相同的地址 { int i; printf("請輸入各學生的信息:學號、姓名、三門課程成績:\n"); for(i=0;i<N;i++) { scanf("%d %s %f %f %f",&stu[i].num,stu[i].name,&stu[i].score[0],&stu[i].score[1],&stu[i].score[2]); stu[i].aver=(stu[i].score[0]+stu[i].score[1]+stu[i].score[2])/3.0; } // scanf輸入每個學生對應的信息(對應成員的值),並計算每個學生的平均分放到各自的aver成員中 } struct student max(struct student stu[]) { int i,m=0; for(i=0;i<N;i++) { if(stu[i].aver>stu[m].aver) // 比較數組元素中各自的aver值 { m=i; } } return stu[m]; // 返回平均分最大的(元素)結構體變量 } void print(struct student stud) // 打印平均分最大的(元素)結構體變量成員的值 { printf("\n成績最高的學生是:\n"); printf("學號:%d\n姓名:%s\n三門成績:%5.1f,%5.1f,%5.1f\n平均成績:%6.2f\n",stud.num,stud.name,stud.score[0],stud.score[1],stud.score[2],stud.aver); }
提高部分
1、共用體類型
- 把不同類型的變量放在同一段內存 的結構,稱為 共用體類型(union)
- 共用體變量所占的內存長度等於最長的成員的長度
- 一般形式:
union 共用體名
{
成員列表
}變量列表;
union data { short int i; char ch; float f; }a,b,c;
ps:共用體只能單個引用成員,共用體可以沒有名字。
2、枚舉類型
如果一個變量只有幾種可能的值,則可以定義為枚舉類型 。所謂“枚舉”是指將變量的值一一列舉出來,變量的值只限於列舉出來的值的范圍內。
聲明枚舉類型:enum 枚舉類型名稱 {枚舉值名稱,枚舉值名稱...};
定義枚舉變量:enum 枚舉類型 名稱 枚舉變量1 枚舉變量2;
#include <stdio.h>
int main(void) { enum Color {red=10,green,blue}; enum Color rgb; for(rgb=red;rgb<=blue;rgb++) { printf("rgb is %d:\n",rgb); } }
#include <stdio.h>
enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN } day; int main() { // 遍歷枚舉元素
for (day = MON; day <= SUN; day++) { printf("枚舉元素:%d \n", day); } }