2024年最全「C语言精华篇」春眠不觉晓,函数知多少?_c语言打春眠不觉晓(3),2024年最新2024最新C C++开发面试大全

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

打开库函数网站可以找到memset的具体用法:
在这里插入图片描述
可以看到,这个函数的意思是:把 dest 指向这块空间的前 count 个字节的内容,替换成我们想要的 ch
 
注意使用memset时要引用头文件#include <string.h>

📝代码示例

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

int main()
{
	char arr[] = "hello Edison";

	int n = 5;

	//把arr1的内容替换成xxxxx Ediosn
	char \*ret = (char\*)memset(arr, 'x', n);

	printf("%s\n", ret);

	return 0;
}

运行结果👇

在这里插入图片描述
把arr1数组里面的字符串的前5个字符,替换成x
 
我们定义的n=5,这里的5是以字节为单位的;
 
字符'x'对应的ASCII码值就是int类型。

以上就是我们参照文档,学的两个库函数

🍑2.2 自定义函数

如果库函数能干所有的事情,那还要程序员干什么?
 
所有更加重要的是自定义函数
 
自定义函数和库函数一样,有函数名,返回值类型和函数参数。
 
但是不一样的是这些都是我们自己来设计。

自定义函数的定义语法为👇

//自定义函数
ret_type fun\_name(para1, \*)
{
	statement;//语句项
	
    return 返回值;//该返回值与返回类型必须相同,如果是void型函数,则不需要返回值,因此可以不写。
}

ret_type 返回类型
fun_name 函数名
para1    函数参数

在使用函数的过程中,我们用 函数名(函数参数) 的形式来调用自定义函数;
在这里插入图片描述

这里直接看个例题

写一个函数可以找出两个整数中的最大值。

📝代码示例

#include <stdio.h>

int get\_max(int x, int y)
{
	return (x > y) ? (x) : (y); //三目操作符,在操作符中讲过,如果x>y则返回x,反之则返回y;
}

int main()
{
	int a = 20;
	int b = 10;

	int max = get\_max(a, b);//定义一个max变量,用来接受最大值;

	printf("max=%d\n", max);
}

运行结果👇

在这里插入图片描述
在程序运行过程中,给 get_max 这个函数传入a、b 这两个参数,函数调用完后会返回a和b中的最大值
 
因此可以用max来接收这个返回值。
 
当然也可以不用接收,因为在函数运行完以后,get_max(a, b)就相当于这个返回值,该返回值可以当做printf的参数可以直接进行打印操作。
 
如下
在这里插入图片描述

再来看一道例题

写一个函数可以交换两个整形变量的内容。

📝代码示例

#include <stdio.h>

void Swap(int\* pa, int\* pb) //我们只需要交换a和b当中的内容,不需要返回值,所以用void
{
	int t = 0;//定义一个临时变量用于交换
	t = \*pa;
	\*pa = \*pb;
	\*pb = t;
}

int main()
{
	int a = 10;
	int b = 20;

	printf("交换前: a=%d b=%d\n", a, b);

	Swap(&a, &b);

	printf("交换前: a=%d b=%d\n", a, b);

	return 0;
}

运行结果👇

在这里插入图片描述

3、函数的参数

函数的参数分为:

1、实际参数,称为实参;
 
2、形式参数,称为形参

🍑3.1 实际参数

真实传给函数的参数,叫实参。
 
实参可以是:常量、变量、表达式、函数等。
 
无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。

🍑3.2 形式参数

形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。
 
形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。

📝代码示例

#include <stdio.h>

void Swap1(int x, int y)
{
	int tmp = 0;
	tmp = x;
	x = y;
	y = tmp;
}

void Swap2(int\* px, int\* py) //我们只需要交换a和b当中的内容,不需要返回值,所以用void
{
	int tmp = 0;
	tmp = \*px;
	\*px = \*py;
	\*py = tmp;
}

int main()
{
	int a = 1;
	int b = 2;

	Swap1(a, b);
	printf("Swap1: a=%d b=%d\n", a, b);

	Swap2(&a, &b);
	printf("Swap2: a=%d b=%d\n", a, b);

	return 0;
}

运行结果👇

在这里插入图片描述
Swap1函数中的x、y,和 Swap2函数中的px、py,都叫做形式参数
 
main函数中传给Swap1函数的 a,b 和 传给Swap2函数的 &a,&b,叫做实际参数
 
这里我们可以通过调试,对函数的实参和形参进行分析:
在这里插入图片描述
可以看出:
 
实参a、b形参x、y不是同一空间;
 
这里可以看到Swap1函数在调用的时候,x,y拥有自己的空间,同时拥有了和实参一模一样的内容。
 
所以我们可以简单的认为:形参实例化之后其实相当于实参的一份临时拷贝。

4、函数的调用

函数的调用分为:

1、传值调用
 
2、传址调用

🍑4.1 传值调用

函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参。

📝代码示例

#include <stdio.h>

void Swap1(int x, int y)
{
	int tmp = 0;
	tmp = x;
	x = y;
	y = tmp;
}

int main()
{
	int a = 10;
	int b = 20;

	Swap1(a, b);
	printf("Swap1: a=%d b=%d\n", a, b);
	              
	return 0;
}

运行结果👇

main函数中,Swap(a, b)中,括号内传的就是a、b的值,也就是10、20
 
那么传值调用,对形参的修改不会影响实参
 
由于形参并不影响实参,函数在调用过程中只是对形参x,y进行了交换,并没有影响到a,b;
 
所以程序运行以后,并不会把a和b的值就行交换
在这里插入图片描述
并且函数在调用结束以后,x,y就已经被销毁了。
在这里插入图片描述

🍑4.2 传址调用

1、传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。
 
2、这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量。

📝代码示例

#include <stdio.h>

void Swap2(int\* px, int\* py)
{
	int tmp = 0;
	tmp = \*px;
	\*px = \*py;
	\*py = tmp;
}

int main()
{
	int a = 1;
	int b = 2;

	Swap2(&a, &b);
	printf("Swap2: a=%d b=%d\n", a, b);

	return 0;
}

运行结果👇

main函数中,Swap(&a, &b)中,括号内传的就是a、b地址
 
那么传址调用,让函数内部可以直接操作函数外的变量;
 
通过这种方式可以使得变量进行真正的交换。
在这里插入图片描述
通过监视可以看出,pxpy就是一个指针,其中放的就是a,b的地址
 
*解引用操作符,它可以通过地址找到地址中存放的变量值
在这里插入图片描述
比如:px就是a的指针,它的值是a的地址,对px解引用就可以找到a地址中存放的变量1,然后我们就可以对变量1进行操作了。
在这里插入图片描述

传值和传址的使用场景

函数内部的形参只需要借用函数外部实参的值的时候用传值调用,比如求两个数的较大值;
 
当函数内部需要对函数外部变量进行操作时用传址调用,比如交换两个数。

5、函数的嵌套调用和链式访问

函数和函数之间可以根据实际的需求进行组合的,也就是互相调用的。

🍑5.1 嵌套调用

📝代码示例

#include <stdio.h>

void fun2()
{
	printf("hello\n");
}

void fun1()
{
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		fun2();
	}
}

int main()
{
	fun1();
	return 0;
}

运行结果👇

在这里插入图片描述
我们通过main函数调用fun1
 
通过fun1调用三次fun2,这就是函数的嵌套调用。
 
注意:函数可以嵌套调用,但是不能嵌套定义。

🍑5.2 链式访问

把一个函数的返回值作为另外一个函数的参数。

📝代码示例

int main()
{

	int len = strlen("abc");

	printf("%d\n", len);

	printf("%d\n", strlen("abc"));//链式访问
}

运行结果👇

在这里插入图片描述

下面我们看一个有趣的代码🎃

#include <stdio.h>

int main()
{
    printf("%d", printf("%d", printf("%d", 43))); //结果是啥?
    
    //注:printf函数的返回值是打印在屏幕上字符的个数
    return 0;
}

