程序员人生 网站导航

c++教程(十三(下):Pointers)

栏目:php教程时间:2016-12-07 08:55:58

————————————————————————

该系列教程为翻译c++官方教程,点击参考英文原版,水平有限,翻译不通的地方敬请体谅!

————————————————————————

指针算法

对指针进行算术操作和整数类型稍有不同。首先,指针只有加法和减法运算是允许的;其他的对指针来讲是没成心义的。但是,不管是加法和减法对指针,根据他们指向数据类型的大小,都有1个略微不同的表现。

当引入基本数据类型,我们看到类型有不同的大小。例如:char大小为1字节,short1般更大,int和long更大;具体大小依赖于系统的精确。例如,让在1个给定的系统中,假设char需要1个字节,那末short需要2个字节,而long需要4个字节。

现在加入我们在编译器中有3个指针:

char *mychar; short *myshort; long *mylong;

指针的初始地址分别为:1000,2000和3000.
那末如果我们履行下面操作:

++mychar; ++myshort; ++mylong;

那末和我们期待的1样,mychar将会指向1001地址,但是myshort将会指向2002,而mylong将会指向3004. 虽然他们都只被增加了1次。缘由是,当向指针添加1个时,指针指向同1类型的下1个元素,因此,它所指向的类型的字节的大小将被添加到指针上。
这里写图片描述
当增加和减去任何数字到1个指针也是适用的。如果我们写成下面这样,那末实现的功能和上面将会完全相同:

mychar = mychar + 1; myshort = myshort + 1; mylong = mylong + 1;

关于自增(+ +)和自减(–)操作,他们都可以被用来作为前缀或后缀的表达,在功能上有轻微的差异:作为1个前缀,表达式在增量产生之前的履行,作为1个后缀,表达式在增量产生后履行。这也适用于表达自增和自减指针,它可以成为更复杂的表达式,还包括部份援用操作符()。记住运算符优先级的规则,我们可以回想1下,后缀式操作符,如自增和自减,比前缀操作符的优先级更高的,如解援用操作符()。因此,下面的表达式:
*p++

等价于 *(p++),它所做的就是增加P值(所以它现在指向下1个元素),但由于++作为后缀,全部表达式被求值后指向原来的指针(它指向的地址递增)。

从本质上讲,这些是用的前缀和后缀增量运算符和与解援用操作符的4种可能的组合(一样适用也减量运算符):

*p++ // same as *(p++): increment pointer, and dereference unincremented address *++p // same as *(++p): increment pointer, and dereference incremented address ++*p // same as ++(*p): dereference pointer, and increment the value it points to (*p)++ // dereference pointer, and post-increment the value it points to

1个典型的-但不是那末简单的语句是:

*p++ = *q++;

由于++的优先级比*更高,p和q是先自增,但由于增量运算符(++)作为后缀而不是前缀,分配到*p值和*Q是自增的。这样都自增。这大致相当于:

*p = *q; ++p; ++q;

一样,加括号更能清晰表达以减少混乱。

指针与常量

指针可以被用来访问1个变量的地址,包括修改指向地址的值。但是也能够在访问指向地址指针读取的时候声明,这样就不可以修改它。对这1点,那末所指向的类型就为const指针。例如:

int x; int y = 10; const int * p = &y; x = *p; // ok: reading p *p = x; // error: modifying p, which is const-qualified

这里p指向1个变量,但指出它是const方式,这意味着它是可读的指针,但不能修改它。注意,这表达&y是int*类型,但这是赋给1个指针类型const int *。这是允许的:1个指向非const可以隐式转换为指向const对象的指针。但不是其他方式!为了安全,指向const指针不可隐式转换为非const指针。

指向const元素的1个指针例子是作为函数的参数:1个函数接受1个指向非const参数作为传递参数的值,而函数不能接受1个指向const对象的指针作为参数。

// pointers as arguments: #include <iostream> using namespace std; void increment_all (int* start, int* stop) { int * current = start; while (current != stop) { ++(*current); // increment value pointed ++current; // increment pointer } } void print_all (const int* start, const int* stop) { const int * current = start; while (current != stop) { cout << *current << '\n'; ++current; // increment pointer } } int main () { int numbers[] = {10,20,30}; increment_all (numbers,numbers+3); print_all (numbers,numbers+3); return 0; }

注意,print_all使用指针指向常量元素。这些指针指向常量的内容不能修改,但他们不是常量本身:即指针依然可以递增或分配不同的地址,虽然他们他们指向的内容不能修改。

下面是将第2维度添加到指针:指针也能够是const指针。这是通过添加const指出类型指定(星号后面):

int x; int * p1 = &x; // non-const pointer to non-const int const int * p2 = &x; // non-const pointer to const int int * const p3 = &x; // const pointer to non-const int const int * const p4 = &x; // const pointer to const int

用const与指针的语法是很辣手的,合适的使用常常会需要1些经验。在任何情况下,取得指针常量(援用)的权限宜早不宜迟,但也不应当过分担心,如果是第1次接触到const和指针的组合,那末更多例子在后面的章节中显示出来。

const指针的语法更混乱的操作是,const限定符可以位于前面或后面,具有的意义相同:

const int * p2a = &x; // non-const pointer to const int int const * p2b = &x; // also non-const pointer to const int

