前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >函数类的学习

函数类的学习

原创
作者头像
暮云
发布2022-10-16 11:58:29
2970
发布2022-10-16 11:58:29
举报
文章被收录于专栏:C/C++语言学习

函数学习

库函数

www.cplusplus.com

www.cppreference.com

代码语言:c++
复制
//从这两个网站可搜索所有的库函数,是一个查询工具
  • IO函数
  • 字符串操作函数
  • 内存操作函数
  • 时间/日期函数
  • 数学函数
  • 其它库函数
代码语言:c++
复制
//内存操作函数memory set = memset
memset(void*ptr,int value,size_t num);
//把ptr所指向的空间的前num个字节的内容设置成指定的value这个值
代码语言:c++
复制
//例
#include<stdio.h>
#include<string.h>
int main()
{
    char arr[]="hello world";
    memset(arr,'6',5);
    printf("%s\n",arr);
    //66666 world
    return 0;
}

这只是单纯的举例,具体使用查询网站

自定义函数

最大区别:自己设计

步骤:

  • 定义函数
  • 使用函数
代码语言:c++
复制
//定义函数
#include<stdio.h>
int add(int a,int b)//定义a,b为两个整型
{
    int z = a + b;
    return z;//因为返回时z为整型,所以返回类型也为整型int
}
//函数的使用
int main()
{
    int x = 100;
    int y = 200;
    int sum = 0;
    sum = add(x,y);//自定义"add"的使用需要用一个变量储存
    //而'x'传给了a,'y'传给b,与定义的函数对应
    printf("%d",sum);
    return 0;
}
  • 指针函数设计
代码语言:c++
复制
//例:设计交换函数,按常规思想无法实现
#include<stdio.h>
void Swap1(int x,int y)
{
    int z = 0;
    z = x;
    x = y;
    y = z;
}
int main()
{
    int a = 10;
    int b = 20;
    printf("a=%d b=%d\n",a,b);
    Swap1(a,b);
    printf("a=%d b=%d",a,b);
    return 0;
    //该代码俩打印结果a=10 b=20,无法实现交换
    //原因是定义的'x'和'y'有自己的地址与'a''b'无任何关系
    //因此'a''b'地址的值不变,打印结果也就不变
}
代码语言:c++
复制
//指针思想
#include<stdio.h>
void Swap2(int* pa, int* pb)
{
    int z = 0;
    z = *pa;//通过指针变量存放的地址,找到该地址存放的内容赋值给z
    *pa = *pb;//同理通过pb存放的地址找到该位置,即b,将改内容赋值给pa存放的地址的位置,即a
    *pb = z;//z变量内容赋值给pb存放的地址的位置,即b
}
int main()
{
    int a = 10;
    int b = 20;
    printf("a=%d b=%d\n",a,b);
    Swap2(&a,&b);
    printf("a=%d b=%d",a,b);
    return 0;
}    

函数参数

  • 实际参数(实参)

真实传给函数的参数,叫实参。实参可以是:常量,变量,表达式,函数等。但是在进行函数调用时,它们必须有确定的值,以便把这些值传给形参。

代码语言:c++
复制
//以该函数为例
#include<stdio.h>
int add(int a,int b)
{
    int z = a + b;
    return z;
}
int main()
{
    int x = 100;
    int y = 200;
    int sum = 0;
    sum = add(x,y);//括号内可以放,常量,变量,表达式,函数
    printf("%d",sum);
    return 0;
}
  • 形式参数(形参)

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

代码语言:c++
复制
#include<stdio.h>
int add(int a,int b)//括号内为形参
{
    int z = a + b;
    return z;
}
//当下面不调用add函数时,上方括号内的a,b不存在
int main()
{
    int x = 100;
    int y = 200;
    int sum = 0;
    sum = add(x,y);
    printf("%d",sum);
    return 0;
}
  • 当实参传给形参的时候,形参其实是实参的一份临时拷贝,因此对形参的修改时不会改变实参的。(指针思想为例)

函数的调用

  • 传值调用

函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参

  • 传址调用(指针思想)

