一、函数
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
注意:递归需要满足的两个必要条件:
- 存在限制条件,当满足这个条件时递归便停止;
- 每次递归调用后会不断接近这个限制条件。
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;
}
注意:可以用递归求解本题,但当输入数字较大时,效率会很低,重复计算次数很多。