3.C语言函数

1函数

函数也被称为子程序,子功能
子程序:一个大型程序中的某部分代码,由一个或多个语句快组成,可以完成某项目的任务,
C语言函数分为库函数和自定义函数

2库函数

①在开发过程中每个程序员都会用到比如:printf,strcopy,为了支持可移植性和提高程序的效率,所以C语言在基础库中提供了一系列类似的库函数,方便程序员进行软件开发

②C语言常用的库函数
IO函数
字符串操作函数
字符操作函数
内存操作函数
时间/日期函数
数学函数
其他库函数

3自定义函数

3.1函数的基本用法

①自定义函数和库函数一样,由函数名,返回值类型和函数参数组成

//函数的形式
函数返回值 函数名(形式参数)
{
函数体;
}
//求和的基本方法
#define _CRT_SECURE_NO_DEPRECATE
#include<stdio.h>
int main()
{
	int num1 = 0;
	int num2 = 0;
	int sum = 0;
	printf("请输入操作数:\n");
	scanf("%d%d", &num1, &num2);//&num1称为取地址num1
	sum = num1 + num2;
	printf("%d\n", sum);
	return 0;
}
//使用函数求和
#define _CRT_SECURE_NO_DEPRECATE
#include<stdio.h>
int Add(int num1, int num2){
	int sum = 0;
	sum = num1 + num2;
	return sum;//如果返回类型是void类型,不能return返回而要用printf打印
}
int main()
{
	int num1 = 0;
	int num2 = 0;
	int sum = 0;
	printf("请输入两个操作数:\n");
	scanf("%d%d", &num1, &num2);
	sum = Add(num1, num2);//函数的调用
	printf("%d\n", sum);
}

!!函数名不能重复,区别于C++和JAVA
函数命名要用驼峰形式,首字母大写
②函数的作用:a)代码可以重复使用
b)便于维护

③函数的声明和定义
函数一般要放在主函数的上面,因为C语言是自上而下执行,如果被放在了后面就会报错,所以如果被放在了后面就要在主函数之前对函数定义

#define _CRT_SECURE_NO_DEPRECATE
#include<stdio.h>
int Add(int num1, int num2);//函数的定义,当函数放在主函数的后面时要对函数定义
int main()
{
	int num1 = 0;
	int num2 = 0;
	int sum = 0;
	printf("请输入两个操作数:\n");
	scanf("%d%d", &num1, &num2);
	sum = Add(num1, num2);//函数的调用
	printf("%d\n", sum);
}
int Add(int num1, int num2){
	int sum = 0;
	sum = num1 + num2;
	return sum;
}

3.2实参和形参

实际参数(实参):真实传给函数的参数,实参可以是常量,变量,表达式,函数等,在函数调用的时候必须有固定的值传给形参
形式参数(形参):函数名后括号中的变量,形式参数只有在函数在调用的过程中被实例化,形参在函数调用完被自动销毁

void Swap1(int x, int y)
{
	int tmp = 0;
	tmp = x;
	x = y;
	y = tmp;
	//按值进行传递,形参的改变不影响实参
}
void Swap2(int *px, int *py)//*px是指针传递num1的地址①访问地址
{
	int tmp = 0;
	tmp = *px;//*px解引用,访问px保存的地址的内容②访问地址对应的内容
	*px = *py;
	*py = tmp;  
	return *px, *py;
//地址发生了交换
}
int main()
{
	int num1 = 1;
	int num2 = 2;
	Swap1(num1, num2);
	printf("调用Swap1交换后的值:%d %d\n", num1, num2);
	Swap2(&num1, &num2);
	printf("调用Swap2交换后的值:%d %d\n", num1, num2);
	return 0;
}
//按值传递,形参的改变不会影响实参;按地址传递,形参会影响实参

Swap1和Swap2函数中的参数x,y,px,py都是形式参数,main函数中传递的num1,num2,&num1,&num2是实参
在这里插入图片描述
num1的值为1,地址为100;px保存着num1的地址100,px的地址为32
①Swap(&num1,&num2)把num1,num2的地址传给了指针变量px和py
②px,py里面放着num1和num2的地址100,200
②tmp =*px,*px:px变量里面保存的内容,*px解引用把指针变量保存的值给了tmp
使得其中的值发生了交换

3.3函数的链式调用

链式调用:把一个函数的返回值作为另外一个函数的参数

