5. 07 C语言 结构体

结构体的定义与使用 

在学习语言的时候,做的最多的就是学生成绩管理系统。里面包含的数据类型丰富、拥有基本的CRUD操作,是一个比较经典的例子。那么,我们结构体的学习,也将使用这个例子。 

结构体的定义 

由学生成绩管理系统的例子不难看出,学生的诸多属性(学号、姓名、年龄、成绩等)构成了学生这个结构体。结构体定义需要用到关键字struct,定义规则如下: 

struct 结构体名称 { 

// 成员列表 
}; // 注意:末尾有; 

如,一个学生结构体: 

struct Student { 

char *studentId;    // 学生学号 
    char *name;         // 学生姓名 
    int age;            // 学生年龄 
    double score;       // 学生成绩 
}; 

因此,如果我们对每一个Student结构体变量进行初始化,都会有学号、姓名、年龄、成绩这几个成员。 

结构体类型变量 

定义结构体变量定义的方式有很多种: 

1. 定义结构体后,定义变量(最优) 

struct Student { 

char *studentId; 
    char *name; 
    int age; 
    double score; 
}; 

struct Student stuA, stuB; // 定义结构体变量stuAstuB 

2. 在定义结构体时,定义变量 

struct Student { 

char *studentId; 
    char *name; 
    int age; 
    double score; 
} stuA, stuB; // 定义结构体变量stuAstuB 

3. 直接定义变量 

struct { 

char *studentId; 
    char *name; 
    int age; 
    double score; 
} stuA, stuB; // 定义结构体变量stuAstuB 

结构体变量初始化 

结构体只能在定义的时候,能为整个结构体变量进行赋值。 

struct Student { 

char *studentId; 
    char *name; 
    int age; 
    double score; 
}; 

struct Student stuA = {"11310110""Karen"15100}; 

// 下面这种写法是错误的,定义与整体初始化不能分开 

struct Student stuB; 
stuB = {"11310110""Karen"15100}; 

结构体成员的访问 

在实际操作中,不可能定义一个结构体变量就能整体初始化。这时,我们只能单个对结构体的成员进行访问,如: 

struct Student { 

char *studentId; 
    char *name; 
    int age; 
    double score; 
}; 

struct Student stuA; 

stuA.studentId = "11310110"; 
stuA.name = "Karen"; 
stuA.age = 15; 
stuA.score = 100; 

// 输出 

printf("学号是:%s\n", stuA.studentId); 
printf("姓名是:%s\n", stuA.name); 
printf("年龄是:%d\n", stuA.age); 
printf("成绩是:%lf\n", stuA.score); 

// 整体赋值:将stuA的数据整体赋值给stuB 

struct Student stuB = stuA; 

结构体变量所占内存大小 

在结构体内存的计算上,有一个自动对齐原则,如,Student这个结构体中,所占内存最大的成员是char *double类型,那么结构体所占的内存大小 = 成员个数 * 成员中占用最大的字节数。 

如上面的学生结构体 = 4 * sizeof(char *) = 32 

 

结构体数组 

和之前学习数组的目的一样,在学生管理系统中,不可能一个一个学生去定义并初始化,所以引入了数组的概念。 

结构体数组的定义 

与结构体变量定义一样,结构体数组的定义也有三种方式: 

1. 定义结构体后,定义数组(最优) 

struct Student { 

char *studentId; 
    char *name; 
    int age; 
    double score; 
}; 

struct Student stu[10]; // 定义一个长度为10的结构体数组 

2. 在定义结构体时,定义数组 

struct Student { 

char *studentId; 
    char *name; 
    int age; 
    double score; 
} stu[10];  // 定义一个长度为10的结构体数组 

3. 直接定义数组 

struct { 

char *studentId; 
    char *name; 
    int age; 
    double score; 
} stu[10];  // 定义一个长度为10的结构体数组 

结构体数组的赋值与访问 

 
struct Student students[10]; 

for (int i = 0; i < 10; i ++) { 

students[i].age = i; 
} 

