程序设计基础

第九章 结构

第9章 结构

9.1 输出平均分最高的学生信息
9.2 学生成绩排序
9.3 修改学生成绩

本章要点

  • 什么是结构? 结构与数组有什么差别?
  • 结构有几种定义形式,它们之间有何不同?
  • 什么是结构的嵌套?
  • 什么是结构变量和结构成员变量?如何引用结构成员变量?
  • 结构变量如何作为函数参数使用?
  • 什么是结构数组?如何定义和使用结构数组?
  • 什么是结构指针?它如何实现对结构分量的操作?
  • 结构指针是如何作为函数的参数的?

9.1 输出平均分最高的学生信息

例9-1. 输出平均分最高的学生信息

假设学生的基本信息包括学号、姓名、三门课程成绩以及个人平均成绩。输入n个学生的成绩信息,计算并输出平均分最高的学生信息

9.1.1 程序解析

                        
#include<stdio.h>
struct student{  /* 学生信息结构定义 */
    int num;  /* 学号 */
    char name[10];  /* 姓名 */
    int computer, english, math;  /* 三门课程成绩 */
    double average;  /* 个人平均成绩 */
};
int main()
{
    int i, n;
    struct student max, stu;
    printf("Enter n:");
    scanf("%d", &n);
    printf("Input the student's number, name and course scores:\n");
    for(i=0; i<n; i++){
        printf("No. %d", n);
        scanf("%d%s%d%d%d", &stu.num, stu.name, &stu.computer, &stu.english, &stu.math);
        stu.average=(stu.computer+stu.english+stu.math)/3.0;
        if(i==0)
            max=stu;
        else if(stu.average>max.average)
            max=stu;
    }
    printf("num:%d, name:%s, average:%.2f\n", max.num, max,name, max.average);
    return 0;
}
                        
                    

结构的概念与定义

结构,是C语言中一种构造数据类型,能够将有内存联系的不同类型数据统一成一个整体,使之相互关联
结构也是变量的集合,可按照对基本数据类型的操作方法单独使用其变量成员

结构与数组,都是构造类型,是多个变量的集体,但数组成员类型相同,结构成员类型不同

结构的定义

结构类型定义的一般形式为
struct 结构名
{
    类型名 结构成员名1;
    类型名 结构成员名2;
......
    类型名 结构成员名n;
};

  • 关键字struct和后面的结构名一起组成一个新的数据类型名
  • 结构定义以分号结束,C语言中将结构的定义看作是一条语句

结构定义示例

                        
struct point
{
    double x;
    double y;
};
                        
                    
  • 如平面点的定义,x和y的类型相同,也可采用数组的形式描述,但采用结构进行描述,更贴近事物本质,更增加程序的可读性,使程序更易于理解
  • 结构适合用于描述具有多个属性的实体或对象

9.1.3 结构的嵌套定义

在实际生活中,一个较大的实体可能由多个成员构成,而这些成员有可能又是由一些更小的成员构成,如下图中学生信息的构成:

                            
struct address{
    char city[20];
    char street[20];
    int code;
    int zip;
};
                            
                        
                            
struct nest_student{
    int num;
    char name[10];
    struct address addr;
    int computer, english, math;
    double average;
}
                            
                        

9.1.4 结构变量的定义和初始化

  • 单独定义:先定义一个结构类型,再定义一个具有这种类型的变量
                            
struct student{
    int num;
    char name[10];
    int computer, english, math;
    double average;
};
struct student s1, s2;
                            
                        
  • 混合定义:在定义结构类型的同时定义结构变量
                            
struct student{
    int num;
    char name[10];
    int computer, english, math;
    double average;
}s1, s2;
                            
                        
  • 无类型名定义:在宛义结构变量时省略结构名,慎用
                            
struct{
    int num;
    char name[10];
    int computer, english, math;
    double average;
}s1, s2;
                            
                        


结构变量初始化:
struct student stu={101, "Zhang", 87, 78, 85};

9.1.5 结构变量的使用

1. 结构变量成员的引用
在C语言中,使用结构成员操作符"."引用结构成员
结构变量名.结构成员名

                        
stu.num=101;
strcpy(stu.name, "Wang");
nest_stu.addr.zip=310053;
                        
                    

结构变量的使用

2. 结构变量的整体赋值
具有相同类型的结构变更可以直接赋值
赋值时,将赋值运算符右侧结构变量的每一个成员的值都赋值给左侧结构变量中相应的成员

                        
struct student s1={101, "Zhang", 78, 87, 85}, s2;
s2=s1;
                        
                    

结构变量的使用

3. 结构变量作为函数参数或返回值
可以在函数间传递结构类型数据
结构变量作为函数参数
定义: double count_average(struct student s)
调用: stu.average=count_average(stu);

优点: 可传递多个数据且参数形式简单
缺点: 对成员较多的大型结构,参数传递时所进行的结构数据复制使得效率较低

9.2 学生成绩排序

例9-2. 学生成绩排序

输入n(n<50)个学生的成绩信息,按照学生的个人平均成绩从高到低输出他们的信息

定义结构数组 struct student stus[50], temp;

