指针

指针

我们已经看到视为变量是如何记忆的细胞,它可以使用他们的标识符访问。   通过这种方式,我们没有关心我们的数据在内存中的物理位置,我们只是使用它的标识符,每当我们想参考我们的变量。  

您的计算机内存可以被想象成一个连续的存储单元,每一个计算机管理(一个字节)的最小尺寸。   在这些单字节的存储单元的编号,以连续的方式,从而,在任何的内存块上,每个单元都具有相同数目的前一加一。  

通过这种方式,可以容易地位于每个单元格在存储器中,因为它有一个唯一的地址,所有存储单元按照连续的图案。   例如,如果我们正在寻找电池1776我们知道这将是对细胞之间的1775和1777年,一个776个细胞后,正是千细胞细胞前2776。  

参考符(&)

只要我们声明了一个变量,需要的内存量分配在内存中的特定位置(它的内存地址)。   我们一般不主动决定的确切位置,变量于细胞的面板,我们想像中的内存 - 幸运的是,这是一个在运行时由操作系统自动执行任务。   然而,在某些情况下,我们可能有兴趣知道我们的变量的地址被存储在运行过程中有它的相对位置,以便操作。  

找到一个变量在内存中的地址,也就是我们所说的该变量的参考 。   &符号(&),称为引用操作符,可以直译为“地址”的变量标识符前,可以通过这个变量引用。   例如:  

 
 ted = &andy; 


这将分配给特德变量 andy的地址,因为我们不再谈论变量本身的内容与参考符(&)变量安迪的名称前时,但关于它的参考(即其地址内存)。  

从现在起,我们将假定, 安迪是放置在运行时的内存地址1776。   这个数字(1776)是为了帮助澄清一些概念,在本教程中,我们发明现在只是一个任意的假设,但在现实中,我们无法知道运行之前的真正价值将在内存中有一个变量的地址。  

考虑下面的代码片段:  

 1 
 2 
 3 
 
 andy = 25; fred = andy; ted = &andy; 


后每一个变量,则执行该包含的值,在下面的图所示:  


首先,我们已经分配值25 安迪 (一个变量,其地址在内存中,我们假设为1776)。  

第二条语句复制到弗雷德的内容变量ANDY(25)。   这是一个标准的赋值操作,因为我们已经做了这么多遍。  

最后,第三个语句复制特德不包含的价值,但在安迪的参考(即它的地址,这是我们假设为1776)。   其原因是,在上述第三个赋值操作,我们前面安迪与参考符(&)的标识符,因此,我们不再指安迪的值,但其参考(其在存储器中的地址)。  

的参考变量存储到另一个变量(在前面的例子像TED),也就是我们所说的一个指针 。   指针是C + +语言,有许多用途,在高级编程的一个非常强大的功能。   更远的将来,我们将看到如何使用这种类型的变量,并宣布。  

引用操作符(*)


刚才我们看到,一个变量的引用存储到另一个变量的指针。   指针“指向”的变量,其参考它们存储。  

使用指针,我们可以直接访问存储在变量,它指向的价值。   要做到这一点,我们根本指针的标识符前面带有星号(*),它作为引用操作符,可以直译为“指出”价值。  

因此,与前面的例子中的值,如果我们写:  

 
 beth = *ted; 


(我们可以读为:“ 贝丝ted所指向的值相等”) 贝丝将采取的值为25,TED1776,指向的值由1776年的25。  


必须明确区分的表达泰德是指1776的值,而*泰德 (带星号*的前标识符)是指在地址1776中存储的值,在这种情况下,为25。   包括或不包括引用操作符(我已经包含了这两个表达式可以读取的解释性评论)注意区别:  

 1 
 2 
 
 beth = ted; // beth equal to ted ( 1776 ) beth = *ted; // beth equal to value pointed by ted ( 25 ) 


注意区别之间的参考和参照运算:  
  • &引用操作,可以理解为“地址”
  • *是引用操作符,可以理解为“所指向的数值”
因此,他们有互补(或相反)的含义。   引用变量&*可以解除引用。  

