目录
一.修炼必备
1.入门必备:VS2019社区版,下载地址:Visual Studio 较旧的下载 - 2019、2017、2015 和以前的版本 (microsoft.com)
2.趁手武器:印象笔记/有道云笔记
3.修炼秘籍:牛客网 - 找工作神器|笔试题库|面试经验|实习招聘内推,求职就业一站解决_牛客网 (nowcoder.com)
4.雷劫必备:leetcode 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
注:遇到瓶颈怎么办?百度百科_全球领先的中文百科全书 (baidu.com)
二.库函数和自定义函数
1.什么是函数
—— 函数,也叫子程序:是一个大型程序中某个部分的代码,由一个或多个语句块组成;一般来说,函数是完成某个功能或者是完成某个任务的,相对于其他代码,有一定的独立性。
2.函数的格式
返回类型 函数名(参数列表……)
{
statement; //语句块
return 返回值;
}
//注:{}是函数体,返回类型可以为void,也就是无返回值
3.库函数
1)什么是库函数
—— 库函数就是C语言自己提供的函数,如我们使用的输入输出函数(printf、scanf)
2)库函数的分类
3)怎么去阅读C语言自带的库函数
—— 若是想要了解更多的库函数,请点击https://cplusplus.com
4)了解两个库函数
//库函数的了解
//1)strcpy()函数:字符串复制
//char* strcpy(char* destination, const char* source);
//解释:
//strcpy()函数的返回值:destination被返回;
//const char* source: 被复制的函数,const表示source中的内容不能被再次改变
//char* destination: 目的函数,source中的内容复制到destination中
//需要头文件: <string.h>
//2)strcat()函数:字符串连接函数
//char * strcat ( char * destination, const char * source );
//strcat的函数:destination被返回;
//const char * source: 连接函数,const: source中内容不能被再次修改
//char * destination: 目的函数,连接函数连接在目的函数后面
//需要头文件: <string.h>
5)一个小case快速了解库函数
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "abcdefg";
char arr2[] = "hughdsh";
char str[101] = "acbdghdgsh";
//字符串复制函数
strcpy(str, arr1);//把arr字符串中内容复制到str中
printf("%s\n", str);//abcdefg
//字符串连接函数
strcat(str, arr2);//把arr2中字符串的内容连接到str字符串的后面
printf("%s\n", str);//abcdefghughdsh
return 0;
}
4.自定义函数
1)什么叫做自定义函数
—— 程序员自己设计的函数就叫做自定义函数,自定义函数遵守函数的一切格式要求
2)一个小case快速了解自定义函数
#include <stdio.h>
//得到两个数的最大值的函数
//返回类型:int 函数名:getMax 参数列表:a,b
int getMax(int a, int b)
{
return a > b ? a : b;
}
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
int max = getMax(a, b);
printf("%d\n", max);
return 0;
}
三.函数的参数
1.实际参数(实参):实参中的值传递给形参中的值,实参可以是常量、变量、表达式、函数等。
注:无论实参是那种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传递给形参
2.形式参数(形参):形参是指函数名后括号中的变量,形参只有函数在被调用的时候才会被实例化(分配内存单元),形参在函数调用结束之后就自动销毁了
3.一个小case快速了解实参和形参
#include <stdio.h>
//int a, int b叫形参
int getSum(int a, int b)
{
return a + b;
}
int main()
{
int a = 10;
int b = 20;
//getSum中的a,b叫做实参,以变量做实参
int sum1 = getSum(a, b);
//1,2以常量值做实参
int sum2 = getSum(1, 2);
//a++,b++以表达式做实参
int sum3 = getSum(a++, b++);
//以函数调用作为实参
int sum4 = getSum(getSum(a, 10), b);
printf("%d %d %d %d\n", sum1,sum2,sum3,sum4);//30 3 30 42
return 0;
}
4.形参实例化之后其实相当于实参的一份临时拷贝
四.函数的调用
1.传值调用:实参的数据值传递给形参,两者的内存地址不同,在形参中的改变不会影响实参
2.传址调用:实参的地址传递给形参,两者的内存地址相同,在形参中的改变会影响实参
3.一个小case快速了解函数调用
#include <stdio.h>
void swap1(int x, int y)
{
//交换两个值,只在函数体内交换,出了函数体形式参数自动销毁
int tmp = x;
x = y;
y = tmp;
}
//地址需要指针变量来接收
void swap2(int* x, int* y)
{
//*:取出地址中对应的值
int tmp = *x;
*x = *y;
*y = tmp;
}
int main()
{
int x = 0;
int y = 0;
scanf("%d %d", &x, &y);
//传值调用:形参的改变不改变实参
swap1(x, y);
//可以发现,在swap1中的交换对实参并没有作用
printf("%d %d\n", x, y);
//传址调用:形参中的改变,实参也跟着改变
swap2(&x, &y);//&:取出对应变量的地址
printf("%d %d\n", x, y);
return 0;
}
五.函数的嵌套调用和链式访问
1.函数的嵌套调用:在一个函数中调用另外一个函数
#include <stdio.h>
void print(int i)
{
printf("%d ", i);
}
int getSum(int x)
{
int i = 0;
int sum = 0;
for (i = 1; i <= x; i++)
{
print(i);//调用另一个函数
sum += i;
}
return sum;
}
int main()
{
printf("\n%d\n", getSum(10));//55
return 0;
}
注:函数不可以嵌套定义
#include <stdio.h>
void print()
{
void get()
{
//错误,不能在一个函数中定义另外一个函数,即函数不能嵌套定义
}
}
int main()
{
print();
return 0;
}
2.函数的链式访问:把一个函数的返回值作为另外一个函数的参数
#include <stdio.h>
int main()
{
printf("%d", printf("%d", printf("%d", 43)));//4321
//printf的返回值是int,即printf中有几个字符就打印几个字符
//printf("%d", 43):打印43
//4和3是两个字符,下一个printf打印2
//2是一个字符,最后打印1
return 0;
}
六.函数的声明和定义
1.函数的声明
1)函数的声明说明了函数名,函数的参数和函数的返回类型,但不能进行具体操作
void swap(int x, int y);
//返回类型:void 函数名:swap 参数:x, y
2)函数的声明一般使用在函数的使用之前,要满足先声明后使用
3)函数的声明一般放在头文件中
//test.h
void print();//函数声明,放在了头文件中
//test.c
#include <stdio.h>
#include "test.h"
//先声明后使用
void print()
{
printf("hello,world\n");
}
int main()
{
print();
}
2.函数定义:函数的具体实现方式,实现函数的功能
#include <stdio.h>
//函数声明
int getSum(int x, int y);
int main()
{
int x = 10;
int y = 20;
printf("%d\n", getSum(x, y));//30
return 0;
}
//函数定义
int getSum(int x, int y)
{
return x + y;
}
注:在单个源文件中,不建议这样做,太过啰嗦,我们直接让声明和定义一起使用
#include <stdio.h>
//函数声明和定义
int getSum(int x, int y)
{
return x + y;
}
int main()
{
int x = 10;
int y = 20;
printf("%d\n", getSum(x, y));//30
return 0;
}
七.函数使用练习
1.使用函数判断一个数是不是素数
#include <stdio.h>
#include <math.h>
int isPrime(int num)
{
int i = 0;
for (i = 2; i <= sqrt(num); i++)
{
//能除尽则不是素数
if (num % i == 0)
return 0;
}
return 1;//是素数
}
int main()
{
int num = 0;
scanf("%d", &num);
int res = isPrime(num);
if (res == 1)
{
printf("%d是素数\n", num);
}
else
{
printf("%d不是素数\n", num);
}
return 0;
}
2.判断一个数是不是闰年
#include <stdio.h>
int is_leap_year(int year)
{
//判断:不是闰年则返回0
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
int main()
{
int year = 0;
scanf("%d", &year);
int res = is_leap_year(year);
if (res)
{
printf("%d是闰年\n", year);
}
else
{
printf("%d不是闰年\n", year);
}
return 0;
}
3.二分查找
#include <stdio.h>
int binarySearch(int arr[], int num, int len)
{
int left = 0;
int right = len - 1;
while (left <= right)
{
int mid = left + (right - left) / 2;//防止数值溢出
if (arr[mid] > num)
{
right = mid - 1;//right左移
}
else if (arr[mid] < num)
{
left = mid + 1;//left右移
}
else
{
return mid;
}
}
return -1;
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int num = 0;
int len = sizeof(arr) / sizeof(arr[0]);//数组长度
scanf("%d", &num);
int index = binarySearch(arr, num, len);
if (index == -1)
{
printf("找不到\n");
}
else
{
printf("找到了,下标是:%d\n", index);
}
return 0;
}
八.函数递归
1.什么是递归
—— 程序调用自身程序的方式叫做递归,递归通常把一个大型复杂的问题转化为一个与原问题较小的问题来解决。递归的注意思考方式在于:大事化小
2.递归的两个必要条件
1)存在限制条件,当符合这个限制条件后,递归不再继续
2)每次递归后越来越接近这个限制条件
3.一个小case快速了解递归
#include <stdio.h>
//写一个递归函数DigitSum(num),输入一个非负整数,返回组成它的数字之和
int DigitSum(int num)
{
if (num > 9)
return num % 10 + DigitSum(num / 10);//大于9的数
else
return num % 10;//最后一个数
}
int main()
{
int num = 0;
scanf("%d", &num);
int sum = DigitSum(num);
printf("%d\n", sum);
return 0;
}