C语言学习——7
一、递归函数
递归:所谓的递归是一种思想 ------ 算法 ------>解决递归问题,带有回溯思想的问题
递归函数:函数自己调用自己,需要控制结束条件,不能无限的调用自己
递归的作用:
1.简化代码
2.特别适合解决递归问题
递归函数实现1-100的累加
//递归累加
int fun(int n)
{
if(n <= 1)
return 1;
return n+fun(n-1);
}
void main()
{
printf("sum = %d\n",fun(100));
}
递归函数实现阶乘
/*===============================================
* 文件名称:eg1.c
* 创 建 者:
* 创建日期:2025年07月21日
* 描 述:阶乘实现
================================================*/
#include <stdio.h>
int fun(int n)
{
if(n <= 1)
return 1;
return n*fun(n-1);
}
int main(int argc, char *argv[])
{
int num = fun(5);
printf("%d\n",num);
return 0;
}
练习
拆分打印 123456 ,递归实现
/*===============================================
* 文件名称:eg3.c
* 创 建 者:青木莲华
* 创建日期:2025年07月21日
* 描 述:拆分打印 "123456"
================================================*/
#include <stdio.h>
void func(char *p)
{
if(*p == '\0') return;
printf("%c\n",*p);
func(p+1);
}
int main(int argc, char *argv[])
{
char *str = "123456";
func(str);
return 0;
}
泛型:打印任意类型的数组
/*===============================================
* 文件名称:eg4.c
* 创 建 者:青木莲华
* 创建日期:2025年07月21日
* 描 述:泛型打印任意类型
================================================*/
#include <stdio.h>
typedef void FUNC(void *); //别名 typedef 原类型 别名;
void print_int(void *p)
{
printf("%d ",*(int *)p);
}
void print_float(void *p)
{
printf("%f ",*(float *)p);
}
void print_str(void *p)
{
printf("%s ",*(char **)p);
}
void show_arr(const void *arr, int len,int size,FUNC *print_data)
{
char *p = (char *)arr;
for(int i = 0 ; i < len ; i++)
{
print_data(p);
p+=size;
}
printf("\n");
}
int main(int argc, char *argv[])
{
int arr[6] = {11,22,33,44,55,66};
show_arr(arr,6,sizeof(int),print_int);
float arr2[5] = {1.11,2.22,3.33,4.44,5.55};
show_arr(arr2,5,sizeof(float),print_float);
char *arr3[32] = {"hello","world","123456","xxxxxx"};
show_arr(arr3,4,sizeof(char *),print_str);
return 0;
}
二、回调函数
实现:泛型、多态编程
functionA functionB
当函数A的参数是一个函数指针,那么函数B的地址就可以成为参数被传入;
如果函数B以参数的形式传入了函数A,那么函数A中就有能力去调用函数B
在特定的情况下,调用了函数B,那么函数B就称为回调函数
回调函数的作用
1.实现泛型、多态编程
2.解决代码的重复问题
//回调函数的示例
int sum(int x,int y)
{
return x+y ;
}
int sub(int x,int y)
{
return x-y;
}
int cal(int x,int y,int (*funcp)(int , int))
{
return funcp(x,y);
}
void main()
{
int result = cal(10,5,sum);
printf("%d\n",result);
result = cal(10,8,sub);
printf("%d\n",result);
}
三、C语言内存空间
1.malloc 申请空间
#include <stdlib.h>
void *malloc(size_ _t size);
/*
参数:
size_ t size: 申请的空间大小,单位:字节
返回值:
成功---申请到空间地址
失败---返回NULL
*/
void *p = malloc(4);
printf("%p\n",p);
*(int *)p = 10;
printf("%d\n",*(int *)p);
2.free 释放空间
//参数 *ptr 要释放的空间的首地址
void free(void *ptr);
注意:释放空间只能释放一次!
3.calloc 分配空间
void *calloc(size_t nmemb, size_t size);
#include <stdlib.h>
int main() {
int *ptr = (int *)calloc(10, sizeof(int));
if (ptr == NULL) {
// 内存分配失败
return 1;
}
// 使用内存
free(ptr); // 释放内存
return 0;
}
4.realloc 追加空间
void *realloc(void *ptr, size_t size);
#include <stdlib.h>
int main() {
int *ptr = (int *)malloc(10 * sizeof(int));
if (ptr == NULL) {
// 内存分配失败
return 1;
}
ptr = (int *)realloc(ptr, 20 * sizeof(int));
if (ptr == NULL) {
// 内存重新分配失败
return 1;
}
// 使用内存
free(ptr); // 释放内存
return 0;
}
练习
申请一片空间存放一个字符串并输出这个字符串到屏幕
/*===============================================
* 文件名称:eg5.c
* 创 建 者:
* 创建日期:2025年07月21日
* 描 述:
================================================*/
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *p = malloc(10);
printf(">:");
scanf("%s",p);
printf("%s\n",p);
return 0;
}
四、typedef
是一个关键字,用于取别名
typedef 类型 别名
typedef int myint; //为int类型取别名
typedef char data_t; //char类型别名
typedef int * p_int; //int型指针取别名
typedef int Arr[9]; //给int [9]取别名 数组
typedef int (*funcp)(int ,int ); //给int (*)(int , int)取别名为funcp 函数指针
typedef int (*Hp)[5]; //给int (*)[5]取别名为Hp 行指针
五、#define
宏定义:(预编译阶段替换)
#define 宏名 表达式
//1.宏定义整型指针
#define p_int int *
p_int p1,p2; // int *p1,p2;
typedef int * p_int;
p_int p1,p2; // int *p1,*p2;
注意:(define只是替换,typedef是新定义的类型)
p1是一个int *指针
p2是一个int 变量
六、结构体
在实际的处理对象中,有许多信息是由多个不同的类型的数组组合在一起进行 描述,而且这些不同类型的数据是互相练习组成了一个有机的整体,此时,我们需要用到 一个新的构造类型数据--结构体(struct)。
结构体的使用为处理复杂的数据结构提供了有效的手段,而且他为函数间传递不同类型的数据提供了方便
1.定义
一般形式
struct 结构体名
{
数据类型 成员名1;
数据类型 成员名2;
……
数据类型 成员名n;
}
有名结构体
struct student
{
char name[20];
int age;
char sex;
}
//定义结构体变量:
struct student a;
//结构体指针:
struct student *p;
无名结构体
不能在定义了结构体之后,再定义无名结构体变量
struct
{
char name[32];
int age;
char sex;
}*a,b,c;
取别名
typedef struct
{
char name[32];
int age;
char sex;
}STU, *PSTU;
//可以再定义新的变量
STU a;
PSTU *p;
//对于有名的
typedef struct student Stu;
typedef struct student *PStu;
赋值(对成员变量进行操作)
练习
1.定义一个学生的结构体,里面包含基本的信息以及一个成绩结构体,可以通过输入结构体的成员以及输出结构体的成员。
/*===============================================
* 文件名称:eg6.c
* 创 建 者:青木莲华
* 创建日期:2025年07月21日
* 描 述:结构体练习
================================================*/
#include <stdio.h>
struct Score
{
float chinese;
float math;
float english;
};
struct Student
{
char *name;
int age;
char *sex;
struct Score s;
};
int main(int argc, char *argv[])
{
struct Student stu;
struct Student *p = &stu;
p->name = "Aoki";
p->age = 20;
p->sex = "男";
p->s.chinese = 100;
p->s.math = 99;
p->s.english = 98;
printf("姓名: %s 年龄: %d 性别: %s\n",stu.name,stu.age,stu.sex);
printf("语文: %.1f 数学: %.1f 英语: %.1f\n",stu.s.chinese,stu.s.math,stu.s.english);
return 0;
}
运行截图
2.初始化&赋值
初始化
typedef struct student
{
char name[20];
int age;
char sex;
}Stu,*PStu;
Stu a = {"张三",18,'m'};
Stu b = a;
注意:结构体初始化的时候可以直接将已有的结构体变量赋值给新的结构体,但是之后不可以直接赋值。
成员变量赋值
typedef struct student
{
char name[20];
int age;
char sex;
}Stu;
Stu stu;
strcpy(stu.name,"zhangsan");
stu.age = 18;
stu.sex = 'x';
强制类型转换赋值整个结构体
typedef struct student
{
char name[20];
int age;
char sex;
}Stu;
Stu stu;
stu = (Stu){"zhangsan",18,'x'};
3.结构体数组
typedef struct student
{
char name[20];
int age;
char sex;
}Stu,*PStu;
Stu a[2] = {
{"张三",18,'x'},
{"李四",19,'x'}
};
4.结构体大小
字节对齐规则
默认对齐 --- 64 --- 8字节
--- 32 --- 4字节
对齐数:看结构体的成员大小
如果结构体最大成员大小大于或者等于了默认的最大对齐数,那么最大对齐数对齐
如果结构体最大成员大小小于默认最大对齐数,那么以结构体最大成员的大小对齐
#pragma pack(4); //设置默认最大对齐数
七、共用体
共用体概念 在C语言中,不同的数据类型的数据可以使用共同的存储区域,这种数据构造类型称之为共用体,简称共用,又称联合体,共用体在定义、说明和使用形式上与结构体 相似,两者本质不同仅在于使用内存的方式上。
定义
union 共用体名
{
成员列表;
}
注意:
1.共用体共用一片内存空间,给成员赋值后,前面赋值的成员只会被覆盖
2.共用体的大小为最大成员的大小,遵循字节对齐原则
union stu
{
char name[32];
int age;
char sex;
};
八、枚举
概念
用于列举有穷的事物
enum 枚举名{
枚举成员1;
枚举成员2;
......
枚举成员n;
};
enum Week{
Mon, //默认值为0
Tues, //1
Weds, //2
Thurs, //3
Fri, //4
Sat, //5
Sun //6
};
定义:
enum 枚举名 变量名;
注意:
1.枚举的变量赋值要枚举成员来赋值
2.枚举成员的值,默认从0开始往后依次加1
3.当给其中的某一个成员赋值之后,那么从这个成员开始往后,以赋值的成员为基准,往后依次加1
作用:
1.增加代码的阅读星
2.相当于批量的宏
作业
1.泛型数组排序,传入任意类型的数组,完成排序
/*===============================================
* 文件名称:work1.c
* 创 建 者:青木莲华
* 创建日期:2025年07月21日
* 描 述:泛型实现一维数组排序
================================================*/
#include <stdio.h>
typedef void FUNC(void * ,int ,int );
typedef void FUNCP(void *); //别名 typedef 原类型 别名;
//整型排序
void sort_int(void *p,int len,int size)
{
for(int i = 0 ; i < len - 1 ; i++)
for(int j = 0 ; j < len - i - 1 ; j++)
if(*(int *)(p+j*size) > *(int *)(p+j*size+size))
{
int temp = *(int *)(p+j*size);
*(int *)(p+j*size) = *(int *)(p+j*size+size);
*(int *)(p+j*size+size) = temp;
}
}
//浮点型排序
void sort_float(void *p,int len,int size)
{
for(int i = 0 ; i < len - 1 ; i++)
for(int j = 0 ; j < len - i - 1 ; j++)
if(*(float *)(p+j*size) > *(float *)(p+j*size+size))
{
float temp = *(float *)(p+j*size);
*(float *)(p+j*size) = *(float *)(p+j*size+size);
*(float *)(p+j*size+size) = temp;
}
}
//字符排序
void sort_char(void *p,int len,int size)
{
for(int i = 0 ; i < len - 1 ; i++)
for(int j = 0 ; j < len - i - 1 ; j++)
if(*(char *)(p+j*size) > *(char *)(p+j*size+size))
{
char temp = *(char *)(p+j*size);
*(char *)(p+j*size) = *(char *)(p+j*size+size);
*(char *)(p+j*size+size) = temp;
}
}
void print_int(void *p)
{
printf("%d ",*(int *)p);
}
void print_float(void *p)
{
printf("%.2f ",*(float *)p);
}
void print_str(void *p)
{
printf("%c",*(char *)p);
}
void show_arr(const void *arr, int len,int size,FUNCP *print_data)
{
char *p = (char *)arr;
for(int i = 0 ; i < len ; i++)
{
print_data(p);
p+=size;
}
printf("\n");
}
void sort(void * const p,int len,int size,FUNC *sort_data)
{
sort_data(p,len,size);
}
int main(int argc, char *argv[])
{
int a[8] = {1,2,33,14,55,62,7,28};
printf("------------int------------\n");
show_arr(a,8,sizeof(int),print_int);
sort(a,8,sizeof(int),sort_int);
show_arr(a,8,sizeof(int),print_int);
float b[8] = {11.2,2.3,31.5,14.5,25.6,6.44,71.22,18.22};
printf("------------float------------\n");
show_arr(b,8,sizeof(float),print_float);
sort(b,8,sizeof(float),sort_float);
show_arr(b,8,sizeof(float),print_float);
char c[32] = "gfedcba";
printf("------------string------------\n");
show_arr(c,7,sizeof(char),print_str);
sort(c,7,sizeof(char),sort_char);
show_arr(c,7,sizeof(char),print_str);
return 0;
}
2.定义一个学生的结构体,里面包含基本的信息以及一个成绩结构体,可以通过输入来给结构体成员以及输出结构体的成员,根据成绩排序
/*===============================================
* 文件名称:work2.c
* 创 建 者:青木莲华
* 创建日期:2025年07月21日
* 描 述:结构体输入学生信息排序后输出
================================================*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Score
{
float ch;
float math;
float eng;
float sum;
}Sco,*PSco;
typedef struct Student
{
char name[10];
int age;
char sex;
Sco sco;
}Stu,*PStu;
void sort(Stu p[],int len)
{
Stu temp;
for(int i = 0 ; i < len - 1 ; i++)
for(int j = 0 ; j < len - 1 - i ; j++)
if(p[j].sco.sum < p[j+1].sco.sum)
{
temp = p[j];
p[j] = p[j+1];
p[j+1] = temp;
}
}
int main(int argc, char *argv[])
{
Stu students[4];
for(int i = 0 ; i < 4 ; i++)
{
printf("请输入第%d个同学的信息以及分数\n",i+1);
printf("格式:姓名 年龄 性别 语文 数学 英语\n");
scanf("%s %d %c %f %f %f",
students[i].name,&students[i].age,&students[i].sex,
&students[i].sco.ch , &students[i].sco.math , &students[i].sco.eng);
students[i].sco.sum = students[i].sco.ch + students[i].sco.math + students[i].sco.eng;
}
sort(students,4);
for(int i = 0 ; i < 4 ; i++)
{
printf("姓名:%s 年龄:%d 性别:%c 语文:%.1f 数学:%.1f 英语:%1.f 总分:%1.f\n",
students[i].name , students[i].age , students[i].sex , students[i].sco.ch ,
students[i].sco.math , students[i].sco.eng , students[i].sco.sum);
}
return 0;
}
运行截图