函数指针的好处,指针的作用是什么啊?
函数指针的好处,指针的作用是什么啊?详细介绍
本文目录一览: C++中设计一个函数用指针作为输入参数有什么好处? 比如a( b)
可以在函数里面修改这个指针指向的值。
你好!
可以在函数里面修改这个指针指向的值。
仅代表个人观点,不喜勿喷,谢谢。
其意义有三点:
要传递一个很大的结构体或类对象,但是并不想在调用方法时额外申请一个对象的空间,此时可以使用指针来传递参数,此时函数内部可以通过指针访问该对象。
想在方法中修改某个输入参数的值时,此时需要借助于传址操作,传递要修改参数的指针给方法。
在实际应用中上面两个场景的目标在C++中都可以使用引用来达成。
当方法需要使用一个参数在不同的调用情况下输入多个不同的对象类型时,可以使用指针进行参数传递,此时可以在运行时将指针的类型强制转换为对应类型对象的指针即可。例如Windows的消息方法,其wParam和lParam都是一个void类型的指针,而消息传递的参数类型实际上是多种多样的。
指针的作用是什么啊?
简单地说指针就是指向变量和对象的地址。
指针的用途非常广泛,比如如果你想通过函数改变一个变量的值,就得用指针而不能用值传递。还有在很多时候变量,特别是对象的数据量实在太大,程序员就会用指针来做形参,只需要传递一个地址就行,大大提高了效率。
以上还只是指针的初步应用,随着你在C语言学习上的逐步深入,你会发现更多的用途的。
你好! 指针就是指向一个特定内存地址的一个变量。 C语言指针可以有效地表示复杂的数据结构、动态分配内存、高效地使用数组和字符串、使得调用函数时得到多个返回值等。 指针的应用往往与数组联系在一起,是最频繁的,也是最基础的。在我们定义数组和函数时,系统都会为其自动分配一个指向其首地址的指针。对于一个数组,其名称就是一个指针变量。
指针的好处,需要和数组比较起来说。具体如下:
1.指针可以随意申请不连续的数据存储空间,而数组是连续的,如果数组空间没有全部占用,那么会造成浪费,比如你申请了a[10],缺只有5个数据输入,那么会浪费掉5个数组空间。如果是指针就不会浪费,用多少申请多少。
2.指针的计算更快速。比如你需要计算一个16*16的矩阵消元,那么数据会非常的多和大,你得申请足够多的数组空间,弄不好还会造成溢出,为什么?因为采用数组计算时,是数据的交换,而不是内存地址的交换。如果采用指针的话,不会浪费空间,不会溢出,因为指针计算时是交换指向数据存储空间的地址,而不是交换数据。数据的大小比地址大得多。
所以采用指针好处多多,同样指针也很危险,如果用不好,还不如用数组。得慢慢体会。谢谢。
指针指向地址,指针的特性就是在地址不变的情况下,可以很方便的修改所指向的内容
最重要的应用有两个,一是函数参数,二是函数指针
函数参数:函数返回值只有一个,如果想回传多个参数,则必须使用指针
函数指针:典型应用就是回调函数(callback)
指针是一种存放另一个变量的地址的变量。
比如申请一个整形变量 int a = 128; 再申请一个指针让这个指针指向变量a.
int *p;
p = &a; //取a在内存中的地址,把a的地址赋给p。这样p就指向了变量a的地址。
第一,指针的使用使得不同区域的代码可以轻易的共享内存数据。当然小伙伴们也可以通过数据的复制达到相同的效果,但是这样往往效率不太好。因为诸如结构体等大型数据,占用的字节数多,复制很消耗性能。
但使用指针就可以很好的避免这个问题,因为任何类型的指针占用的字节数都是一样的(根据平台不同,有4字节或者8字节或者其他可能)。
第二,指针使得一些复杂的链接性的数据结构的构建成为可能,比如链表,链式二叉树等等。
第三,有些操作必须使用指针。如操作申请的堆内存。还有:C语言中的一切函数调用中,值传递都是“按值传递”的。如果要在函数中修改被传递过来的对象,就必须通过这个对象的指针来完成。
扩展资料
指针的表现形式是地址,核心是指向关系指针运算符“*”的作用是按照指向关系访问所指向的对象.如果存在A指向B的指向关系,则A是B的地址,“*A”表示通过这个指向关系间接访问B。
如果B的值也是一个指针,它指向C,则B是C的地址,“*B”表示间接访问C如果C是整型、实型或者结构体等类型的变量或者是存放这些类型的数据的数组元素,则B(即C的地址)是普通的指针,称为一级指针,用于存放一级指针的变量称为一级指针变量。
参考资料来源:百度百科-指针
指针究竟有什么用?
别的话不想多说,说多了你也不理解,用什么语言不重要,只有经验累积到一定程度你才会有体会,任何技术的存在都有其历史渊源,指针最大的好处两点
1,大数据传递,只要传递地址就等于传递N多数据,速度快
2,传递函数地址,实现回调,事件调用(这个对于设计模式非常有用)
回调函数,建议去了解下windows的消息机制,回调函数是多任务的基础,细节就不展开了。函数地址的传递是个非常有用的技术,可以实现很多灵活的操作,没有一定工作经验是无法体会的。
举个极其简单例子吧,有一个int的数组,要遍历所有元素查找最大值,要写一个循环,循环中编写比较大小的代码,比如 if (a>b){max=a.....},最后返回最大值,这个没有问题。现在我要增加一种算法,求最小值,那么你必须另外写个函数,同样的循环体,不同的地方就是循环内的代码不同,要改成 if (a
<b){min=a.....},诸如此类的算法很多,当你的业务中有大量的循环处理时,你会发现需要编写n多的函数,其中除了函数名称和循环体内算法不一样外,函数构成几乎一模一样. 另一方面,如果我要遍历的不是int类型数组呢?那岂不要写n多的重载函数?
一个有思(tou)想(lan)的程序员绝对不可接受这样的情况出现.
如何缩减代码量,可不可以将不同的核心处理代码单独打包定义,而我只要编写一个包含循环体的遍历函数就可以了呢?而我只需要定义打包各类不同的算法,当我需要时把其中算法代码的地址传递给循环函数,不就可以了吗?更进一步,如果函数或者核心处理代码能够接受和设别不同类型元素的数组,那岂不是非常完美了?
因此能够传递函数地址的需求就出现了,其实回调函数,事件响应都是这个机制,函数指针的意义是当编译前无法确定处理方式时,或者如何处理数据的决定权不在循环内时,就需要事件回调函数或事件触发机制来完成,而这些机制的基础就是函数指针.
所以指针的意义可不是简单的操作一个变量那么简单,它的影响意义相当深远,以我的知识面所知,为实现多态以至于工厂模式建立的基础.
PS:不要认为VB C#没有指针,如果没有VB就无法实现回调和事件响应. 也不要认为操作内存没用,那是你还不需要用到.
顺便截一段代码片段,我日常工作需要VBA遍历数据表的遍历器的循环部分,就用到了事件触发和处理单元挂接的机制.
再补充一下C#的委托,其实委托也是利用的指针,只不过C#中隐藏了,换了个名称:委托.本质是一样的.C#中存在大量的泛型类,其实就是实现了一个接口多种调用的需求,所谓泛型类就是一个变量或者一个函数接口可以存储传递不同的数据类型,而不像int这种基础类型只能存储整数类型,如此一来减少了很多代码量,当然代价就是性能.
比如list类型,它是个泛型数组类,封装了很多方法/函数,其中find方法就是前面我上面提到的需求,find只提供循环遍历,查找的匹配条件需要另外给出,如此一来C#无需提供N多的重载函数,增加了灵活性减少的代码量,由于FIND的工作就是查找,因此参数很简单,要求匹配函数返回bool值,指示循环是否结束.
FIND的参数就是个函数委托/指针,FIND内部有个循环从索引0开始遍历所有元素,取得元素之后就会调用proc,而proc就是程序员提供的匹配代码,要求返回bool.如果为true则循环结束返回找到的对象.注意list的元素可以是任何对象实例.
C#实现了很多程序员的需求,而vb中则因为是早期的语言,只能自己编写遍历器,但是只要你理解这些需求或思想,完全可以实现相同的功能.
学习编程最重要的是学习思想而不是代码,语言和代码真的不重要,它们只是用来实现你思想的工具.码这么多字,只是想说明一点,你以为不需要不应该存在的东西一直存在着,只是因为语言的更新封装了变形了更方便了. 此例中proc就是个指针而且是函数指针,C#中声明一个委托就是声明指针,只是称呼不一样,调用或者代码形式不一样.
什么是指向函数的指针,有什么好处
下面这个说的很清楚:
函数指针和指针函数有什么区别???!?!?
比如
int (*P)()
int *p()
这两个哪个是函数指针哪个是指针函数 并详细区分之?!
答:
前一个是个函数指针,如果有个函数是这样定义的
int pfunction( )
那就可以用指针指向这个函数
p=pfunction;
然后调用时就可以这样用
p();
后一个是指针函数,他的返回值是一个指向整型变量的指针,
好处就是方便选择程序执行的路径,如:
typedef void (* PFUNC)(void);
void fun0(){ ... }
FPUNC ppFun[10] = NULL;
//初始化ppFun;
ppFun[0] = fun0;
.
.
.
ppFun[9] = fun9;
for(int i = 0; i < 10; i++)
{
(*ppFun[i])();
}
使用函数指针可以简化一些操作,可以优化一些代码,可以...好像有很多优点...
typedef int (*IntFunc)();
int func1()
{
//...
}
int func2()
{
//...
}
int main()
{
IntFunc intfunc_arr[2]={func1, func2};
int n;
scanf("%d\n", &n);//Input 0 OR 1
intfunc_arr[n](); //exec func1 or func2
IntFunc intfunc;
//...
if (n==0)
intfunc = func1;
else
intfunc = func2;
...
intfunc();
}
我不复制了,你自己看吧:
http://www2.ratvu.com/dubiao/cpp/07/03.htm
至于“好处”,一般调用电脑硬件函数是能用到,实际不怎么常用
函数指针是指向函数的指针变量。 因而“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。
C在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。有了指向函数的指针变量后,可用该指针变量调用函数,就如同用指针变量可引用其他类型变量一样,在这些概念上是大体一致的。函数指针有两个用途:调用函数和做函数的参数。
遍历函数里的形参为什么用一个函数指针void(vi)(ElemType),这样有什么好处?
这样没有写死要用某一个固定的函数,可以动态的改变
这个玩意叫回调函数,楼主可以百度一下“回调函数”,就知道他的用处了。
他是通过函数地址来调用一个函数的,比方说,你开一个线程,那么你就要知道线程函数的入口地址,这时,你就要用到回调函数了。
遍历函数里的形参用一个函数指针void(*vi)(ElemType*)的好处:提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者;当特定的事件或条件发生的时候,调用者使用函数指针调用回调函数对事件进行处理。
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方法直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
函数指针有什么优点啊?和直接调用函数不一样吗?求高人指点
我给你解释一下为什么要用函数指针:
有的通用函数中要涉用到另一个函数,但函数名称未定,是让用户编的,
当然要做成函数指针,
如果通用定积分计算,被计算函数是待定的,是由调用者确定的函数;
通用排序函数也是,比较函数与交换函数也是让用户自已编的,
这也得是函数指针
那当然不一样了
----
如果简单的调用,没多大区别
函数指针通常用作回调函数。你只提供了一个函数的原型,具体的实现用调用者来设定
//这个是我定义的函数
void test( void (*Fn)())
{
Fn();
}
void print()
{
//
}
void QQ()
{
//
}
test(print)
test(QQ)
求C语言中指针优点和注意事项说明(要有例子的)
优点就是任何类型的指针都占4个bit(32位机)
而其他的形式不一定,float占4个,double占8个,char[1000]占1000个。
在函数中使用指针传递可以减少内存使用.....
本人刚刚开始学,直觉到了这么一点点区别。
不要见笑
Joel Spolsky认为,对指针的理解是一种aptitude,不是通过训练就可以达到的。虽然如此,我还是想谈一谈这个C/C++语言中最强劲也是最容易出错的要素。
鉴于指针和目前计算机内存结构的关联,很多C语言比较本质的特点都孕育在其中,因此,本篇和第六、第七两篇我都将以指针为主线,结合在实际编程中遇到的问题,来详细谈谈关于指针的几个重要方面。
指针类型的本质分析
1、指针的本质
指针的本质:一种复合的数据类型。下面我将以下面几个作为例子进行展开分析:
a)、int *p;
b)、int **p;
c)、int (*parValue)[3];
d)、int (*pFun)();
分析:
所谓的数据类型就是具有某种数据特征的东东,比如数据类型char,它的数据特征就是它所占据的内存为1个字节, 指针也很类似,指针所指向的值也占据着内存中的一块地址,地址的长度与指针的类型有关,比如对于char型指针,这个指针占据的内存就是1个字节,因此指针也是一种数据类型,但我们知道指针本身也占据了一个内存空间地址,地址的长度和机器的字长有关,比如在32位机器中,这个长度就是4个字节,因此指针本身也同样是一种数据类型,因此,我们说,指针其实是一种复合的数据类型,
好了,现在我们可以分析上面的几个例子了。
假设有如下定义:
int nValue;
那么,nValue的类型就是int,也就是把nValue这个具体变量去掉后剩余的部分,因此,上面的4个声明可以类比进行分析:
a)、int *
*代表变量(指针本身)的值是一个地址,int代表这个地址里面存放的是一个整数,这两个结合起来,int *定义了一个指向整数的指针,类推如下:
b)、int **
指向一个指向整数的指针的指针。
c)、int (*)[3]
指向一个拥有三个整数的数组的指针。
d)、int (*)()
指向一个函数的指针,这个函数参数为空,返回值为整数。
分析结束,从上面可以看出,指针包括两个方面,一个是它本身的值,是一个内存中的地址;另一个是指针所指向的物,是这个地址中所存放着具有各种各样意义的数据。
2、对指针本身值的分析
下面例子考察指针本身的值(环境为32位的计算机):
void *p = malloc( 100 );
请计算sizeof ( p ) = ?
char str[] = “Hello” ;
char *p = str ;
请计算sizeof ( p ) = ?
void Func ( char str[100])
{
请计算 sizeof( str ) = ? //注意,此时,str已经退化为一个指针,详情见
//下一篇指针与数组
}
分析:上面的例子,答案都是4,因为从上面的讨论可以知道,指针本身的值对应着内存中的一个地址,它的size只与机器的字长有关(即它是由系统的内存模型决定的),在32位机器中,这个长度是4个字节。
3、对指针所指向物的分析
现在再对指针这个复合类型的第二部分,指针所指向物的意义进行分析。
上面我们已经得到了指针本身的类型,那么将指针本身的类型去掉 “*”号就可得到指针所指向物的类型,分别如下:
a)、int
所指向物是一个整数。
b)、int*
所指向物是一个指向整数的指针。
c)、int ()[3]
()为空,可以去掉,变为int [3],所指向物是一个拥有三个整数的数组。
d)、int ()()
第一个()为空,可以去掉,变为int (),所指向物是一个函数,这个函数的参数为空,返回值为整数。
4、附加分析
另外,关于指针本身大小的问题,在C++中与C有所不同,这里我也顺带谈一下。
在C++中,对于指向对象成员的指针,它的大小不一定是4个字节,这主要是因为在引入多重虚拟继承以及虚拟函数的时候,有些附加的信息也需要通过这个指针进行传递,因此指向对象成员的指针会增大,不论是指向成员数据,还是成员函数都是如此,具体与编译器的实现有关,你可以编写个很小的C++程序去验证一下。另外,对一个类的静态成员(static member,可以是静态成员变量或者静态成员函数)来说,指向它的指针只是普通的函数指针,而不是一个指向类成员的指针,所以它的大小不会增加,仍旧是4个字节。
指针运算符&和*
“&和*”,它们是一对相反的操作,’&’取得一个物的地址(也就是指针本身),’*’得到一个地址里放的物(指针所指向的物)。这个东西可以是值(对象)、函数、数组、类成员(class member)等等。
参照上面的分析我们可以很好地理解&与*。
使用指针的好处?
关于指针的本质和基本的运算符我们讨论过了,在这里,我想再笼总地谈一谈使用指针的必要性和好处,为我们今后的使用和对后面篇章的理解做好铺垫。简而言之,指针有以下好处:
1)、方便使用动态分配的数组。
这个解释我放在本系列第六篇中进行讲解。
2)、对于相同类型(甚至是相似类型)的多个变量进行通用访问。
就是用一个指针变量不断在多个变量之间指来指去,从而使得非常应用起来非常灵活,不过,这招也比较危险,需要小心使用:因为出现错误的指针是编程中非常忌讳的事情。
3)、变相改变一个函数的值传递特性。
说白了,就是指针的传地址作用,将一个变量的地址作为参数传给函数,这样函数就可以修改那个变量了。
4)、节省函数调用代价。
我们可以将参数,尤其是大个的参数(例如结构,对象等),将他们地址作为参数传给函数,这样可以省去编译器为它们制作副本所带来的空间和时间上的开销。
5)、动态扩展数据结构。
因为指针可以动态地使用malloc/new生成堆上的内存,所以在需要动态扩展数据结构的时候,非常有用;比如对于树、链表、Hash表等,这几乎是必不可少的特性。
6)、与目前计算机的内存模型相对应,可按照内存地址进行直接存取,这使得C非常适合于一些较底层的应用。
这也是C/C++指针一个强大的优点,我会在后面讲述C语言的底层操作时,较详细地介绍这个优点的应用。
7)、遍历数组。
据个例子来说吧,当你需要对字符串数组进行操作时,想一想,你当然要用字符串指针在字符串上扫来扫去。
…实在太多了,你可以慢慢来补充^_^。
指针本身的相关问题
1、问题:空指针的定义
曾经看过有的.h文件将NULL定义为0L,为什么?
答案与分析:
这是一个关于空指针宏定义的问题。指针在C语言中是经常使用的,有时需要将一个指针置为空指针,例如在指针变量初始化的时候。
C语言中的空指针和Pascal或者Lisp语言中的NIL具有相同的地位。那如何定义空指针呢?下面的语句是正确的:
char *p1 = 0;
int *p2;
if (p != 0)
{
...
}
p2 = 0;
也就是说,在指针变量的初始化、赋值、比较操作中,0会被编译器理解为要将指针置为空指针。至于空指针的内部表示是否是0,则随不同的机器类型而定,不过通常都是0。但是在另外一些场合下,例如函数的参数原型是指针类型,函数调用时如果将0作为参数传入,编译器则不能将其理解为空指针。此时需要明确的类型转换,例如:
void func (char *p);
func ((char *)0);
一般情况下,0是可以放在代码中和指针关联使用的,但是有些程序员(数量还不少呦!也许就包括你在内)不喜欢0的直白,认为其不能表示作为指针的特殊含义,于是要定义一个宏NULL,来明确表示空指针常量。这也是对的,人家C语言标准就明确说:“ NULL应该被定义为与实现相关的空指针常量”。但是将NULL定义成什么样的值呢?我想你一定见过好几种定义NULL的方法:
#define NULL 0
#define NULL (char *)0
#define NULL (void *)0
在我们使用的绝大多数计算系统上,例如PC,上述定义是能够工作的。然而,世界上还有很多其它种类的计算机,其CPU也不是Intel的。在某些系统上,指针和整数的大小和内部表示并不一致,甚至不同类型的指针的大小都不一致。为了避免这种可移植性问题,0L是一种最为安全的、最妥帖的定义方式。0L的含义是: “值为0的整数常量表达式”。这与C语言给出的空指针定义完全一致。因此,建议采用0L作为空指针常量NULL的值。
其实 NULL定义值,和操作系统的的平台有关, 将一个指针定义为 NULL, 其用意是为了保护操作系统,因为通过指针可以访问任何一块地址, 但是,有些数据是不许一般用户访问的,比如操作系统的核心数据。 当我们通过一个空(NULL)的指针去方位数据时,系统会提示非法, 那么系统又是如何知道的呢??
以windows2000系统为例, 该系统规定系统中每个进程的起始地址(0x00000000)开始的某个地址范围内是存放系统数据的,用户进程无法访问, 所以当用户用空指针(0)访问时,其实访问的就是0x00000000地址的系统数据,由于该地址数据是受系统保护的,所以系统会提示错误(指针访问非法)。
这也就是说NULL值不一定要定义成0,起始只要定义在系统的保护范围的地址空间内,比如定义成(0x00000001, 0x00000002)都会起到相同的作用,但是为了考虑到移植性,普遍定义为0 。
2、问题:与指针相关的编程规则&规则分析
指针既然这么重要,而且容易出错,那么有没有方法可以很好地减少这些指针相关问题的出现呢?
答案与分析:
减少出错的根本是彻底理解指针。
在方法上,遵循一定的编码规则可能是最立竿见影的方法了,下面我来阐述一下与指针相关的编程规则:
1) 未使用的指针初始化为NULL 。
2) 在给指针分配空间前、分配后均应作判断。
3) 指针所指向的内容删除后也要清除指针本身。
要牢记指针是一个复合的数据结构这个本质,所以我们不论初始化和清除都要同时兼顾指针本身(上述规则1,3)和指针所指向的内容(上述规则2,3)这两个方面。
遵循这些规则可以有效地减少指针出错,我们来看下面的例子:
void Test(void)
{
char *str = (char *) malloc(100);
strcpy(str, “hello”);
free(str);
if(str != NULL)
{
strcpy(str, “world”);
printf(str);
}
}
请问运行Test函数会有什么样的结果?
答:
篡改动态内存区的内容,后果难以预料,非常危险。因为free(str);之后,str成为野指针,if(str != NULL)语句不起作用。
如果我们牢记规则3,在free(str)后增加语句:
str = NULL;
那么,就可以防止这样的错误发生。
函数形参引用和指针有什么区别?
指针是用来指向某个变量,而引用是给变量取个别名,其作用就如同typedef一样。
用引用作形参时在调用函数里就像操作实参一样,不需要考虑实参的地址问题
用指针做形参时,由于指针的值是变量的地址,所以要通过对地址解引用来操作其所指的变量。
在C++里优先选择引用类型作为形参,因为操作一个变量比操作一个指针要简单的多
但用指针作为形参的好处是它可以通过自增或自减改变它的指向。
温馨提示:建议调用函数时,用引用类型的形参!
请问结构体指针变量在程序设计中的优点,最好举例说明!
这两者作为函数参数,还是有很大的区别的,我说说自己的理解。
如:
typedef
struct
A{int
a;...}A;
//定义结构体A
void
Func(A
a);
//通过结构体变量传参
void
Func(A*
pA);
//通过结构体指针传参
调用函数时,因为函数参数要临时存放到栈中,若结构体变量作为参数,则需要生成一个结构体A的副本,将其存放到栈中;
而结构体指针作为变量,只需将指针pA存放到栈中即可,提高了程序的空间效率。
其次,结构体指针作为函数参数:
可以在函数中通过该指针引用结构体,当在函数中修改了结构体的成员变量后(如:pA->a
=
0),指针pA所指向的结构体本身也被改变了。
不同的是,当结构体变量作为函数参数:
在函数中可通过变量直接使用结构体,但要注意的是,如果在函数中修改了结构体的成员变量后(如:
a.a
=
0),结构体本身并未发生变化,只是副本被改变。