• 【C语言】函数的定义、传参与调用(一)


     目录

    导读:

    1. 为什么要用函数

    2. C语言中函数的分类

    2.1 库函数

    2.1.1 什么是库函数

    2.1.2 C语言常用的库函数

    2.2 自定义函数

    2.2.1 什么是自定义函数

    2.2.2 定义函数的方法

    2.2.3 举例

     3. 函数的参数

    3.1 传参不同的对比

    3.2 形式参数(形参)和实际参数(实参)

    3.3 解析代码

    4. 函数的调用

    4.1 传值调用

    4.2 传址调用 

    4.3 练习 

    4.3.1 传值练习

    4.3.2 传址练习

    博主有话说


    导读:

    本章节我们来学习一下函数是什么,为什么要用函数,怎样取定义一个函数

    相关的库函数使用可以看一下:

    字符串操作函数

    字符串操作函数

    1. 为什么要用函数

    • 使用函数可以使代码变得模块化和更易读,同时也可以减少代码的重复性。
    • 函数可以接受参数,以便在不同的情况下执行相同的操作。在代码的其他部分需要调用这个操作时,只需要调用函数而不必重复编写代码。
    • 函数可以使代码更容易维护和测试,因为它们将相对独立的代码块隔离出来。
    • 通过使用函数,可以使代码更加清晰、简洁和易于理解。

    2. C语言中函数的分类

    库函数                    自定义函数

    2.1 库函数

    2.1.1 什么是库函数

    库函数是现成的函数库中可用的函数。

    这些函数通常作为程序员的工具,在编程过程中被调用使用。库函数通常包含在操作系统或者编程语言的标准库中,以便程序员方便地调用这些函数来完成特定的任务,例如字符串操作、文件操作、网络操作等。库函数经过长时间的使用和测试,已经经过优化,因此程序员可以使用这些函数来提高代码的可维护性、可读性和执行效率。

    2.1.2 C语言常用的库函数

    字符串操作函数:如strlen()、strcpy()、strcat()、strcmp()等

    动态内存分配函数:如malloc()、calloc()、realloc()、free()等。

    时间函数:如time()、asctime()、mktime()等

    数学函数:如sin()、cos()、tan()、log()、exp()、sqrt()等

     注意:

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

    2.2 自定义函数

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

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

    2.2.1 什么是自定义函数

    自定义函数和库函数一样,有函数名,返回值类型和函数参数。

    但是不一样的是这些都是我们自己来设计。这给程序员一个很大的发挥空间

    2.2.2 定义函数的方法

    ret_type fun_name( para1,  *  )

    {

            statement;//语句项

    }

    ret_type 返回类型

    fun_name 函数名

    para1     函数参数

    2.2.3 举例

    写一个函数可以找出两个整数中的最大值。

    1. //get_max函数的设计
    2. int get_max(int x, int y)
    3. {
    4. return (x > y) ? (x) : (y);
    5. }
    6. int main()
    7. {
    8. int num1 = 10;
    9. int num2 = 20;
    10. int max = get_max(num1, num2);
    11. printf("max = %d\n", max);
    12. return 0;
    13. }

     

     3. 函数的参数

    3.1 传参不同的对比

    我们来看下面的代码:

    写一个函数,实现交换两个整形变量的内容。

    1. void Swap1(int x, int y)
    2. {
    3. int tmp = 0;
    4. tmp = x;
    5. x = y;
    6. y = tmp;
    7. }
    8. int main()
    9. {
    10. int num1 = 10;
    11. int num2 = 20;
    12. Swap1(num1, num2);
    13. printf("Swap1::num1 = %d num2 = %d\n", num1, num2);
    14. return 0;
    15. }

    我们把num1和num2传参给Swap1这个函数,x 和 y 分别来接收,让其实现两个数的交换,结构如何呢?

    我们发现两个值并没有实现交换,我们换一种传参方式试一下

    1. void Swap2(int* px, int* py)
    2. {
    3. int tmp = 0;
    4. tmp = *px;
    5. *px = *py;
    6. *py = tmp;
    7. }
    8. int main()
    9. {
    10. int num1 = 10;
    11. int num2 = 20;
    12. Swap2(&num1, &num2);
    13. printf("Swap2::num1 = %d num2 = %d\n", num1, num2);
    14. return 0;
    15. }

    这次我们把num1和num2的地址传给Swap2函数,让指针变量*px和*py来接收,结果又是如何呢?

    成功交换!

    这就是形参和实参的区别

    3.2 形式参数(形参)和实际参数(实参)

    形式参数:

    形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有 效。

    实际参数: 

    真实传给函数的参数,叫实参。

    实参可以是:常量、变量、表达式、函数等。

    无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。

    上面 Swap1 和 Swap2 函数中的参数 &num1 , x,y,px,py都是形式参数。

    在main函数中传给 Swap1 的 num1、num2 和传给Swap2函数的&num1、&num2 是实际参数。

    3.3 解析代码

    Swap1:

    我们来进入调试,查看两块代码的不同

    当函数调用时,实参的值被复制到函数的形参中。

    这意味着,形参在函数的局部作用域内创建,并且在函数调用结束时被销毁。

    因此,在内存中,形参的值存在于函数的栈帧中,而实参的值仍然存在于调用函数的上下文中。

    Swap1 函数在调用的时候,x,y拥有自己的空间,同时拥有了和实参一模一样的内容。

    所以我们可以简单的认为:形参实例化之后其实相当于实参的一份临时拷贝。

    Swap2:

    指针变量px和py存储着num1和num2的地址,改变对px和py解引用操作后,指向的就是num1和num2这片空间的值,才能实现两者的调换

    4. 函数的调用

    在函数调用中,参数可以通过传值调用或传址调用来传递。

    4.1 传值调用

    传值调用是指将实参的值复制一份传递给形参的过程。

    在函数内部,对形参的任何修改都不会影响到实参。

    这种方式比较简单,但是如果需要传递大量的参数或者需要频繁修改参数的值,可能会比较低效

    4.2 传址调用 

    传址调用是指将实参的地址传递给形参的过程。

    在函数内部,可以通过该地址直接访问实参的内容。

    如果对形参进行修改,就相当于对实参进行了修改,因为它们指向同一块内存。

    这种方式比较高效,但是需要注意不要意外修改实参的内容。

    4.3 练习 

    4.3.1 传值练习

    判断一个数是否是素数

    1. int isPrime(int num)
    2. {
    3. int i;
    4. if (num < 2)
    5. {
    6. //小于 2 的数都不是素数
    7. return 0; // 返回 false
    8. }
    9. for (i = 2; i * i <= num; i++)
    10. {
    11. //从 2 开始到 sqrt(num) 循环
    12. if (num % i == 0)
    13. {
    14. // 如果可以整除,说明不是素数
    15. return 0; // 返回 false
    16. }
    17. }
    18. return 1; // 如果上述循环完毕还没有返回 false,则说明是素数,返回 true
    19. }
    20. int main()
    21. {
    22. int num;
    23. printf("请输入一个整数:");
    24. scanf("%d", &num);
    25. if (isPrime(num))
    26. {
    27. printf("%d是素数\n", num);
    28. }
    29. else
    30. {
    31. printf("%d不是素数\n", num);
    32. }
    33. return 0;
    34. }

    测试:

    1       3       8       9

     

    4.3.2 传址练习

    写一个函数,每调用一次这个函数,就会将n值增加1

    1. void increase(int* n)
    2. {
    3. (*n)++;
    4. }
    5. int main()
    6. {
    7. int a = 1;
    8. printf("a = %d\n", a);
    9. increase(&a);
    10. printf("a = %d\n", a);
    11. increase(&a);
    12. printf("a = %d\n", a);
    13. return 0;
    14. }

    博主有话说

    有关函数的内容今天就到这里,接下来还有函数的嵌套调用、声明和定义以及函数递归。

    更多内容关注博主,掌握最新内容

  • 相关阅读:
    TCP协议_三次握手与四次挥手
    计算机网络性能指标——时延,时延带宽积,RTT和利用率
    角度新奇!第一次看到这样使用MyBatis的,看得我一愣一愣的。
    STDF-Viewer 解析工具说明
    蓝桥杯练习题三 - 纸牌三角形(c++)
    object property order
    利用AlarmManager完成精准的轮询
    一些性能优化的东西
    营丘福稻品牌山东大米 国稻种芯·中国水稻节:淄博高青招牌
    Linux服务器线上优化
  • 原文地址:https://blog.csdn.net/qq_64818885/article/details/133518736