零基础玩转C语言系列第四章——编程重点内容之函数

简介: 编程重点内容之函数

目录

一、什么是函数

二、C语言中函数的分类

1.库函数

2.自定义函数

三、函数调用

四、链式访问

五、函数递归



【前言】:函数这块内容可是学习C语言的重点内容之一哦,所以铁汁们千万不要掉以轻心,不难,但是要多花心思去体会去理解,我可以,相信你们也可以,咱们一起加油!



一、什么是函数

数学中我们常见到函数的概念。但是你了解C语言中的函数吗?

维基百科中对函数的定义:子程序

  • 在计算机科学中,子程序,是一个大型程序中的某部分代码,由一个或多个语句块组成。它负责完成一项特定任务,而且相较于其他代码,具备相对的独立性。
  • 一般会有输入参数,并且带有返回值,提供对过程的封装和细节的隐藏。

二、C语言中函数的分类

  1. 库函数
  2. 自定义函数


1.库函数

为什么会有库函数?

1. 我们知道在我们学习C语言编程的时候,总是在一个代码编写完成之后迫不及待的想知道结果,想把这个结果打印到我们的屏幕上看看。这个时候我们会频繁的使用一个功能:将信息按照一定的格式打印到屏幕上(printf)

2. 在编程的过程中我们会频繁的做一些字符串的拷贝工作(strcpy)

3. 在编程是我们也计算,总是会计算n的k次方这样的运算(pow)

像上面我们描述的基础功能,它们不是业务性的代码。我们在开发的过程中每个程序员都可能用的到, 为了支持可移植性和提高程序的效率,所以C语言的基础库中提供了一系列类似的库函数,方便程序员进行软件开发。

那怎么学习库函数呢?

笔者使用的是MSDN,一个文档,里面几乎涵盖了所有C语言库函数。

输入你想查找的库函数名,它就能显示对应的函数原型,以及如何使用等等,非常方便。

简单的总结一下,C语言常用的库函数有:

  • IO函数
  • 字符串操作函数
  • 字符操作函数
  • 内存操作函数
  • 时间/日期函数
  • 数学函数
  • 其他库函数

注意:使用库函数必须要知道的一个秘密就是:使用库函数,必须包含#include对应的头文件!

注意哦,英文其实挺重要的,最起码要看得懂文献!但是铁汁们不要害怕,多看看,多搜搜,慢慢也就熟悉套路了,加油加油!

2.自定义函数

如果库函数能干所有的事情,那还要程序员干什么?

所有更加重要的是自定义函数。

自定义函数和库函数一样,有函数名,返回值类型和函数参数。 但是不一样的是这些都是我们自己来设计。这给程序员一个很大的发挥空间。


三、函数调用

用一个易错题引入知识点:交换两个变量的值

#include<stdio.h>
//定义一个交换两个整型变量值的函数
void swap1(int num1, int num2)
{
  int temp = num1;
  num1 = num2;
  num2 = temp;
}
int main()
{
  int num1 = 10;
  int num2 = 20;
  printf("交换前:\n");
  printf("%d %d\n", num1, num2);
  putchar('\n');
  swap1(num1, num2);//函数调用
  printf("交换后:\n");
  printf("%d %d\n", num1, num2);
  return 0;
}

可能大家会写成上面这个代码,但是实际上运行起来却没有得到我们想要的答案,不信你看...

程序虽然运行起来了,但是没有得到我们想要的答案,这是为什么呢?

这就说明了程序中没有语法错误,但是存在逻辑问题。

这就要提到一个考点了:

当函数传值调用的时候,实参传给形参,形参其实是实参的一份临时拷贝,所以对形参的修改是不会影响实参的。

所以改写如下:

#include<stdio.h>
//函数定义
void swap2(int* num1, int* num2)
{
  int temp = *num1;
  *num1 = *num2;
  *num2 = temp;
}
int main()
{
  int num1 = 10;
  int num2 = 20;
  printf("交换前:\n");
  printf("%d %d\n", num1, num2);
  putchar('\n');
  swap1(&num1, &num2);//函数调用
  printf("交换后:\n");
  printf("%d %d\n", num1, num2);
  return 0;
}

