美文网首页
万变不离其宗:C语言函数的灵魂思想

万变不离其宗:C语言函数的灵魂思想

作者: KangSmit的算法那些事儿 | 来源:发表于2020-05-02 23:30 被阅读0次
封面

学会思想就够了!
理解获得意想不到的结果——新技术的诞生!

函数定义公式:


image.png

函数可以作为定义返回值,也可作为函数内部的应用函数。
注意:每个C程序的入口和出口都位于main函数之中。编写程序时,并不是将所有的内容都放在主函数main中。

函数调用的一般形式为:
functionName(param1, param2, param3 ...);

functionName 是函数名称,param1, param2, param3 ...是实参列表。实参可以是常数、变量、表达式等,多个实参用逗号,分隔。

先来看一个例子:

1、函数的声明

注意:这里的函数为新定义的函数,以下是声明函数之后,主函数调用其他函数。

#include<stdio.h>

int Function();         /*声明函数*/

int main()
{
    printf("我在函数之前\n"); /*输出提示信息*/
    Function();     /*调用函数*/
    printf("函数的结尾\n");  /*输出提示信息*/
    return 0;
}

int Function()      /*定义函数*/
{
    printf("我是函数\n");       /*输出提示信息*/
    /*函数结束*/
}

执行结果:

image.png

当然我们可以把定义的函数和主函数程序块交换一个位置,结果仍然相同,因此主函数总是去调用定义的新函数内容。这主要看个人的书写习惯吧!我比较喜欢把定义的函数放在前面,主函数放在后面。即:

#include<stdio.h>

int Function();         /*声明函数*/


int Function()      /*定义函数*/
{
    printf("我是函数\n");       /*输出提示信息*/
    /*函数结束*/
}

int main()
{
    printf("我在函数之前\n"); /*输出提示信息*/
    Function();     /*调用函数*/
    printf("函数的结尾\n");  /*输出提示信息*/
    return 0;
}

执行结果:


image.png

类似地,我们这里举出一个简单例子:

#include<stdio.h>
/*自定义一个函数*/
int fun2020(int x,int y)
{
    if((x*x+y*y)%2==0)
    {
        return 0;
    }
    else
    {
        return 1;
    }
 } 
 
 /*定义一个主函数去调用上诉函数*/
 int main()
 {
    int num1,num2,i,j;
    printf("请输入两位数:\n");
    scanf("%d%d",&num1,&num2);
    /*声明调用的函数*/ 
    i=fun2020(num1,num2);
    j=num1*num1+num2*num2;
    if(i==0)
    {
        printf("%d和%d的平方和%d是偶数\n",num1,num2,j); 
    }
    else
    {
        printf("%d和%d的平方和%d是奇数\n",num1,num2,j);
    }
     
  } 
 

执行结果:

请输入两位数:
66
88
66和88的平方和12100是偶数

2、函数的参数调用

递归:

#include<stdio.h>
/*自定义一个函数*/
int fun2020(int n)
{
    int m;
    if(n==0||n==1)
    {
        return m=1;
    }
    else
    {
        m=n*fun2020(n-1);
    }
    return m;
 } 
 
 /*定义一个主函数去调用上诉函数*/
 int main()
 {
    int i,j;
    printf("请输入一个数:\n");
    scanf("%d",&i);
    if(i<0)
    {
        printf("输入错误 \n"); 
    }
    else
    {
        j=fun2020(i);
        printf("%d的阶乘为%d",i,j);
    }
     
  } 
 

受到以上方法的启发,这里来判断三角形

/*三角形*/
#include<stdio.h>
#include<stdlib.h>
/*自定义一个函数*/
int feimagougu(int a, int b,int c)
{ 
    if(((a+b)>c&&abs(a-b)<c))
    {
        return 0;
    }
    else
    {
        return 1;
    }
 } 
 
 /*定义一个主函数去调用上诉函数*/
 int main()
 {
    int x,y,z,i;
    printf("请输入三个数:\n");
    scanf("%d%d%d",&x,&y,&z);
    /*一定别忘了要声明函数,不然不能调用*/
    i=feimagougu(x,y,z);
    if(i==0)
    {
        printf("是三角形 \n"); 
        printf("这三边长分别为%d,%d和%d",x,y,z);
    }
    else
    {
        printf("不是三角形 \n"); 
    }
    
  } 
 

执行结果:

image.png

同样的方法,可以获得如下:

3、输入任意三个数判断是否为勾股数

/*任意输入三个数,判断是否为勾股数*/
#include<stdio.h>
/*自定义一个函数*/
int feimagougu(int a, int b, int c)
{ 
    if((a*a+b*b)==(c*c))
    {
        return 0;
    }
    else
    {
        return 1;
    }
 } 
 
 /*定义一个主函数去调用上诉函数*/
 int main()
 {
    int x,y,z,i;
    printf("请输入三个数:\n");
    scanf("%d%d%d",&x,&y,&z);
    /*一定别忘了要声明函数,不然不能调用*/
    i=feimagougu(x,y,z);
    if(i==0)
    {
        printf("这三个数为勾股数 \n"); 
        printf("这三个数分别为%d,%d和%d",x,y,z);
    }
    else
    {
        printf("这三个数为非勾股数 \n"); 
    }
    
  } 
 

