第九章 使用结构体类型处理组合类型(用户自定义数据类型)


定义和使用结构体变量

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