这下实现交换了, 为什么swap1不行,swap2却可以呢?

swap1是传值调用,实参num1,num2和形参x,y使用的不是同一块内存空间,虽然形参拥有了和实参一模一样的内容,但是分别占用了不同的内存块,此时形参相当于实参的一份临时拷贝,对形参的修改不会影响实参;


而swap2是传址调用,形参里面放的是实参的地址。这种传参方式可以让形参和实参建立起真正的联系,此时对于形参的修改可以改变函数外部的实参。

还有对于函数调用这块内容要注意的是,函数可以嵌套调用,但是不可以嵌套定义哦。

四、链式访问

链式访问就是:把一个函数的返回值作为另一个函数的参数。

如:

char arr[20] = "hello";
printf("%d\n", strlen(arr));//这就是链式访问

嘿嘿,这里补充一个好玩的笔试题:

printf("%d", printf("%d", printf("%d", 43)));

问屏幕上打印的是什么?

屏幕上打印的是:4321

为什么呢?这就有点让人不解了,那我就帮铁汁解一下惑。

printf()函数的返回值是打印在屏幕上字符的个数。

这个知识点就说到这咯,大家尝试自己理解哦。

五、函数递归

函数递归真的非常重要!!!不过我在之前的博文中已经讲得非常明白咯,铁汁们一定要看一下呀!

蓝桥杯算法竞赛系列第二章——深入理解重难点之递归(上)_安然无虞的博客-CSDN博客

好,函数今天就讲到这了,这部分的内容不多,但这篇提到的知识点都很重要,小友一定要花点心思哦。喏,送你一朵小红花啦。


