您的位置:首页 > 移动开发 > Objective-C

Object-C基础(4)—— 函数

2016-03-26 16:09 176 查看
C是一门结构化的编程语言,Objective-C是C的超集。

为什么要定义函数?

为了方便复用某段代码,可以将这段代码定义成一个函数,以后每次调用该函数,就相当于让程序去执行这段代码。

定义函数(function)的语法

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

{

}

返回值类型:可以是任何有效的类型(基本类型、构造类型、引用类型)。

所谓返回值类型,决定了该函数执行成功之后,所返回的结果的类型。

因此如果没有返回值类型,应该将返回值类型声明为void。

如果不写返回值类型,表明返回值类型为int。

如果声明了返回值类型(包括不写),程序应该在函数体使用return语句来返回函数的返回值。

函数名:标识符即可。

实际上,函数名应该一个或多个有意义的单词连缀而成。

形参列表: 形参类型 形参名, 形参类型 形参名, ...

每个形参都必须由 形参类型和形参名所组成。

调用函数

注意点:

1. 声明函数时指定了几个形参,调用函数时就需要传入几个参数、而且参数的类型要一致。

2. 函数的返回值,既可用变量去装;也可立即拿来用掉(将函数返回值放入表达式中)。

函数声明

C语言是从上到下的,默认要求:函数必须先定义、再使用。

对于如下两种情况:

- 函数定义在函数调用处的后面。

- 函数定义在另一个源文件中。

此时就需要使用函数声明 —— 函数声明就是告诉编译器:这个函数是存在的。

函数声明:就是重要函数的返回值类型、函数名、形参类型即可,不要函数执行体。

注意:函数声明时既可有形参名,也可没有形参名。

import语句,就是导入大量的函数声明。

由于函数声明必须在所有函数调用的前面,因此程序就需要将#import语句放在程序在最上面。

函数的传参机制

Object-C的传参机制是“值传递”,程序传入函数的只是参数本身的副本(复制品),

因此函数所参数所作的修改,对参数本身是没有任何影响的。

注意:对于传递指针的情形,实际上传递的依然是指针的复制品(副本)。

递归函数

如果一个函数,调用了自身,该函数就会形成递归函数。

递归,可实现一个隐式的循环。

与循环类似的是,递归也必须有结束的时候。

递归:一定要有结束的时,要向已知的方向递归。

使用数组本身(数组的本质就是指针)作为参数

注意:

1. 当在函数中声明数组类型的参数时,既可指定数组的长度,也可不指定数组的长度,但通常都不会指定。

2. 由于数组本身是一个指针,因此传入函数的并不是数组本身,只是一个指针的副本。

因此函数无法通过sizeof来获取被传入的数组的长度。

3. 由于数组本身是指针,因此函数对数组元素所做的修改会影响数组本身的元素的。

内部函数与外部函数

C语言是结构化程序设计语言,因此函数是C的一等公民:

一个C程序通常是由于很多个函数组成,程序员开发的函数,可能还需要依赖系统内置的函数。

由此可见:C语言程序,可能由成千上万的函数组成,但最多只能有一个main函数

—— 它作为程序的入口,其他函数都是直接或间接地被main函数调用,所有函数的地位是平等。

每个函数都可调用别的函数,也可被别的函数调用。

static修饰符的作用之一:把外部东西(函数、全局变量),变成内部东西(函数、全局变量)。

- static函数,就是内部函数——只能在当前源文件中被调用。

- 没static修饰或extern修饰的函数,可以任何地方被调用(只要先做函数声明即可)。

对于内部函数,程序只有通过直接把源代码import进来才可以调用内部函数。

而外部函数,程序即使拿不到定义函数的源代码,只要有定义函数的源代码生成的库,程序也可通过函数声明之后来调用外部函数。

局部变量与全局变量

C的变量分为:

局部(local)变量:在函数里、方法里定义的变量,都是局部变量。

局部变量保存在各自的栈区中,函数、方法执行结束时,栈区被销毁。