执行结果:

image.png

4、调用其他函数

其实从上面的函数之间的调用分析,我们已经知道函数调用的初步过程了,为了更细说明其中的思想,那么如何在函数之间互相调用取值?这里再举例说明:


image.png
/*在主函数中调用其他函数*/
#include<stdio.h>
void Move();    /*声明搬运函数*/
void Build();   /*声明建造函数*/
void Paint();   /*声明粉刷函数*/

//使用主函数main调用其他函数 
int main()
{
    Move(); /*执行搬运函数*/
    Build();        /*执行建造函数*/
    Paint();    /*执行粉刷函数*/
    return 0;   /*程序结束*/
}

//构造各个函数的功能和方法 
/*执行搬运功能  */
void Move()
{
    printf("这个函数可以搬运货物\n");
}
/*执行建造功能  */
void Build()
{
    printf("这个函数可以建造一栋高楼\n");
}
/*  执行粉刷功能  */
void Paint()
{
    printf("这个函数可以粉刷墙面\n");
}

执行结果:

image.png

备注:

返回值类型为void的方法.
定义格式:
修饰符  void 方法名(参数列表){
    方法体;
    return; // 可以省略
}

void: 空的意思, 不能用来定义变量,只能用来作为返回值类型使用

注意点:
1. 不能定义变量来接收
2. 不能直接放在输出语句中


5、返回值的调用

以下是一输入任意两数求差的例子:

#include<stdio.h>
//先声明定义的函数 
int Fun(int iNumber1,int iNumber2);

//定义一个函数Fun
int Fun(int iNumber1,int iNumber2)
{
    int iResult;    /*定义一个整型变量用来存储返回的结果*/
    //以上定义的iResult也可定义多个 
    iResult=iNumber1-iNumber2;  /*进行减法计算,得到计算结果*/
    return iResult; 
    /*return语句返回计算结果,这里要注意的是,返回值给了函数,
    一般只能返回一个值,因此其他函数调用它时调用的return返回的结果*/
}

//定义一个主函数main调用以上函数 
int main()
{
    
    int x,y,Result; /*定义3个整型变量*/
    printf("请任意输入两个数:\n");
    scanf("%d%d",&x,&y);
    Result=Fun(x,y);/*进行x-y的减法计算,并将结果赋值给变量iResult*/
    printf("Fun(%d,%d)=%d\n",x,y,Result); 
    return 0;   /*程序结束*/
}
//切记,定义函数中的iResult和主函数中Result不能重名,否则报错或不能运行 
//scanf()函数里的参数一定别忘了取地址符:& 
 

执行结果:

image.png

6、使用数组元素作为函数参数

由于实参可以是表达式形式,数组元素可以是表达式的组成部分,因此数组元素可以作为函数的实参,与用变量作为函数实参一样,是单向传递。

#include<stdio.h>
void ShowMember(int iMember);   /*声明函数*/


void ShowMember(int iMember)    /*函数定义*/
{
    printf("这名员工的编号为00%d\n",iMember);/*输出数据*/
}


int main()
{
    int iCount[10]; /*定义一个整型的一维数组*/
    int i;      /*定义整型变量,用于循环*/
    for(i=0;i<10;i++)   /*进行赋值循环*/
    {
        iCount[i]=i;    /*为数组中的元素进行赋值操作*/
    }
    for(i=0;i<10;i++)       /*循环操作*/
    {
        ShowMember(iCount[i]);/*执行输出函数操作*/
    }
    return 0;
}


执行结果:

image.png

类似地,我们再举一个有难度的例子,计算一个函数列二维数组,生成10*10矩阵值:

\begin{array}{l} a(i,j) = \cos i + \sin j + {e^{i - j}} + {( - 1)^{i + j}}, {\rm{ where }} i,j{\rm{ = 0}},{\rm{1}}, \cdots ,{\rm{9}}{\rm{.}} \end{array}

#include<stdio.h>
#include <math.h>
#include <complex.h>
void ShowMember(int k,int l,int iMember);   /*声明函数*/


void ShowMember(int k,int l,int iMember)    /*函数定义*/
{
    
    printf("a[%d][%d]=%4d  ",k,l,iMember);/*输出数据*/
}


int main()
{
    int iCount[10][10]; /*定义一个整型的数组*/
    int i,j;        /*定义整型变量,用于循环*/
    for(i=0;i<10;i++)   /*进行赋值循环*/
    {
        for(j=0;j<10;j++)
        {
            iCount[i][j]=cos(2*i)+sin(2*j)+exp(i-j)+pow(-1,i+j);    /*为数组中的元素进行赋值操作*/
        }   
    }
    
    for(i=0;i<10;i++)       /*循环操作*/
    {
        for(j=0;j<10;j++)
        {
            ShowMember(i,j,iCount[i][j]);/*执行输出函数操作*/
        }
    printf("\n");//生成10*10矩阵形式 
    }
    return 0;
}


执行结果:

image.png