#define _CRT_SECURE_NO_DEPRECATE
#include<stdio.h>
int Add(int num1, int num2){
	int sum = 0;
	sum = num1 + num2;
	return sum;
}
int Add3(int num1, int num2, int num3){
	return Add(num1, num2) + num3;//函数的链式调用
}
int main()
{
	int num1 = 0;
	int num2 = 0;
	int num3 = 0;
	int sum = 0;
	printf("请输入三个操作数:\n");
	scanf("%d%d", &num1, &num2,&num3);
	sum = Add3(num1,num2,num3);//函数的调用
	printf("%d\n", sum);
}

3.4函数递归

递归:调用函数本身(把大问题改为小问题)
递归的条件:①调用自己本身②存在限制条件,当满足限制条件后,递归停;每次递归调用结束后都越来越接近限制条件

//使用库函数求字符串长度
int main()
{
	char *str = "hello";
	int len = strlen(str);//strlen()函数可以用来计算字符串的长度,遇到\0停止;\0和0都代表0,'0'代表48
	printf("%d\n", len);
	return 0;
}
调用函数实现求字符串长度
int MyStrlen(char *str)//*str的地址就是首字母()
{
	if (*str == '\0'){
		return 0;
	}
	else
	{
		return 1 + MyStrlen(str + 1);//Mystrlen(str+1)首字母右移
	}
}
int main()
{
	char *str = "hello";//""默认字符串后面有个\0
	int len = MyStrlen(str);
	printf("%d\n",len);
	return 0;
}

3.5头文件,源文件,测试文件

在这里插入图片描述
①add.h只是声明
②add.c执行add.h,#include "add.h"把头文件引过来
③test.c测试文件
头文件
在这里插入图片描述

在这里插入代码片

源文件
在这里插入图片描述
测试文件
在这里插入图片描述
①头文件中的ifndef/define/endif的作用:预防头文件重复引入
②#include <add.h>和#include "add.h"的区别:#include <filename.h>:include目录下找;#include "filename.h"先去自己的头文件目录下找再去include目录下找

4结构体

//定义的一个学生类型结构体
/* struct Student//struct定义结构体的关键字
{
	char name[20];
	int age;
}stu2 = {"zhang",18};
*/
typedef struct Student
{
	char name[20];
	int age;
}stu2;//加上typedef是stu类型,在后续就可以定义变量
//结构体整体化只有一次机会,就是在定义的时候初始化
//结构体和数组一样,是聚合类型
int main()
{
	stu2 s = { "zhang", 18 };
	struct Student stu1 = { "caocao", 180 };//把学生类型结构体具体抽象成一个人,stu1 是变量
	strcpy(stu1.name, "sun");//使用strcpy()函数对结构体已经定义的值修改,对stu1赋值只能赋一次,就是定义的时候,后续想修改只能通过strcpy函数一个一个修改
	return 0;
}

练习

①斐波那契

//斐波那契前2项时1,从第三项开始时前两项之和
Feibonaiqie(int n)//递归求斐波那契
{
	if (n == 1 || n == 2)
	{
		return 1;
	}
	else
		return Feibonaiqie(n - 1) + Feibonaiqie(n - 2);
}
Feibonaiqie2(int n)//斐波那契数列
{
	int i = 0;
	int f1 = 1;
	int f2 = 1;
	int f3 = 0;
	for (i = 3; i <= n; i++)//!!i一定要从3开始
	{
		f3 = f1 + f2;
		f1 = f2;
		f2 = f3;
	}
	return f3;
}
	int main()
	{
		//printf("%d\n",Feibonaiqie(2));
		//printf("%d\n", Feibonaiqie(3));
		printf("%d\n", Feibonaiqie(9));
		printf("%d\n", Feibonaiqie2(9));
		return 0;
	}

②汉诺塔

在这里插入图片描述
从A移到C上

void Move(char pos1, char pos2)
{
	printf("%c->%c ", pos1, pos2);
}
void Hannuota(int n, char pos1, char pos2, char pos3)
{
	if (n == 1)
	{
		Move(pos1,pos3);//如果只有一个直接移到第三个上面
	}else
	{
		Hannuota(n-1,pos1,pos3,pos2);//把上面的n-1个先通过第三个柱子移到第二个上面
		Move(pos1, pos3);//把第一个柱子上最下面的一个移到第三个上面
		Hannuota(n - 1, pos2, pos1, pos3);//把第二个柱子上的所有通过第一个移到第三个上面达到目的

	}
}
int main()
{
	Hannuota(1,'A','B','C');
	printf("\n");
	Hannuota(4, 'A', 'B', 'C');
}

作业

①0-999999之间的水仙花数

