首页 > 其他分享 >初识C语言——函数

初识C语言——函数

时间:2024-03-31 15:33:07浏览次数:32  
标签:return 函数 形参 int C语言 初识 printf 实参

        哈喽呀,各位小伙伴,本肉段er~又来给大家送知识啦!不禁感慨一下,这两周的溜肉段er 还是比较勤奋滴呢,嘻嘻嘻!

        这一次,肉段er 将为各位小伙伴们介绍一下 C 语言中的函数,包括函数是什么、函数的分类、函数的参数以及函数的声明和定义。请各位小伙伴跟随肉段er 的步伐一起进入函数的世界吧!

一、函数的概念

        一提到函数,各位小伙伴第一时间肯定是想到了数学中的函数,俺也一样(高中时被函数支配的恐惧可是印象深刻呢,【捂脸】)。其实,C语言中的函数(称它为子程序好像更加准确一些)就是一个完成某项特定任务的一小段代码,这段代码是有特殊的写法和调用方法的。

        我们看到的一个完整的C语言程序其实是由无数个小的函数组合而成的,也可以理解为,一个大的任务被分解成多个较小的任务(即函数)完成。当然,我们可以通过重复调用某些函数来提升软件开发的效率。

二、函数的分类

        在C语言中,我们一般会遇到两类函数:库函数和自定义函数。

2.1 库函数

1. 定义
        库函数:顾名思义,即为放在标准库里的函数。这个很好理解,打个比方:         程序猿 小A 说:“我要写一个能实现打印功能的函数”。         程序猿 小B 说:“我要写一个能实现输入功能的函数”。         ......         程序猿 小Z 说:“我要写一个能实现计算平方根的函数”。         这时,小明同学提议说:“你们写了这么多函数,能不能把它们汇总到一个地方呢?这样其他人想要实现某些功能的时候,直接使用你们写的函数岂不是很方便。”         小明说罢,一位智者站了出来,说道:“这样吧,我来建立几个仓库,并设定一些标准,你们可以根据这些标准把那些函数放在对应的库中,以后大家直接从需要的库中调用这些函数就可以啦!”         在场人员纷纷鼓掌称赞......于是,库函数就诞生了。
2. 使用说明

        库函数的学习和查看工具有很多,下面贴出了C/C++官方的链接,感兴趣的小伙伴们可以进去看看哦。(C/C++官⽅的链接:https://zh.cppreference.com/w/c/header)

        另外,要注意!!!库函数是在标准库中对应的头文件中声明的,所以库函数的使用,务必包含对应的头文件,漏写可是会报错滴呦。

3. 举例
例 1 :计算一个数的平方根
#include <stdio.h>
#include <math.h>

int main()
{
	double a = 0;
	scanf("%lf", &a);
	double result = sqrt(a);
	printf("%lf\n", result);

	return 0;
}

运行结果:

        说明:我们通过查看官网中的标准库头文件可知,sqrt( ) 函数对应的头文件为 <math.h>,scanf( ) 和 printf( ) 函数对应的头文件均为 <stdio.h>,所以我们应在程序中 #include 上这些头文件才可以。另外,由于我们要计算开平方的结果,那结果可能是浮点数,故要注意在定义变量和书写占位符时要对应好。

2.2 自定义函数

        自定义函数:正如其名,当库函数的功能无法满足我们的需求时,就需要我们自己去定义一些函数来实现。

1. 语法形式

        自定义函数的语法形式如下:

re_type fun_name(形式参数)
{

}
  • re_type:表示函数计算结果的返回类型,有时返回类型可以是void,表示什么都不返回;
  • fun_name:函数的名字,这个是需要我们自己定义的噢,但是不要给人家瞎起名,还是得有意义才行;
  • ( ) 里放的是形式参数,函数有几个参数,都要在括号里要交代清楚这些参数的类型和名字;当然,函数也可以没有参数,这时,括号里就不需要写什么了,空着就好;
  • { } 括起来的是函数体,即完成计算的过程。
2. 举例

          例1:写一个加法函数,完成两个整型变量的加法操作。

#include <stdio.h>

int ADD(int x, int y)
{
return x + y;
}

int main()
{
    int a, b;
    scanf("%d %d", &a, &b);
    int c = ADD(a, b);
    printf("%d\n", c);

return 0;
}

        讨论与分析:

        通过题干可知,我们要构建一个加法函数,根据函数的语法形式可写出函数的整体框架。这时,小明产生疑问:“为什么return 后面跟的是一个表达式呢?我写成 ‘ int z = x + y; return z; ’ 可以吗?” 肉段儿老师欣慰一笑,并夸赞道,小明同学的提问非常有意义哈!这个问题直接引出了 return 语句使用的注意事项:

        (1) return 后面可以是一个数,也可以是一个表达式,如果是表达式,则先执行表达式,再返回表达式的结果;return后面也可以什么都不写,这种情况适用于函数返回类型为void的情况。

        (2) return语句执行后,函数就彻底返回了,return后面的代码不再执行。

        (3) 如果函数中存在if 等分支的语句,则要保证每种情况都有return返回,否则会出现编译错误。

        了解完return 语句的注意事项后,想必大家也就明白了为什么直接写 ‘ return x+y ’了吧!接下来,当我们创建完加法函数后,就可以对其进行调用啦,从代码中可以看出来,我调用ADD函数完成了a和b的相加,然后将函数返回的求和结果放在 c 中。最后,打印结果 c 。Over !!!

三、函数的参数

        学到这里,可能会有细心的小明发现,我们在创建函数和调用函数时,函数的参数有些许不同,这种情况则涉及到函数参数的相关知识了。下面,让我们继续深入探索叭!

3.1 实参

        在函数使用的过程中,函数的参数被分为实参和形参。我们先来讲一下实参。

        实参(实际参数):真实传递给函数的参数,在例1中,我们调用ADD函数时传递给函数的参数 a 和 b 就是实参。

3.2 形参

        形参(形式参数):只是形式上存在,不会向内存申请空间,不会真实存在的参数;在例1中,我们定义加法函数时在括号里写的 x 和 y 就属于形式参数。

       :形式参数只有在函数被调用的过程中为了存放实参传递过来的值,才会向内存申请空间,这个过程为形参的实例化

3.3 实参与形参的关系

        讲到这里,我们已经对实参和形参两位朋友有了基本的认识,那它们两个之间是什么关系捏?让我们带着这个问题继续向下看吧!

        例2:调试代码,观察实参与形参的内存地址

#include <stdio.h>

int ADD(int x, int y)
{
    return x + y;
}

int main()
{
    int a = 0;
    int b = 0;
    scanf("%d %d", &a, &b);
    int c = ADD(a, b);
    printf("%d\n", c);


    return 0;
}

        讨论与分析:

       在例2中,我们仍以两个数求和为例,写完代码后,开始在键盘上按F11进入调试;然后,在监视窗口添加监视项(在这里,我们分别添加了实参a 、b,形参x、y,实参地址&a、&b,形参地址&x、&y);通过不断进行逐语句调试(调试快捷键:F11),可以观察到形参x、y 确实得到了实参a 、b 的值,但实参地址 &a、&b 与形参地址 &x、&y 并不相同。

        由上可知,实参是传递给形参的,但是他俩并不是共用一个内存空间的,而是拥有各自独立的内存空间;也就是说,当你改变形参时,实参并不会随之改变。总而言之,形参是实参的一份临时拷贝

3.4 数组做函数参数

        在函数参数的最后一 part ,我们来讨论一下数组做函数参数的情况。

        例3:用函数来实现对一个整型数组的内容,全部置 -1的功能,再使用另一个函数完成打印数组的功能。

#include <stdio.h>
void set_arr(int arr[],int length)
{
    for(int i = 0; i < length; i++)
    {
    arr[i] = -1;
    }
}

void print_arr(int arr[], int length)
{
    for(int i = 0; i < length; i++)
    {
    printf("%d ", arr[i]);
    }
    printf("\n");
}

int main()
{
    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    int len = sizeof(arr) / sizeof(arr[0]);
    set_arr(arr,len);
    print_arr(arr,len);
    return 0;
}

        通过观察例3,我们可以了解到数组传参的几个重要知识:

  • 函数的形参要和函数的实参个数匹配;
  • 函数的实参是数组,形参也可以写成数组形式
  • 如果形参是一维数组,数组大小可以省略不写
  • 如果形参是二维数组,行可以省略,但列不能省略
  • 数组传参,形参并不会创建新的数组
  • 形参操作的数组和实参的数组是同一个数组

四、函数的声明和定义

        啊啊啊,本篇文章的最后一个部分啦!!!坚持住呀,各位友友(溜肉段er 站在函数世界的终点,奋力挥舞着手上的加油棒,并激动地喊道:“加油,努力,C语言考第一!”)。

        (OK, 转回正题)在这一部分,我们讲一下函数的声明和定义。下面,我们分别从单个文件和多个文件两个方面来进行阐述。

4.1 单个文件

        在这里,我们仍然用一个例子来进行具象化说明:

        例4:写⼀个函数判断⼀年是否是闰年。

#include <stdio.h>

//函数的定义
int is_leap_year(int y)
{
     if(((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
         return 1;
     else
         return 0;
}

int main()
{
    int y = 0;
    scanf("%d", &y);
    int r = is_leap_year(y);//函数的调用
    if(r == 1)
        printf("闰年\n");
    else
        printf("⾮闰年\n");
    return 0;
}

        在例4中,‘ int is_leap_year (int y) ’ 部分即为函数的定义,而主函数中的 ‘ int r = is_leap_year(y); ’  为函数的调用。

        这种场景属于函数定义在函数调用之前,直接运行不会有问题。但如果我们把函数的定义放在函数调用的后面,如下代码:

#include <stdio.h>


int main()
{
    int y = 0;
    scanf("%d", &y);
    int r = is_leap_year(y);//函数的调用
    if(r == 1)
        printf("闰年\n");
    else
        printf("⾮闰年\n");
    return 0;
}

//函数的定义
int is_leap_year(int y)
{
     if(((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
         return 1;
     else
         return 0;
}

        这时,编译器会出现‘ is_leap_year ’ 未定义的警告。那该怎么办呢?

        解决这个问题其实只需要在函数调用前声明一下‘ is_leap_year ’ 这个函数就可以啦。

        声明的格式为:函数类型  函数名(函数的参数);其中,函数声明中参数只保留类型,省略掉名字也是可以的。例如:‘ int is_leap_year( int y ); ’ 就是函数的声明。修改后的代码如下:

#include <stdio.h>

int is_leap_year(int y);//函数声明

int main()
{
    int y = 0;
    scanf("%d", &y);
    int r = is_leap_year(y);//函数的调用
    if(r == 1)
        printf("闰年\n");
    else
        printf("⾮闰年\n");
    return 0;
}

//函数的定义
int is_leap_year(int y)
{
     if(((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
         return 1;
     else
         return 0;
}

        总结来说,函数的调用一定要满足:先声明后使用;函数的定义也是一种特殊的声明,所以函数定义放在调用之前也是可以的。

4.2 多个文件

        当然,在我们平时工作中写代码时,代码可能比较多,不会将所有的代码都放在一个文件中,更多的是根据程序的功能将代码拆分放在多个文件中。

        一般情况下,函数的声明、类型的声明都会放在头文件( .h )中,函数的实现是放在源文件(.c )中,例如:

ADD.c

//函数的定义
int ADD(int x, int y)
{
	return x + y;
}

ADD.h

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

TEST.c

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

int main()
{
    int a = 0;
    int b = 0;
    scanf("%d %d",&a, &b);
    int c = ADD(a,b);//函数的调用
    printf("%d\n", c);
    return 0;
}

        通过上述代码可知,当我们调用函数时,同样需要在 TEST.c 文件中包含该函数所在的头文件。值得注意的是,与库函数头文件包含方式写法略有不同,要包含自定义函数所在头文件时需写成:#include "ADD.h" 。

五、总结

        到这里,函数的基础知识也就学完啦!在这一篇博客中,我们首先了解了函数的概念;接着,继续研究了函数的分类(库函数和自定义函数如何使用);然后,我们深入学习了函数的参数,主要包括:实参和形参的具体解释和数组做函数参数的注意事项;最后,我们分别从单个文件和多个文件出发说明了函数调用一定要满足先声明后使用的规则。

        终于!在这个阳光明媚的周日下午,一篇干货满满的博客新鲜出炉啦!希望这篇博客的内容能够对初学C语言的小伙伴们有一些帮助,这也是我写博客的初衷。另外,多说一句,只学不练,永远是纸上谈兵,要想让编程水平飞速进步,还是得需要多加练习才行。最后的最后,一句话送给看到这里的友友们,也送给自己:“ 放弃很简单,但坚持一定很酷!”

标签:return,函数,形参,int,C语言,初识,printf,实参
From: https://blog.csdn.net/mewgulfLOVE/article/details/136821430

相关文章

  • Fiddler系列课程笔记(一):初识Fiddler,深入理解HTTP协议
    Fiddler系列课程笔记(一):初识Fiddler,深入理解HTTP协议1.fiddler简介1.1什么是B/S架构?(Browser/Server)【补充】:tomcat是公司常用的一个web服务器,用来部署资源(文件、图片等),提供服务的。1.2我们可以查看URL(统一资源定位符)怎么获取服务器资源的1.2.1login.html的访问......
  • C语言02-常量、二进制、数据类型
    第4章常量1.常量特点程序运行时,其值不能改变的量,即为常量。2.常量分类字面量常量标识符常量3.常量定义方式(标识符常量)①#define宏定义②const关键字(C99标准增加)4.两种定义方式区别类型检查:const编译阶段会进行类型检查,#define方式不......
  • 数据结构-C语言描述(队列的链表实现)
    概述在日常生活中,先进先出似乎更加符合我们的日常认知。 排队的人群中,队首的人总是先离开,而队尾的人总是后离开。1.队列的基本原理和操作我们知道队列也是一种线性表,而今天我们就用非顺序储存结构(链表)来实现它。首先我们先明确队列的基本操作原理:因为同时涉及到队首和队......
  • 初始C语言
    自我简绍:本人双非院校大一新生,集成电路设计与集成系统专业。我认为C语言是学习其他语言的基础,可以为以后学其他语言打好基础,很有必要好好学习学习,并且网上有很多项目都是开源的,可以很好的去实际。未来编程目标:首先将C语言系统的仔细学一下,然后再学学数据结构与算法。我想......
  • 练习3-2 计算符号函数的值
    对于任一整数n,符号函数sign(n)的定义如下:请编写程序计算该函数对任一输入整数的值。输入格式:输入在一行中给出整数n。输出格式:在一行中按照格式“sign(n)=函数值”输出该整数n对应的函数值。输入样例1:10输出样例1:sign(10)=1输入样例2:0输出样例2......
  • 【C语言】贪吃蛇【附源码】
    欢迎来到英杰社区https://bbs.csdn.net/topics/617804998一、游戏说明:一个基于C语言链表开发的贪吃蛇游戏:1.按方向键上下左右,可以实现蛇移动方向的改变。2.短时间长按方向键上下左右其中之一,可实现蛇向该方向的短时间加速移动。3.按空格键可实现暂停,暂停后按任意键继......
  • C++: 虚函数,一些可能被忽视的细节
    C++:虚函数,一些可能被忽视的细节引言:关于C++虚函数,对某些细节的理解不深入,可能导致我们的程序无法按预期结果运行,或是表明我们对其基本原理理解不够透彻。本文详细解答以下几个问题:实现多态,忘记写virtual会怎么样?虚函数的默认参数可以重载吗?纯虚函数真的不能有实现吗?析构函数可......
  • C语言 键盘输入与屏幕输出——数据的格式化屏幕输出
    目录顺序结构C语言如何实现数据的输入和输出?数据的格式化屏幕输出printf()格式字符printf()的格式修饰符顺序结构一般而言,顺序结构程序涉及如下三个基本操作:*输入数据*处理数据*输出数据顺序结构的特点 *自上而下,依次按顺序执行C语言如何实现数据的输入和输出?......
  • Pointer-like classes像指针又像函数
    Pointer-likeclasses像指针又像函数智能指针概念:一个类做出来像类又像指针示例代码:#pragmaonce#ifndef__SHAREPOINTER__#define__SHAREPOINTER__​template<classT>classshared_ptr{public:shared_ptr(T*p):px(p){}T&operator*()const{return*px;}......
  • QTP/UFT 学习笔记:函数方法等记录
    ​原记录在CSDN上的,后来被自动转VIP了,我搬过来免费看看,小东西没必要VIP,主打一个知识无价,朴实无华。1、Back效果等同于浏览器窗口上的【回退】按钮,使浏览器返回上一个页面​​![](https://img2024.cnblogs.com/blog/1202750/202403/1202750-20240331130946866-2132113900.png)......