指针与函数

指针和函数

一、程序栈

指针对函数功能的贡献极大,它们能够将数据传递给函数,并且允许函数对数据进行修改。我们可以将复杂数据用结构体指针的形式传递给函数和从函数返回,如果指针持有函数的地址,就能动态控制程序的执行流。

要理解函数及其和指针的结合使用,需要理解程序栈,调用函数的时候,会创建函数的栈帧并将其推到程序栈上,函数返回时,其栈帧从程序栈上弹出。

在使用函数时,有两种情况指针很有用。首先是将指针传递给函数,这是函数可以修改指针所引用的数据,也可以高效地传递大块信息。另外一种情况是声明函数指针,本质上,函数表示法就是指针表示法,函数名字经过求值变成函数的地址,然后函数参数会被传递给参数。

程序栈是支持函数执行的内存区域,通常和堆共享,也就是说,他们共享同一块内存区域,程序栈通常占据这块区域的下部,而堆用的则是上部。

栈帧的组织由以下几种元素组成(返回地址、局部数据存储、参数存储、栈指针和基指针)

(1)  返回地址

函数完成后要返回的程序内部地址

(2)  局部数据存储

为局部变量分配的内存

(3)  参数存储

为函数参数分配的内存

(4)  栈指针和基指针

运行时系统用来管理栈的指针。栈指针通常指向栈顶部,基指针通常存在并执行栈帧内部的地址,比如返回地址,用来协助访问栈帧内部的元素。这两个指针都不是c指针,他们是运行时返回管理程序栈的地址。

 

二、    通过指针传递和返回数据

传递指针可以让多个函数访问指针所引用的对象,而不是把对象声明为全局可访问,这意味着只有需要访问这个对象的函数才有访问权限,而且也不需要复制对象。

1、指针传递数据

void test(int *px,int *py)

{

    int x;

    x=*px;

    *px=*py;

    *py=x;

}

int *plobal;

int main(int argc, char* argv[])

{

    int x=1;

    int y=2;

    test(&x,&y);

    printf("x=%d\n",x);

    printf("y=%d\n",y);

 

   return 0; 

}

2、传递指向常量的指针(就是px指向的值数据不能被修改)

void test(const int *px,int *py)

{

    *py=*px;

}

int *plobal;

int main(int argc, char* argv[])

{

    int x=1;

    int y=2;

    test(&x,&y);

    printf("x=%d\n",x);

    printf("y=%d\n",y);

 

   return 0; 

}

3、返回指针

返回指针很容易,只要返回的类型是某种数据类型的指针即可。

(1)  使用malloc在函数内部分配内存并返回其地址,调用者负责释放返回的内存

下面的例子,定义一个函数,为其传递一个整数数组的长度和一个值初始化每个元素,函数为整数数组分配内存,用传入的值进行初始化,然后返回数组地址。

int* test(int size,int value)

{

    int* arr =(int*)malloc(size*sizeof(int));

    for(inti=0;i<size;i++)

    {

       *(arr+i)=value+i;

    }

    return arr;

}

int *plobal;

int main(int argc, char* argv[])

{

    int*px=test(2,4);

   return 0; 

}

 

最后,还得记得free(px).

(2)  传递一个指针对象给函数并让函数修改它,这样分配和释放对象的内存都是调用者的责任

 

int* test(int *arr,int size,int value)

{

    if(arr!=NULL)

    {

       for(inti=0;i<size;i++)

       {

           arr[i]=value;

       }

    }

    return arr;

}

int * plobal;

int main(int argc, char* argv[])

{

    int*vector=(int*)malloc(5*sizeof(int));

   

    int*px=test(vector,5,45);

    for(inti=0;i<5;i++)

    {

       printf("%d\n",px[i]);

    }

   

    return 0; 

}

(3) 局部数据指针(不要返回局部变量的地址,因为局部变量的内存会被后续的函数调用中被覆盖

在下面的程序中,一旦函数返回,返回的数组地址就无效,可能数组的长度仍然不变,但是其值已经被覆写了。

int* test(int size,int value)

{

    int temp=size;

    intarr[45];

    for(int i=0;i<45;i++)

       arr[i]=value+i;

    return arr;

}

int * plobal;

int main(int argc, char* argv[])

{

    int*px=test(2,4);

    for(inti=0;i<45;i++)

    {

       printf("%d\n",px[i]);

    }

   

    return 0; 

}

(4) 输入参数是指针变量,函数内部可以修改指针的引用值,当不要修改指针的值

(5) 输入参数是指针的指针

将指针传递给函数时,传递的是值。如果我们想修改原指针,而不是指针的副本,就需要传递指针的指针。在下例中,我们传递了一个整数数组的指针,为该数组分配内存并将其初始化,函数会用第一个参数返回分配的内存。在函数中,我们先分配内存,然后初始化,所分配的内存地址应该被赋给一个整数指针。为了在调用函数中修改这个指针,我们需要传入指针的地址,所以,参数被声明为int指针的指针。在调用函数中,我们需要传递指针的地址:

三、函数指针

函数指针是持有函数地址的指针,指针能够指向函数。使用函数指针的一个顾虑是:这种做法可能会导致程序运行变慢,处理器可能无法配合流水线做分配预测。

1、声明函数指针

void (*foo)();

声明一个名为foo的函数指针,星号表示这是个指针,void表示返回类型,(*foo)表示函数指针变量的名字,()表示参数。声明函数指针一定要小心,因为C不会检查参数传递是否正确。

2、使用函数指针

先声明函数指针:int (*fptr1)(int);

int test(int x)

{

    return x*x;

}

 

int main(int argc, char* argv[])

{

    int (*fptr1)(int);

    int n=5;

    fptr1=test;//也可以这样赋值,但是没有必要fptr1 = &test

    printf("%dsquare is %d\n",n,fptr1(n));

    return 0; 

}

3、传递函数指针,即将函数指针作为参数

#include "stdafx.h"

#include<iostream>

#define MAXSIZE100  //定义线性表的最大长度

int add(int num1,int num2)

{

    return num1+num2;

}

int subtract(int num1 ,int num2)

{

    return num1-num2;

}

typedef int(*fptroperation)(int,int);//定义一个指针函数

int compute(fptroperation operation,int num1,int num2)//指针函数作为形参

{

    return operation(num1,num2);

}

int main(int argc, char* argv[])

{

    printf("%d\n",compute(add,5,6));//调用该函数

    printf("%d\n",compute(subtract,5,6));//调用该函数

    return 0; 

}

 

4、返回函数指针

返回函数指针需要把函数的返回类型声明为函数指针,

四、总结

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值