【IOS 开发学习总结-OC-7.10-★】 objective-c——函数与指针

来源:互联网 发布:威斯敏斯特大学 知乎 编辑:程序博客网 时间:2024/05/17 10:06

指针变量出了可以指向普通的 int变量,float 变量和数组外,还可以指向函数的入口。

用函数指针变量调用函数

定义函数后,C 语言允许定义一个指针变量来指向该函数。
使用函数指针的步骤:
1. 定义函数指针变量。语法格式个为:函数返回值类型(*指针变量名)();
2. 将任何已有的函数入口赋值给函数指针变量。如:pt=avg;
关于上面句子的2点说明:
- C 语言允许任何已有的函数赋值给函数指针变量。所以,同一个函数指针变量在不同时间可指向不同的函数。
- 为函数指针变量赋值时,只需给出函数名即可,无需使用(),也无需传入参数。注意:是将函数入口赋给指针变量,而不是调用函数后将返回的结果赋给函数指针变量。
3. 使用函数指针变量来调用函数。语法格式为:(*函数指针变量)(参数);
示例代码:

#import <Foundation/Foundation.h>int max(int* data , int len){    int max = *data;    // 采用指针遍历data数组的元素    for(int* p = data ; p < data + len ; p++)    {        // 保证max始终存储较大的值        if(*p > max)        {            max = *p;        }    }    return max;}int avg(int* data , int len){    int sum = 0;    // 采用指针遍历data数组的元素      for(int* p = data ; p < data + len ; p++)    {        // 累加所有数组元素的值        sum += *p;    }    return sum / len;}int main(int argc , char * argv[]){    @autoreleasepool{        int data[] = {20 , 12 , 8 , 36, 24};        // 定义指向函数的指针变量:fnPt,并将max函数的入口赋给fnPt        int (*fnPt)() = max;        NSLog(@"最大值:%d" , (*fnPt)(data , 5));        // 将avg函数的入口赋给fnPt        fnPt = avg;        NSLog(@"最大值:%d" , (*fnPt)(data , 5));    }}

说明:使用函数指针变量可以以增加函数调用的灵活性,这样我们可以将函数指针变量作为参数传入另一个函数。另外,函数指针变量不支持传统指针变量所支持的运算——对2各函数指针变量比较大小,加减一个整数,执行减法没有实际意义。

用函数指针变量作为函数参数★

有时需要定义一个函数,该函数大部分计算逻辑都能确定,但某些处理逻辑暂时无法确定——这需要某些程序代码动态改变,如果希望调用函数时能动态传入这些代码,就需要在函数中定义函数参数,调用该函数时传入不同的函数作为参数,即可动态改变这段代码。
如下程序:

#import <Foundation/Foundation.h>void map(int* data , int len , int (*fn)()){    // 采用指针遍历data数组的元素    for(int* p = data ; p < data + len ; p++)    {        // 调用fn函数(fn函数是动态传入的)        printf("%d , " , (*fn)(*p));    }    printf("\n");}int noChange(int val){    return val;}// 定义一个计算平方的函数int square(int val){    return val * val;}// 定义一个计算立方的函数int cube(int val){    return val * val * val;}int main(int argc , char * argv[]){    @autoreleasepool{        int data[] = {20 , 12 , 8 , 36, 24};        // 下面程序代码3次调用map()函数,每次调用时传入不同的函数        map(data , 5 , noChange);        NSLog(@"计算数组元素平方");        map(data , 5 , square);        NSLog(@"计算数组元素立方");        map(data , 5 , cube);    }}

编译运算结果:
20 , 12 , 8 , 36 , 24 ,
计算数组元素平方
400 , 144 , 64 , 1296 , 576 ,
计算数组元素立方
8000 , 1728 , 512 , 46656 , 13824 ,

由此可以看出,定义函数指针变量的形参就可以在在调用函数时动态传入函数,就可以动态地改变被调用函数的部分代码。这种用法,其实就是”命令模式”。

返回指针的函数

函数可以返回普通的数值也可以返回一个指针。

函数返回指针的一种危险情况

由于函数返回的指针只保存了一个地址值,如果该指针指向被调用函数中定义的局部变量,将很危险。因为函数调用结束后,该函数中声明的局部变量所占用的空间已经释放,那么该指针指向的内存单元中的数据将是不确定的。
有2种方式保证函数返回的指针是有效的
1. 如果函数的指针指向被调用函数中声明的局部变量,该局部变量应用 static 修饰。
2. 让函数返回的指针指向暂时不会被释放的数据。如指向 main() 函数中的变量——只有等到 main() 函数执行完成时,main 函数中的变量才会被释放。因此在 main() 函数结束前,函数返回的指针是安全的。
示例代码:

#import <Foundation/Foundation.h>#define LENGTH 5int* map(int* data ,int (*fn)()){    static int result[LENGTH];    int i = 0;    // 采用指针遍历data数组的元素    for(int* p = data; p < data + LENGTH ; p++)    {        // 调用fn函数(fn函数是动态传入的)        result[i++] = (*fn)(*p);    }    // 返回result的首地址    return result;}int noChange(int val){    return val;}// 定义一个计算平方的函数int square(int val){    return val * val;}// 定义一个计算立方的函数int cube(int val){    return val * val * val;}int main(int argc , char * argv[]){    @autoreleasepool{        int data[] = {20 , 12 , 8 , 36, 24};        // 下面程序代码3次调用map()函数,每次调用时传入不同的函数        int* arr1 = map(data , noChange);        for(int i = 0 ; i < LENGTH ; i ++)        {            printf("%d , " , *(arr1 + i));        }        printf("\n");        int* arr2 = map(data , square);        for(int i = 0 ; i < LENGTH ; i ++)        {            printf("%d , " , *(arr2 + i));        }        printf("\n");        int* arr3 = map(data , cube);        for(int i = 0 ; i < LENGTH ; i ++)        {            printf("%d , " , *(arr3 + i));        }        printf("\n");    }}

由于函数返回的指针指向 map() 函数声明的 result[LENGTH] 数组的首地址,为了保证函数调用完成后,函数返回的指针依然指向有效内存,程序中使用了 static 修饰的result[LENGTH] 数组。

0 0
原创粉丝点击