int main()
{
	//①判断i是几位数因为水仙花数要每一位立方之和②判断是不是水仙花
	int i = 0;
	for (i = 0; i <= 999999; i++)
	{
		int count = 0;
		int tmp = i;//把i赋值给tmp,否则在判断完i的位数之后i就会变成0,赋值之后重复赋值
		 int sum = 0;
		while (tmp != 0)
		{
			count++;
			tmp = tmp / 10;//12:12/10,1/10=0得到i是两位数
		}
		tmp = i;
		while (tmp != 0){
			sum = sum + pow((double)(tmp %10), count);
			tmp = tmp / 10;
		}
		if (sum == i){
			printf("%d ", i);
		}
	}
	return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
void Menu()
{
	printf("************\n");
	printf("**猜字游戏**\n");
	printf("***1.play***\n");
	printf("***0.exit***\n");
	printf("************\n");
}
void game()
{
	int input = 0;
	int randNum = rand() % 100;
	while (1){
		printf("请输入你要猜的数字:");
		scanf("%d", &input);
		if (input < randNum){
			printf("你猜小了\n");
		}else if (input > randNum){
			printf("你猜大了\n");
		}
		else{
			printf("你猜对了\n");
			break;
		}
	}
	}
int main()
{
	int input = 0;
	srand ((unsigned int)time(NULL));//设置随机种子使得每次产生的随机数不一样,每次运行的时候会获取当前电脑的时间,参数使NULL代表time的返回值不保存
	do{
		Menu();
		printf("请老铁输入你的操作:");
		scanf("%d", &input);
		switch (input){
		case 1:
			game();
			break;
		case 0:
			printf("拜拜\n");
			break;
		default:
			printf("请重新输入\n");
			break;
		}
	}while(input);
	return 0;
}

③输入小写字符输出大写字符,输入大写字符输出小写字符,输入数字不输出

int main()
{
	int ch = 0;
	while ((ch = getchar()) != EOF)
	{
		if (ch >= 'a'&&ch <= 'z')
		{
			putchar(ch - 32);
		}
		else if (ch >= 'A'&&ch <= 'Z'){
			putchar(ch + 32);
		}
	}
	}

④用函数实现初始化数组,清空数组,数组逆置,

void Init(int arr[], int set, int len)//初始化数组	
{
	int i = 0;
	for (i = 0; i < len; i++)
	{
		arr[i] = set;
	}
}
void Show(int arr[], int len)
{
	int i = 0;
	for (i = 0; i < len; i++)
	{
		printf("%d", arr[i]);
	}
	printf("%\n");
}
void Reverse(int arr2[], int len)//数组逆置
{
	int left = 0;
	int right = len - 1;
	while (left < right){
		int tmp = arr2[left];
		arr2[left] = arr2[right];
		arr2[right] = tmp;
		left++;
		right--;
	}
}
void Empty(int arr[], int len)//清空数组
{
	int i = 0;
	for (i = 0; i < len; i++)
	{
		arr[i] = 0;
	}
}
int main()
{
	int arr[10];
	Init(arr, 2, 10);
	Show(arr, 10);
	int arr2[4] = { 1, 2, 3, 4 };
	Reverse(arr2, 4);
	Show(arr2,4);
	Empty(arr, 10);
	Show(arr, 10);
}

⑥乘法口诀

void ShowMuti(int n)
{
	int i = 0;
	for (i = 1; i <= n; i++)
	{
		int j = 1;
		for (j = 1; j <= i; j++)
		{
			printf("%d*%d=%d ", i, j, i*j);
		}
		printf("\n");
	}
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	ShowMuti(n);
	return 0;
}

递归练习

①用递归实现字符串反向排列

void reverse_string(char *str)
{
	assert(str != NULL);
	char tmp = *str;
	int len = strlen(str);
	*str = *(str + len - 1);
	*(str + len - 1) = '\0';
	if (strlen(str + 1) >= 2)
		reverse_string(str + 1);
	*(str + len - 1) = tmp;
}

int main()
{
	char str[10] = "hello";
	reverse_string(str);
	printf("%s", str);
}

②求数字各位数之和

int DigitSum(int n)
{
	if (n > 9)
	{
		return DigitSum(n / 10) + n % 10;
	}
	else
	{
		return n % 10;
	}
}
int main()
{
	int  ret = DigitSum(1728);
	printf("%d\n", ret);
	return 0;
}

③幂次方

int Pow(int n, int k)
{
	if (k == 0)
	{
		return 1;
	}
	return n*Pow(n, k - 1);
}
int main()
{
	int  ret = Pow(2, 3);
	printf("%d\n", ret);
	return 0;
}

④求字符串长度

int my_strlen(const char *str)
{
	int count = 0;
	while (*str)
	{
		count++;
		str++;
	}
	return count;
}
int main()
{
	const char *p = "zhang";
	int len = my_strlen(p);
	printf("len=%d\n", len);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值