早些时候,我们进行了以下两个赋值操作:  

 1 
 2 
 
 andy = 25; ted = &andy; 


右后这两个语句,下列词汇会给真实结果:  

 1 
 2 
 3 
 4 
 
 andy == 25 &andy == 1776 ted == 1776 *ted == 25 


第一个表达式是很清楚考虑, 安迪上进行赋值操作是安迪= 25。   第二个使用引用操作符(&),返回的地址变量安迪 ,我们假设它有一个价值1776。   第三个是有些明显,因为是真实的,第二个表达式进行赋值操作上TED TED =&安迪 。   第四个表达式使用引用操作符(*),正如我们刚才看到的,可以理解为“所指向的数值”,ted所指向的值确实是25。  

所以,经过这一切,你可能还可以推断,只要ted所指向的地址保持不变,下面的表达式也将是真实的:  

 
 *ted == andy 


声明变量的指针类型

的指针直接参考值,它指向的能力,有必要在其声明中指定的数据类型的指针将会指向。   这是不一样的东西指向一个char指向int浮点数 。  

指针的声明的格式如下:  

类型*名称;  

其中类型是数据类型的值的指针以指向。   此类型是不同的指针本身!   但类型的数据的指针指向。   例如:  

 1 
 2 
 3 
 
 int * number; char * character; float * greatnumber; 


这三种申报指针。   每一个的目的是指向不同的数据类型,但实际上所有的人都指针和所有的人都会占据相同的空间量,在存储器中(在存储器中的指针的大小取决于平台上的代码将会运行)。   然而,它们指向到的数据不占据相同的空间量也不相同类型的:第一个点,一个int,第二个到一个char,最后一个 float。   因此,虽然这三个实例变量是所有的人都占用相同的内存大小的指针,他们说,有不同的类型: 整数,字符*和 float *,它们指向的类型而定。  

我想强调,声明一个指针时,我们使用星号(*)只意味着它是一个指针(这是其类化合物符的一部分),不应该被混淆与引用操作符,我们已经看到了早一点,但它也写有一个星号(*)。   他们根本就是两个不同的事物具有相同的符号表示。  

现在有一个看看这段代码:  

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 
 // my first pointer #include <iostream> using namespace std; int main () { int firstvalue, secondvalue; int * mypointer; mypointer = &firstvalue; *mypointer = 10; mypointer = &secondvalue; *mypointer = 20; cout << "firstvalue is " << firstvalue << endl; cout << "secondvalue is " << secondvalue << endl; return 0; } 
  的FirstValue 10 
  secondvalue 20 


请注意,即使我们从来没有直接到任的FirstValuesecondvalue值,两端设置了间接通过mypointer使用设置的值。   程序是这样的:  

首先,我们已指派值参考mypointer的FirstValue使用引用操作符(&)。   然后,我们已分配值10的内存位置由mypointer指出,因为在这一刻指向的内存位置的FirstValue,这其实修改的价值的FirstValue的 。  

为了说明的指针,可能需要几个不同的值,在同一个程序,我已经重复的过程与secondvalue,相同的指针,mypointer。  

下面是一个例子,多一点点阐述:  

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 
 // more pointers #include <iostream> using namespace std; int main () { int firstvalue = 5, secondvalue = 15; int * p1, * p2; p1 = &firstvalue; // p1 = address of firstvalue p2 = &secondvalue; // p2 = address of secondvalue *p1 = 10; // value pointed by p1 = 10 *p2 = *p1; // value pointed by p2 = value pointed by p1 p1 = p2; // p1 = p2 (value of pointer is copied) *p1 = 20; // value pointed by p1 = 20 cout << "firstvalue is " << firstvalue << endl; cout << "secondvalue is " << secondvalue << endl; return 0; } 
  的FirstValue 10 
  secondvalue 20 


我已经可以读取每一行代码如何作为注释符号(&)“地址”和星号(*)“所指向的数值”。  

