C语言——函数

@toc数组

1.函数是什么?

数学中咱们常见到函数的概念。可是你了解C语言中的函数吗? 维基百科中对函数的定义:子程序 markdown

  • 在段落引用计算机科学中,子程序(英语:Subroutine, procedure, function, routine, method,subprogram, callable unit),是一个大型程序中的某部分代码, 由一个或多个语句块组
    成。它负责完成某项特定任务,并且相较于其余代 码,具有相对的独立性。
  • 通常会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码一般被集成为软 件库。

 

2.C语言中函数的分类:

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

(1)库函数

那怎么学习库函数呢?
C语言库查询:www.cplusplus.com
以下:
图片.png
简单的总结,C语言经常使用的库函数都有:函数

  • IO函数
  • 字符串操做函数
  • 字符操做函数
  • 内存操做函数
  • 时间/日期函数
  • 数学函数
  • 其余库函数
    库函数实例
    图片.png
    1.代码以下(strcpy示例):
    将字符串拷贝到另外一地址
    #define _CRT_SECURE_NO_WARNINGS
    #include <stdio.h>
    #include <string.h>
    int main()
    {
    char arr1[] = "hello";
    char arr2[] = "###########";
    strcpy(arr2, arr1);
    //strcpy->string copy 字符串拷贝,拷贝字符串(含‘\0’)
    //strcpy(拷贝目的地,字符串拷贝地址)
    printf("%s\n", arr1);

    图片.png
     
    2.代码以下(memset示例):
    字符串替换工具

    #define _CRT_SECURE_NO_WARNINGS
    #include <stdio.h>
    #include <string.h>
    int main()
    {
    char arr1[] = "hello world";
    memset(arr1, '*', 5);
    //memset(目的地,改变值(整形),改变个数)
    printf("%s\n", arr1);
    return 0;
    }

    图片.png

 
: 可是库函数必须知道的一个秘密就是:使用库函数,必须包含 #include对应的头文件。 这里对照文档来学习上面几个库函数,目的是掌握库函数的使用方法。
如何学会使用库函数?
 
学会查询工具的使用:学习

MSDN(Microsoft Developer Network)
www.cplusplus.com
zh.cppreference.com指针

(2)自定义函数

函数的组成:
图片.png
 
定义函数
函数体:即定义的函数中{}中的部分,交代的是函数的实现
咱们举一个栗子:code

写一个函数能够找出两个整数中的最大值。blog

#define _CRT_SECURE_NO_WARNINGS
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
//求两数中的较大值
//定义函数
int get_max(int x, int y)
{
if (x &gt; y)
return x;
else
return y;
}
int main()
{
int a = 0;
int b = 0;
scanf("%d%d", &a, &b);
//函数的使用
int max = get_max(a, b);
printf("max = %d\n", max);
max = get_max(100, 300);
printf("max = %d\n", max);
return 0;
}

图片.png

//使用函数编写代码实现两数交换
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
//直接传递值进行交换,无效
//对形参的修改不会改变实参
//形参是实参的一份临时拷贝
void Swap1(int x,int y)//形参
//void表示空,无,此函数没有返回值,全部用void
{
    int tmp = 0;
    tmp = x;
    x = y;
    y = tmp;
    printf("x = %d  y = %d\n", x, y);//x,y交换成功,但x,y的值与a,b交换没有关系
}
//经过指针,取地址交换a,b的值有效
void Swap2(int* pa, int* pb)//形参
{
    int tmp = 0;
    tmp = *pa;
    *pa = *pb;
    *pb = tmp;
    printf("*pa = %d  *pb = %d\n", *pa, *pb);
}
int main()
{
    int a = 0;
    int b = 0;
    scanf("%d%d", &a, &b);
    printf("a = %d  b = %d\n", a, b);
    int tmp = 0;
    //tmp = a;
    //a = b;
    //b = tmp;//将这三条交换程序写成函数
    //调用Swap1函数——传值调用
    Swap1(a, b);//实参
    printf("a = %d  b = %d\n", a, b);//无效交换
    //调用Swap2函数——传址调用
    Swap2(&a, &b);//实参
    printf("a = %d  b = %d\n", a, b);//交换有效
    return 0;
}

图片.png
 

3.函数的参数

(1)实际参数(实参):真实传给函数的参数,叫实参。实参能够是:常量、变量、表达式、函数等。不管实参是何种类型的量,在进行函数调用时,它们都必须有肯定的值,以便把这些值传送给形参。
(2)形式参数(形参):形式参数是指函数名后括号中的变量,由于形式参数只有在函数被调用的过程当中才实例化(分配内存单元),因此叫形式参数。形式参数当函数调用完成以后就自动销毁了。所以形式参数只在函数中有效。three

上面Swap1和Swap2函数中的参数 x,y,pa,pb 都是形式参数;在main函数中传给Swap1的a,b和传给Swap2的a,b是实际参数。<br/>形参实例化以后其实至关于实参的一份临时拷贝。
 

4.函数的调用

(1)传值调用:
函数的形参和实参分别占有不一样内存块,对形参的修改不会影响实参。
(2)传址调用:
传址调用是把函数外部建立变量的内存地址传递给函数参数的一种调用函数的方式。
这种传参方式可让函数和函数外边的变量创建起正真的联系,也就是函数内部能够直接操做函数外部的变量。

 

5.函数实例

1)写一个函数能够判断一个数是否是素数

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
//求100-200间的素数
//素数返回1,不是素数返回0
int is_prime(int n)
{
    int m = 0;
    //用小于n的值试除n,能整除即不是素数
    for (m = 2; m<n; m++)//任何一个数的值必不大于其开根号的平方和,9<=3^2+3^2
    {
        if (n%m == 0)
            return 0;
        //在此处不能写else,return 1
        //由于只作了一次判断
    }
    if (m == n)//只有当for循环m<n不成立时跳到这,即m == n,此判断可不写
        return 1;
}
int main()
{
    int i = 0;
    for (i = 100; i <= 200; i++)
    {
        if (is_prime(i) == 1)
            printf("%d ", i);
    }
    return 0;
}