特征:只在定义该变量的函数、方法内有效,函数、方法执行完,局部变量立即消失。

全局(global)变量:在文件范围内定义的变量,都是全局变量。

全局变量保存在整个程序的内存(静态存储区)中。程序不结束,静态存储区不会消失。

特征:只要程序不退出,全局变量将一直有效。

细分局部变量,又可分为:

- 形参:从函数被调用开始,形参开始生效,函数结束时,参数失效。

- 方法里局部变量:从定义该变量开始生效,函数结束时,该变量失效。

- 代码块的局部变量:从定义该变量开始生效,代码块结束时,该变量失效。

包括在if条件体、循环体、for循环的初始化语句中定义的变量,都属于代码块的局部变量,离开了定义该变量的花括号区域,那么该变量就失效了。

细分全局变量

- static全局变量,就是内部[全局]变量——只能在当前源文件中被调用。

- 没static修饰的全局变量,可以任何地方被调用(只要先做变量声明即可)。

变量声明:如果程序要使用其他源程序中定义的全局变量时,就必须做变量声明。语法是:

extern 类型变量名;

局部变量的存储机制:

定义局部变量时,有如下几个修饰符:

auto - 有auto和没auto效果是一样的。也就是说,你定义的所有的局部变量,默认就相当于有个auto。

auto修饰的局部变量,会被保存到函数或方法的栈区中。

static - 把局部变量放到静态存储区中。

对于static的局部变量而言,只要程序不退出,静态局部变量将一直有效。

由于static局部变量会一直有效,因此程序只有第一次调用函数时,才会对static局部变量赋初始值。

register - 控制把局部变量放入寄存器中。

但OS并不保证register变量一定会进入寄存器,所以实际上这个修饰用的并不多。

关于定义变量的原则:

1. 程序应该优先使用局部变量(全局变量是非常糟糕的设计、会造成牵一发而动全身的效果)。

2. 如果局部变量需要能在函数、方法结束时,依然可以保存上次运行的数据,或者该变量只希望第一次调用时被初始化,该局部变量应该用static修饰。

3. 实在没办法,才考虑使用全局变量。

典型的,当一个程序单元需要把数据共享给另外一个程序单元时,正确做法是参数传递,而不是全局变量。

static修饰符有2个作用:

- 修饰全局函数、全局变量,使之变成内部函数、内部全局变量。

- 修饰局部变量,使之成为静态局部变量——静态局部变量会被保存到程序的静态存储区。

extern修饰符也有2个作用:

- 声明全局变量。

- 修饰外部函数。————但实际上,不用extern效果也是一样的。

预处理

预处理:程序在编译阶段就会处理调用东西,这些预处理指令不会保留到运行阶段。

对于源程序中包含的预处理,编译器会在编译阶段处理完成,到运行时就不存在预处理指令。

预处理的特征:

- 通常在程序的开头。

- 必须以#开始。

#define 或 #undef定义宏变量和取消宏

#define定义的又被称为:“宏(macro)变量”。

#define的作用是:编译器在处理程序之前,先执行查找、替换。

通过#define定义宏变量有两个好处:

- 可以方便程序以后修改。

- 可以提高程序的可读性。

#undef:取消宏定义

#define还可以定义带参数的宏

对于带参数的宏定义而言,有两点要注意:

- 定义宏的参数时,并不是定义函数的参数,因此宏的参数无需指定参数类型。

- 使用宏的参数时,一定要参数放在圆括号中。

使用#ifdef #ifndef #else #endif执行条件编译。

它的用法基本上和前面介绍的分支是一样的。

它们的主要作用是判断指定的宏是否存在,根据指定宏是否存在来执行相应的分支。

使用#if #elif #else#endif执行条件编译。

预处理的if分支比普通的if分支的效率要高的多。

能用预处理的if分支,应该尽量使用预处理的if分支。

记住:只要你的if条件中包含了变量、函数调用等表达式,就只能使用普通的if分支。

#include和#import

#include和#import的功能是类似的,但#import的功能更强大一些。

#import就可以自动避免重复include导致的错误。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: