C语言程序设计——函数

一、函数的定义

函数又称作子程序,是一个大型程序中的某部分代码,由一个或多个语句块组成。它负责完成某项特定的任务,而且相较于其他代码,具备相对独立性。

二、 函数——库函数

库函数作为C语言基础库所提供的函数,具有帮助开发的功能。例如prinf、scanf等就是库函数,属于标准输入输出函数。

想了解函数的具体用法可以查询https://cplusplus.com/reference/等网站。

以下介绍两种库函数,均为<string.h>中的函数

1.  strcpy ——string copy ——字符串拷贝

 

 通过网站的查询,我们可以了解函数的基本功能与使用方法。对于strcpy函数来说,我们捕捉到以下关键信息:

1)基本语法形式:strcpy( str1 , str2 ) ;

2)str1为destination(目的地),即被替换者;str2为source(源头),即替换模板。所以该函数的功能是将str2位置的字符串内容复制到str1内,即用str2的内容替换str1的内容;

3)网站配备了使用范例,读者可以在范例上直接修改编辑来查看结果,更好帮助理解。

2.  memset —— memory set ——字符串替换

 对于memset函数我们理解到以下几点:

1)基本语法形式:memset ( str , char ,int);

2)str指要进行编辑的字符串;char指准备替换的字符;int指准备替换掉的字节数(从头开始);

3)因为替换的是char类型,所以字节数=1*替换数,后续可能遇到其他类型数组,需要注意可能不再是以1为单位。

三、函数——自定义函数

ret_type(函数返回类型) fun_name(函数名)(para1(参数),para...)

{

        statement;

}

设置一个交换两个变量值的函数

void Swap1(int x,int y)
{
    int tmp = 0;
    tmp = x;
    x = y;
    y = tmp;
}

int main()
{
    int a =10;
    int b =20;
    printf("a=%d b=%d\n",a,b);
    Swap1(a,b);
    printf("a=%d b=%d\n",a,b);
    return 0;
}

//output:
//a=10 b=20
//a=10 b=20

通过这个代码,我们并不能成功完成交换数值的任务。这是因为将a,b传入函数时,新建了x,y两个变量,这是函数内所做的变换均作用于x和y。即此时存在四个储存空间a,b,x,y,而函数所做的改变并不能影响到a和b,所以未能完成任务。

这个时候就需要我们更深一步来解决这个问题——指针:

int main()
{
    int a = 10;
    int* pa = &a; //pa为指针变量
    *pa = 20; //解引用操作
    printf("%d\n",a);
    return 0;
}

指针与地址联系紧密,当我们创建一个变量时,需要向电脑申请一块地址来存储该变量。例如创建一个int型变量,则向系统申请了一块4个字节大小的储存空间,即32个bit位。而这个储存空间则是四个连续的十六进制数字表示,如0x00ff4840……我们对这个变量的赋值就会存储在这个空间中。所以当使用scanf时会用到&,就是将该值保存到变量的地址中。

逆向思考一下,我们同样可以通过地址找到变量所存的值,这时候就用到了指针。在数据类型之后加*就构成了指针数据类型。

int* pa = &a;

代表将int型数据a的地址存储到pa这个指针变量内;

*pa = 20;

代表将pa这个指针变量所存储的地址对应变量的值赋予20,因为pa存储的是a的地址,所以成功将20赋值给了a。这个操作也被叫做解引用操作 。

借助指针的帮助,我们就可以顺利完成上述任务:

void Swap2(int* px,int* py)
{
    int tmp = 0;
    tmp = *px;
    *px = *py;
    *py = tmp;
}

int main()
{
    int a =10;
    int b =20;
    printf("a=%d b=%d\n",a,b);
    Swap2(&a,&b);
    printf("a=%d b=%d\n",a,b);
    return 0;
}

//output:
//a=10 b=20
//a=20 b=10

 这样函数所做的操作均是对a,b地址内的操作,所以可以成功影响a和b的赋值。

