C语言学习-函数(上)

C/C++
215
0
0
2024-04-11

6688b6b66419461c821b502734ed8c5c.png

目录

库函数:

自定义函数:

Return的用法:

数组做函数参数:

嵌套调用和链式访问:

库函数:

#include <stdio.h>
#include <math.h>
int main()
{
    double d = 16.0;
    double r = sqrt(d);
    printf("%lf\n", r);
    return 0;

自定义函数:

#include<stdio.h>
int Add(int x, int y)//形式上的参数,简称形参
//函数的参数就相当于,⼯⼚中送进去的原材料,函数的参数也可以是 void ,明确表⽰函数没有参数。
//如果有参数,要交代清楚参数的类型和名字,以及参数个数。
{
    int z = 0;
    int z = x + y;
    return z;
    //在这个函数中,变量z存储了变量x和y的和,并通过return 语将结果返回给调用方。returnz的作用是将z的值作为函数的结果返回。
    //调用 Add 函数时,可以通过接收返回值的变量来获取计算结果
}
//{}括起来的部分被称为函数体,函数体就是完成计算的过程。
// 
//(2)形参实际化

//(1)先写出这个函数应用场景
int main()
{
    int a = 0;
    int b = 0;
    //输入
    scanf("%d %d", &a, &b);
    //计算求和
    int z = Add(a, b);//a和b是真实传给Add的参数,是实际参数,简称实参
    //输出
    printf("%d", z);

    return 0;
}

Return的用法:

return后边可以是⼀个数值,也可以是⼀个表达式,如果是表达式则先执⾏表达式,再返回表达式 的结果。例如:

#include <stdio.h>
int Add(int x,int y)
{
    return x+y;
}

return后边也可以什么都没有,直接写 return; 这种写法适合函数返回类型是void的情况。

#include <stdio.h>
void test()
{
    int n = 0;
    scanf("%d", &n);
    printf("hehe\n");
    if (n == 5)
        return ;//直接跳出返回空值void
    printf("haha\n");
}

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

注意:这里的return和break不同,break只能用于跳出循环,但是后面的操作还能继续,而return语句执⾏后,函数就彻底返回,后边的代码不再执⾏。 .代码如下:

d27cad7872a94af6acac6bb3b09f4100.png

return返回的值和函数返回类型不⼀致,系统会⾃动将返回的值隐式转换为函数的返回类型。 返回结果:3

int test()
{
    return 3.14;
}

int main()
{
    int n = test();
    printf("%d\n", n);

    return 0;
}

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

#include <stdio.h>
int test()
{
    int n = 1;
    if (n == 5)
        return 1;
    else
        return -1;

}

int main()
{
    int m = test();
    printf("%d\n", m);
    return 0;
}

数组做函数参数:

使⽤函数解决问题时,会将数组作为参数传递给函数,在函数内部对数组进⾏操作。

例如:写⼀个函数对将⼀个整型数组的内容,全部置为-1,再写⼀个函数打印数组的内容。

//写⼀个函数对将⼀个整型数组的内容,全部置为-1,再写⼀个函数打印数组的内容。
#include<stdio.h>
void set_arr(int arr[], int sz)
{
  int i = 0;
  for (i = 0; i < sz; i++)
     {
      arr[i] = -1;
     }
}

void print_arr(int arr[], int sz)
{
    int i = 0;
    for (i = 0; i < sz; i++)
    {
        printf("%d", arr[i]);
    }
    printf("\n");
}
int main()
{
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    int sz = sizeof(arr) / sizeof(arr[0]);//计算出数组元素个数才能遍历
    print_arr(arr, sz);//先打印出原来的元素
    //先写一个函数,将arr中的内容全部设为-1
    set_arr(arr,sz);
    //写一个函数,将arr中的内容打印出来
    print_arr(arr,sz);
    return 0;
}
数组传参的重点: • 函数的形式参数要和函数的实参个数匹配 • 函数的实参是数组,形参也是可以写成数组形式的 • 形参如果是 ⼀维数组数组大小可以省略不写--->arr[] • 形参如果是 ⼆维数组⾏可以省略,但是列不能省略--->arr[][必写] • 数组传参,形参是不会创建新的数组的 • 参操作的数组和 参的数组是 同⼀个数组

二维数组传参举例:

//二维数组传参
#include <stdio.h>
void print_arr(int arr[][5], int r, int c)
{
    int i = 0;
    for (i = 0; i < r; i++)
    {
        int j = 0;
        for (j = 0; j < c; j++)
        {
            printf("%d ", arr[i][j]);
        }
        printf("\n");

    }

}

int main()
{
    int arr[3][5] = { 1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7 };
    print_arr(arr, 3, 5);//数组传参
    return 0;
}

嵌套调用和链式访问:

嵌套调用:函数之间的互相调⽤,每个函数就⾏⼀个乐⾼零件,正是因为多个乐⾼的零件互相⽆缝 的配合才能搭建出精美的乐⾼玩具,也正是因为函数之间有效的互相调⽤,最后写出来了相对⼤型的 程序。

例子:假设我们计算某年某⽉有多少天?,如果要函数实现,可以设计2个函数:

• is_leap_year():根据年份确定是否是闰年

• get_days_of_month():调⽤is_leap_year确定是否是闰年后,再根据⽉计算这个⽉的天数

603d7f5cb4064f988db105558853b6b2.jpeg

闰年:能被400整除的年份.


//嵌套调用
//例子:假设我们计算某年某⽉有多少天?,如果要函数实现,可以设计2个函数:
//is_leap_year():根据年份确定是否是闰年
//get_days_of_month():调⽤is_leap_year确定是否是闰年后,再根据⽉计算这个⽉的天数
#include <stdio.h>
//(3)进一步细化判断是否为闰年
int is_leap_year(int y)
{
    if (y %400 == 0 ||( y % 100 != 0 && y %4 == 0))
        return 1;
    
    else
        return 0;
}

//(2)通过函数封装进行模块的细化--获取某年某月有多少天
int get_days_of_month(int y, int m)
{
    //巧妙利用数组进行12个月天数的输入,将月份和它对应的天数对齐
    int days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
        //         0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12
    int d = days[m];//通过月份访问天数
    if(is_leap_year(y) && m==2)//判断是否为闰年并且是否为二月
    {
        d += 1;
    }
    return d;
}


//(1)根据题目含义先写出大概模块
int main()
{
    int y = 0;//年
    int m = 0;//月
    scanf("%d %d", &y, &m);//输入年月
    int d=get_days_of_month(y,m);//天数
    printf("%d", d);//打印天数
    return 0;

}

通过封装函数,可以让使用者在使用过程中重复调用,不用再重新进行代码的编写

summary:

• main 函数调⽤ scanf 、 printf 、 get_days_of_month

• get_days_of_month 函数调⽤ is_leap_year

函数之间可以嵌套调⽤,但是函数是不能嵌套定义

链式访问:将⼀个函数的返回值作为另外⼀个函数的参数,像链条⼀样将函数串起来就是函数的链式访问。


#include <stdio.h>
int main()
{
 int len = strlen("abcdef");//1.strlen求⼀个字符串的⻓度
 printf("%d\n", len);//2.打印⻓度 
 return 0;
}
#include <stdio.h>
int main()
{
 printf("%d\n", strlen("abcdef"));//链式访问
 return 0;
}

把strlen的返回值直接作为printf函数的参数,这样就是⼀ 个链式访问.

看⼀个有趣的代码,下⾯代码执⾏的结果是什么呢?

#include <stdio.h>
int main()
{
   printf("%d", printf("%d", printf("%d", 43)));
   return 0;
}

------------------------>运行结果为4321,这是为什么呢?

------------------------>个代码的关键是明⽩ printf 函数的返回是啥?

8ab64b8f70bf4f24a98fb94fe6fc4801.png

根据c语言官网printf函数返回值可知它返回的是打印在屏幕上字符的个数 .

上⾯的例⼦中,我们就第⼀个printf打印的是第⼆个printf的返回值,第⼆个printf打印的是第三个 printf的返回值。 第三个printf打印43,在屏幕上打印2个字符,再返回2 第⼆个printf打印2,在屏幕上打印1个字符,再放回1 第⼀个printf打印1 所以屏幕上最终打印:4321