C语言学习笔记4:函数

本文详细介绍了C语言中的函数概念,包括函数的分类(库函数与自定义函数),自定义函数的基本语法,形参与实参的区别,以及如何处理数组作为函数参数。还探讨了static和extern关键字在函数和全局变量作用域及链接属性上的影响。
摘要由CSDN通过智能技术生成

函数的概念

C语言中的函数是一个完成某项特定任务的一段代码,又称为子程序。我们可以类比成数学中的函数,两者同一性质,两者的函数都是一个工厂,对于数据进行储存加工处理,得到我们想要的结果。

函数分为库函数自定义函数

这里我们着重讨论自定义函数

自定义函数

基本语法形式:

返回类型        函数名(形式参数)

{

}

//大括号括起来的部分是函数体,代表函数完成任务的过程

例如:

double sum(double x, double y)

{

.....

}

返回类型用来表示函数计算结果的类型,有些时候函数并不进行计算,没有计算结果,因此返回类型为void,即什么都不返回

函数名依据具体情况而定,英语不好可以查的doge_

函数举例

举个例子,我们想要完成两个浮点型的乘法运算

#include <stdio.h>

float mul(float a,float b)
{
    float c = 0;
    c = a * b;
    return c;
}
//这个函数体还可以简化一下
//{
//    return a * b;
//}
//直接返回两个浮点型的计算结果,同样的效果

int main()
{
    float x = 0;
    float y = 0;
    printf("请输入两个浮点数\n");
    scanf("%f%f",&x,&y);
    float z = mul(x , y);//调用我们定义的函数
    printf("%f\n",z);
}

函数部分我们需要交代清楚参数的个数参数的类型形参的名字

参数的个数依实际情况而定,函数可以有返回值也可以没有,不返回就用void

形参和实参

我们看一下前面的代码

形参

在函数名mul后的a,b称为形式参数

如果只定义了mul函数,而不去调用,mul的参数a,b只是形式上存在(虚拟存在),不会向内存申请空间,形参只有在函数被调用时才向内存申请空间。

实参

调用mul函数时,传递给函数的参数x,y,称为实参,是真实传递给函数的值

形参和实参的关系

实参是传递给形参的,这个过程称为形式的实例化,形参是实参的一份临时拷贝,对于形参的修改,不会改变实参

return语句

return后可以是一个值,也可以是一个表达式,如果是表达式则先执行表达式,再返回表达式的结果

return后也可以什么都没有,直接写“return;”,此时是函数返回类型是void的情况

return返回的值和函数返回类型不一致时,系统自动就返回值转化为函数的返回类型

如果函数中存在if等分支语句,要保证每种情况都有return返回,否则会报错

例如:

此时报出警报,原因是if的情况考虑不周,如果不等于2,其他情况呢?

数组做函数的参数

写一个函数将一个整型数组的内容全部置换成6,再写一个函数打印数组的内容

函数的框架应该如下

int main()
{
    int arr1[5] = { 0,1,2,3,4};
    int size1 = sizeof(arr1) / sizeof(arr1[0]);
    replace_arr(arr1, size1);//将数组的元素全部置换为6
    print_arr(arr1, size1);//打印数组的所有内容

    return 0;
}

我们想要对数组内容进行置换,得把数组作为参数传给函数,在函数内部设置数组时,需要遍历数组,也需要知道数组元素个数,所以要给  replace_arr()传两个参数,同样print_arr()也需要两个参数

在设计之前,需要了解以下知识:

函数形式参数要和函数实际参数个数匹配

函数的实参是数组,形参也可以为数组

形参如果是一维数组,数组大小可省略不写

形参如果是二维数组,行可省略,列不可省略

数组传参,形参不会创建新的数组

形参操作的数组和实参操作的数组是同一个数组,改变形参数组就是在改变实参数组(这需要到后面的知识才能理解)

同时置换和打印不许需要返回类型,用void即可

void replace_arr(int arr2[], int size2)
{
    int i = 0;
    for (i = 0; i < size2; i++)
    {
        arr2[i] = 6;
    }
}

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

我们将两部分进行组合

#include <stdio.h>

void replace_arr(int arr2[], int size2)
{
    int i = 0;
    for (i = 0; i < size2; i++)
    {
        arr2[i] = 6;
    }
}

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

int main()
{
    int arr1[5] = { 0,1,2,3,4};
    int size1 = sizeof(arr1) / sizeof(arr1[0]);

    print_arr(arr1, size1);//打印数组的所有内容
    replace_arr(arr1, size1);//将数组的元素全部置换为6
    print_arr(arr1, size1);//打印数组的所有内容

    return 0;
}

链式访问

链式访问是将一个函数的返回值作为另外一个函数的参数,像链条一样将函数穿起来,就像复合函数求导的链式法则一样

比如

printf("%d\n", strlen("1234"));

这里就是将strlen("1234")的返回值传给printf()函数的

再看一个例子

printf("%d ", printf("&d ",printf("%d ",12)));

这段代码打印结果是什么?首先我们需要知道printf()的函数返回是打印在屏幕上字符的个数

看上面的例子

第三个printf打印12 ,在屏幕上打印3个字符,返回3

第二个printf打印3 ,在屏幕上打印2个字符,返回2

第一个printf打印2 。

所以最后屏幕打印12 3 2 。

这个地方需要注意我在%d后面多打了一个空格,空格也算字符

函数的定义和声明

在单个文件中,函数的定义在主函数前,就不需要再声明了,如果在主函数之后定义,则需要在主函数前声明定义的函数,因为C语言编译是从上到下一条语句一条语句执行的。函数声明中,只保留类型,省略掉参数也是可以的,但是我推荐就按规矩办事,不要偷这个懒了

这里着重讨论多个文件

在一项工程中,代码量很大,我们需要分工合作,每个人解决一个板块,如果放在一个文件中,只能一个人做完下一个人继续,效率极低,所以我们需要将代码拆分成多个文件。

一般来说,函数的声明、类型的声明放在头文件中,函数的实现放在源文件中,函数的定义再放一个源文件中,比如我们一开始的乘法代码

此时我们的代码依旧正常运行,这个地方需要注意声明文件用""双引号

static(静态的)和extern(外部)

static用来

修饰全局变量               修饰局部变量                修饰函数

extern用来声明外部变量

在这之前先了解作用域和生命周期

作用域是一段代码作用的范围

局部变量的作用域是变量所在的局部范围

全局变量作用域是整个项目

生命周期是一个变量从创建到销毁的时间段

局部变量的生命周期是进入作用域变量创建,生命周期开始,出作用域变量销毁,生命周期结束

全局变量的生命周期是整个程序的生命周期

static修饰局部变量

第一段代码a出了作用于就被销毁

第二段代码a出了作用域并未销毁,也没有重新创建变量,二十累计上次的数值继续计算

结论:static修饰局部变量改变了局部变量的生命周期,本质是改变了变量的存储类型,局部变量位于栈区,被修饰后存储到了静态区,和全局变量的生命周期一样了,但是不改变作用域

使用:未来一个局部变量出了函数作用域,还想保留值,等下次进入函数继续使用

static修饰全局变量

第二张图片中多加了个static,文件链接错误

extern用于声明外部符号

结论:

全局变量默认具有外部链接属性,一个全局变量经过static修饰后,使全局变量作用域变小,外部连接属性变为内部连接属性

使用:一个全局变量只想在本文件中使用,不想被其他文件发现

同理,static修饰函数后,函数默认具有外部链接属性变为内部链接属性,只能在本文件中使用,不能跨文件使用

使用:一个函数只想在所在源文件中使用,不想被其他源文件使用

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值