请注意,有指针p1p2,都与不引用操作符(*)的表达式。   表达式中使用引用操作符(*)的含义是非常不同的,从一个不:当这个操作符之前的指针名,表达式是指被指向的值,而当指针的名字没有出现这个操作符,它是指指针本身的值(即指针指向的地址)。  

请您注意另一件事,可能是线路:  

 
 int * p1, * p2; 


此声明在前面的例子中使用的两​​个指针。   但是要注意,有一个星号(*)的每个指针,为了保证两个类型是int *(int类型的指针)。  

否则,第二个变量的类型,在该行宣布将一直INT(不是 int *)由于优先级的关系。   如果我们写:  

 
 int * p1, p2; 


P1的确是int *类型,,但P2将有类型为int(空格并不重要,所有为此目的)。   这是由于运算符的优先级规则。   但无论如何,只需记住,你必须把每一个星号指针是足以让大多数指针用户。  

指针和数组

阵列的概念是非常绑定到一个指针。   事实上,一个数组的识别符是相当于它的第一个元素的地址,作为一个指针的第一个元素的地址,它指向,因此,实际上它们是相同的概念。   例如,假设这两个声明:  

 1 
 2 
 
 int numbers [20]; int * p; 


以下分配操作将是有效的:  

 
 p = numbers; 


在此之后,将是p数字等效,将具有相同的属性。   唯一的区别是,我们可能会改变另一个指针 p的值,而数字将永远指向第20 int类型的元素与它定义。   因此,与p,这是一个普通的指针, 数字是一个数组,一个数组可以看作一个常量指针 。 因此,下面的分配将是无效的:  

 
 numbers = p; 


因为数字是一个数组,所以它作为一个常量指针,我们不能分配给常数。  

由于变量的特性,是完全有效的,包括在下面的示例中的指针的所有表达式:  

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 
 // more pointers #include <iostream> using namespace std; int main () { int numbers[5]; int * p; p = numbers; *p = 10; p++; *p = 20; p = &numbers[2]; *p = 30; p = numbers + 3; *p = 40; p = numbers; *(p+4) = 50; for ( int n=0; n<5; n++) cout << numbers[n] << ", " ; return 0; } 
  10,20,30,40,50, 


本章关于阵列,我们用方括号([])多次在指定的索引数组中的元素,这是我们想要引用。   那么,这些支架符号运算符[],参照运算称为偏移运营商 。   他们按照*取消引用变量,但他们也加括号之间的数字被解除引用的地址。   例如:  

 1 
 2 
 
 a[5] = 0; // a [offset of 5] = 0 *(a+5) = 0; // pointed by (a+5) = 0 


这两个表达式是等效的,都有效,如果a一个指针,或者,如果a是一个数组。  

指针初始化

声明指针时,我们可能要明确指定变量,我们希望它们指向:  

 1 
 2 
 
 int number; int *tommy = &number; 


这段代码的行为相当于:  

 1 
 2 
 3 
 
 int number; int *tommy; tommy = &number; 


当指针初始化需要的地方,我们总是分配指针指向( 汤米 ),从来没有值被指向(汤米 )的参考价值。   你必须考虑到,在声明一个指针的时刻,星号(*)表示,它是一个指针,它是不是引用操作符(虽然两者使用相同的符号:*)。   请记住,他们是两个不同功能的标志之一。   因此,我们必须小心,不要混淆了以前的代码:  

 1 
 2 
 3 
 
 int number; int *tommy; *tommy = &number; 


这是不正确的,反正在这种情况下,不会有太大的意义,如果你仔细想想。  

阵列的情况下,编译器允许的特殊情况下,我们要初始化在同一时刻与常量的指针指向指针声明的内容:  

 
 const char * terry = "hello" ; 


在这种情况下,内存空间保留包含“你好”,然后被分配到这个内存块的第一个字符指针毛圈 。   如果我们想象的“hello”存储在地址1702开始的内存位置,我们可以代表以前的声明如下:  


重要的是要指出毛圈包含值1702,而不是1702,虽然的确是这两个地址的“h”,也不是“你好”。  

