day12

一、函数指针数组

1 > 当想要存储多个函数入口地址时,需要定义多个函数指针变量来存储

2 > 数组就是一次性定义多个变量的操作

3 > 想要存储多个函数指针变量,就可以定义一个函数指针数组来完成,对函数的批量处理

4 > 定义格式:数据类型 ( *数组名[数组长度] )(形参列表)


#include <stdio.h>
    //定义求和函数
    int
    qiuhe(int m, int n)
{
    return m + n;
}

//定义求差函数
int qiucha(int m, int n)
{
    return m - n;
}

//定义求最大函数
int qiumax(int m, int n)
{
    return m > n ? m : n;
}

int main(int argc, const char *argv[])
{
    //定义函数指针数组存储三个函数的入口地址
    int (*funPtrArr[3])(int, int) = {qiuhe, qiucha, qiumax};
    //funPtrArr[0] = qiuhe;
    //统一调用
    for (int i = 0; i < 3; i++)
    {
        printf("结果为:%d\n", funPtrArr[i](5, 3));
    }

    return 0;
}

二、二级指针

1 > 指针变量也是在内存中占相应的存储空间的,共占8字节的空间

2 > 既然有地址空间,就有起始地址,该地址也是一个比较难记忆的数字,我们可以定义一个指针变量来存储

3 > 存储指针变量的地址的指针变量,我们称为二级指针变量

4 > 定义格式:数据类型 **指针名;

5 > 二级指针变量的使用:
                                                                                                                                                                                                                                                                           

指针变量-- -- > 指向的一级指针中的地址
                                                                                                                                                          *指针变量-- --->一级指针变量中的值
                                                                                                                                                             **指针变量-- -- > 一级指针变量所指向内存空间中的值
#include <stdio.h>
#include <string.h>

    int main(int argc, const char *argv[])
{
    int num = 520;    //定义一个普通变量
    int *ptr = &num;  //将普通变量的地址赋值给指针变量
    int **qtr = &ptr; //将指针变量的地址赋值给二级指针变量

    printf("num = %d\n", num);     //通过普通变量访问值
    printf("*ptr = %d\n", *ptr);   //通过一级指针变量访问值
    printf("**qtr = %d\n", **qtr); //通过二级指针变量访问值

    //qtr = &(&num);          //该语句是错误的,C语言中所有表达式的结果都是一个右值

    int arr[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; //定义二维数组
    //arr <==> &arr[0]  ==> &&arr[0][0]
    qtr = arr;                                  //?
    printf("sizeof(qtr) = %ld\n", sizeof(qtr)); //8
    printf("sizeof(arr) = %ld\n", sizeof(arr)); //36

    printf("qtr = %p, arr = %p\n", qtr, arr);             //一样
    printf("qtr+1 = %p, arr+1 = %p\n", qtr + 1, arr + 1); //一样
    //printf("*qtr = %p\n", *qtr);
    当二级指针执行二维数组时,不能直接访问元素
    //printf("%d\n", qtr[0][0]);     //不可以访问
    return 0;
}

#include <stdio.h>
#include <string.h>

//使用指针函数来将被调函数中的数据返回给主调函数
int *fun1()
{
    static int num = 520;

    return &num;
}

//使用参数的形式将被调函数中的变量地址返回
void fun2(int **qtr)
{
    static int key = 1314;

    *qtr = &key;
}

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

    int *ptr = NULL; //定义一个指针变量

    //将该指针变量指向函数中的某个静态成员变量
    ptr = fun1();

    //将指针变量
    fun2(&ptr);
    printf("*ptr = %d\n", *ptr);
    return 0;
}

三、万能指针

1 > 万能指针可以接收任何类型的变量的地址

2 > 定义格式:void *指针名;

3 > 注意:万能指针变量,只能接收给定空间的起始地址,并没有数据类型的限制

4 > 万能指针变量,不能直接进行取值运算,只能转变成具体的指针变量进行取值

#include <stdio.h>
#include <string.h>

    int main(int argc, const char *argv[])
{
    int num = 0x12345678;
    char key;

    //定义万能指针变量
    void *ptr = &num;
    printf("&num = %p, ptr = %p\n", &num, ptr);
    //printf("*ptr = %d\n", *ptr);     //不能直接操作

    key = *(char *)ptr; //将万能指针转变成具体的指针使用
    printf("key = %#x\n", key);

    return 0;
}

#include <myhead.h>

//void *类型的指针,常用于函数的形参使用
void fun(void *ptr)
{
    *(int *)ptr = 520;
}

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

    //调用功能函数
    fun(&num);

    printf("num = %d\n", num); //

    return 0;
}

五、结构体

1.1 引入目的

1 > 系统中提供的数据类型不够使用了,没有条件,创造条件,自己定义数据类型以供程序使用

2 > 结构体本质上是数据类型,属于构造数据类型

3 > 定义:由相同数据类型或不同数据类型构成的数据的集合,叫做结构体

1.2 定义及初始化

1 > 定义格式 struct 结构体名称
{
    成员类型1 成员变量1;
    成员类型2 成员变量2;
      。。。 成员类型n 成员变量n;
};
注意事项:
1、struct是定义结构体类型的关键字,不能省略 2、结构体名称:标识符,符合命名规则,一般建议首字母大写 3、成员属性使用一对花括号包裹起来 4、成员类型可以是基本数据类型,也可以是构造数据类型、指针类型 5、定义结束后,必须加上 分号结尾 6、举个例子 struct Stu
{
    char name[20]; //姓名
    int age;       //年龄
    double score;  //成绩
};

2 > 使用结构体类型定义变量 1、定义格式 struct 结构体名称 变量名; 2、注意:定义变量时,strcut也不能省略 3、也可以在进程类型定义时,顺便定义一个结构体变量: struct Stu
{
    char name[20]; //姓名
    int age;       //年龄
    double score;  //成绩
} s1;
此时的s1就是一个结构体变量

#include <myhead.h>

    //定义一个英雄类型
    struct Hero
{
    char name[30];     // 英雄名称
    int blood;         //英雄血量
    char skill[4][20]; //技能
    int kill;          //击杀人头数
    int die;           //死亡数量
    int assiant;       //辅助数量
} h2;                  //定义类型时,顺便定义一个变量

//定义类型顺便定义变量
struct
{
    char name[20]; //学生姓名
    int age;       //年龄
    double score;  //成绩
} s1;              //该结构体称为无名结构体

int main(int argc, const char *argv[])
{
    //使用自定义类型,定义一个英雄变量
    struct Hero h1, h3;

    return 0;
}

3 > 初始化结构体变量
        初始化结构体变量也有四种方式
#include <myhead.h>

    //定义一个英雄类型
    struct Hero
{
    char name[30];                                            // 英雄名称
    int blood;                                                //英雄血量
    char skill[4][20];                                        //技能
    int kill;                                                 //击杀人头数
    int die;                                                  //死亡数量
    int assiant;                                              //辅助数量
} h2 = {"德玛西亚之力", 800, {"q", "w", "e", "r"}, 0, 2, 10}; //定义类型时,顺便定义一个变量

//定义类型顺便定义变量
struct
{
    char name[20];       //学生姓名
    int age;             //年龄
    double score;        //成绩
} s1 = {"李华", 18, 65}; //该结构体称为无名结构体

int main(int argc, const char *argv[])
{
    //使用自定义类型,定义一个英雄变量
    struct Stu h1 = {"张三", 20, 99};

    struct Stu s2 = {.age = 32, .score = 100}; //只给部分成员初始化

    return 0;
}

1.3 结构体访问成员

1 > 普通结构体变量访问成员是,使用成员运算符 ‘.’ 来进行,读作 "的" 例如:s1.name s1.score

2 > 结构体指针变量访问成员,使用成员运算符 '->'来进行,读作 '的' 例如:struct Stu *ptr = &s1;
ptr->name ptr->score

3 > 在进行成员访问时,访问的最终的类型,就是最后一个成员所表示的结果类型
 例如:s1.name 是字符数组类型, ptr->score 是double类型

4 > 当一个结构体类型中的某个成员变量也是一个结构体变量时,如果要进行最深一级的访问,需要使用成员运算符一级一级进行访问

#include <stdio.h>
#include <string.h>

    //定义生日结构体类型
    struct Date
{
    int year;  //年份
    int month; //月份
    int day;   //日期
};

//定义学生类型
struct Stu
{
    char name[20];        //姓名
    double score;         //成绩
    struct Date birthday; //生日
};

/***************主程序**********************/
int main(int argc, const char *argv[])
{
    //定义一个学生,并初始化
    struct Stu s = {"张三", 99.5, {2000, 1, 1}};
    s.score = 100; //访问成员更改内容
    printf("%s, %.2lf, %d-%d-%d\n",
           s.name, s.score, s.birthday.year, s.birthday.month, s.birthday.day);
    //更改名字
    strcpy(s.name, "lisi");
    printf("%s, %.2lf, %d-%d-%d\n",
           s.name, s.score, s.birthday.year, s.birthday.month, s.birthday.day);
    printf("*********************************************\n");

    struct Stu *ptr = &s; //定义指针变量指向结构体变量
    printf("%s, %.2lf, %d-%d-%d\n",
           ptr->name, ptr->score, ptr->birthday.year, ptr->birthday.month, ptr->birthday.day);

    return 0;
}

1.4 结构体变量的输入输出

1 > 通过成员运算符,找到结构体变量的普通成员后,本质上就是一个普通变量的输入输出

2 > 实例

#include <stdio.h>
#include <string.h>

    //定义生日结构体类型
    struct Date
{
    int year;  //年份
    int month; //月份
    int day;   //日期
};

//定义学生类型
struct Stu
{
    char name[20];        //姓名
    double score;         //成绩
    struct Date birthday; //生日
};

/***************主程序**********************/
int main(int argc, const char *argv[])
{
    //定义一个学生,并初始化
    struct Stu s = {"张三", 99.5, {2000, 1, 1}};
    s.score = 100; //访问成员更改内容
    printf("%s, %.2lf, %d-%d-%d\n",
           s.name, s.score, s.birthday.year, s.birthday.month, s.birthday.day);
    //更改名字
    strcpy(s.name, "lisi");
    printf("%s, %.2lf, %d-%d-%d\n",
           s.name, s.score, s.birthday.year, s.birthday.month, s.birthday.day);
    printf("*********************************************\n");

    struct Stu *ptr = &s; //定义指针变量指向结构体变量
    printf("%s, %.2lf, %d-%d-%d\n",
           ptr->name, ptr->score, ptr->birthday.year, ptr->birthday.month, ptr->birthday.day);

    printf("********************************************\n");
    struct Stu s1; //定义一个结构体变量
    printf("请输入学生的姓名:");
    scanf("%s", s1.name);
    printf("请输入学生的成绩:");
    scanf("%lf", &s1.score);
    printf("请输入学生的出生年月日(用空格隔开):");
    scanf("%d%d%d", &s1.birthday.year, &s1.birthday.month, &s1.birthday.day);
    printf("%s, %.2lf, %d-%d-%d\n",
           s1.name, s1.score, s1.birthday.year, s1.birthday.month, s1.birthday.day);

    return 0;
}

1.5 结构体数组

1 > 结构体数组本质上也是一个数组,只是每个元素是结构体变量

2 > 定义格式:strcut 结构体名 数组名[常量];
3 > 举个例子:


#include <stdio.h>
#include <string.h>
    //定义结构体类型
    struct Hero
{
    char name[20]; //姓名
    int blood;     //血量
    int kill;      //斩获人头数
    int die;       //死亡次数
    int ass;       //辅助次数
};

//宏定义
#define MAX 10

//主程序
int main(int argc, const char *argv[])
{
    //定义一个英雄数组
    struct Hero hero[MAX];
    int size = 0; //实际使用的个数

    //初始化数组
    memset(hero, 0, sizeof(hero));

    printf("请输入英雄个数:");
    scanf("%d", &size);

    //循环输入英雄的相关信息
    for (int i = 0; i < size; i++)
    {
        printf("请输入第%d个英雄的名称:", i + 1);
        scanf("%s", hero[i].name);
        printf("请输入第%d个英雄的血量:", i + 1);
        scanf("%d", &hero[i].blood);
        printf("请输入第%d个英雄的人头数:", i + 1);
        scanf("%d", &hero[i].kill);
        printf("请输入第%d个英雄的死亡数:", i + 1);
        scanf("%d", &hero[i].die);
        printf("请输入第%d个英雄的辅助数:", i + 1);
        scanf("%d", &hero[i].ass);
        printf("\n");
    }

    //输出英雄的信息
    printf("本局比赛的结果如下:\n");
    printf("英雄\t血量\t人头\t死亡\t辅助\n");
    for (int i = 0; i < size; i++)
    {
        printf("%s\t%d\t%d\t%d\t%d\n",
               hero[i].name, hero[i].blood, hero[i].kill, hero[i].die, hero[i].ass);
    }

    //求出本局的 mvp
    struct Hero mvp;      //存放最有价值的英雄
    double mvp_value = 0; //存放数据
    double value;         //存放当前英雄的数据
    //先将第一个当做最值
    mvp = hero[0];
    for (int i = 0; i < size; i++)
    {
        //跟任意一个英雄的数据进行比较
        value = hero[i].kill * 0.8 - hero[i].die * 0.2 + hero[i].ass * 0.4;
        mvp_value = mvp.kill * 0.8 - mvp.die * 0.2 + mvp.ass * 0.4;
        if (mvp_value < value)
        {
            //退位让新
            mvp = hero[i];
        }
    }
    printf("本局的mvp为:%s, %d, %d, %d\n", mvp.name, mvp.kill, mvp.die, mvp.ass);

    //按斩获人头数进行降序排序
    for (int i = 1; i < size; i++)
    {
        for (int j = 0; j < size - i; j++)
        {
            if (hero[j].kill < hero[j + 1].kill)
            {
                struct Hero temp = hero[j];
                hero[j] = hero[j + 1];
                hero[j + 1] = temp;
            }
        }
    }

    printf("排序后的结果为:\n");
    printf("英雄\t血量\t人头\t死亡\t辅助\n");
    for (int i = 0; i < size; i++)
    {
        printf("%s\t%d\t%d\t%d\t%d\n",
               hero[i].name, hero[i].blood, hero[i].kill, hero[i].die, hero[i].ass);
    }

    return 0;
}

