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

来源:互联网 发布:恋恋有词软件 编辑:程序博客网 时间:2024/06/06 02:33

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导致的错误。

1 0
原创粉丝点击