vs2022
学习视频: b站比特c语言就业班
函数
分类:
1.库函数
2.自定义函数
一.库函数
MSDN下载参考:MSDN的下载和使用
库函数及其包含的头文件:cplusplus
c、c++语言中文网:cppreference
cplusplus的使用:
常用库函数:
1.IO函数:getchar、putchar、scanf、printf等
2.字符串操作函数:strcmp、strlen等
3.字符操作函数:toupper(小写转大写)等
4.内存操作函数:memcpy、mencmp、memset等
5.时间/日期函数:time等
6.数字函数:sqrt、pow等
7.其他库函数
二.自定义函数
1.两数最大值
2.交换两数值
传值调用
指针
swap(int* x,int* y) {//传指调用
int c = 0;
c = *x;
*x = *y;
*y = c;
return 0;
}
int main() {
int a = 10;
int b = 20;
printf("交换前:a:%d\tb:%d\n", a, b);
//交换值,无需返回值
swap(&a,&b);
printf("交换后:a:%d\tb:%d\n", a, b);
return 0;
}
形参和实参
实际参数(实参):真实传给函数的参数,叫实参。实参可以是∶常量、变量、表达式、函数等。无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。
形式参数(形参):形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。
函数的调用
1.传值调用
2.传指调用
100-200的素数
1000-2000闰年
整形有序数组的二分查找(折半查找)下标
形参x[]:定义x是数组,所以带[]
实参arr:传递的数组名即可
数组传参
不是传递了数组本身
只传递了数组第一个元素的地址
所以:不可以在自定义函数内计算数组长度,要在main内提前计算好长度
函数的嵌套调用和链式访问
函数不能嵌套定义
(1)嵌套调用
(2)链式访问
函数的声明和定义
函数的定义:在main后面:先声明,再使用。在main之前:可以不声明。
集成环境
.h:声明。引用头文件:#include “xxx.c”。
.c:定义。
创建、引用静态库
三.函数递归
递归:程序调用自身的编程技巧称为递归(recursion )。递归做为一种算法在程序设计语言中广泛应用。一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的主要思考方式在于:把大事化小。
必要条件:
1.存在限制条件,当满足限制条件,递归不再继续
2.每次递归调用之后,都越来越接近限制条件
另外:层次不要太深
例1:依次输出四位数的千、百、十、个位数值
void print(unsigned int a) {
//%10:返回个位数值。
//反复利用printf,输出各个a的个位数值
if (a > 9) {
print(a / 10);
}
printf("%d ", a % 10);
}
int main() {
unsigned int num = 0;
scanf("%u", &num);
print(num);
return 0;
}
递归错误:栈溢出
每一次函数调用,都需要在栈区分配一块内存空间,称为其的栈帧空间
递归层次太深,栈区不够分配,产生栈溢出
内存:
栈区:局部变量、函数形参
堆区:动态内存分配(malloc、free、calloc、realloc等)
静态区:全局变量、静态变量
例2:不创建临时变量,求字符串长度
//有临时变量count
int mystrlen(char* ch) {
int count = 0;
while (*ch != '\0') {
count++;
ch++;
}
return count;
}
int main() {
char arr[] = "hello";
printf("%d", mystrlen(arr));
return 0;
}
int mystrlen(char* ch) {
//执行一次相当于:判断一次此地址的数组值arr[i]
//若成功if:计入1;失败else:计入0
//相当于:1 + 1 + 1 + 1 + 0 = 5
if (*ch != '\0') {
return 1 + mystrlen(ch + 1);
}
else
return 0;
}
int main() {
char arr[] = "hello";
printf("%d", mystrlen(arr));
return 0;
}
四.递归与迭代
1.阶乘
//阶乘:递归
int Fac(int x) {
if (x < 1)
return 1;
else
return x * Fac(x - 1);
}
int main() {
int n = 1;
scanf("%d", &n);
int ret = Fac(n);
printf("%d", ret);
return 0;
}
//阶乘:迭代
//int main() {
// int n = 0;
// scanf("%d", &n);
//
// int i = 0;
// int ret = 1;
// for (i = 1; i <= n; i++) {
// ret = ret * i;
// }
// printf("%d\n", ret);
// return 0;
//}
2.斐波那契数:进行重复大量的计算
//递归
int Fid(int x) {
if (x <= 2)
return 1;
else
return Fid(x - 1) + Fid(x - 2);
}
int main() {
int n = 0;
scanf("%d", &n);
printf("%d", Fid(n));
return 0;
}
//循环
int main() {
int n = 0;
scanf("%d", &n);
int a = 1, b = 1, c = 1;
while (n>2) {
c = a + b;
a = b;
b = c;
n--;
}
printf("%d", c);
return 0;
}
五.作业
编写程序,输出1-100的所有数字中出现了多少9.
int A(int n,int* count) {
//递归
while (n >= 10) {
A(n % 10,count);
n = n / 10;
}
if (n == 9)
*count = *count + 1;
return 0;
}
int main() {
int n = 1;
int m = 0;
for (; n <= 100; n++) {
A(n,&m);
}
printf("出现了%d个9\n", m);
return 0;
}
计算1/1-1/2+1/3-…+1/99-1/100的值。
int main() {
float n = 0, count = 0, m = -1;
for (int i = 1; i <= 100; i++) {
m *= -1;
//m=-m;
count += m/i;
//一个为小数,即是小数除法
}
printf("%f", count);
}
返回两个数给主函数。
return只能返回一个数字给主函数。
应当:形参用数组、指针,全局变量等。
函数可以嵌套调用,不可以嵌套定义。
栈区、栈、堆栈:局部变量、函数参数、调用函数时返回值等临时变量。
堆区、堆:动态内存分配。
静态区:全局变量、静态变量static。
逆序输出字符串,不使用库函数。
由两端对调,完成逆序输出。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int my_strlen(char* str) {
int count = 0;
while (*str != '\0') {
count++;
str++;
}
return count;
}
递归逆序
//void reverse_string(char* str) {
// char tmp = *str;
// int len = my_strlen(str);
// *str = *(str + len - 1);
// *(str + len - 1) = '\0';
// if (my_strlen(str + 1) >= 2) {
// reverse_string(str + 1);
// }
// *(str + len - 1) = tmp;
//}
//循环逆序
void reverse_string(char* str) {
int left = 0;
int right = my_strlen(str) - 1;
while (left < right) {
char tmp = str[left];
str[left] = str[right];
str[right] = tmp;
left++;
right--;
}
}
int main() {
char arr[] = "abcdef";
reverse_string(arr);//数组名arr是数组arr首元素的地址
printf("%s\n", arr);
return 0;
}