1.6 结构体的大小 1 > 结构体变量所占内存空间的大小,是各个成员所占内存空间之和 2 > 要遵循字节对齐原则,有两个 1、结构体中的每个成员,在分配内存时,要以数据类型对齐一次 2、所有成员分配内存结束后,整体需要对齐一次: 32位系统以 min(最大字节的成员,4) 对齐
    64位系统以 min(最大字节的成员,8) 对齐
    3 > 在C语言中一个空的结构体类型,占0字节
#include <myhead.h>
    //一个空的结构体在内存中占0个字节
    struct A
{
};

//定义结构体类型
struct B
{
    short value_a;
    short value_b; // 1122
};

//定义结构体类型
struct C
{
    short value_a;
    char value_b; //1120
};

//定义结构体类型
struct D
{
    char value_b;
    short value_a; //1022
};

//定义结构体类型
struct E
{
    char value_a;
    int value_b;
    short value_c; // 100022223300
};

//定义结构体类型
struct F
{
    char value_a;
    short value_c;
    int value_b; // 10223333
};

//定义结构体类型
struct G
{
    char *value_a;
    short value_c;
    int value_b; //1111111122003333
};
//定义结构体类型
struct H
{
    int value_b;
    char *value_a;
    short value_c; //111100002222222233000000
};

int main(int argc, const char *argv[])
{
    printf("sizeof(struct A) = %ld\n", sizeof(struct A)); //0
    printf("sizeof(struct B) = %ld\n", sizeof(struct B)); //4
    printf("sizeof(struct C) = %ld\n", sizeof(struct C)); //4
    printf("sizeof(struct D) = %ld\n", sizeof(struct D)); //4
    struct D d;
    printf("&d = %p, &d.value_b = %p, &d.value_a = %p\n",
           &d, &d.value_b, &d.value_a);
    printf("sizeof(struct E) = %ld\n", sizeof(struct E)); //12
    printf("sizeof(struct F) = %ld\n", sizeof(struct F)); //8
    printf("sizeof(struct G) = %ld\n", sizeof(struct G)); //16
    printf("sizeof(struct H) = %ld\n", sizeof(struct H)); //24

    return 0;
}

作业
使用结构体完成学生(学号、姓名、性别、成绩)管理系统

1 > 使用菜单实现

2 > 功能1:完成对学生信息的录入,确定人数,完成输入

2 > 功能2:完成对学生信息的输出

3 > 功能3:输出成绩最高和最低学生的信息

4 > 功能4:输出学生的总成绩和平均成绩

5 > 功能5:对学生信息按成绩进行排序,根据传入的升降序,确定排序功能、

6 > 功能6:提示并输入要查找的学生名字,查找该名字是否存在于该班级

7 > 功能0:退出