运行结果👇

在这里插入图片描述
那么如何理解这段代码呢?
 
这个程序实际上就是用printf的返回值作为printf的参数;
 
因此想要弄明白这个程序,我们得先知道printf的返回值;
在这里插入图片描述
所以printf函数返回的是打印在屏幕上的字符的个数
 
代码分析:1、最内层的printf打印43;
 
2、第二层的printf打印的是最内层printf的返回值,也就是43这个内容的元素个数2;
 
3、最外层打印的是printf("%d", 2)的返回值,返回值是其元素个数1;
 
4、最后屏幕会打印出4321这四个数。

6、函数的定义和声明

🍑6.1 函数的声明

1、告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,函数声明决定不了。
 
2、函数的声明一般出现在函数的使用之前。要满足先声明后使用
 
3、函数的声明一般要放在头文件中的。

🍑6.2 函数的定义

函数的定义是指函数的具体实现,交待函数的功能实现。

这里我们可以简单的说一下

add.h

放置函数的声明

#ifndef \_\_TEST\_H\_\_
#define \_\_TEST\_H\_\_

//函数的声明
int Add(int x, int y);

add.c

放置函数的实现

#include "test.h"

//函数Add的实现
int Add(int x, int y)
{
	return x + y;
}

test.c

main函数里面去调用这个函数,要使用之前,只需要包括头文件:#include <add.h>即可;

#include <stdio.h>
#include "add.h"

int main()
{
	int a = 10;
	int b = 20;
	
	int ret = Add(a, b);
	
	printf("%d\n", ret);
	return 0;
}

这种分文件的书写形式,在后期写三字棋和扫雷的时候,就可以用分模块来写。

7、函数递归

🍑7.1 什么是递归?

递归就是程序自己调用自己的过程;
 
它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解;
 
递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
 
递归的主要思考方式在于:把大事化小

🍑7.2 递归的条件

存在限制条件,当满足这个限制条件的时候,递归便不再继续。
 
每次递归调用之后越来越接近这个限制条件。

这里我们通过例题来详解函数的递归

📃练习一

接受一个整型值(无符号),按照顺序打印它的每一位。
 
输入:1234
 
输出:1 2 3 4

🧐思路

我们想要从高位向低位输出,就必须要依次获取:最高位到最低位的数字;
 
因此我们可以用1234除以10,并把1234 / 10的结果进行判断,看其是否小于10
 
如果小于10则不再进行除以10的操作,这样我们就可以得到最高位1了;
 
为了获取其他位的数字,我们可以在每次除以10之前进行取模10的操作,得到剩下的位。
在这里插入图片描述

📝代码示例

#include <stdio.h>

void print(int n)
{
	if (n > 9)
	{
		print(n / 10);
	}
	printf("%d ", n % 10);
}

int main()
{
	int num = 1234;


![img](https://img-blog.csdnimg.cn/img_convert/98165d557302dd41fb2faa6954314919.png)
![img](https://img-blog.csdnimg.cn/img_convert/a498f65e24d07b1ae6ea8942dec7c3bc.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618668825)**

  
>     
>  如果**小于10**则不再进行除以10的操作,这样我们就可以得到最高位**1**了;  
>     
>  为了获取其他位的数字,我们可以在每次除以10之前进行取模10的操作,得到剩下的位。  
>  ![在这里插入图片描述](https://img-blog.csdnimg.cn/7607d3aadc4042f58f1cdb4b4647805f.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6aOe5ZCR5pif55qE5a6i5py6,size_16,color_FFFFFF,t_70,g_se,x_16)
> 
> 
> 


📝代码示例



#include <stdio.h>

void print(int n)
{
if (n > 9)
{
print(n / 10);
}
printf("%d ", n % 10);
}

int main()
{
int num = 1234;

[外链图片转存中…(img-uEItUl1T-1715755160202)]
[外链图片转存中…(img-0f7p2KOh-1715755160203)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值