第九章 使用結構體類型處理組合類型(用戶自定義數據類型)


定義和使用結構體變量

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;

}
View Code

 

 

結構體數組

例子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;
}
View Code

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;
}
View Code

 

結構體指針

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;
}
View Code

  第二個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;
}
View Code

    程序分析過程: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);
}
View Code

 

鏈表部分

 

提高部分

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); } }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM