C语言-函数-学会方程你的数学能力会乘风破浪突飞猛进-学会函数你的编程能力将百尺竿头更进一步

    技术2025-01-13  16

    工欲善其事,必先利其器。

    方程是一种数学工具,列方程解方程能够有效解决数学问题。

    函数是一种编程技巧,设计函数实现函数能够提高程序设计的效率。

    函数之所以难学,是因为它太多变了,有多种形态。

    课本不写全吧,作者会被骂。

    课堂不讲全吧,老师会被骂。

    于是乎,老师满堂灌,学生糊涂蛋。

    学生要想不当糊涂蛋,必须拼命地训练。

    师傅领进门,修行在个人,绝不是推诿责任,而是事物发展的规律。

    客官,如果您有时间,请慢慢听我胡扯。

    一、建议初学者,把变量定义全部写在函数外,成为全局变量

    #include<stdio.h> int a,b,c; void main(void) { scanf("%d%d",&a,&b); c=a+b; printf("%d\n",c); }

    这样理解:

    1、把这个程序整体看做一个学校,a、b、c相当于书记、校长、副校长的名字;

    2、main函数相当于学校的一个系;这个程序简单,所以暂时只有一个系;

    3、main函数内部相当于系的内部,系内部当然都知道校领导们的名字

    怎么样,通俗易懂吧。

    注:对于各种程序设计竞赛,主要考察算法,因此总体上程序代码不会太长,而且对效率的要求比较高,采取这种全局变量是经常性的手段。

    二、代码闹独立,要称王

    我们可以像main函数一样,再设计几个其他函数,把程序代码封装起来。

    例如:

    #include<stdio.h> int a,b,c; void input(void) { scanf("%d%d",&a,&b); } void calculate(void) { c=a+b; } void output(void) { printf("%d\n",c); } void main(void) { input();//输入 calculate();//计算 output();//输出 }

    (函数调用示意图,来自百度图片搜索)

    分析:

    1、main函数的代码都不安分,一气化三清,代码独立啦,分解为新的三个函数,input、calculate、output

    2、好处是,分而治之好管理了,等大家遇到比较复杂的程序,超过100行那种,就理解得深刻了。

    3、如果到此为止,大家一定会说,函数真得太好了,使得程序逻辑更清楚了,也根本没什么难度嘛。

    注意:到此为止,你已经能够用函数参加竞赛了,而且如果你算法好的话,拿个冠军都可以。

    下面的部分,都是要考虑到大型程序,多人协作时容易产生函数名冲突、变量名冲突,而采取的措施,是越来越复杂。


    函数理论复杂就复杂在,他不提倡使用全局变量(即在函数外定义变量),因为多个函数共享变量容易出矛盾,程序结果出现问题不太容易追责。他们的理想是,每一个函数是一个独立王国,只有一个入口和一个出口,来我国的人,必须从入口进,从出口出。也可以把每一个函数比作一个机器,比如榨汁机,苹果塞进去,苹果汁出来;葡萄塞进去,葡萄汁出来。内部怎样实现的,使用的人不必知道。

    好了,这样以来,事情变复杂了。就好比两个男女青年谈恋爱,本来是以爱情为主,一见钟情,电光石火,水到渠成。现在非要加上一些其他条件,什么高富帅、白富美,结果剩男剩女一大堆,问题不好优化啊。

    我们先改造代码。

    三、改造我们的代码

    #include<stdio.h> void input(int *a,int *b) { scanf("%d%d",a,b); } int calculate(int a,int b) { int c; c=a+b; return c; } void output(int c) { printf("%d\n",c); } void main(void) { int a,b,c; input(&a,&b);//输入 c=calculate(a,b);//计算 output(c);//输出 }

    分析:

    1、为了达到每个函数独立的目的,还需要有理论的支撑。函数外定义的变量叫“全局变量”,函数内定义的变量叫“局部变量”。全局变量、局部变量各在内存的什么地方分配才能高效?

    2、mai函数的a、b和input中的a、b只是重名而已,但是他们不在同一个系,不会冲突。什么样的机制才能保障他们不冲突?

    3、以上,说出来轻松,编译程序却要精心设计,才能应对变化。

    4、最主要的,这些设计的原理,却会成为找工作时面试官的题目。所以在各种课本,函数不仅单独一章,还和其后各章相关联。

    因此,同志们,同学们,在大一的阶段,40个课时,只能学基本语法,就像幼儿园学个拼音、儿歌、数个数,哪能讲什么语法,讲了也没什么效果。

    C 语言背后原理,或者其他语言背后的原理,有一门课叫做编译原理的,会慢慢到来。

    你想,一门课的东西,你非要你的C语言老师给你讲清楚,臣妾估计也是打死都做不到啊。

    编译原理三大经典书籍(龙书 虎书 鲸书):

    https://blog.csdn.net/shenwansangz/article/details/44217233

    编译原理三大圣书——龙书、虎书、鲸…

    https://blog.csdn.net/xiaolanmyself/article/details/16944135

    同学,你骨骼不太惊奇,不建议你看,知道这三本书的名字,会吹吹牛bi得了。

    如果你去看了,我怕你会“学习计算机编程,从入门到放弃”......

    四、函数语法

    函数返回值类型   函数名(参数列表)

    {

    //函数体

    }

    上面就是函数的语法形式。

    就像是自然语言有语法一样,程序设计语言也是有语法的。

    你写文章头疼,编程也会头疼。只不过编程要比写文章简单很多。

    其中最难的是,参数列表的写法与解释。

    无他,唯手熟尔。

    只有多读程序,多写程序,才能够掌握。

    可是,亲爱的计算机专业大学生们,每个学期那么多课程,怎么会有时间写程序呢?

    无他,唯有舍得,舍弃哪些对你的人生目标不重要的科目,及格就行;把功夫放在编程上,才能得到!

    1、简单数据传值

    void func(int a,int b)

    {.....}

    参数 int a,int b;就是最普通的定义方法,因此是传值。

    2、简单数据传地址

    void func(int *a,int *b)

    {.....}

    参数 int *a,int *b; 是指针的形式,因此a、b中只能存储地址值

    3、关于返回值

    int calculate(int a,int b) {     int c;     c=a+b;     return c; }

    函数体中可以用 return语句返回一个值。那么return后面那个量的类型是什么,函数的返回值类型就设计成什么。

    4、传递一维数组

    void func(int a[],int n)

    {.......}

    void func(int *b,int n)

    {.......}

    这两种写法等价。或者说,前者的本质是后者,前者符合人们日常思维习惯,后者符合计算机计算思维。

    5、传递二维数组

    #define N 100

    void func(int a[][N],int n)

    {.......}

    void func(int *b[100],int n)

    {.......}

    这两种写法等价。或者说,前者的本质是后者,前者符合人们日常思维习惯,后者符合计算机计算思维。

    6、传递结构体

    struct node

    {

    int a;

    int b;

    };

    void func(struct node mynode){.....}

    void func(struct node *mynode){.....}

    结构体可以定义复杂类型,其和函数的结合,解释同普通变量

     

    五、函数指针

    本部分目的:基于函数指针,介绍C语言中快速排序函数的用法。

    因此是一石二鸟,既介绍了函数指针,也介绍了快速排序函数。

    在此基础上如果你能想到,啊,原理函数指针能够增加函数设计的通用性,有利于代码复用,那你是非常有悟性的。

    qsort:quick sort,快速排序。

    其出世之日,电闪雷鸣,震惊了世界,其他排序算法的速度不能望其项背。

     

    1、项目驱动

    对于一个整数数组,请分别对其中数据进行升序和降序排列。

    2、函数原型

    •#include <stdlib.h> //头文件

    •void qsort( void *buf, size_t num, size_t size, int (*compare)(const void *, const void *) );

    •buf:待排序数据的首地址

    •num:待排序数据个数

    •size:每个数据的大小,单位是字节

    •compare:比较函数。

    •可以通过重新定义compare比较函数,来调整是升序还是降序。

    int (*compare)(const void *, const void *) 这是函数的原型,即你必须按照这种个数来自己定义该函数。

    3、比较函数的写法

    int Asending(const void *x,const void *y) {//升序比较函数 int *a,*b; a=(int*)x; b=(int*)y; if(*a>*b) return 1; else if(*a==*b) return 0; else return -1; } int Desending(const void *x,const void *y) {//升序比较函数 int *a, *b; a=(int*)x; b=(int*)y; if(*a>*b) return -1; else if(*a==*b) return 0; else return 1; }

    注意:比较函数的名字无所谓,但是其参数和返回值类型是系统规定好的。你必须符合规则。

    4、主函数

    void printArray1D(int a[],int n) {//打印数组中数据 int i; for(i=0;i<n;i++) { printf("%d ",a[i]); } printf("\n"); } int main() { int a[]={1,4,6,2,5,3};//数组 int n=sizeof(a)/sizeof(int);//数据个数 //升序排列 qsort(a,n,sizeof(int),Asending); printArray1D(a,n) ; //降序排列 qsort(a,n,sizeof(int),Desending); printArray1D(a,n) ; return 0; }

    注意:主调函数在调用qsort时,把比较函数当作参数传递给qsort,其内部机制为:

    x会指向a[i],y会指向a[j]

    若compare(x,y)返回值为1,则交换a[i]和a[j]的值,否则不交换。

    所以你调整比较函数的返回值是 1 还是 -1,就能调整是升序还是降序。

    5、对复杂类型数据排序

    当数据不是简单数据类型时,比如对平面上的点排序,先按照x的大小从小到大排,如果x相等,则按照y的值从小到大排。

    #include<stdio.h> #include<stdlib.h> struct point { int x; int y; }; int Asending(const void *x,const void *y) {//升序比较函数 struct point *a,*b; a=(struct point*)x; b=(struct point*)y; if(a->x > b->x) return 1; else if(a->x == b->x) { if(a->y > b->y) return 1; else if(a->y == b->y) return 0; else return -1; } else return -1; } int Desending(const void *x,const void *y) {//升序比较函数 struct point *a,*b; a=(struct point*)x; b=(struct point*)y; if(a->x > b->x) return -1; else if(a->x == b->x) { if(a->y > b->y) return -1; else if(a->y == b->y) return 0; else return 1; } else return 1; } void printArray1D(struct point a[],int n) {//打印数组中数据 int i; for(i=0;i<n;i++) { printf("(%d %d) ",a[i].x,a[i].y); } printf("\n"); } int main() { struct point a[]={{2,8},{2,6},{1,9},{1,7}};//数组 int n=sizeof(a)/sizeof(struct point);//数据个数 printArray1D(a,n) ; //升序排列 qsort(a,n,sizeof(struct point),Asending); printArray1D(a,n) ; //降序排列 qsort(a,n,sizeof(struct point),Desending); printArray1D(a,n) ; return 0; }

    运行结果:

     

    (over) 

     

    Processed: 0.008, SQL: 9