#include <stdio.h>
#include <string.h>
struct human
{
    int xuehao;      //学号
    char mingzi[20]; //学生姓名
    char a[20];      //性别
    int score;       //成绩
};
int input(struct human q[], int sum)
{
    int N = 0;//本次要增加的人数
    int M = sum;//接受sum
    if (M == 5)//sum达到最大值
    {
        printf("人数已满\n");
        return 0;//增加人数为0
    }
    printf("请输入这次要输入的学生人数\n");
    scanf("%d", &N);
    printf("学号(6位数字)\t姓名\t性别(girl,men)\t成绩(百分制)\n");//打印各个属性及规则
    for (int i = M; i < M + N; i++)
    {
        if (sum == 5)
        {
            printf("人数已满\n");
            return 0;
        }
        printf("请输入第%d位学生的学号\n", i + 1);
        scanf("%d", &q[i].xuehao);
        printf("请输入第%d位学生的姓名\n", i + 1);
        scanf("%s", q[i].mingzi);
        printf("请输入第%d位学生的性别\n", i + 1);
        scanf("%s", q[i].a);
        printf("请输入第%d位学生的成绩\n", i + 1);
        scanf("%d", &q[i].score);
        sum++;
    }
    printf("当前学生人数为%d人\n", sum);
    return N;
}
void print(struct human q[], int sum)
{
    printf("学号  \t姓名\t性别\t成绩\n");//打表
    for (int i = 0; i < sum; i++)
    {

        printf("%d\t%s\t%s\t%d\n", q[i].xuehao, q[i].mingzi, q[i].a, q[i].score);
    }
}
void maxmin(struct human q[], int sum)
{
    int maxi = 0;
    int mini = 0;
    for (int j = 1; j < sum; j++)
    {
        if (q[j].score > q[maxi].score)
        {
            maxi = j;
        }
        if (q[j].score < q[mini].score)
        {
            mini = j;
        }
    }
    printf("成绩最高学生学号%d\t姓名%s\t性别%s\t成绩%d\n", q[maxi].xuehao, q[maxi].mingzi, q[maxi].a, q[maxi].score);//输出最好学生的信息
    printf("成绩最低学生学号%d\t姓名%s\t性别%s\t成绩%d\n", q[mini].xuehao, q[mini].mingzi, q[mini].a, q[mini].score);//输出最差学生的信息
}
void printsumsorce(struct human q[], int sum)
{
    double sumscore = 0.0;
    for (int i = 0; i < sum; i++)//遍历学生成绩
    {
        sumscore += q[i].score;//累加成绩
    }
    printf("学生总成绩为%1f\t平均成绩为%1f\n", sumscore, sumscore / sum);//保留1位小数
}
void paixung(struct human q[], int flag, int sum)
{
    for (int i = 1; i < sum; i++)//外循环
    {
        for (int j = 0; j < sum - i; j++)//内循环
        {
            if (q[j].score > q[j + 1].score && flag == 1 || q[j].score < q[j + 1].score && flag == 0)//如果flag==1升序,flag==0降序
            {
                struct human s;//定义一个结构体变量
                s.xuehao = q[j].xuehao;//对s赋值
                strcpy(s.a, q[j].a);
                strcpy(s.mingzi, q[j].mingzi);
                s.score = q[j].score;
                q[j].xuehao = q[j + 1].xuehao;//q[j+1]赋值给q[j]
                strcpy(q[j].a, q[j + 1].a);
                strcpy(q[j].mingzi, q[j + 1].mingzi);
                q[j].score = q[j + 1].score;
                q[j + 1].xuehao = s.xuehao;//s赋值给q[j+1]
                strcpy(q[j + 1].a, s.a);
                strcpy(q[j + 1].mingzi, s.mingzi);
                q[j + 1].score = s.score;
            }
        }
    }
    printf("排序成功\n");//提示排序成功
}
void chazhao(struct human q[], char a[], int sum)
{
    for (int i = 0; i <=sum - 1; i++)
    {
        if (strcmp(q[i].mingzi,a)==0)//字符串比较
        {
            printf("可在班级中找到\n");
            return;//直接退出
        }
    }
    printf("没有在班级中找到\n");//循环结束没有找到
}
int main()
{
    int sum = 0;
    char w = ' ';
    int flag = 0;
    struct human q[5];
    char z[20];
    memset(q, 0, sizeof(q));//q的初始化
    while (1)
    {
        //打印菜单
        printf("1>录入学生信息\n2>输出学生信息\n3>输出成绩最高和最低学生的信息\n4>输出学生的总成绩和平均成绩 \n5>对学生信息按成绩进行排序,根据传入的升降序,确定排序功能\n6>查找学生\nq>退出\n");
        scanf("%c",&w);
        switch (w)
        {
        case '1':
            sum += input(q, sum);//sum增加对应人数
            break;
        case '2':
            print(q, sum);
            break;
        case '3':
            maxmin(q, sum);
            break;
        case '4':
            printsumsorce(q, sum);
            break;
        case '5':
            printf("请输入flag数值 1为升序,0为降序\n");
            scanf("%d", &flag);//输入flag
            getchar();
            paixung(q, flag, sum);
            break;
        case '6':
            printf("请输入要寻找的学生姓名\n");
            scanf("%s", z);
            chazhao(q, z, sum);
            break;
        case 'q':
            return 0;
        default:
            break;
        }
    }
    return 0;

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值