函数分为库函数和自定义函数,库函数是编译器自带的函数,自定义函数则是程序员自己定义的函数。

库函数

strcpy 字符串拷贝函数

#include <stdio.h>
#include <string.h>
int main()
{
    char arr1[] = "bit";
    char arr2[] = "###########";
    strcpy(arr2, arr1);
    printf("%s\n", arr2);   // 每个字符串最后一位都是'\0',打印时遇到这个字符就会停止打印
    return 0;
}

程序实现了将一个字符串的内容覆盖进另一个字符串,在写程序的时候需要注意的是,被覆盖的需要比需要拷贝的字符串长,否则就是一个bug。这就是头文件为string.h内部的一个函数,能够实现字符串的拷贝。

memset 内存设置函数

#include <stdio.h>
#include <string.h>
int main()
{
    char arr[] = "hello world";
    //将hello替换为*****
    //memset(目标地址,'要换进去的字符',数量);
    memset(arr, '*', 5);
    printf("%s\n", arr);
    return 0;
}//主要是要学会在专业的网站上学会查询库函数的使用,zh.cppreference.com,cplusplus.com

msmset函数能够实现将内存里的某些段的字符屏蔽掉,或者修改为某个字符。也是头文件为string.h 的一个函数。对于库函数的学习最重要的还是要认识到,要学会在函数库或者专业的网站上进行查询,[zh.cppreference.com, cplusplus.com ,进入网站对库函数进行查询,不一定要全部记住,但是要会查。

自定义函数

自定义函数有形参和实参,形参主要就是为了接受实参的量,或者指针变量。主要是为了在主函数外部实现某个单一的功能,一个函数能实现的功能越单一越好,更加简洁的实现某个功能,不需要每次实现某个功能都要输入对应的代码。

两个数取最大值

#include <stdio.h>
int getmax(int x, int y)
{
    return (x > y) ? (x) : (y);
    /*if (x > y)
        return x;
    else
        return y;*/
}
int main()
{
    int a = 20;
    int b = 30;
    int max = 0;
    max = getmax(a, b);
    printf("%d\n", max);
    return 0;
}

在外部写出一个函数,实现两个数里取大的,属于传值调用,有返回值的函数,返回值为一个整形,所以用int定义函数,内部使用更简单的三目运算符。

交换两个数的值

#include <stdio.h>

void Swap1(int x, int y)
{
    x = x ^ y;
    y = x ^ y;
    x = x ^ y;
}//事实证明,这个函数无法实现两个变量数值的交换
void Swap2(int* px, int* py)
{
    *px = *py ^ *px;
    *py = *py ^ *px;
    *px = *py ^ *px;
}
int main()
{
    int a = 10;
    int* pa = &a;
    int b = 30;
    int* pb = &b;
    printf("&a=%d &b=%d\n", pa, pb);
    printf("&a=%x &b=%x\n", pa, pb);
    printf("&a=%p &b=%p\n", pa, pb);
    printf("a=%d b=%d\n", *pa, *pb);//*解引用操作符,表示指针指向的数字,
    printf("a=%d b=%d\n", a, b);
    Swap1(a, b);   //传值调用 只需要用到变量的值而无需改变外部的变量值的时候
                            //无需返回值的函数,函数类型为void,意为返回一个空值,
    printf("a=%d b=%d\n", a, b);
    Swap2(&a, &b); //传址调用 外部的变量需要在函数内部进行直接改变的时候
                              //存入指针变量并且能让指针变量正常使用的只能是取地址操作符取到的地址
    printf("a=%d b=%d\n", a, b);
    return 0;
}

第一次写出函数,运行之后发现无法实现变量的值的调换,仔细看过,并没有发现什么问题,逐步调试过后,才发现,被调换了值的是被赋值了的形参,与真正需要调换值的变量并无关系,在监视窗口中查询地址,发现形参和实参也是存在不同的地址之下,最终在老师的指导之下,才明白,这是需要函数直接通过地址操纵变量,叫做传址调用, 形参的种类需要是指针变量,输入的形参也是取形参的地址。
另外我比较好奇指针到底会在不同的类型之中会打印成什么样子,“printf("a=%d b=%d\n", pa, pb);”打印的是a和b的值,“printf("&a=%p &b=%p\n", pa, pb);”是将a和b的地址打印在指针变量中,是十六位十六进制的地址,“printf("&a=%x &b=%x\n", pa, pb);”讲地址打印在十六进制数中,值和printf("&a=%x &b=%x\n", pa, pb);一样,形式不同,“printf("&a=%d &b=%d\n", pa, pb);”是直接用十进制打印出地址的值,但是值还是和地址一样。

用函数判断一个数是否为素数

#include <stdio.h>
#include <math.h>
int Prime(int x)
{
    int i = 0;
    for (i = 2; i <= sqrt(x); i++)
    {
        if (x % i == 0)
        {
            return 0;
        }
    }
    //if (i > sqrt(x))
        return 1;
}
int main()
{
    int a = 0;
    printf("请输入一个正整数:\n");
    scanf("%d", &a);
    if (Prime(a))
        printf("是一个素数\n");
    else
        printf("不是一个素数\n");
    return 0;
}

判断一个数是否为素数的规则还是很清晰的,看看这个数是否除了自身和1之外能被第二个数整除,不能就是一个素数。sqrt为求算术平方根,需要math.h的头文件,函数的调用为传值调用,返回一个整形。

判断一个年份是否为闰年

#include <stdio.h>
int Leap(int x)
{
    if ((x % 4 == 0 && x % 100 != 0) || (x % 400 == 0))
    {
        return 1;
    }
    else
        return 0;
}
int main()
{
    int year = 0;
    printf("请输入一个年份:\n");
    scanf("%d", &year);
    if (Leap(year))
        printf("是闰年");
    else
        printf("不是闰年\n");
    return 0;
}

还是一个传值调用的函数,返回值为一个整形,将函数的返回值用于主函数if语句的判断条件。

用函数实现有序数组的二分查找

#include <stdio.h>
int binary_search(int arr[],int a,int s)
{
    //算法的实现
    int left = 0;

    int right = s - 1;
    int i = 0;
    while (left <= right)
    {
        int mid = (left + right) / 2;
        if (a > arr[mid])
        {
            left = mid + 1;
        }
        else if (a < arr[mid])
        {
            right = mid - 1;
        }
        else
            return mid;
    }
    return -1;

}
int main()
{
    int arr[] = {1,2,3,4,5,6,7,8,9,10};
    int a = 0;
    int sz = sizeof(arr) / sizeof(arr[0]);
    printf("请输入想要查找的数字:\n");
    //如果找到了返回这个数的下标,如果没找到,返回-1
    scanf("%d", &a);
    int ret = binary_search(arr, a, sz);
    //本质上传输到函数内部的是arr的地址,是一个指针变量,并不是整个数组。
    if (ret == -1)
        printf("没找到");

    else
        printf("该数为arr[%d]\n",ret);

    return 0;
}

需要注意的点,第一次在写程序过程中并不能实现想要的效果,无论输入多少,函数都会返回一个相同的值,调试函数的时候在监视窗口才看到,形参在赋值的时候,只是得到了数组的第一个数,所以取地址,使得函数内部用指针访问数组,就能够访问到整个数组,然后数组的长度也就无法在函数内部求,所以直接将数组的长度作为一个参数加入函数之中,二分法也是了解的,所需要的功能得以实现。

每运行一次变量的值加一

#include <stdio.h>
void Add (int* p)
{
    *p = *p + 1;
}
int main()
{
    int num = 0;
    printf("%d\n", num);
    Add(&num);  //这是需要在函数内部改变自变量的值,传址调用;
    printf("%d\n", num);
    Add(&num);
    printf("%d\n", num);
    Add(&num);
    printf("%d\n", num);
    return 0;
}

一个传值调用的无返回值函数,需要通过函数改变实参的值,所以要通过指针直接访问参量,改变参量的值。

函数的声明和定义

声明和定义是分开来放的,声明放在头文件中,函数的定义放在另一个源文件中,共同构成一个实现某个功能的函数模块,在代码中需要使用到函数时,就将头文件的名称用双引号输入在#include 之后,下面就能调用在该目录之下的声明过的函数。
函数的模块将会在函数的递归之中重点使用。