备注:还可以使用指针作为函数参数,也就是将函数参数声明为一个指针,例如:

#include<stdio.h>
void  Evaluate(int* pPoint);/*声明函数,参数为可变长度数组*/
void  Display(int* pPoint);/*声明函数,参数为可变长度数组*/
int main()
{
      int iArray[10];   /*定义一个具有10个元素的整型数组*/
    ......
}

void  Display(int* pPoint)/*定义函数,参数为可变长度数组*/
{
    ......
}

void  Evaluate(int* pPoint) /*定义函数,参数为可变长度数组*/
{
    ......
}


7、主函数参数main()

运行程序时,有时需要将必要的参数传递给主函数。
主函数main的形式参数如下:
main (int argc, char * argv[] )
两个特殊的内部形参argc和argv是用来接收命令行实参的,这是只有主函数main才能具有的参数。

  • argc参数: argc参数保存命令行的参数个数,是整型变量。这个参数的值至少是1,因为至少程序名就是第一个实参。
  • argv参数: argv参数是一个指向字符指针数组的指针,这个数组里的每一个元素都指向命令行实参。所有命令行实参都是字符串,任何数字都必须由程序转变成为适当的格式。

argc、argv的具体含义

argc和argv参数在用命令行编译程序时有用:
main( int argc, char* argv[], char **env )

第一个参数,int型的argc,为整型,用来统计程序运行时发送给main函数的命令行参数的个数,在VS中默认值为1。
第二个参数,char*型的argv[],为字符串数组,用来存放指向的字符串参数的指针数组,每一个元素指向一个参数。各成员含义如下:

  • argv[0]指向程序运行的全路径名
  • argv[1]指向在DOS命令行中执行程序名后的第一个字符串
  • argv[2]指向执行程序名后的第二个字符串
  • argv[3]指向执行程序名后的第三个字符串
  • argv[argc]为NULL

第三个参数,char**型的env,为字符串数组。env[]的每一个元素都包含ENVVAR=value形式的字符串,其中ENVVAR为环境变量,value为其对应的值。平时使用到的比较少。

下面给出例子说明:


image.png

8、指针作为函数参数

指针变量作参数后就很容易解决上面的问题:

#include <stdio.h>
void swap(int *p1, int *p2){
    int temp;  //临时变量
    temp = *p1;
    *p1 = *p2;
    *p2 = temp;
}
int main(){
    int a = 2019, b = 2020;
    swap(&a, &b);
    printf("a = %d, b = %d\n", a, b);
    return 0;
}

运行结果:

a = 2020, b = 2019

调用 swap() 函数时,将变量 a、b 的地址分别赋值给 p1、p2,这样 p1、p2 代表的就是变量 a、b 本身,交换 p1、p2 的值也就是交换 a、b 的值。函数运行结束后虽然会将 p1、p2 销毁,但它对外部 a、b 造成的影响是“持久化”的,不会随着函数的结束而“恢复原样”。

需要注意的是临时变量 temp,它的作用特别重要,因为执行*p1 = *p2;语句后 a 的值会被 b 的值覆盖,如果不先将 a 的值保存起来以后就找不到了。

相关文章

  • 万变不离其宗:C语言函数的灵魂思想

    学会思想就够了!理解获得意想不到的结果——新技术的诞生! 函数定义公式: 函数可以作为定义返回值,也可作为函数内部...

  • iOS开发 -- C语言基础3(函数)

    iOS开发 -- C语言基础3(函数) 什么是函数 一、函数的分类 C语言中的函数就是面向对象中的"方法",C语言...

  • 是否还需要在源文件中添加“extern C”?

    c++调用c语言的函数时我们一般在c语言函数声明处用extern "C"包c函数。例如: extern "C"的主...

  • gcc

    C语言 c语言是面向函数的语言,所以c语言中全部都是函数 看看单文件中对函数的生命和调用。 要先对函数进行声明再进...

  • 2018-08-29日常C笔记

    C语言初学笔记 C语言程序是由函数组成的C语言程序启动时,系统就会自动调用名字叫main的函数C语言规定了函数定义...

  • Redis 源码简洁剖析 02 - SDS 字符串

    C 语言的字符串函数 C 语言 string 函数[https://devdocs.io/c-strings/],...

  • 函数变参的使用

    介绍C/C++,java,和go语言对函数变参的使用。 1. C/C++语言的变参 1.1 变参函数声明 变参函数...

  • 2.头文件与类的声明

    C语言和C++语言中 函数与数据使用方法的不同 C语言中由于C语言中没有某些关键字,所以数据可以被全部函数所使用 ...

  • 游戏开发中的ECS架构实用性如何?

    其实ECS并不是什么新的东西,它的思想早在程序刚开始的时候就有了,学过C语言的同学都知道 C语言写代码基于 函数逻...

  • scanf函数

    scanf函数 一、是什么? C语言下的scanf()函数是样式化输入函数,也称为阻塞式函数,有C语言自带的库提供...

网友评论

      本文标题:万变不离其宗:C语言函数的灵魂思想

      本文链接:https://www.haomeiwen.com/subject/metlghtx.html