传址调用是把函数外部创建变量的内存地址传给函数参数的一种调用函数的方式 这种方式可以让函数和函数外边的变量建立起真正的联系,即函数内部可以直接操作函数外部变量

代码语言:c++
复制
//传址调用,例
//每使用一次自定义函数,num值加1
#include<stdio.h>
void Add(int*p)
{
    (*p)++;//加括号是因为++的优先级比*p大,不加括号结果为p++
}
int main()
{
    int num = 0;
    Add(&num);
    printf("num = %d\n",num);//1
    Add(&num);
    printf("num = %d\n",num);//2
    Add(&num);
    printf("num = %d\n",num);//3
}
  • 注意点:自定义函数时无法将数组传递到定义函数内
代码语言:c++
复制
//二分查找为例
//先看代码后看注释
#include<stdio.h>
int binary_search(int arr,int k)
{
    int sz = sizeof(arr)/sizeof(arr[0]);
    int left = 0;
    int right = sz - 1;
    int mid = (left+right)/2;
    while(left <= right)
    {
        if(arr[mid]<k)
        {
            left = mid + 1;
        }
        else if(arr[mid]>k)
        {
            right = mid - 1;
        }
        else
        {
            return mid;
        }
    }
    return -1;
}
int main()
{
    int arr[]={1,2,3,4,5,6,7,8,9,10};
    int k = 5;
    //            此处arr传递的为指针,即数组arr第一个元素的地址
    int s = binary_search(arr,k);
    // 所以上方arr为指针
    if(s == -1)
    {
        printf("找不到该数字\n");
    }
    else
    {
        printf("找到了,该下标是:%d\n",s);
    }
    return 0;
}
// 该函数无法运行

修改如下

代码语言:c++
复制
#include<stdio.h>
int binary_search(int arr[],int k,int sz)
{
    int left = 0;
    int right = sz - 1;
    int mid = (left+right)/2;
    while(left < right)
    {
        if(arr[mid]<k)
        {
            left = mid + 1;
        }
        else if(arr[mid]>k)
        {
            right = mid - 1;
        }
        else
        {
            return mid;
        }
    }
    return -1;
}
int main()
{
    int arr[]={1,2,3,4,5,6,7,8,9,10};
    int k = 5;
    int sz = sizeof(arr) / sizeof(arr[0]);
    int s = binary_search(arr,k,sz);
    if(s == -1)
    {
        printf("找不到该数字\n");
    }
    else
    {
        printf("找到了,该下标是:%d\n",s);
    }
    return 0;
}

函数嵌套调用和链式访问

嵌套调用

代码语言:c++
复制
#include<stdio.h>
void new_line()
{
    printf("hollow\n");
}
void three_time()
{
    int i = 0;
    for(i=0;i<3;i++)
    {
        new_line();
    }
}
int main()
{
    three_time():
    return 0;
}
//打印三次"hollow".

链式访问

把一个函数的返回值作为另外一个函数的参数

代码语言:c++
复制
#include<stdio.h>
int main()
{
    int len = 0;
    //1
    len = strlen("abc");
    printf("%d\n",len);
    //2
    printf("%d\n",strlen("abc"));
}
//将strlen("abc")的结果作为printf函数的参数,即方式2
//两种方式都可以运行,方式2为链式访问,更为简洁

函数的声明和定义

函数声明

1.告诉编译器有个函数叫什么,参数是什么,返回类型是什么。

2.函数的声明一般出现在函数的使用之前。先声明后使用。

3.函数的声明一般要放在头文件中。

函数定义

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

代码语言:c++
复制
//函数声明
#include<stdio.h>
int Add(int x, int y);
 
int main()
{
    int a = 10;
    int b = 20;
    int sum = 0;
    //函数调用
    sum = Add(a,b);
    printf("%d\n",sum);
    return 0;
}
//函数定义
int Add(int x,int y)
{
    int z=x+y;
    return z;
}
//这种写法比较啰嗦,浪费时间
  • 真正写自定义函数的用法