与星号相邻,在这类情况下,const的顺序是1件简单的风格。本章使用前缀const,由于历史的缘由,可以扩大很多种,但二者是完全等价的。每种风格的优点在互联网上仍有剧烈的争辩。

指针和字符串

前面指出,字符串是包括空终止字符序列的数组。在前面的章节,字符串被用来直接插入cout来初始化字符串和字符数组。

但也能够直接访问。字符串数组类型是包括所有字符加终止null字符的数组,每一个元素的类型是const char(像字面表示的1样,永久不会被修改)。例如:

const char * foo = "hello";

这里声明1个“hello”的字符串数组,然后Foo指针指向其第1个元素。如果我们假定“hello”是存储在地址1702的内存位置,我们可以表示为:

这里写图片描述

注意foo是1个值为1702的指针变量,不是‘h’,也不是‘hello’,虽然地址1702是指向这些元素的地址。
Foo是指向这1序列的指针,由于指针与数组的表示方式是相通的,foo可以1下面两种方式访问:

*(foo+4) foo[4]

上面两种方式都可以得到值‘o’(即数组的第5个元素)。

指向指针的指针

C++允许定义指向指针的指针,也就是指向了数据(或其他指针),所使用的符号就是在指针前面简单的加上*。

char a; char * b; char ** c; a = 'z'; b = &a; c = &b;

像这里,随机初始化3个内存地址为7230,8092,10502,那末上面就能够表示为:
这里写图片描述

每一个变量的值在其相应的单元格中表示的每一个变量,它们在内存中的值所表示的值在他们内存值上上方。
在这个例子中的c是1个指向指针的指针,可间接用于3个不同的层次,它们中的每个对应于1个不同的值:
(1) C是char**类型,值为8092
(2) *c是char*类型,值为7230
(3) **c为char类型,值为‘z’

空指针

空指针是1种特殊的类型,在c++,void代表空类型。因此,void空指针指向的数据没有类型(因此它的长度和相干属性不肯定)。

这就是的空指针有很大的灵活性,可以指向任何数据类型,从1个整型或1个浮点型到1个字符串字符的空指针。一样相反,他们就有很大的局限性:他们指向的数据不能直接援用(这是合乎逻辑的,由于我们不知道类型),由于这个缘由,在1个void指针需要转化为其他1些指针类型时,被援用之前需要指向1个具体的数据类型的地址。

下面是1个传递函数参数的例子:

// increaser #include <iostream> using namespace std; void increase (void* data, int psize) { if ( psize == sizeof(char) ) { char* pchar; pchar=(char*)data; ++(*pchar); } else if (psize == sizeof(int) ) { int* pint; pint=(int*)data; ++(*pint); } } int main () { char a = 'x'; int b = 1602; increase (&a,sizeof(a)); increase (&b,sizeof(b)); cout << a << ", " << b << '\n'; return 0; }

C++中sizeof是1个获得数据类型大小的操作符。对非动态的数据,这个值是常量。因此例如sizeof(char)是1,由于char型数据占用1个字节大小。

无效的指针和空指针

在原则上,指针需要指向有效的地址,如变量的地址或数组中元素的地址。但指针实际上可以指向任何地址,包括没有任何有效元素的地址。典型的例子是未初始化的指针和指向数组中不存在的元素:

int * p; // uninitialized pointer (local variable) int myarray[10]; int * q = myarray+20; // element out of bounds

不管p还是q都没有指向某个已知值的地址,但上述任何语句都不会致使毛病。在C++中,指针是可以指向任何地址值,不管在那个地址是不是有值。甚么会致使毛病对的是援用这样1个指针(即,访问他们实际指向的值)。这样的访问指针会致使未定义行动,在运行时出现毛病值访问1些随机值。
有时,1个指针需要显式指向无处,而不单单是1个无效的地址。对这类情况,存在1个特殊的值,即任何指针类型都可以采取:null指针值。这个值可以以两种方式在C++表示:1个整数为零的值,或nullptr关键字:

int * p = 0; int * q = nullptr;

在这里,P和Q都是空指针,意味着它们不指向任何地方,这里它们实际上是相等的:所有的null指针等于其他的null指针。也很常见的是,在旧的代码中使用定义的常量 NULL来援用空指针值:

int * r = NULL;

NULL包括在标准库中,被定义成null常量指针(比如0或nullptr)
不要将null指针与void指针弄混淆了。1个null指针是1个值,任何指针都可以表示它,不指向任何地方,而1个void指针是1个指向没有特定类型的指针的指针类型。1个是指存储在指针中的值,另外一个是指向它指向的数据类型。

指向函数的指针

C++允许操作的函数指针。典型用处是传递函数作为对另外一个函数的1个参数。函数指针与语法与1个普通的函数相同,除函数的名字是用括号括起来()和在名字之前插入星号(*)。

// pointer to functions #include <iostream> using namespace std; int addition (int a, int b) { return (a+b); } int subtraction (int a, int b) { return (a-b); } int operation (int x, int y, int (*functocall)(int,int)) { int g; g = (*functocall)(x,y); return (g); } int main () { int m,n; int (*minus)(int,int) = subtraction; m = operation (7, 5, addition); n = operation (20, m, minus); cout <<n; return 0; }

在上面的例子中,minus就是1个有两个int参数类型的函数指针。它直接初始化到函数subtraction:

int (* minus)(int,int) = subtraction;
------分隔线----------------------------
------分隔线----------------------------

最新技术推荐