函数

函数是C语言重要的组成部分,你现在,或者以后(如果C没什么变化的话)所写的任何一个C语言程序都是由一个一个的函数组合在一起的,当然,现在或许你只会在主函数 main中写一个小程序,那么在看了本篇文章后,我觉得自己编写多个函数在一个程序中运行肯定不是问题啦,对于理解C语言的模块化编程也有很大的帮助。

前面已经学过很多数据类型,如指针,数组,结构体,等数据类型,想想,在使用之前,我们首先需要进行什么操作? 没错,首先是定义。当然,使用函数之前也要先定义一个函数。下面给出如何定义:

类型说明符 函数名 (传递的参数类型 行参名...)

{

    //此处的内容与主函数 main()大括号的一样

}

想一想,上面的定义方式是否感觉很眼熟?

还记得你接触的第一个程序吧?它的核心部分就是

int main()

{

//内容

return 0;  

}


其实这就是一个主函数,每一个c语言程序的运行都需要它的存在。它的名称是被固定的,不可整改的,即 main,会发现,main后面的小括号里面什么也没有,这说明这个main函数是不带参数的,这也是我们经常使用的。当然main函数也可以带参数,形如 int main(int argc,char *argv[]) ,具体可参见:http://blog.csdn.net/cnctloveyu/article/details/3905720   

上面的定义格式中的类型说明符指明了函数的返回值类型(一般所写的main函数最后都有 return 0;这代表运行正常, 也可以省略,如果省略编译时会自动加上,所以main函数的返回值为 int ),如果没有返回值 需要加上 void 代表返回值为空。形如 void print(){} 现在这就表示定义了一个返回值类型为空的名称为print且没有形式参数的函数。下面我将使用到自己定义的print函数。

#include<stdio.h>
void print() //print函数的定义
{
printf("you are someone\n"); //语句
return ;
}
int main()
{
print();//在主函数中调用print函数
}

运行结果:

假如没有在主函数中调用所写的print函数,程序也没错,但是print也就没用到了。了解一个程序的执行过程是很关键的一步,作为一个C语言程序的运行顺序,简单来说就是以main函数为出发点,从上到下是根本,然后跟着所写的语句执行这个顺序。

下面再写一个稍微复杂的程序:比较两个数a,b的大小,如果a大,输出a,如果b大,输出b。

#include<stdio.h> //
int Max(int c,int d) //Max函数的定义 //
{
//此时c的值等于a的值,d==b
//如果c比d大,Max的返回值为c,否则,返回值为d
if(c>d) //
return c; //
else //
return d; //7
}
int main()
{
int a,b,c;//
scanf("%d%d",&a,&b);//3
//将a的值穿给形式参数 c,将b的参数穿给d
//将Max的返回值,即a,b的最大值赋值给c
c=Max(a,b);//4 //
printf("%d\n",c);//输出c //
return ; //
}

(附加:外部函数应该写在什么位置?

一般来说,为了方便起见,把外部函数放在调用它的函数的上方,这样可以不用再在主函数中对其进行申明。如果要放在你想放的位置,则必须要在主函数中对这个函数申明,以上面的程序为例,申明Max函数,需要在主函数里面加上申明语句:int Max(int c,int d);c和d这两个标识符可以去掉

#include<stdio.h> //

int main()
{
int a,b,c;
int Max(int c,int d); //2
//Max函数的申明,这样可以把Max函数放在main函数的后面
//一般都把申明与数据的定义放在同一位置
//或者 int Max(int,int);
scanf("%d%d",&a,&b);//3
//将a的值穿给形式参数 c,将b的参数穿给d
//将Max的返回值,即a,b的最大值赋值给c
c=Max(a,b);//4 //
printf("%d\n",c);//输出c //
return ; //
}
int Max(int c,int d) //Max函数的定义 //
{
//此时c的值等于a的值,d==b
//如果c比d大,Max的返回值为c,否则,返回值为d
if(c>d) //
return c; //
else //
return d; //7
}

比较一下上面两个程序的区别)

上面的程序就实现了求两个数当中的最大值。程序的运行顺序为 程序中所标注的 1~10  ,重复代表有可能是重复当中的某一个。现在看看这两个程序,与最上面的程序相比是不是多了很多东西? 第二和第三个程序定义了一个Max函数,它有返回值,所以return后面接的是一个与这个返回值一致的某个数或者表达式,第一个程序,定义了返回值的类型为void类型,为空,所以没有返回值,没有返回值可以写作 return;或者空着不写这一语句. 另外可以看到我在main函数中定义了变量c,同时,在Max函数中我也定义了一个变量c,作为形参。不是说,程序中的变量名不能相同吗?其实,这和变量的作用域有关。变量分为 两种,全局变量和局部变量,全局变量即在函数外部定义的变量,局部变量是在函数内部定义的变量,前面可能没提到过,全局变量只需要在函数的外部定义一次,即能在其下方所有的函数中使用这个变量,而局部变量定义在函数的内部,只能在这一个函数中使用,如果其他的函数要用到它,需要进行参数的传递,1.通过值传递,2.通过地址传递 ,传递给需要用到的那个函数。

下面讲讲这两种传递吧

1.值传递

只能传递某些变量的数值到自定义的函数里面,而不能访问变量的地址,不能访问变量的地址就意味着不能在自定义的函数体里面对这个变量进行操作,前面所写的比较两个数的大小就用到了值传递,因为在这个地方我们只需要了解到a,b两个的值,就可以判断到底是a大还是b大,并不需要对a与b的值进行更改等操作。

然而,很多时候,我们并不是只是想知道某个变量的值,例如:给你两个数,让你交换两个数的位置,然后输出。看到这,你肯定会想这不是很简单的事吗!!于是你就写出了下面的这些程序:

way1

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

way2

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

相信上面的两个程序你能够写出来。当然它们也都是十分正确的。可是我现在讲的是关于函数参数的地址传递啊,所以在实现这个程序的同时,我还要求你用到函数,并且其参数是地址,想想吧,现在应该怎么做呢?

回想上一讲的内容,指针,指针不正可以存放地址吗,可以通过指针接收主函数中的变量的地址,然后传送到自定义的函数中去,之后,在自定义的函数中就可以访问到主函数中的地址了,能访问地址,就能对与地址对应的变量进行操作。

code:

#include<stdio.h>
void swap(int *p,int *q) //指针p,q作为swap函数的形参,分别接收来自主函数的a,b的地址
{
//此时 *p和在主函数中的a一样,只是名字不一样,*q同理
int c;
c=*p;
*p=*q;
*q=c;
return; //因为是无返回void型的函数,也可以直接去掉这一行
}
int main()
{
int a,b;
scanf("%d%d",&a,&b); //输入两个数
swap(&a,&b);//&为取地址符,这样就可以把a和b的地址作为函数的实参传递给swap函数
printf("%d %d\n",a,b);//输出a和b
}

上面的代码与前面写的两个代码的功能是完全一样的,只是上面的代码有助于理解内容,所以复杂化了。

如果你看懂了这个代码,你可能会想,用其他的方法能不能实现呢?难道一定要用到指针吗?

很多人容易犯的错误就是不通过地址传递,通过值传递就想实现这,那么,可以编写一下试试,

code:

#include<stdio.h>
void swap(int p,int q)
{
//交换p与q的值
int c;
c=p;
p=q;
q=c;
//此时p与q的值被交换了,但是a与b的值并没有被交换
return; //swap函数结束
}
int main()
{
int a,b;
scanf("%d%d",&a,&b);
swap(a,b);//把a与b的数值传递给swap函数,在swap函数中不能再次访问到a与b
printf("%d %d\n",a,b);//输出a和b,结果与输入的一样,并没有交换
return ;
}

当然把主函数中的printf("%d %d\n",a,b);删掉。然后再再swap函数中的return;上面加上一句printf("%d %d\n",p,q);。这样也能实现功能,但是这样和上面的第五个程序并没有本质的区别。

还有一个方法,记得前面提到的全局变量不。它的作用域是它的定义下面的所有的函数。

code

#include<stdio.h>
int a,b;//定义a,b为全局变量,作用于下面的所有函数
void swap()
{
//交换a和b
int c;
c=a;
a=b;
b=c;
return; //swap函数结束
}
int main()
{
scanf("%d%d",&a,&b);
swap();//无需传递参数,因为a与b一直都存在于main主函数和swap函数
printf("%d %d\n",a,b);
return ;
}

由于重复的代码比较多,所以就不放上运行结果了。可以自己粘贴运行一下。

这样也实现了相同的功能。因为a,b是全局变量,所以不用通过地址传递也能在swap中访问到a与b的地址

关于函数的就说这么多吧。虽然还有不少没提到,不过这也足够初学者去理解了。

简单学C——第七天的更多相关文章

  1. [老老实实学WCF] 第七篇 会话

    老老实实学WCF 第七篇 会话 通过前几篇的学习,我们已经掌握了WCF的最基本的编程模型,我们已经可以写出完整的通信了.从这篇开始我们要深入地了解这个模型的高级特性,这些特性用来保证我们的程序运行的高 ...

  2. 从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator-更新至Prism7.1

    原文:从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator-更新至Prism7.1 事件聚合器EventAggregator [7.1updated]除了app部分,没 ...

  3. 从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator?

    原文:从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator? 从PRISM开始学WPF(一)WPF? 从PRISM开始学WPF(二)Prism? 从PRISM开始学WP ...

  4. NOIP模拟测试29「爬山·学数数·七十和十七」

    爬山题解不想写了 学数数 离散化然后找到以每一个值为最大值的连续子段有多少个,然后开个桶维护 那么怎么找以每一个值为最大值的连续子段个数 方法1(我的极笨的方法) 考试时我的丑陋思路, 定义极左值为左 ...

  5. 简单学C——第四天

    数组 在学数组之前,有必要把前面的知识复习一遍,当然我的复习,仅仅只是提一下,而对于你,则应该认真的看一下前面的知识点,不懂可以百度,哈哈. 前面我们大致学了 1.定义变量,2.数据的输入与输出,3. ...

  6. 简单学C——第二天

                 控制结构(-) 相信大家对流程图肯定很熟悉.下面我将介绍的正是关于此方面的,c语言中,控制结构大体分为选择结构和循环结构. 一.选择结构:     先贴出一般用于选择结构的语 ...

  7. 简单学c——前言

      1.学C语言需要什么基础吗? 零基础. 2.什么是C语言? C语言是一种编程语言. 3.什么是编程语言? 编程语言是用来定义计算机程序的形式语言,是一种被标准化的交流技巧,用来向计算机发出指令. ...

  8. 8.22 NOIP模拟测试29(B) 爬山+学数数+七十和十七

    T1 爬山 二分最高高度,$O(1)$判断是否可行. #include<iostream> #include<cstdio> #define ll long long usin ...

  9. 从零开始学Python第七周:面向对象进阶(需修改)

    一,类的属性 (1)示例 通过属性获取已经创建对象的个数 class Plane: pCount = 0 #类属性 def __init__(self,name,category): self.nam ...

随机推荐

  1. hadoop2.2.0集群安装

    位说明. 位).Jdk使用的1.7(1.6也可以).网络配置好,相互可以ping通,java环境安装完毕.   第一部分 Hadoop 2.2 下载 位). 下载地址:http://apache.cl ...

  2. SpringMVC项目接入Springfox实战遇到的问题集合

    为了方便的管理项目中API接口,目前总是会写好接口后,然后又要去维护一个文档,这对于开发者来说太心累了, 在网上找了好多关于API接口管理和生成文档的资料,一次偶然跟51的大神交流发现了Swagger ...

  3. SSO之CAS备忘

    http://blog.chinaunix.net/uid-28380443-id-4740103.html 自己负责的公司基于CAS单点登录平台架构已经上线运行,很多细节的东西是时候备忘一下了,开源 ...

  4. 获取手机root的方法

  5. java小算法—大衍数列

    题目:    中国古代文献中,曾记载过“大衍数列”, 主要用于解释中国传统文化中的太极衍生原理. 它的前几项是:0.2.4.8.12.18.24.32.40.50 ... 其规律是:对偶数项,是序号平 ...

  6. ueditor编辑器图片自定义存放目录及路径修改

    百度编辑器ueditor功能强大,很多人士以应用项目开发中,但是里面有一个公众的问题就是上传图片存放目录太深,默认是ueditor/php/upload下,前不久测试后图片存放目录可以改变,但是路径会 ...

  7. Matlab mex编程

    经典教程:mex 编程 http://classes.soe.ucsc.edu/ee264/Fall11/cmex.pdf Matlab 快速编程: http://www.ee.columbia.ed ...

  8. Cocos2d-x3.0TestCpp文件夹笔记(二)

    3.Actions-Basic:此demo中体现ccp由Point取代 ①ActionManual:直接设置精灵的属性demo. const Color3B Color3B::RED    (255, ...

  9. [互联网面试笔试汇总C/C++-7] 寻找两个链表的第一个交点-微策略

    题目:有两个链表,找出他们的第一个交点,要求每个链表只能遍历一次,可以对链表进行任何操作,空间O(1). 思路: 这个题目刚开始看觉得要遍历一次有点困难,但是仔细一想,人家告诉说可以对链表进行任何操作 ...

  10. QT开发pjsip的VOIP,A8平台运行

    QT开发pjsip的VOIP 开发环境 平台:A8 环境:Linux-3.0.8 实现功能:使用QT开发VOIP进行初始化.拨号.挂起 测试工具:minisipserver服务器 效果 界面: min ...