代码语言:c++
复制
//创建一个( ).h的头文件,将函数声明放进去
int Add(int x,int y)
代码语言:c++
复制
//再创建一个( ).c的源文件,将函数定义放进去
int Add(int x,int y)
{
    int z=x+y;
    return z;
}
代码语言:c++
复制
//最后在要写代码的源文件(test.c)中使用自定义的函数
#include<stdio.h>
#include"Add.h"//用""引自己定义的函数
int main()
{
    int a = 10;
    int b = 20;
    int sum = 0;
    sum = Add(a,b);
    printf("%d\n",sum);
    return 0;
}
  • 这样写更加方便

函数递归

程序调用自身的编程技巧称为递归。一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需要少量的程序就课描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的主要思考方式在于:把大事化小

代码语言:c++
复制
//例
#include<stdio.h>
int main()
{
    printf("hehe\n");
    main();
    return 0;
}
//最终结果导致栈溢出,即栈区空间耗尽"stack overflow",因为递归无条件

https://stackoverflow.com程序员的知乎

接受 一个整型值,按照顺序打印它的每一位。

代码语言:c++
复制
#include<stdio.h>
void print(int n)
{
    if(n>9)
    {
        print(n/10);
    }
    printf("%d ",n%10);
}
// 这就是递归思想。假设输入的是123,在第一次调用print时,"123"进入if语句,n变为12,再调用print进入if语句,n变为1,此时代码往下走,打印数为1,随后回到第二次调用print时刻,此时n=12,打印数位2,再回到第一次调用print时刻,此时n=123,打印数为3。这就是"递"和"归"
int main()
{
    int num = 0;//123
    scanf("%d",&num);
    print(num);
    return 0;
}
//这不会无线循环,因为有定义条件

递归的两个必要条件

  • 存在限制条件,当满足这个限制条件的时候,递归便不再继续
  • 每次递归调用之后越来越接近这个限制条件。

不允许创建临时变量,求字符串长度

代码语言:c++
复制
//依照上方代码思考
#include<stdio.h>
int my_strlen(char*str)
{
    if (*str!='\0')
        return 1+my_strlen(str+1);
    else
        return 0;
}
int main()
{
    char arr[]="bit";
    int len = my_strlen(arr);//传上去的为第一个元素的地址
    printf("len = %d\n",len);
    return 0;
}
  • 限制条件一般用if语句

递归与迭代

  • 递归
代码语言:c++
复制
//n的阶乘,这里只打自定义函数
int Fac(int n)
{
    if(n <= 1)
        return 1;
    else
        return n*Fac(n-1);
}
代码语言:c++
复制
//求第n个斐波那契数  即 1 1 2 3 5 8 13 21 34 55
//使用递归运算效率低下
int count = 0;
int Fib(int n)
{
    if(n=3)
    {
        count++;//看一下n=3是被重复计算多少次
    }
    if(n<=2)
        return 1;
    else
        return Fib(n-1)+Fib(n-2);
}
int main()
{
    int n = 0;
    int ret = 0;
    scanf("%d",&n);
    ret = Fib(n);
    printf("ret = %d\n",ret);
    printf("count = %d",count);//count=39088169
    return 0;
}
  • 迭代
代码语言:c++
复制
//迭代思想,跟循环挺像
#include<stdio.h>
int Fib(int n)
{
    int a = 1;
    int b = 1;
    int c = 1;
    while(n>2)
    {
        c = a+b;
        a = b;
        b = c;
        n--;
    }
    return c;
}
int main()
{
    int n = 0;
    int ret = 0;
    scanf("%d",&n);
    ret = Fib(n);
    printf("ret = %d\n",ret);
    return 0;
}
  • 有时候迭代相较于递归更好更快

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 函数学习
    • 库函数
      • 自定义函数
        • 函数参数
          • 函数的调用
            • 函数嵌套调用和链式访问
              • 嵌套调用
              • 链式访问
            • 函数的声明和定义
              • 函数声明
              • 函数定义
            • 函数递归
              • 递归的两个必要条件
              • 递归与迭代
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档