C语言基础 指针总结

数组名与指针变量的区别

 

请看下面的代码:

int i, *pa, a[] = {3,4,5,6,7,3,7,4,4,6};

pa = a;

for (i = 0; i <= 9; i++)

{

printf("%d\n", *pa);

pa++; /*注意这里,指针值被修改*/

}

可以看出,这段代码也是将数组各元素值输出。不过,你把循环体{}中的 pa

12

改成 a 试试。你会发现程序编译出错,不能成功。看来指针和数组名还是不同的。

其实上面的指针是指针变量,而 数组名只是一个指针常量。这个代码与上面的代

码不同的是,指针 pa 在整个循环中,其值是不断递增的,即指针值被修改了。

数组名是指针常量,其值是不能修改的,因此不能类似这样操作:a++

前面 4、5 节中 pa[i],*(pa+i)处,指针 pa 的值是使终没有改变。所以

变量指针 pa 与数组名 a 可以互换

 

int i, a[] = {3,4,5,6,7,3,7,4,4,6};

int *const pa = a; /* 注意 const 的位置:不是 const int *pa */

//pa为所指内容的地址

for (i = 0; i <= 9; i++)

{

printf("%d\n", *pa);

pa++ ; /*注意这里,指针值被修改*/

}

这时候的代码能成功编译吗?不能。因为 pa  指针被定义为常量指针了

 

const int ic = 20;

int const ic = 20;没有区别

const int *pi

int const *pi

也没有区别

 

值传递、地址传递、引用传递

void Exchg1(int x, int y) /* 定义中的x,y变量被称为Exchg1

函数的形式参数 */

{

int tmp;

tmp = x;

x = y;

y = tmp;

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

}

问:你认为这个函数是在做什么呀?

答:好像是对参数 x、y 的值对调吧?

请往下看,我想利用这个函数来完成对 a,b 两个变量值的对调,程序如

下:

main()

{

int a = 4,b = 6;

Exchg1(a, b); /*a,b 变量为 Exchg1 函数的实际参数。*/

printf("a = %d, b = %d.\n”, a, b);

return(0);

}

 

Exchg1(a, b)时所完成的操作代码如下所示。

int x = a; /* ← */

int y = b; /* ← 注意这里,头两行是调用函数时的隐含操作 */

int tmp;

tmp = x;

x = y;

y = tmp;

请注意在调用执行 Exchg1 函数的操作中我人为地加上了头两句:

int x = a;

int y = b;

这是调用函数时的两个隐含动作。它确实存在,现在我只不过把它 显式地

写了出来而已。问题一下就清晰起来啦。(看到这里,现在你认为函数里面交换

操作的是 a、b 变量或者只是 x、y 变量呢?)

原来  ,其实函数在调用时是隐含地把实参 a 、b  的值分别赋值给了 x 、y,

之后在你写的

之后在你写的 Exchg1  函数体内再也没有对 a 、b 进行任何的操作了。交换的只

进行任何的操作了。交换的只

是 x 、y  变量。并不是 a 、b 。当然 a 、b  的值没有改变啦!函数只是把 a 、b 的

值通过赋值传递给了

值通过赋值传递给了 x 、y ,函数里头操作的只是 x 、y  的值并不是 a 、b 的值。

这就是所谓的参数的值传递了。

的值。

这就是所谓的参数的值传递了。

地址传递

 

再看调用处:Exchg2(&a, &b);

它将 a 的地址(&a)代入到 px,b 的地址(&b)代入到 py。同上面的值

传递一样,函数调用时作了两个隐含的操作:将&a,&b 的值赋值给了 px、py。

px = &a;

py = &b;

呵呵!我们发现,其实它与值传递并没有什么不同,只不过这里是将 a、b

的地址值传递给了 px、py,而不是传递的 a、b 的内容,而(请好好地在比较

比较啦)整个 Exchg2 函数调用是如下执行的:

px = &a; /* ← */

py = &b; /* ← 请注意这两行,它是调用 Exchg2 的隐含动作。*/

int tmp = *px;

*px = *py;

*py = tmp;

printf("*px =%d, *py = %d.\n", *px, *py);

针 这样,有了头两行的隐含赋值操作。我们现在已经可以看出,指针 px 、py

是 的值已经分别是 a 、b  变量的地址值了。接下来,对*px 、*py 的操作当然也就

是对

的操作当然也就

是对 a 、b  变量本身的操作了

同理  引用传递  

 

复杂问题简单化

展开函数,注意拷贝的副本使用

 

指向指针的指针

内存地址→ 5 6 7 8 9 10 11 12 13

-------------------------------------------------------------------------------------------------------

… | 50 |     |      | 5|           | 9 |

-------------------------------------------------------------------------------------------------------

|short int i|char a| |short int * pi|short int ** ppi|

从图中看出,指针变量 ppi 的内容就是指针变量 pi 的起始地址。于是……

ppi 的值是多少呢?—— 9。

*ppi 的值是多少呢?—— 5,即 pi 的值。

**ppi 的值是多少呢?——50,即 i 的值,也是*pi 的值

 

函数指针

就象某一数据变量的内存地址可以存储在相应的指针变量中一样,函数的

首地址也以存储在某个函数指针变量里的

指针是个变量,指不同的位置,调用不同的函数

 

MyFun  的函数名与 FunP  函数指针都是一样的,即都是函数指针。

MyFun  函数名是一个函数指针常量,而 FunP 是一个函数数指针变量,这是它

们的关系。

是一个函数数指针变量,这是它

们的关系。

2 )但函数名调用如果都得如(*MyFun)(10)这样,那书写与读起来都是不

方便和不习惯的。所以

这样,那书写与读起来都是不

方便和不习惯的。所以 C  语言的设计者们才会设计成又可允许 MyFun(10)这种

形式地调用(这样方便多了并与数学中的函数形式一样,不是吗?)。

这种

形式地调用(这样方便多了并与数学中的函数形式一样,不是吗?)。

3 )为统一起见,FunP  函数指针变量也可以 FunP(10) 的形式来调用。

4 )赋值时,即可 FunP = &MyFun  形式,也可 FunP = MyFun 。

typedef函数指针

用途:

函数指针通常用来实现回调,也可以用来对模块调用以函数表的形式进行优化。

使用方法:

 1、定义函数指针类型

使用typedef更直观更方便

// 定义一个原型为int Fun( int a );的函数指针

typedef int (*PTRFUN) ( int aPara );

typedef的功能是定义新的类型。这里定义了一种PTRFUN的类型,并定义这种类型为指向某种函数的指针,这种函数以一个int为参数并返回char类型。后面就可以像使用int,char一样使用PTRFUN了。

 2、函数指针变量的定义

PTRFUN pFun; // pFun 为函数指针变量名

int (*pFun2) ( int a ); // pFun2也是函数指针变量名

3、函数指针作为函数的参数传递

// 定义回调函数

int CallBack( int a )

{

return ++a;

}

 

// 定义回调者函数

void Caller( PTRFUN cb )

// void Caller( int (*cb) ( int ) ) // 也可这样申明

{

int nPara = 1;

int nRet = cb( nPara );

}

 

// 使用回调

void Test()

{

Caller( CallBack ); // 直接使用回调函数

PTRFUN cb = CallBack; // int (*cb) ( int ); cb = CallBack;

int nRet1 = cb( 99 ); // nRet1 = 100;

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值