指针毛圈点的字符序列,并且可以读取,如果它是一个数组(记住,就像是一个常量指针数组)。   例如,我们可以访问的第五个元素的数组,这两个表达式:  

 1 
 2 
 
 *(terry+4) terry[4] 


两个表达式有一个值的'o'(第五元素的数组)。  

指针算术


要对指针进行算术运算是一个有点不同,而不是进行定期整数数据类型。   首先,只有加法和减法运算与他们被允许进行,其他就没有任何意义,在世界上的指针。   但不论是加法和减法有不同的行为与指针的大小的数据类型,它们指向。  

当我们看到不同的基本数据类型,我们看到了一些占用内存比别人更多或更少的空间。   例如,让我们假设一个特定的机器在一个给定的编译器, 字符占用1个字节, 占用2个字节,  4。  

假设,我们在此编译器定义了三个指针:  

 1 
 2 
 3 
 
 char *mychar; short *myshort; long *mylong; 


我们知道它们指向的内存位置1000,20003000分别。  

因此,如果我们这样写:  

 1 
 2 
 3 
 
 mychar++; myshort++; mylong++; 


mychar,你可能期望的,将包含价值1001。   但不是那么明显,myshort将包含价值2002,将包含3004 mylong,即使他们已分别被只增加一次。   其原因是,当添加一个到一个指针,使它指向与它已被定义的下面的元素相同类型的,因此,指出不同的大小(以字节为单位)加到指针。  


这是既适用时,添加和减去任意数量的指针的指针。   它会发生完全一样的,如果我们写:  

 1 
 2 
 3 
 
 mychar = mychar + 1; myshort = myshort + 1; mylong = mylong + 1; 


增加(+ +)减( - )运营商有更大的运算符的优先级比引用操作符(*),但都有一个特殊的行为,作为后缀(表达式求值前增加了它的价值时) 。   因此,下面的表达式可能会导致混乱:  

 
 *p++ 


因为+ +具有更高的优先级比*,这个表达式就相当于*(P +)。   因此,它做什么的是增加值P(所以它现在指向的下一个元素),但因为+ +作为后缀整个表达式评为原始参考(指针指向的地址所指向的数值前增加)。  

注意到其中的差别:  

(* P)+ +  
在这里,表达式将已被被评价为增加了一个通过p指向的值。   P(指针本身)的值不会被修改(什么正在修改的是它正在通过这个指针指向)。  

如果我们写的:  

 
 *p++ = *q++; 


因为+ +具有更高的优先级比*,p和 q增加,但由于同时增加运营商(+ +)作为后缀,而不是前缀,对* p的值赋给* Q p和增加。   然后两者都增加。   这将是大致等效于:  

 1 
 2 
 3 
 
 *p = *q; ++p; ++q; 


像往常一样,我建议你使用圆括号(),以避免意外的结果,并给予更多的代码的可读性。  

指针的指针

C + +中允许使用指向指针的指针,其中,在其转弯点的数据(或什至其他指标)。   为了做到这一点,我们只需要添加一个星号(*)在其声明中每个级别的参考:  

 1 
 2 
 3 
 4 
 5 
 6 
 
 char a; char * b; char ** c; a = 'z' ; b = &a; c = &b; 


此,假设随机选择的7230,809210502为每个变量的内存位置,可以表示为:  


每个变量的值写入每个细胞内,根据细胞是他们各自的内存地址。  

在这个例子中的新事物是变量 c,它可以用来在三个不同级别的间接寻址中,他们每个人将对应于一个不同的值:  

  • c具有类型为char **和值8092
  • * C char *类型和值7230
  • ** c具有类型char'Z'

void指针

void类型的指针是一种特殊类型的指针。   在C + +, 无效代表缺席的类型,所以void指针是指向这一点,没有类型的值(因而也是一个不确定的长度和未定性能废弃)。  

这使得void指针指向任何数据类型,从整数值或浮一串字符。   但是作为交换,他们有极大的局限性:数据指出他们不能直接解引用(这是合乎逻辑的,因为我们有没有类型解引用到),并出于这个原因,我们将始终有来投的地址void指针到提领前其他一些指针类型指向一个具体的数据类型。  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值