参数 

参数分为实际参数(实参)和形式参数(形参)

实参就是真实传递给函数的参数,必须具有特定的值,以便传递给形参;形参则是函数名后括号内的变量,在函数结束后就自动销毁了,所以形参只在函数中有效。

当实参传递给形参的时候,形参其实是实参的一份临时拷贝,对形参的修改是不会改变实参的。

函数的调用

传值调用

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

传址调用

把函数外部变量的内存地址传递给形式参数,可以让函数直接操作函数外部的变量。

二分查找(函数版)

int binary_search(int arr[],int k)
{
    int sz = sizeof(arr)/sizeof(arr[0]);
    int left = 0;
    int right = sz - 1;
    
    while(left<=right)
    {
        int mid = (left + right)/2;
        if(arr[mid]<k)
        {
            left = mid + 1;
        }
        else if(arr[mid]>k)
        {
            right = mid - 1;
        }
        else
        {
            return mid;
        }
    }
    return -1;
}

int main()
{
    //二分查找算法
    //在一个有序数组中查找具体某个数字
    //找到则返回下标,找不到则返回-1

    int arr[] = {1,2,3,4,5,6,7,8,9,10};
    int k = 7;
    int ret = binary_search(arr,k);
    if(ret == -1)
    {
        printf("找不到\n");
    }
    else
    {
        printf("找到了,下标为:%d\n",ret);
    }
    return 0;
}

经过该代码,竟然发现输出结果始终为找不到,说明代码出了问题。

这是因为数组在传递过程中出了“意外”。我们知道,数组内的元素数量是可以很大的,如若向变量一样使用函数时再新建一个,那么对储存来说压力很大,所以数组再传递过程中实际上传递的是数组arr的首元素地址,因此可以说arr在传递过程中本质上是一个指针。也是因为只传递了第一个元素的地址,所以代码函数中的sz始终是1。对此,只要在外部计算好sz便可以解决这个问题。

int binary_search(int arr[],int k,int sz)
{
    int left = 0;
    int right = sz - 1;
    
    while(left<=right)
    {
        int mid = (left + right)/2;
        if(arr[mid]<k)
        {
            left = mid + 1;
        }
        else if(arr[mid]>k)
        {
            right = mid - 1;
        }
        else
        {
            return mid;
        }
    }
    return -1;
}

int main()
{
    //二分查找算法
    //在一个有序数组中查找具体某个数字
    //找到则返回下标,找不到则返回-1

    int arr[] = {1,2,3,4,5,6,7,8,9,10};
    int sz = sizeof(arr)/sizeof(arr[0]);
    int k = 7;
    int ret = binary_search(arr,k,sz);
    if(ret == -1)
    {
        printf("找不到\n");
    }
    else
    {
        printf("找到了,下标为:%d\n",ret);
    }
    return 0;
}

tip:*的运算等级在后置++之后,所以要这样写:(*p)++,※容易忽略

 嵌套调用

即一个函数体的内部可以调用另一个函数

链式访问

即把一个函数的返回值当作另一个函数的参数

int main()
{
    printf("%d",printf("%d",printf("%d",43)));
    return 0;
}

//output:
//4321

通过网站库函数查找了解得知printf有返回值,返回打印字符数,所以这里打印4321 。

函数的声明和定义

函数声明:

Ⅰ 告知函数名、参数、返回类型等信息;

Ⅱ 函数声明一般在函数使用之前,满足先声明后使用;

Ⅲ 函数的声明一般放置在头文件中

函数的定义:

函数的具体实现与功能

例:

//函数声明 add.h
int Add(int x, int y);
//函数的定义 add.c
int Add(int x, int y)
{
    int z = x+y;
    return z;
}
//函数调用 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语言心得与笔记记录,部分举例来源于B站C语言教学up主鹏哥 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

犀利卓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值