相关文章
|
4天前
|
存储 算法 Linux
C语言 多进程编程(一)进程创建
本文详细介绍了Linux系统中的进程管理。首先,文章解释了进程的概念及其特点,强调了进程作为操作系统中独立可调度实体的重要性。文章还深入讲解了Linux下的进程管理,包括如何获取进程ID、进程地址空间、虚拟地址与物理地址的区别,以及进程状态管理和优先级设置等内容。此外,还介绍了常用进程管理命令如`ps`、`top`、`pstree`和`kill`的使用方法。最后,文章讨论了进程的创建、退出和等待机制,并展示了如何通过`fork()`、`exec`家族函数以及`wait()`和`waitpid()`函数来管理和控制进程。此外,还介绍了守护进程的创建方法。
C语言 多进程编程(一)进程创建
|
4天前
|
Linux C语言
C语言 多进程编程(三)信号处理方式和自定义处理函数
本文详细介绍了Linux系统中进程间通信的关键机制——信号。首先解释了信号作为一种异步通知机制的特点及其主要来源,接着列举了常见的信号类型及其定义。文章进一步探讨了信号的处理流程和Linux中处理信号的方式,包括忽略信号、捕捉信号以及执行默认操作。此外,通过具体示例演示了如何创建子进程并通过信号进行控制。最后,讲解了如何通过`signal`函数自定义信号处理函数,并提供了完整的示例代码,展示了父子进程之间通过信号进行通信的过程。
|
4天前
|
Linux C语言
C语言 多进程编程(四)定时器信号和子进程退出信号
本文详细介绍了Linux系统中的定时器信号及其相关函数。首先,文章解释了`SIGALRM`信号的作用及应用场景,包括计时器、超时重试和定时任务等。接着介绍了`alarm()`函数,展示了如何设置定时器以及其局限性。随后探讨了`setitimer()`函数,比较了它与`alarm()`的不同之处,包括定时器类型、精度和支持的定时器数量等方面。最后,文章讲解了子进程退出时如何利用`SIGCHLD`信号,提供了示例代码展示如何处理子进程退出信号,避免僵尸进程问题。
|
3天前
|
消息中间件 Unix Linux
C语言 多进程编程(五)消息队列
本文介绍了Linux系统中多进程通信之消息队列的使用方法。首先通过`ftok()`函数生成消息队列的唯一ID,然后使用`msgget()`创建消息队列,并通过`msgctl()`进行操作,如删除队列。接着,通过`msgsnd()`函数发送消息到消息队列,使用`msgrcv()`函数从队列中接收消息。文章提供了详细的函数原型、参数说明及示例代码,帮助读者理解和应用消息队列进行进程间通信。
|
3天前
|
缓存 Linux C语言
C语言 多进程编程(六)共享内存
本文介绍了Linux系统下的多进程通信机制——共享内存的使用方法。首先详细讲解了如何通过`shmget()`函数创建共享内存,并提供了示例代码。接着介绍了如何利用`shmctl()`函数删除共享内存。随后,文章解释了共享内存映射的概念及其实现方法,包括使用`shmat()`函数进行映射以及使用`shmdt()`函数解除映射,并给出了相应的示例代码。最后,展示了如何在共享内存中读写数据的具体操作流程。
|
3天前
|
消息中间件 Unix Linux
C语言 多进程编程(二)管道
本文详细介绍了Linux下的进程间通信(IPC),重点讨论了管道通信机制。首先,文章概述了进程间通信的基本概念及重要性,并列举了几种常见的IPC方式。接着深入探讨了管道通信,包括无名管道(匿名管道)和有名管道(命名管道)。无名管道主要用于父子进程间的单向通信,有名管道则可用于任意进程间的通信。文中提供了丰富的示例代码,展示了如何使用`pipe()`和`mkfifo()`函数创建管道,并通过实例演示了如何利用管道进行进程间的消息传递。此外,还分析了管道的特点、优缺点以及如何通过`errno`判断管道是否存在,帮助读者更好地理解和应用管道通信技术。
|
4天前
|
存储 Ubuntu Linux
C语言 多线程编程(1) 初识线程和条件变量
本文档详细介绍了多线程的概念、相关命令及线程的操作方法。首先解释了线程的定义及其与进程的关系,接着对比了线程与进程的区别。随后介绍了如何在 Linux 系统中使用 `pidstat`、`top` 和 `ps` 命令查看线程信息。文档还探讨了多进程和多线程模式各自的优缺点及适用场景,并详细讲解了如何使用 POSIX 线程库创建、退出、等待和取消线程。此外,还介绍了线程分离的概念和方法,并提供了多个示例代码帮助理解。最后,深入探讨了线程间的通讯机制、互斥锁和条件变量的使用,通过具体示例展示了如何实现生产者与消费者的同步模型。
|
3天前
|
C语言
C语言 字符串操作函数
本文档详细介绍了多个常用的字符串操作函数,包括 `strlen`、`strcpy`、`strncpy`、`strcat`、`strncat`、`strcmp`、`strncpy`、`sprintf`、`itoa`、`strchr`、`strspn`、`strcspn`、`strstr` 和 `strtok`。每个函数均提供了语法说明、参数解释、返回值描述及示例代码。此外,还给出了部分函数的自实现版本,帮助读者深入理解其工作原理。通过这些函数,可以轻松地进行字符串长度计算、复制、连接、比较等操作。
|
3天前
|
Linux C语言
C语言 多进程编程(七)信号量
本文档详细介绍了进程间通信中的信号量机制。首先解释了资源竞争、临界资源和临界区的概念,并重点阐述了信号量如何解决这些问题。信号量作为一种协调共享资源访问的机制,包括互斥和同步两方面。文档还详细描述了无名信号量的初始化、等待、释放及销毁等操作,并提供了相应的 C 语言示例代码。此外,还介绍了如何创建信号量集合、初始化信号量以及信号量的操作方法。最后,通过实际示例展示了信号量在进程互斥和同步中的应用,包括如何使用信号量避免资源竞争,并实现了父子进程间的同步输出。附带的 `sem.h` 和 `sem.c` 文件提供了信号量操作的具体实现。
|
4天前
|
SQL 关系型数据库 C语言
PostgreSQL SQL扩展 ---- C语言函数(三)
可以用C(或者与C兼容,比如C++)语言编写用户自定义函数(User-defined functions)。这些函数被编译到动态可加载目标文件(也称为共享库)中并被守护进程加载到服务中。“C语言函数”与“内部函数”的区别就在于动态加载这个特性,二者的实际编码约定本质上是相同的(因此,标准的内部函数库为用户自定义C语言函数提供了丰富的示例代码)
下一篇
DDNS