2024年C C++最新「C语言精华篇」春眠不觉晓,函数知多少?_c语言打春眠不觉晓,史上超级详细

img
img

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

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

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

简单的总结,C语言常用的库函数都有👇

IO函数:输入和输出函数,例如:input/outputprintf/scanfgetchar/putchar等等;
 
字符串操作函数:比如求字符串长度的strlen函数,字符串之间的比较strcmp、字符串拷贝strcpy等等;
 
字符操作函数:比如判断字符的大小写,将小写字母转化为大写字母用toupper、大写转换为小写tolower
 
内存操作函数:内存复制、查找等操作,例如:memcpymemsetmemmovememcmp等等;
 
时间/日期函数:获取时间,例如:time
 
数学函数:开平方sqrt,还有:absfabspow

那我们来参照文档,学习两个库函数

注意:使用库函数,必须包含 #include 对应的头文件

strcpy函数

打开库函数网站cplusplus可以找到strcpy的具体用法:
在这里插入图片描述
可以看到strcpy其实就是字符串拷贝的意思;
 
意思就是:将字符串 strSource 中的字符,复制到字符串 strDestination 中,包括结束字符\0
 
因此在使用这个函数的时候,我们需要向函数参数传入 strDestination (目标数组)和 strSource (源数组)两个字符串,同时该函数的返回值是char*,它会将拷贝后的 strDestination(目标数组)起始地址返回给我们。
在这里插入图片描述
注意使用strcpy时要引用头文件#include <string.h>

📝代码示例

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

int main()
{
	char arr1[] = "xxxxxxxxx";//目标空间

	char arr2[] = "edison";

	strcpy(arr1, arr2);//将arr2数组的字符串拷贝到arr1数组中

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

	return 0;
}

运行结果👇

在这里插入图片描述
注意:这里的复制其实并不是真正的复制,准确的说是覆盖!
 
即把 arr2 的所有内容(包括\0)都覆盖到 arr1 对应位置;
 
也就是说,虽然打印出来 arr1 是edison,但是实质上 arr1 等于e d i s o n \0 x x \0
 
我们可以调试看一下
在这里插入图片描述
补充: 1、源字符串必须以 \0结束。如果源字符串没有\0,就会一直拷贝源字符串地址后面的所有内容,直到找到\0为止;
 
2、也会将源字符串中的 \0拷贝到目标数组中;
 
3、目标空间必须足够大,以确保能存放源字符串;如果目标空间不够大,则会导致源字符串拷贝不进去。
 
4、目标空间必须可变,即目标空间没有const修饰;
 
(关于const的用法可以看这篇文章:深入理解const的用法

memset函数

打开库函数网站可以找到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;


![img](https://img-blog.csdnimg.cn/img_convert/aa331aca36f8a49532e14b56e1d6a1cc.png)
![img](https://img-blog.csdnimg.cn/img_convert/134f4aa9ab94f2d4b417901d4f0ac5d8.png)

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

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

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

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;

[外链图片转存中…(img-NRjGc2xU-1715555423076)]
[外链图片转存中…(img-9sqav3LK-1715555423077)]

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值