C语言自学第七课——函数

一、函数

1. 库函数

定义
库函数解析网站:https://cplusplus.com/reference/

例1:strcpy函数

以网站内<string.h>头文件中strcpy函数为例
在这里插入图片描述

(1)图片说明

strcpy //函数名称
char * strcpy ( char * destination, const char * source ); //书写形式
Copy string //解释
Copies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point). //详细解释

注意:*前的是函数的返回类型,例如char * strcpy:strcpy函数返回类型是char类型。

(2)strcpy函数应用
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>//注意引用strcpy函数的头文件

int main()
{
	//知识点复习:const:关键字,用于限定一个变量为只读,变成常量; char:字符型数据类型,引申字符; 
	//新学习:char*:指针; memory:内存
	//单词:array:数组; pointer:指针; pointed:被指向; string:字符串; terminate:终止

	char arr1[20] = { 50 };//注意:数字外需要加{}!!!
	char arr2[] = "I am pretty.";
	strcpy(arr1, arr2);//解释:将arr2复制到arr1里去
	printf("%s",arr1);//复习:%s:字符串的转换说明
	return 0;
}

例2:memset函数

以网站内<string.h>头文件中memest函数为例
在这里插入图片描述

(1)图片说明

memset //函数名称
void * memset ( void * ptr, int value, size_t num ); //书写形式
Fill block of memory //解释
Sets the first num bytes of the block of memory pointed by ptr to the specified value (interpreted as an unsigned char). //详细解释

(2)memset函数应用
#include <stdio.h>
#include <string.h>

int main()
{
	//新学习:*类型:指针类型; void*:无类型指针,可以用来表示任何类型的指针; 
	//新学习:memory:内存; memest = memory set:内存设置; ptr:字符寄存器; value:值; size_t = unsigned int:无符号整型(没有负数的整型)
	char arr[] = "shuimu is pretty.";
	memset(arr,'x', 6);//解释:把"x"(value)替换成arr(ptr)中的前6(num)个字节
	printf("%s",arr);
	return 0;
}

2. 自定义函数

例3

例3:创造一个能找出两个数之间的较大值的函数。

#include <stdio.h>

int getmax(int x, int y)//前需要加int表示输入定义了getmax函数
{
	int c = 0;
	if (x > y)
		c = x;
	else
		c = y;
	return c;//注意:这个返回值是getmax函数的返回值c(两数的较大值)
}

int main()
{
	int a = 10;
	int b = 20;
	int max = getmax(a,b);//传值调用
	printf("%d",max);
	return 0;
}

例4

例4:写一个函数,可以交换两个整型变量的值。

Swap自定义函数逻辑
第一步:自定义x,y,再自定义一个空位z。先将x放到z的空间里,此时x空间空闲,再将y放到x的空间里,此时y空间空闲,最后将z放到y空间里。
第二步:此时swap函数里的x、y所对应的不是a、b的地址,它们分别独自有各自的地址,不相互对应。所以,需要指针,通过指针获取a、b的地址与x、y一一对应。

#include <stdio.h>

//当函数类型返回为void时,表示这个函数不需要返回任何值
void Swap(int* pa, int* pb)//pa和pb就是指针变量
{
	int z = 0;
	z = *pa;//*pa就是通过指针找到的pa所在地址的对象,也就是a
	*pa = *pb;
	*pb = z;
}

int main()
{
	int a = 5;
	int b = 6;
	Swap(&a, &b);//&a表示取出a的地址。传址调用
	printf("a=%d,b=%d",a,b);
	return 0;
}

3. 知识点

(1)实际参数

简称:实参
定义:真实传给函数的参数。实参可以是常量、变量、表达式、函数等。无论实参是哪种类型的,在函数调用的时候都有确定的值,以便把这个值传给形参。例如,例3中的a、b。

(2)形式参数

简称:形参
定义:函数被定义时,函数括号中的变量。形参只有在函数被调用的时候才会发挥作用,函数被调用后就无效了。例如,例3中的x、y。

二、函数调用

1. 传值调用

定义:函数调用的是实际参数的值,此时实参和形参分别占有不同的内存块,对形参进行修改不会影响实参。例如,例3中的getmax(a , b);

例5:写一个函数可以判断一个数是不是素数。

思路
第一步:scanf函数输入一个数;
第二步:假设prime函数可以判断是否为素数,置入if语句,如果prime函数为1,则为素数,如果不为1,则不为素数;
第三步:书写prime函数

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

