网站建设
网站推广
网络推广
Network promotion
关键词SEO优化
品牌推广
两V一抖
广告媒介投放
品牌网站建设
企业网站建设
门户网站建设
网站代运营
集团网站建设
外贸网站建设
营销型网站建设
网站运营维护
案例
方案
网站方案
Solution
教育培训
商城
美容化妆品
LED
软件IT
房地产
装饰行业
节能环保
手机数码
集团上市公司
金融行业
物流
钟表
数码电器
旅游
其他
电商网站开发
电商网站开发
E-commerce & System
定制化电子商务系统
产品商城网站建设方案
移动手机电商网站解决方案
微信会员电商解决方案
系统开发
P2P金融平台
产品众筹平台
股权众筹平台
微信小程序
微信小程序
微商城
微官网
微活动
我们
我们
About Us
了解我们
关于快上网
实力认可
快上网与众不同
理念与信仰
售后支持
我们的客户
客户列表
客户评价
联系
联系
Contact Us
联系我们
业务热线:
028-86922220
邮箱:
service@cdxwcx.com
人才招聘
HR电话:
13518219792
精准传达 • 有效沟通
从品牌网站建设到网络营销策划,从策略到执行的一站式服务
网站建设
>
查看其它板块
网站建设知识
网站营销推广
网站设计观点
网站优化排名
网站商城开发
星号的秘密-创新互联
琼山网站建设公司
创新互联建站
,琼山网站设计制作,有大型网站制作公司丰富经验。已为琼山成百上千提供企业网站建设服务。企业网站搭建\成都外贸网站建设公司要多少钱,请找那个售后服务好的
琼山做网站
的公司定做!ong>1
、乘法运算符
2
、定义指针
int *p = 0; 还是 int* p = 0;? 后一种比较容易这样理解:定义了一个变量p,它是指针型的(更详细一点,是指向int的指针型),相比而言,前面一种定义似乎是定义了*P这个奇怪的东西。但是后面一种写法会带来一个容易产生的误解: int* p1, p2; 这儿给人的感觉似乎是定义了两个指针型变量p1和p2,但是,事实上,这种直觉是错误的,正确的理解方式是int *p1, p2;即p1是指针型的,而p2确是整型的。 在MS VC++ 6.0中,是按照后面一种格式写的。
3
、何谓指针?
指针仅仅表示一个内存中的某个地址? 非也,注意到,我们在定义指针的时候,都关联了一个类型,如int,char,或者是string等等,如果说指针仅仅表示一个内存中的地址,那何必要关联这么多变化的东西呢?完全可以DWORD p=0;这样解决问题。 关联了的数据类型是作何用的呢? 它可以指示编译器怎样解释特定地址上内存的内容,以及该内存区域应该跨越多少内存单元。如 int *p; 编译器可以从这个定义中获得信息:1、p指向的内存存放的是整型数据,2、由于该内存区域只存放了一个数据,跨越的内存区域为4个字节,即p+1的效果是跳过了四个字节。 另一个复杂一点的例子,如 struct a {int x1; short x2; a *next; } 定义指针 a *p;那么编译器对这个指针又作何解释呢? 1、p指向的内存区域依次存放了三种类型的数据,分别是int,short和一个指针型数据。 2、p指向的内存区域跨越了12个字节,即p+1的效果是跳过了12个字节。(为何不是10?对齐的原因) 但是,C++中定义了一种特殊的指针,它去处了一般指针中对内存区域内容以及大小的解释,以满足特定定的需要,如我们只需要某块内存的首地址,不需要考虑其中的数据类型以及大小。这种形式为 void *; 这种类型的指针可以被任意数据类型的指针赋值,如上面的a* 型,void *q = p; 唯一例外的是,不能把函数指针赋给它。
4
、关于const
修饰符
当const遇到指针,麻烦事就来了,看:const int* p; int* const p; const int* const p; 这三个表达式,第一个表示p是一个指针,p本身平凡无比,但是p所指向的对象是一个特殊的对象--整型常量;第二个表示:这个p指针不是一个普通的指针,它是个常量指针,即只能对其初始化,而不能赋值,另外,这个指针所指向的对象是一平凡的int型变量;第三个则结合了前两者:指针和指向的对象都非同寻常,都是常量。 有了const,赋值的问题就变得麻烦起来, 首先,对于 const int* p;这儿由于p指向的对象是个常量,所以在通过p来引用这个对象的时候不可对其进行赋值!对于一个常量对象,不可以用普通的指针指向,而必须用这种指向常量的指针,原因很简单,通过普通指针可以改变指向的那个值,但是对于一个非常量对象,即普通变量,可不可以将其地址赋给指向常量的指针呢?是可以的,但是一旦这样指向之后,由于这个指针本身定义的是指向常量的指针,因而编译器统一认为其是指向变量的,因而此时不可以通过该指针修改所指向的对象的值。 第二,对于 int* const p;这儿p本身是个常量指针,所以根本就不能赋值,所以不存在赋值的问题。不可以用常量对其进行初始化,因为这个指针不是指向常量的;只能用变量对其初始化。 第三,对于 const int* const p;这儿,只能初始化,不能赋值。可以利用常量进行初始化;也可以利用变量对其初始化,不过不可以利用该指针对该变量进行赋值。 const int* p这种指向常量对象的指针常用来用作某些函数的形参,用意是从编译器的角度防止用户在函数中将传递进去的参数修改,虽然用户本身也可以避免,但是这样更可靠一点--当用户不小心作出修改实参的行为时,编译器发现并阻止这种行为。 this指针是const xx* const型的。
5
、函数与指针
指向函数的指针:可以利用它代替函数名来调用函数。 如何定义函数指针,由于一个程序中可以用多个函数名相同的情形(即函数的重载),因而,定义函数指针的时候,必须包含函数的参数,这样才能准确地将指针指向某函数。 定义:int (*p)(const char*, int); 表示p是一个指向函数的指针,该函数的两个参数为const char* 和int,另外该函数返回int型值。 容易混淆的是:int *p(const char *, int); 缺少了一个括号,此时编译器的解释是 int* p(const char*, int);即其含义是一个函数的声明,函数名为p,返回一个指向int型的指针。那么 int* (*p)(const char*, int);则是定义了一个函数指针p,它指向一个函数,该函数的两个参数为const char*和int,该函数返回一个指向int型的指针 函数指针的初始化与初始化: 函数名如同数组名,编译器将其解释为指向该类型函数的指针,故而,可以领用函数名,或者&函数名对函数指针进行初始化或者赋值,另外,可以用另一个函数指针对该指针进行初始化以及赋值。重要的一点是指针与函数名,指针与指针必须具有完全相同的参数表和返回类型(必须完全完全一样,任何一点不同都不可以)。不存在隐式的类型转换,用户必须保证完全的一致性。 初始化或者赋值为0,表示不指向任何函数。 利用函数指针调用函数是可以p(x,y)这样调用,也可以(*p)(x,y)这样调用,前提是p已经正确的赋值或者初始化。 函数返回指针:可以返回一个非基本类型的对象。
6
、数组与指针
int a[3] = {1,2,3}; 考虑 a,a[0], &a, 以及 &a[0]这三个表达式的含义: 首先这三个表达式的数值结果是一样的--数组的首地址(即数组中第0个元素的地址),但是编译器对三者的解释不同: 对于a,编译器将其解释为一个指针,指向的是一个整型数据,因而利用a+1即指向数组中的第一的元素,a+2指向第二个元素。 对于a这个指针有些特殊的性质: a不是一个普通的指针,它同时是一个数组名,即关联了一个数组,因而某些性质上与普通的指针不同。 普通的指针可以被赋值,即可以用一个地址或者另一个指针修改当前指针的指向,然而对于a这种关联了一个数组的指针,如果允许这样赋值的话,那么数组中的元素将无法被访问,所以不允许对数组名代表的指针进行赋值。在这一点上a相当于指针常量,即只能被初始化,不可以进行赋值。 虽然a不可以被赋值,但是将a赋给其他的元素是完全可以的,这一点同普通的指针没有不同。 综上,a相当于一个指针常量。(type* const型的) 本质上a[i]操作被编译器解释为*(a+i)操作,即[]运算符是通过数组名指针实现的,因而&a[0]的含义即&(*a),显然对一个指针先*(解引用),再&(引用),等价于什么都没做,还是这个指针本身,因而a完全等价于&a[o],--(&a[0])[i]等价于a[i],形式有点诡异,呵呵。而对于&a这个表达式,奇怪的是这个也是数组的首地址,那么就是说,这个数组的首地址中存放了一个指针常量(即数组名),但是数组的首地址中不是存放的一个int型的数字吗?这是怎么回事呢?难道一个地址能存放两个东西? 暂时无法解释,可以这样认为编译器发现这种&和数组名的结合运算时,即返回数组首地址,只不过,这是,这仅仅是个纯粹的地址,它不再具有指针的特性,即编译器不再将其解释为指针,用户不可以通过+1运算来访问下一个数组元素。它的+1就是数学上的+1。 当数组变为多维,问题变成怎么样了呢? 考虑二维数组 int b[4][3] = {{1,2,3}, {4,5,6}, {7,8,9}, {10,11,12}}; b,&b, b[0], &b[0], &b[0][0]几个表达式的含义: 首先,c++中数组元素的存放是以行序为主序,即第一段存放第一行的数据,第二段存放第二行的数据,....,如此。 首先考虑数组名b,编译器同样将数组名b解释为一个指针,但是显然这个指针不是普通的指针。这个b指向数组所有元素的首地址,这一点是勿庸置疑的,那么这个指针一步跨越的内存是多大呢?在本例中,b一步跨越12个字节,即b一步跨越数组中的一行元素,实际上b是一个指针的指针,或者说指向指针的指针,即b所指向的内容是一个指针,(同样对于b+1,b+2),b[i][j]这种访问方式本质上即:先通过+i,将指针跳跃到第i行,从而获得了指向第i行首地址的指针b[i],然后通过这个指针,再通过+j,跳跃j步,到达了第j个元素,即找到第i行,第j列的元素。 所以b是指针的指针,b[i]是指针,这儿,b[i]类似于一维中的a。 那么&b呢?&b仍然是数组的首地址,但是跟一维类似的是,这是个纯粹的地址,不再具有指针的特性,它的+1就是数学上的+1,不可以利用+1来访问下一个元素。同样的道理对于&b[i],&运算符加上之后,本来是作为指针的b[i]被剥夺的指针的资格,返回一个纯粹的地址。 实际上,由于[]本质上是对指针的解引用,那么我们访问数组元素时可以不拘于a[i][j]这种方式,可以这样:(*(a+i))[j], 或者*(a[i]+j),或者 *(*(a+i)+j),这几种写法是等价的。 对于&b[i][j]呢?我们把b[i][j]换一种写法,写成*(*(b+i)+j),这样问题就容易看清楚了,原来的*b[i][j]就等价于&(*(*(b+i)+j)),我们可以把最外层的括号脱掉,就成了*(b+i)+j,即b[i]+j,显然这是一个指针,指向第i行,第j列元素的指针,对该指针的解释是一次跨越一个int型的数据。 让我们再变态一点,考虑三维的情形,虽然三维的数组不多见,还是考虑一下吧,毕竟空间的坐标是用三维表示的。 int c[2][3][4] = {{{1,2,3,4},{5,6,7,8},{9,10,11,12}}, {{13,14,15,16},{17,18,19,20},{21,22,23,24}}}; 首先,数组名c,编译器将c解释为一个指针,指向数组的首地址,由于行序是主序,所以,该指针一步跨越12个整型数,共48个字节,实际上即跨越了一个二维数组。 对于&c,跟一维二维的情形类似,是一个纯粹的地址. c[i]呢?可以推测,c[i]与二维中的b类似,即指向指针的指针,c[i]一步跨越4个整数,16个字节。c[i]是指向指针的指针,那么c便是指向指向指针的指针的指针(晕~)。 c[i]亦等价于*(c+i) 至于c[i][j],这才是真正的int型的指针,即指向真实数据的指针,一步跨越一个int型,4个字节。跟二维类似,对于&c[i][j],编译器返回一个地址,虽然跟c[i][j]的值一样,但是只是一个纯粹的地址,跨越单元为一个字节。 对于c[i][j][k],不需要废话,对于&c[i][j][k],这是一个地址吗?这是一个指针吗?我们还是要借助[]的另一种表示方法:c[i][j][k]等价于*(*(*(c+i)+j)+k),那么&c[i][j][k]就等价于*(*(c+i)+j)+k,即c[i][j]+k,即指向第(i,j,k)个元素的指针,一步跨越单元为一个int型。 让我们来看一看,寻找第(i,j,k)个元素有哪些写法: 1、c[i][j][k] 2、*(c[i][j]+k) 3、*(*(c[i]+j)+k) 4、*(*(*(c+i)+j)+k) 5、(*(c+i))[j][k] 6、(*(*(c+i)+j))[k] 7、*((*(c+i))[j]+k) 8、(*(c[i]+j))[k] 可见,共八种写法,实际上就是一共有三个解引用,选择用[]还是用*,这样,总共有8个组合。(那么二维的就是4种,一维的2种)
7
、typedef
与指针
typedef似乎很简单,如typedef int integer;然而,这些简单的typedef语句容易让人产生一种误解,typedef就是一种宏替换,把后面的自定义类型替换成前面的已知类型,事实是这样的吗?显然不是! 考虑这样的问题:如何定义一个指向整型的指针类型?如何定义一个函数指针类型? 第一个问题很简单:typedef int* int_pointer;即可,对于第二个问题,似乎就没有那么简单了,首先,看函数指针的定义方法:int (*p)(const&, int); 这个p指向的函数必须返回int,形参必须是const&和int。现在要将这种指针类型命名为func_pointer,其定义的方法如下: typedef int (*func_pointer)(const&, int); 可以这样来理解:typedef int integer;将typedef去掉,那就是个变量的定义,这儿即定义了一个int型的变量integer,考虑这个integer是什么类型的,那么这个typedef语句就是将integer定义为这个类型的。将typedef int (*func_pointer)(const&, int);中的typedef去掉,就成了一个函数指针定义,即func_pointer被定义为函数指针类型变量,那么原来的typedef即将func_pointer定义为函数指针类型。
8
、函数,数组与指针
int (*testCases[10])(); 这个表达式是什么意思?指针,数组,函数糅合在了一起问题变得复杂起来。它定义了数组,testCases[10],数组中的元素是函数指针,函数指针的类型是 int (*)(); 怎么来理解这种定义呢?首先考虑数组的定义,数组的定义一般模式是: 类型 数组名[大小]; 考虑这个表达式,似乎是定义了一个数组,但是数组名[大小]被夹在了中间,那么类型是什么呢,发现类型并不是简单的数据类型,而是一个函数指针类型int (*p)(),这个函数没有参数,返回int型。从而这个表达式的含义是:定义了一个函数指针型的数组,大小是10。 可以利用typedef来简化这种定义: typedef int (*PFV)(); PFV testCases[10]; 其实int (*testCases[10])();这儿我们定义了一个函数指针数组,数组是主体。 下面考虑这样的问题:如何定义一个指向数组的指针? 指向数组的指针,好像比较新鲜,所谓指向数组的指针,即指针的一步跨越是一个数组,跟指向整型的指针一步跨越一个整型一个道理。事实上前面已经碰到了指向数组的指针,如二维数组名,实际上就是一个指向数组的指针,它一次跨越一行的数据,实际上即是跨越了一个一维数组,而三维数组名呢,也是一个指向数组的指针,它一次跨越的是低维组成的一个二维数组。 数组指针(即指向数组的指针)的定义: int (*ptr)[3]; 这个表达式定义了一个数组指针ptr,ptr一次跨越一个由3个int型组成的一维数组。发现其定义的方式与函数指针定义的方式很相似,只是把()换作了[]。 更进一步,如果要定义一个指向数组的指针,而数组中的元素不是简单的int型,而是比较复杂的类型,那该如何定义呢?事实上数组指针这种东西就已经够稀有的了,一般编程绝对不会用到,我们只需要能读懂一些比较复杂的东西就行了,自己没有必要构造这么复杂的类型。 比较复杂的表达式: 1、int (*(*(*p())[])())[]; 首先,根据p()判断p是一个函数,再根据p()前面的*号判断该函数返回一个指针,下面就看这个指针指向的是什么类新了,我们可以把*p()替换成一个*pointer,这个pointer就是函数p返回的指针,那么就成了int (*(*(*pointer)[])())[];再根据(*pointer)[],这说明了指针pointer是指向的一个数组,那么这个数组中的元素是什么类型呢?由于数组名实际上就是个指针,我们把(*pointer)[](即(*p())[])替换成一个array,这样就成了 int (*(*array)())[];发现array是一个函数指针,从而数组中的每个元素是函数指针,而这个函数呢,又返回一个指针类型,把(*array)()用func代替,就成了int (*func)[];这说明了func函数返回的是指向数组的指针,数组中的元素是int型。 这个表达式够酷!!! 2、p = (int( * (*)[20])[10])q; 这是一个强制类型转换,q被强制类型转换成一个这样的指针类型,这个指针呢直线一个具有20个元素的数组,这个数组中的元素也是指针,是指向另外一种数组,这种数组是含有10个int型数据的一维数组。 可见,分析复杂的表达式时(所谓复杂,即糅合了指针,数组,函数三样,缺少了一样就不会复杂了),从括号的最里层做起,最里层的东西是复杂表达式的“根节点”,然后一层一层脱,脱的时候,是这样的,比如里层是个数组,那么就是说这个数组的元素是什么呢,那就是外层的东西,如果里层是个有返回值的函数,那么就是说这个函数返回什么值呢?那就是外层的东西,就这样一层一层地把表达式解析清楚。 关于typedef还有一些要说的: typedef int (*PFV)(); 这是定义了一个函数指针,那么PFV p;就可以定义了一个指向函数的指针。 typedef int (*p[10])(); 这是把p定义为函数指针数组,那么 p array;语句就可以定义了一个函数指针数组,数组名即为array,array这个数组含10个元素。 typedef int (*parray)[3];这是定义了一个指向整型数组的指针,那么 parray ptr;就定义了一个指向数组的指针。如何对这个ptr赋值或者初始化呢?事实上,是通过二维数组名来对其进行赋值(初始化)的,因为二维数组名作为指针来讲,就是一个指向数组的指针,一次跨越一个数组。 typedef int a[3][3]; 这个语句什么意思呢?这是把a定义为一个3*3的整型数组类型。当a b = {1}时就完成了一个3×3的整型数组的定义初始化的工作。 同样,简单一点 typedef int a[3];这个语句是把a定义为一个一维数组类型。 typedef void func(int); 这个语句定义了一个函数类型。通过这个typedef,我们可以比较清晰地定义出函数指针,func* p;即可。 typedef char* string; const string str; 这个str是什么类型的呢?const char * str,即指向常量的指针类型?事实上,答案有些不可思议,str是一个常量指针,而不是指针常量,即const修饰符针对的是指针,而不是char。
9
、引用与指针
引用类似与指针常量,只可初始化,不可赋值。别名(alias)是引用(reference)的另一种叫法。通过引用可以间接地操操纵对象。 常量引用,即类似与指向常量的常量指针,对常量引用的初始化,有一点特殊,可以用常量,变量,甚至是常数对其进行初始化。 对于用变量初始化常量引用,那么不能通过这个引用修改这个变量,但是本来的变量名可以。这一点,类似变量地址赋给常量指针。通过常量指针不可以修改变量,但是变量自身的变量名可以。 可以有指针的引用,如 int a = 1; int* p = &a; int* &r = p; 那么r就成了指针p的引用。如果是const int* p = &a;说明是常量指针,那么定义引用的时候,就要如此定义,const int* &r = p;这个语句说明r是一个指针的引用,这个指针是个指向常量的指针变量,而并不意味着这个引用是个常量引用。那如果说这个指针不仅仅是常量指针,而且是个指针常量,即const int* const p;那么定义引用时要注意应该const int* const &r = p;这样表明该引用是个常量引用。这里有一个问题当用一个变量的地址初始化引用时如,int a = 22; int* const &pi_ref = &a;需要注意应该定以为常量引用,因为&a不是变量名,而是类似常数。而若const int a = 22;则应该const int* const &pi_ref = &a;即中间的const是用来定义常量引用的,而前面的const反映的是引用指向的对象(指针)是指向的的const对象。 我们有对象名,或者对象的指针,这些都可以操纵对象,为何要引入引用的概念呢? 事实上,引用最常用的是用作函数的形参。要在函数中操纵一个外部对象的时候,利用引用是一个好办法。 关于引用 首先,引用只可初始化,不可被赋值,因为,被初始化后的引用,就成了被引用的对象的别名,再行赋值,就不是对引用本身的赋值了,而是对所引用的对象的赋值了。
网站标题:星号的秘密-创新互联
路径分享:
http://www.cdkjz.cn/article/dsscdp.html
返回首页
了解更多建站资讯
相关资讯
linux命令去掉网关 linux 删除网关
横向超出隐藏css样式 css横向居中
android单选试题 android面试题选择题
笔记本mysql怎么连接 怎样连接mysql
jquery输入动态匹配 用jquery实现动态添加
数字框html5 数字框框
ios开发者微信美化 ios微信美化教程
需要开发者更新在ios9 需要开发者更新app怎么办
多年建站经验
多一份参考,总有益处
联系快上网,免费获得专属《策划方案》及报价
咨询相关问题或预约面谈,可以通过以下方式与我们联系
大客户专线 成都:
13518219792
座机:
028-86922220
在线咨询
提交需求