for (int i = 0; i < 10; i ++) { 

printf("%d个学生的年龄 = %d\n", i + 1, students[i].age); 

 

结构体指针 

指向结构体变量的指针 

与指向基本类型的指针类似,结构体指针指向的是一个结构体变量的地址。定义方式为: 

struct 结构体名称 *指针变量名; 

如,定义一个指向学生结构体的指针: 

struct Student { 

char *studentId; 
    char *name; 
    int age; 
    double score; 
}; 

struct Student *pStu; // 定义结构体指针 

结构体指针的赋值与访问 

赋值 

struct Student { 

char *studentId; 
    char *name; 
    int age; 
    double score; 
}; 

struct Student *pStu; // 定义结构体指针 

// 赋值 

struct Student stu = {"11310110""Karen"15100}; // 定义结构体变量 
pStu = &stu; // 将结构体变量stu的首地址给指针pStu 

访问 

结构体指针访问成员的方式有两种: 

1. 先取*然后访问 

 
printf("学生%s的年龄为%d\n", (*pStu).name, (*pStu).age); 
// 输出:学生Karen的年龄为15 

2. 使用->访问 

printf("学生%s的年龄为%d\n", pStu->name, pStu->age); 
// 输出:学生Karen的年龄为15 

 

结构体的嵌套 

比如,现在有这样一个需求: 

定义一个人的结构体,有姓名、出生日期等成员,应该怎么定义? 

或许可以这样定义: 

struct Person { 

char *name; 
    int year; 
    int month; 
    int day; 
}; 

这样也可以,但是我认为这个设计不好,年月日应该是日期的成员,怎么会是一个人的成员呢!所以,有了以下定义: 

struct Date { 

int year; 
    int month; 
    int day; 
}; 

struct Person { 

char *name; 
    struct Date birth; 
}; 

结构体嵌套的赋值与访问 

// 定义结构体变量 

struct Person me; 

me.name = "Karen"; 
me.birth.year = 2000; 
me.birth.month = 1; 
me.birth.day = 1; 

 

预习 

 

1. malloc 动态内存管理 

 

在头文件 <stdlib.h> 中定义 

void* malloc(size_t size ); 

 

分配size个字节的未初始化的存储空间。 

 

如果分配成功,返回指向分配内存块最低(第一个)字节的指针,且其对所有的目标类型都进行适当地对齐。 

 

如果size为零,其行为由实现定义(可能返回空指针,也可能返回某个不能用来访问存储空间的非空指针)。 

参数 

size 

- 

要分配的字节数 

返回值 

指向新分配的内存开始位置的指针,或者在错误发生时为空指针。该指针必须用free()释放。 

 

 

#include <stdio.h> 

#include <stdlib.h> 

     

int main(void) 

{ 

    int *p1 = malloc(4*sizeof(int));  // allocates enough for an array of 4 int 

    int *p2 = malloc(sizeof(int[4])); // same, naming the type directly 

    int *p3 = malloc(4*sizeof *p3);   // same, without repeating the type name 

     

    if(p1) { 

        for(int n=0; n<4; ++n) // populate the array 

            p1[n] = n*n; 

        for(int n=0; n<4; ++n) // print it back out 

            printf("p1[%d] == %d\n", n, p1[n]); 

    } 

     

    free(p1); 

    free(p2); 

    free(p3); 

} 

   

 

 

2.  

Stack is a LIFO (last in first out) data structure. 栈先进后出 

 

图像

 

3. 队列 

Queue is a FIFO (first in first out) data structure.队列先进先出,。 

队列实现了先入先出的语义 (FIFO) 。队列也可以使用数组和链表来实现: 

图像

 

 4.1 队列 

         队列只允许在队尾添加数据,在队头删除数据。但是可以查看队头和队尾的数据。还有一种是双端队列,在两端都可以插入和删除: 

图像

 

4. 链表 

 

5.memcpy 

明天要问到: 

1. 栈和队列的特点 

2. 链表的特点 

3. 链表与数组的区别(优劣势) 

4. 链表需要用到的知识点(指针、结构体 

1、定义一个结构体,描述日期的年月日; 

  1)提示用户输入日期,计算该日在本年中为第几天? 

  2)求今年任意2天的天数差? 

 

 

#include <stdio.h> 

#include <stdlib.h> 

 

 

enum Year getLeapYear(int year); 

 

#pragma mark - Globle Variables 

 

struct Date  { 

     

    int year; 

    int month; 

    int day; 

     

} ; 

 

enum Year {leapYear = 0, commonYear}; 

 

int totalDay; 

 

 

 

//判断用户输入的是否为闰年 

enum Year getLeapYear(int year) { 

     

    if ((year % 4 == 0 && year % 100 != 0 ) || year % 400 == 0) { 

         

        return leapYear; 

    } 

     

    return commonYear; 

} 

 

//取得当前日期天数(返回值 + 用户输入的day = 总的天数) 

int getDaysOfYear(int month) { 

     

    

    int sumDays = 0; 

     

    switch (month-1) { 

             

        case 12:  sumDays += 31; 

             

        case 11:  sumDays += 30; 

             

        case 10:  sumDays += 31; 

             

        case 9:   sumDays += 30; 

             

        case 8:   sumDays += 31; 

             

        case 7:   sumDays += 31; 

             

        case 6:   sumDays += 30; 

             

        case 5:   sumDays += 31; 

             

        case 4:   sumDays += 30; 

             

        case 3:   sumDays += 31; 

             

        case 2:   sumDays += 28; 

             

        case 1:   sumDays += 31;break; 

             

        default:  break; 

             

    } 

    return sumDays; 

} 

 

int main(int argc, const char * argv[]) { 

 

    // 提示用户输入日期,计算该日在本年中为第几天? 

    int totalDay = 0; 

     

    struct Date userDate; 

     

    printf("Please input year/month/date (year month date):\n"); 

     

    scanf("%d%d%d", &userDate.year, &userDate.month, &userDate.day); 

     

    enum Year isYear = getLeapYear(userDate.year); 

     

    if (isYear == commonYear) { 

         

        totalDay = getDaysOfYear(userDate.month); 

         

         

    } else { 

         

        totalDay = getDaysOfYear(userDate.month) + 1; 

    } 

     

    totalDay += userDate.day; 

     

    printf("%d/%d is %d days of year %d\n\n",userDate.month, userDate.day, totalDay ,userDate.year); 

     

    //求今年任意2天的天数差? 

     

    int difference = 0; 

     

    struct Date date1, date2; 

     

    date1.year = 2015; 

    date2.year = 2015; 

     

     

    printf("Input a date (month date): \n"); 

    scanf("%d%d", &date1.month, &date1.day); 

     

    printf("Input another date (month date): \n"); 

    scanf("%d%d", &date2.month, &date2.day); 

     

    difference = getDaysOfYear(date1.month) + date1.day - getDaysOfYear(date2.month) - date2.day; 

     

    difference = abs(difference); 

     

    printf("Difference of these two dates = %d \n", difference); 

     

     

    return 0; 

} 

 

 

2、某班有5个学生,三门课。分别编写实现以下要求:  

1 写一个函数,输出一名学生的所有信息 

2 求各门课的平均分;  

3 找出有两门以上不及格的学生,并输出其学号和不及格课程的成绩;  

4 找出三门课平均成绩在85-90分的学生,并输出其学号和姓名 

注:结构体元素有:num,name,score[3] 

 

#include <stdio.h> 

 

typedef struct Student Stu; 

 

struct Student { 

     

    char *num; 

    char *name; 

    float score[3]; 

     

} ; 

 

//输出一名学生的所有信息 

void printStudent(Stu *studt) { 

     

    puts(studt -> name); 

    puts(studt -> num); 

    printf("Math = %.1f, English = %.1f, Chinese = %.1f\n", 

           studt -> score[0], studt -> score[1], studt ->score[2]); 

     

} 

 

//求各门课的平均分 

void getAverageScore(Stu stu[], int length) { 

     

    for (int i = 0; i < 3; i++) { 

         

        float sumScore[3] = {0.0}; 

         

        for (int j = 0; j < length; j++) { 

             

            sumScore[i] += stu[j].score[i]; 

        } 

         

        printf("Average score = %.2f\n", sumScore[i] / length); 

    } 

     

     

} 

//找出有两门以上不及格的学生,并输出其学号和不及格课程的成绩; 

void noPassStudent(Stu stu[], int length) { 

     

    for (int i = 0; i < length; i++) { 

         

        int count = 0; 

         

        for (int j = 0; j < 3; j++) { 

             

            if (stu[i].score[j] < 60) { 

                 

                count++; 

            } 

        } 

         

        if (count > 1) { 

             

            printf("%s ", stu[i].num); 

            puts(stu[i].name); 

             

            //输出不及格的成绩 

            for (int k = 0; k < 3; k++) { 

                 

                if (stu[i].score[k] < 60) { 

                     

                    printf("%.2lf\n", stu[i].score[k]); 

                } 

            } 

        } 

        printf("\n"); 

    } 

    

} 

 

//找出三门课平均成绩在85-90分的学生,并输出其学号和姓名 

 

void getGoodStudent(Stu stu[], int length) { 

     

    for (int i = 0; i < length; i++) { 

         

        float avgScoreOfStudent = 0; 

        float sumScoreOfStudent = 0; 

         

        for (int j = 0; j < 3; j++) { 

             

            sumScoreOfStudent += stu[i].score[j]; 

        } 

         

        avgScoreOfStudent = sumScoreOfStudent / 3; 

         

        if (avgScoreOfStudent > 85 && avgScoreOfStudent < 90) { 

             

            puts(stu[i].num); 

            puts(stu[i].name); 

        } 

    } 

     

} 

 

 

 

int main (int argc, const char * argv[]) { 

     

 

    Stu studentsOfClass[5] = {{"20131003""Jack",  904980}, 

                              {"20131252""Mike",  504960}, 

                              {"20131021""Lucus"729385}, 

                              {"20131325""David"858887}, 

                              {"20131124""Sam",   725355}}; 

     

    Stu *pointer = studentsOfClass; 

     

    //输出每一名学生的所有信息 

    for (int i = 0; i < 5; i++) { 

     

        printStudent(pointer); 

        pointer ++; 

    } 

     

    getAverageScore(studentsOfClass, 5); 

     

    noPassStudent(studentsOfClass, 5); 

     

    getGoodStudent(studentsOfClass, 5); 

     

    return 0; 

     

} 



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值