int prime(int x)//return的是整型1,所以用的数据类型是int
{
	//判断素数:x除以2至(x-1)之间的任何数的余数都不为0
	int a;
	for (a = 2; a < x; a++)
	{
		if (x % a == 0)//%运算符:左侧除以右侧的余数
			return 0;
	}
	return 1;
}

int main()
{
	int i = 0;
	scanf("%d",&i);//scanf函数需要使用&符号!!!
	if (prime(i) == 1)//==运算符是相等的意思
		printf("%d是素数", i);
	else
		printf("%d不是素数",i);
	return 0;
}

2. 传址调用

定义:函数调用的是实际参数的地址,此时形参和实参之间建立了直接的联系,可以通过操作形参直接改变实参。例如,例4中的swap(&a , &b);

例6:写一个函数,每调用一次就会将num的值就+1。

思路
调用对象的值在不断改变,此时需要用传址调用。

#include <stdio.h>

void Add(int* x)//注意指针运用的格式
{
	(*x)++;//注意:此处需要用()
}

int main()
{
	int num = 0;
	Add(&num);
	printf("%d\n",num);//打印:1

	Add(&num);
	printf("%d\n", num);//打印:2

	Add(&num);
	printf("%d\n", num);//打印:3
	return 0;
}

3. 嵌套调用

定义:在一个函数定义中嵌套调用另一个函数。
注意:函数不能嵌套定义。

4. 链式访问

定义:把一个函数的返回值作为另一个函数的参数。

例7:在printf函数中链式访问strlen函数。

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

int main()
{
	printf("%d",strlen("lxx"));//strlen()函数此时作为printf()函数的参数
	return 0;
}

三、函数声明

当函数定义置于函数使用之后,此时需要函数声明。
定义:函数名称(参数,返回类型)
函数的声明一般放在头文件中。

四、函数递归

定义:程序调用自身的编程技巧。

例1

输入一个无符号整型值,按顺序打印它的每一位。

例如输入895.
895%10 = 5
(895/10)%10 = 9
((895/10)/10)%10 = 8

在这里插入图片描述
注意:递归需要满足的两个必要条件

  1. 存在限制条件,当满足这个条件时递归便停止;
  2. 每次递归调用后会不断接近这个限制条件。

Stack overflow栈溢出

内存在使用时分为栈区堆区静态区
栈区存有局部变量、函数形参等,堆区是动态内存分配的,静态区存有全局变量、静态变量。
栈区内存有限,当栈区内存已满,就是栈溢出

例2

编写函数不允许创建临时变量,求字符串的长度。

第一步:根据已学知识求字符串长度——strlen函数;

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

int main()
{
	char arr[] = "shuimu";
	printf("%d",strlen(arr));//strlen()函数是求字符串的长度,对应%d
	return 0;
}

第二步:自定义函数my_strlen来模拟strlen函数;

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

int my_strlen(char* str)//字符串类型的指针char*
{
	int i = 0;
	while (*str != '\0')//当数组的第一个位置不为\0就开始循环
	{
		i++;
		*str++;
	}
	return i;
}

int main()
{
	char arr[] = "shuimu";
	printf("%d",my_strlen(arr));//strlen()函数是求字符串的长度,对应%d
	return 0;
}

第三步:不允许创建临时变量(i),使用函数递归。

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

int my_strlen(char* str)
{
	if (*str != '\0')
		return 1 + my_strlen(str + 1);//str+1取的是str地址的下一个
	else
		return 0;
}

int main()
{
	char arr[] = "shuimu";
	printf("%d",my_strlen(arr));//strlen()函数是求字符串的长度,对应%d
	return 0;
}

例3

求n的阶乘。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int Fac(int i)
{
	if (i > 0)
		return i * Fac(i - 1);
	else
		return 1;
}

int main()
{
	int num = 0;
	scanf("%d",&num);
	printf("%d", Fac(num));
	return 0;
}

例4

求第n个斐波那契数。
注意:斐波那契数:第三个数是前两个数之和。如:1 1 2 3 5 8 … …

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int Fib(int i)
{
	if (i > 2)
		return Fib(i - 1) + Fib(i - 2);
	else
		return 1;
}

int main()
{
	int num = 0;
	scanf("%d",&num);
	printf("%d",Fib(num));
	return 0;
}

注意:可以用递归求解本题,但当输入数字较大时,效率会很低,重复计算次数很多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值