一、函数指针数组
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 = # //将普通变量的地址赋值给指针变量
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 #
}
//使用参数的形式将被调函数中的变量地址返回
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 = #
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;