`
hcmfys
  • 浏览: 357746 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

c++ point

    博客分类:
  • c#
阅读更多
介绍

曾碰到过让您迷惑不解、类似于int * (* (*fp1) (int) ) [10];这样的变量声明吗?本文将由易到难,一步一步教会您如何理解这种复杂的C/C 声明:我们将从每天都能碰到的较简单的声明入手,然后逐步加入const修饰符和typedef,更有函数指针,最后介绍一个能够让您准确地理解任何C/C 声明的“右左法则”。需要强调一下的是,复杂的C/C 声明并不是好的编程风格;我这里仅仅是教您如何去理解这些声明。注意:为了确保能够在同一行上显示代码和相关注释,本文最好在至少1024x768分辨率的显示器上阅读。

基础

让我们从一个很简单的例子开始,如下:

int n;

这个应该被理解为“declare n as an int”(n是个int型的变量)。

接下去来看一下指针变量,如下:

int *p;

这个应该被理解为“declare p as an int *”(p是个int *型的变量),或说p是个指向一个int型变量的指针。我想在这里展开讨论一下:我觉得在声明一个指针(或引用)类型的变量时,最好将*(或&)写在紧靠变量之前,而不是紧跟基本类型之后。这样能够避免一些理解上的误区,比如:

int* p,q;

第一眼看去,似乎是p和q都是int*类型的,但事实上,只有p是个指针,而q是个最简单的int型变量。

我们还是继续我们前面的话题,再来看一个指针的指针的例子:

char **argv;

理论上,对于指针的级数没有限制,您能够定义一个浮点类型变量的指针的指针的指针的指针...

再来看如下的声明:

int RollNum[30][4];
int (*p)[4]=RollNum;
int *q[5];

这里,p被声明为一个指向一个4元素(int类型)数组的指针,而q被声明为一个包含5个元素(int类型的指针)的数组。

另外,我们还能够在同一个声明中混合实用*和&,如下:

int **p1; // p1 is a pointer to a pointer to an int.
int *&p2; // p2 is a reference to a pointer to an int.
int &*p3; // ERROR: Pointer to a reference is illegal.
int &&p4; // ERROR: Reference to a reference is illegal.

注:p1是个int类型的指针的指针;p2是个int类型的指针的引用;p3是个int类型引用的指针(不合法!);p4是个int类型引用的引用(不合法!)。

const修饰符

当您想阻止一个变量被改变,可能会用到const关键字。在您给一个变量加上const修饰符的同时,通常需要对他进行初始化,因为以后的任何时候您将没有机会再去改变他。例如:

const int n=5;
int const m=10;

上述两个变量n和m其实是同一种类型的--都是const int(整形恒量)。因为C 标准规定,const关键字放在类型或变量名之前等价的。我个人更喜欢第一种声明方式,因为他更突出了const修饰符的作用。

当const和指针一起使用时,容易让人感到迷惑。例如,我们来看一下下面的p和q的声明:

const int *p;
int const *q;

他们当中哪一个代表const int类型的指针(const直接修饰int),哪一个代表int类型的const指针(const直接修饰指针)?实际上,p和q都被声明为const int类型的指针。而int类型的const指针应该这样声明:

int * const r= &n; // n has been declared as an int

这里,p和q都是指向const int类型的指针,也就是说,您在以后的程式里不能改变*p的值。而r是个const指针,他在声明的时候被初始化指向变量n(即r=&n;)之后,r的值将不再允许被改变(但*r的值能够改变)。

组合上述两种const修饰的情况,我们来声明一个指向const int类型的const指针,如下:

const int * const p=&n // n has been declared as const int

 下面给出的一些关于const的声明,将帮助您完全理清const的用法。但是请注意,下面的一些声明是不能被编译通过的,因为他们需要在声明的同时进行初始化。为了简洁起见,我忽略了初始化部分;因为加入初始化代码的话,下面每个声明都将增加两行代码。

char ** p1; // pointer to pointer to char
const char **p2; // pointer to pointer to const char
char * const * p3; // pointer to const pointer to char
const char * const * p4; // pointer to const pointer to const char
char ** const p5; // const pointer to pointer to char
const char ** const p6; // const pointer to pointer to const char
// 本文转自 C Builder 研究 - http://www.ccrun.com/article.asp?i=623&d=7l5wwi
char * const * const p7; // const pointer to const pointer to char
const char * const * const p8; // const pointer to const pointer to const char

注:p1是指向char类型的指针的指针;p2是指向const char类型的指针的指针;p3是指向char类型的const指针;p4是指向const char类型的const指针;p5是指向char类型的指针的const指针;p6是指向const char类型的指针的const指针;p7是指向char类型const指针的const指针;p8是指向const char类型的const指针的const指针。

typedef的妙用

typedef给您一种方式来克服“*只适合于变量而不适合于类型”的弊端。您能够如下使用typedef:

typedef char * PCHAR;
PCHAR p,q;

这里的p和q都被声明为指针。(假如不使用typedef,q将被声明为一个char变量,这跟我们的第一眼感觉不太一致!)下面有一些使用typedef的声明,并且给出了解释:

typedef char * a; // a is a pointer to a char

typedef a b(); // b is a function that returns
// a pointer to a char

typedef b *c; // c is a pointer to a function
// that returns a pointer to a char

typedef c d(); // d is a function returning
// a pointer to a function
// that returns a pointer to a char

typedef d *e; // e is a pointer to a function
// returning a pointer to a
// function that returns a
// pointer to a char

e var[10]; // var is an array of 10 pointers to
// functions returning pointers to
// functions returning pointers to chars.

typedef经常用在一个结构声明之前,如下。这样,当创建结构变量的时候,允许您不使用关键字struct(在C中,创建结构变量时需要使用struct关键字,如struct tagPOINT a;而在C 中,struct能够忽略,如tagPOINT b)。

typedef struct tagPOINT
{
int x;
int y;
}POINT;

POINT p; /* Valid C code */



函数指针

函数指针可能是最容易引起理解上的困惑的声明。函数指针在DOS时代写TSR程式时用得最多;在Win32和X-Windows时代,他们被用在需要回调函数的场合。当然,更有其他很多地方需要用到函数指针:虚函数表,STL中的一些模板,Win NT/2K/XP系统服务等。让我们来看一个函数指针的简单例子:

int (*p)(char);

这里p被声明为一个函数指针,这个函数带一个char类型的参数,并且有一个int类型的返回值。另外,带有两个float类型参数、返回值是char类型的指针的指针的函数指针能够声明如下:

char ** (*p)(float, float);

那么,带两个char类型的const指针参数、无返回值的函数指针又该如何声明呢?参考如下:

void * (*a[5])(char * const, char * const);

“右左法则”[重要!!!]

The right-left rule: Start reading the declaration from the innermost parentheses, go right, and then go left. When you encounter parentheses, the direction should be reversed. Once everything in the parentheses has been parsed, jump out of it. Continue till the whole declaration has been parsed.

这是个简单的法则,但能让您准确理解任何的声明。这个法则运用如下:从最内部的括号开始阅读声明,向右看,然后向左看。当您碰到一个括号时就调转阅读的方向。括号内的任何内容都分析完毕就跳出括号的范围。这样继续,直到整个声明都被分析完毕。

对上述“右左法则”做一个小小的修正:当您第一次开始阅读声明的时候,您必须从变量名开始,而不是从最内部的括号。

下面结合例子来演示一下“右左法则”的使用。

int * (* (*fp1) (int) ) [10];

阅读步骤:
1. 从变量名开始 -------------------------------------------- fp1
2. 往右看,什么也没有,碰到了),因此往左看,碰到一个* ------ 一个指针
3. 跳出括号,碰到了(int) ----------------------------------- 一个带一个int参数的函数
4. 向左看,发现一个* --------------------------------------- (函数)返回一个指针
5. 跳出括号,向右看,碰到[10] ------------------------------ 一个10元素的数组
6. 向左看,发现一个* --------------------------------------- 指针
7. 向左看,发现int ----------------------------------------- int类型

总结:fp1被声明成为一个函数的指针,该函数返回指向指针数组的指针.

再来看一个例子:

int *( *( *arr[5])())();

阅读步骤:
1. 从变量名开始 -------------------------------------------- arr
2. 往右看,发现是个数组 ---------------------------------- 一个5元素的数组
3. 向左看,发现一个* --------------------------------------- 指针
4. 跳出括号,向右看,发现() -------------------------------- 不带参数的函数
5. 向左看,碰到* ------------------------------------------- (函数)返回一个指针
6. 跳出括号,向右发现() ------------------------------------ 不带参数的函数
7. 向左,发现* --------------------------------------------- (函数)返回一个指针
8. 继续向左,发现int --------------------------------------- int类型

总结:??

更有更多的例子:

float ( * ( *b()) [] )(); // b is a function that returns a
// pointer to an array of pointers
// to functions returning floats.

void * ( *c) ( char, int (*)()); // c is a pointer to a function that takes
// two parameters:
// a char and a pointer to a
// function that takes no
// parameters and returns
// an int
// and returns a pointer to void.

void ** (*d) (int &, char **(*)(char *, char **)); // d is a pointer to a function that takes
// two parameters:
// a reference to an int and a pointer
// to a function that takes two parameters:

// a pointer to a char and a pointer

 // to a pointer to a char



// and returns a pointer to a pointer
// to a char
// and returns a pointer to a pointer to void

float ( * ( * e[10]) (int &) ) [5]; // e is an array of 10 pointers to
// functions that take a single
// reference to an int as an argument
// and return pointers to

// an array of 5 floats.

 

 

 

 


 

 

分享到:
评论

相关推荐

    c++ point 类

    类的继承与多态课程的渗透灌溉的,面向对象程序编程的

    C++ point类 求矩形面积及两点距离

    1) 定义一个Point类,其属性包括点的坐标,提供计算两点之间距离的方法; (2) 定义一个矩形类,其属性包括左上角和右下角两个点,提供计算面积的方法; (3) 创建一个矩形对象,提示用户输入矩形左上角和右下...

    C++point的编写

    仅供参考 .

    C++point.pptx

    简单快速的教会你C++指针的各种使用,让你在C++的指针方块上毫无阻碍

    Rec-Point c++

    ### C++知识点解析 #### 一、类定义与构造函数 在给定的代码中,定义了两个类:`Point` 和 `Rec`。 - **`Point` 类**: - 定义了一个二维平面上的点。 - 包含了两个私有成员变量 `x` 和 `y` 表示点的坐标。 - ...

    curvature_curvature_点云曲率_C++_pointcloud_

    在C++中,Point Cloud Library (PCL) 是一个广泛使用的开源库,专门用于处理3D点云数据。PCL 提供了丰富的功能,包括点云的滤波、分割、特征提取等。对于计算点云的曲率,我们需要首先计算每个点的法向量。法向量是...

    灰点point gray相机 C++硬触发回调实例

    灰点相机C++硬触发实例 VS2013 main.cpp 需要自己选择需要的代码

    如何获得窗口句柄

    HWND WindowFromPoint(POINT& Point); ``` **参数说明:** - `Point`: 包含屏幕坐标点的结构体。 **示例代码:** ```c++ POINT pt; GetCursorPos(&pt); HWND hWnd = WindowFromPoint(pt); ``` **注意点:** - ...

    用c++编写一个程序,设计一个点类Point,求两个点之间的距离。

    用c++编写一个程序,设计一个点类Point,求两个点之间的距离。

    CC++中typedefstruct和struct的用法.doc

    在C/C++编程语言中,`struct`关键字用于定义自定义的数据结构,它允许我们将多个不同类型的数据成员组合在一起。而`typedef`则是一种类型别名的声明方式,它可以用来为已存在的类型创建一个新的名字。当`struct`和`...

    ARM C and C++ Libraries and Floating-Point Support

    ### ARM C和C++库及浮点支持详解 #### 概述 ARM C和C++库及浮点支持是ARM工具链的一个重要组成部分,主要用于帮助开发者在基于ARM架构的微控制器上开发高效、稳定的嵌入式系统应用。本文将详细介绍ARM C/C++库的...

    中国的acm题目,相当不错,做完就可以进阶了

    大学这些年的题目,好东西,acm题目,有关个人学习的相当不错的资料

    pointnet++编译后的文件.zip

    在CUDA环境中,编译通常涉及CUDA C++源文件(如`.cu.o`),这些文件是编译器将CUDA代码转换为GPU可执行的中间对象文件。`tf_sampling_g.cu.o`和`tf_grouping_g.cu.o`很可能包含了PointNet++中的关键操作,如采样和...

    C++ 课程作业 多态性 运算符重载-综合(Point类)

    请定义一个Point类,将前置++和后置++运算符重载为成员函数,实现成员变量m_x和m_y的加一操作 同时重载流插入运算符,实现对Point类对象的格式化输出。例如 Point p; cout; 输出结果为: (0,0) 请根据给定的main...

    VC API常用函数简单例子大全

    ```c++ HWND WINAPI FindWindow( LPCSTR lpClassName, LPCSTR lpWindowName ); ``` **函数说明**: `FindWindow` 函数是用于根据窗口类名或窗口标题名来获取指定窗口的句柄(HWND)。此函数非常实用,尤其是在需要...

    C++服务器开发精髓笔记

    2. Pimpl(Point to Implementation) Pimpl是一种C++编程模式,旨在隐藏核心数据和私有函数,保持对外接口不变。优点包括核心数据被隐藏,对使用者透明,提高安全性,接口与实现分离,降低编译依赖。 3. C++11新...

    C++ 14.0.zip

    - **二进制复数(Binary literals for floating-point constants)**:C++14引入了二进制浮点数字面量,如`0b1.0p3`,这在处理位操作和硬件接口时非常有用。 - **`std::make_unique`**:为`std::unique_ptr`提供了...

    pointnet++权重文件

    PointNet++是这一领域的里程碑式工作,由Charles R. Qi等人在2017年提出,它是PointNet(一种对3D点云数据进行深度学习的架构)的扩展版本。PointNet++的主要目标是处理点云的局部结构,从而提高对复杂3D形状的理解...

    聚类经典程序kmeans的c++源码

    《KMeans算法的C++实现解析》 KMeans算法是一种广泛应用的数据聚类方法,它以其简单易懂和高效性在机器学习领域占有重要地位。在本文中,我们将深入探讨KMeans算法的基本原理,并通过C++源码分析其具体实现过程。 ...

    c++调用C# COM 参数是结构体数组

    在 C# 中,结构体数组是使用数组类型来定义的,如 `_CAPI_Point3d[] tst = new _CAPI_Point3d[count];`。在这个例子中,我们定义了一个 _CAPI_Point3d 结构体数组,数组长度为 count。 Marshal 类 在 C# 中,...

Global site tag (gtag.js) - Google Analytics