2)写一个函数,实现一个整形有序数组的二分查找

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
//数组元素查找
// 能找到返回数组下标,不能找到返回-1
 //arr其实是一个地址
int binary_search(int arr[], int k, int sz)
{
    int left = 0;
    //数组传参仅传数组首元素地址,在函数内部不能获得数组个数
    //int sz = sizeof(arr) / sizeof(arr[0]);
    int right = sz - 1;
    while (left <= right)
    {
        int mid = (left + right) / 2;
        if (arr[mid] > k)
            right = mid -1;
        else if (arr[mid] < k)
            left = mid +1;
        else
            return mid;
    }
    return -1;
}
int main()
{
    int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
    int k = 7;
    int ret = 0;
    int sz = sizeof(arr) / sizeof(arr[0]);
    ret = binary_search(arr, k, sz);
    if (ret == -1)
    {
        printf("找不到指定的数字\n");
    }
    else
    {
        printf("找到了,下标是%d\n",ret );
    }
    return 0;
}

 

6.函数的嵌套调用和链式访问

嵌套调用:

#include <stdio.h>
void new_line()
{
 printf("hehe\n");
}
void three_line()
{
    int i = 0;
 for(i=0; i<3; i++)
   {
        new_line();
   }
}
int main()
{
 three_line();
 return 0; 
 }

链式访问:把一个函数的返回值做为另一个函数的参数。
实例:

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

图片.png
这是由于printf的返回值是打印字符的个数,即printf("%d", printf("%d", printf("%d", 43)))—>printf("%d", printf("%d", 2))—>printf("%d", 1),即打印4321.

 

7.函数的声明和定义

函数声明:
1.告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。可是具体是否是存在,无关
紧要。
2.函数的声明通常出如今函数的使用以前。要知足先声明后使用。

  1. 函数的声明通常要放在头文件中的。
     
    函数定义:

    函数的定义是指函数的具体实现,交待函数的功能实现。

图片.png

通常来讲,咱们最好将函数的定义部分放到函数调用前面,这样就能够避免函数声明的部分(编译器读取代码是从上往下依次扫描的),例如上面的这个代码能够写成这样:

图片.png
 
函数分写
test.h的内容 放置函数的声明

#ifndef __TEST_H__
#define __TEST_H__
//函数的声明
int Add(int x, int y); 
#endif //__TEST_H__

test.c的内容 放置函数的实现

#include "test.h"
//函数Add的实现
int Add(int x, int y) 
{
return x+y;
}

咱们看到过不少t头文件都会加上相似上面的代码,为何要加上这些代码呢?

防止同一个头文件被屡次使用头文件在使用的时候,其实是将整个头文件的内容复制到这条语句处,若是同一个头文件屡次使用,就会产生大量重复且无效的代码,下降代码的效率和增长代码所在内存。

相关文章
相关标签/搜索