9.2.1 程序解析

                        
#include<stdio.h>
struct student{  /* 定义学生信息结构 */
    int num;
    char name[10];
    int computer, english, math;
    double average;
};
int main()
{
    int i, index, j, n;
    struct student stus[50], temp;  /* 定义结构数组 */

    printf("Enter n:");
    scanf("%d", &n);
    for(i=0; i<n; i++){
        printf("Input info of NO. %d\n", i+1);
        printf("Number Name, computer, english, math:");
        scanf("%d%s%d%d%d", &stus[i].num, stus[i].name, &stus[i].computer, &stus[i].english, &stus[i].math);
        stus[i].average=(stus[i].computer+stus[i].english+stus[i].math)/3.0;
    }
    /* 给结构数组排序,采用选择排序法 */
    for(i=0; i<n-1; i++){
        index=1;
        for(j=i+1; j<n; j++){
            if(stus[j].average<stus[index].average)
                index=j;
        }
        temp=stus[index];
        stus[index]=stus[i];
        stus[i]=temp;
    }
    /* 输出排序后的信息 */
    printf("Num\tname\taverage\n");
    for(i=0; i<n; i++)
        printf("%d\t%s\t%.2f\n", stus[i].num, stus[i].name, stus[i].average);
    return 0;
}
                        
                    

结构数组操作

一个结构变量只能表示一个实体信息,如果有多个相同类型的实体,需要构建结构数组表示
结构数组是结构与数组的结合,与变通数组的不同之处在于,每个数组元素都是一个结构类型的变量
结构数组的定义方法与结构变量类似:
struct student stus[50];
表示stus是一个结构数组,有50个数组元素,每个元素都是一个结构类型struct student的变量

结构数组的初始化和引用

结构数组的初始化与数组的初始化没有本质区别

                        
struct student stus[50]={
    {101, "Zhang", 78, 87, 85},
    {201, "Wang", 83, 92, 79}
};
                        
                    

结构数组元素的成员引用,格式为:结构数组名[下标].结构成员名
使用方法与同类型变量完全相同
stus[i].num=101;
strcpy(stus[i].name, "Feng");
stus[i]=stus[k];

9.3 修改学生成绩

例9-3. 修改学生成绩

输入n(n<50)个学生的成绩信息,再输入一个学生的学号、课程以及成绩,在自定义函数中修改该学生指定课程的成绩

自定义函数: pos=update_score(stus, n, num, course, score);

9.3.1 程序解析(1)

                        
#include<stdio.h>
struct student{
    int num;
    char name[20];
    int computer, english, math;
    double average;
};

int update_score(struct student *p, int n, int num, int course, int score)
{
    int i, pos;
    for(i=0; i<n; i++, p++)
        if(p->num==num)
            break;
    if(i<n){
        switch(course){
            case 1:
            p->computer=score; break;
            case 2:
            p->english=score; break;
            case 3:
            p->math=score; break;
        }
        pos=i;
    }else{
        pos=-1;
    }

    return pos;
}
                        
                    

9.3.1 程序解析(2)

                        
int main()
{
    int i, pos, n, num, course, score;
    struct student stus[50];   /* 定义结构数组 */

    /* 输入n个学生信息 */
    printf("Input n: ");
    scanf("%d", &n);
    for(i = 0; i < n; i++){
        printf("Input the info of No.%d:\n", i+1);
        printf("number:");
        scanf("%d", &stus[i].num);
        printf("name:");
        scanf("%s", stus[i].name);
        printf("computer score:");
        scanf("%d", &stus[i].computer);
        printf("math score:");
        scanf("%d", &stus[i].math);
        printf("english score:");
        scanf("%d", &stus[i].english);
    }

    /* 输入待修改学生信息 */
    printf("Input the number of updated student: ");
    scanf("%d", &num);
    printf("Choice the course: 1.math 2.english 3.computer: ");
    scanf("%d", &course);
    printf("Input the new score: ");
    scanf("%d", &score);

    /*调用函数,修改学生成绩*/
    pos = update_score(stus, n, num, course, score);

    /*输出修改后的学生信息*/
    if(pos == -1){
        printf("Not found!\n");
    }else{
        printf("After update:\n");
        printf("num\t computer\t english\t math\n");
        printf("%d\t %d\t %d\t %d\n", students[pos].num, students[pos].computer, students[pos].english, students[pos].math);
    }
    return 0;
}
                        
                    

结构指针的概念

指针可以指向任何一种变量,而结构变量也是C语言中的一种合法变量,因此,指针也可以指向结构变量,这就是结构指针,即指向结构类型变量的指针

                        
struct student stu={101, "Zhang", 78, 87, 84};
struct student *p;
p=&stu;
(*p).num=101;  /* 用*p访问结构成员 */
p->num=101;  /* 用指向运算符"->"访问指针所指向的结构成员
                        
                    

当p指向结构变量Stu时,以下三条语句等效
stu.num=101;
(*p).num=101;
p->num=101;

结构指针作为函数参数

将结构指针作为函数的参数,可以完成比基本类型指针更为复杂的操作
如自定义函数
int update_score(struct student *p, int n, int num, int course, int score);
在调用时
pos=update_score(stus, n, num, course, score);
stus就是struct student类型的数组
与结构变量作为函数参数相比,用结构指针作为函数参数的效率更高,而在此例中,也只能采用指针作为函数参数才能通过间接访问实现程序功能