【C++注意事项】4 指针 Pointers

和上一节的引用类似,指针(pointer)是“指向(point to)”另外一种类型的复合类型。与引用类似,指针也实现了对其他对象的间接访问。然后指针和引用相比有许多不同。其一,指针本身就是一个对象,允许对指针赋值和拷贝,而且在指针的生命周期内它可以先后指向几个不同的对象。其二,指针无须在定义时赋初值。和其他内置类型一样,在块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的值。

因为引用不是对象,没有实际地址,所以不能定义指向引用的指针。

指针的值(即地址)应属下列4种状态之一:

1)指向一个对象

2)指向紧邻对象所占空间的下一个位置

3)空指针,意味着指针没有指定任何对象

4)无效指针,也就是上述情况之外的其他值

试图拷贝或以其他方式访问无效指针的值都将引发错误。编译器并不负责检查此类错误,这一点和试图使用未经初始化的变量是一样的。访问无效指针的后果无法预计,因此程序员必须清楚任意给定的指针是否有效。因此解引用符也只适用于那些确实指向了某个对象的有效指针。

所谓的解引用符就是使用操作符*来访问指针指向的对象。

int ival= 42;
int *p= &ival;  // p存放着变量ival的地址,或者说p是指向变量ival的指针
cout<<*p;  // 由符号*得到指针p所指的对象,输出42
*p= 0;  // 由符号*得到指针p所指的对象,即可经由p为变量ival赋值
cout<<*p;  // 输出0

取地址符(&)和解引用符(*)的多重含义:

int i= 42;   
int &r= i;  // &紧随类型名出现,因此是声明的一部分,r是一个引用
int *p;  // *紧随类型名出现,因此是声明的一部分,p是一个指针
p= &i;  // &出现在表达式中,是一个取地址符
*p= i;  // *出现在表达式中,是一个解引用符
int &r2= *p;  // &是声明的一部分,*是一个解引用符

空指针(null pointer)不指向任何对象,在试图使用一个指针之前代码可以检查它是否为空。下面有3种生成空指针的方式:

// 需要首先#include cstdlib
inht *p1=NULL;

过去的程序会用到一个名为NULL的预处理变量(preprocessor variable)来给指针赋值,这个变量在头文件cstdlib中定义,它的值就是0。

int *p2= 0;

直接将p2初始化为字面常量0

int *p3= nullptr;

这是C++11新标准所引入的一种方法。

需要注意的是不能将int变量直接赋值给指针,即便int变量的值恰好等于0也不行。

void*是一种特殊的指针类型,可用于存放任意对象的地址。

但是不能直接操作void*指针,因为我们并不知道这个对象到底是什么类型,也就无法确定能在这个对象上做哪些操作。


English…


With two exceptions, which we will see at later, the types of the pointer and the object to which it points must match:

double dval;
double *pd= &dval;  // ok: initializer is the address of a double
double *pd2= pd;  // ok: initializer is a pointer to double
int *pi= pd;  // error: types of pi and pd differ
pi= &dval;  // error: assigning the address of a double to a pointer to int

The types must match because the type of the pointer is used to infer the type of the object to which the pointer points. If a pointer addressed an object of another type, operations performed on the underlying object would fail.

As with reference, we can define pointers that point to either const or not const types. Like a reference to const, a pointer to const may not be used to change the object to which the pointer points. We may store the address of a const object only in a pointer to const:

const double pi= 3.14;  // pi is const; its value may not be changed
double *ptr= &pi;  // error: ptr is a plain pointer
const double *cptr=&pi;  // ok: cptr may point to a double that is const
*cptr= 42;  // error: cannot assign to *cptr

The first exception is that we can use a pointer to const to point to a nonconst object:

double dval= 3.14;  // dval is a double; its value can be changed
cptr= &dval;  // ok: but can't change dval through cptr

Defining a pointer as a pointer to const affects only what we can do with the pointer. It is important to remenber that there is no guarantee that an object pointed to by a pointer to const won’t change.

It may be helpful to think of pointers and reference to const as pointers or references “that think they point to refer to const.”

const pointers

Unlike references, pointers are objects. Hence, as with any other object type, we can have a pointer that is itself const. Like any other const object, a const pointer must be initialized, and once initialized, its value(i.e., the address that it holds) may not be changed. We indicate that the pointer is const by putting the const after the *. This placement indicates that it is the pointer, not the pointed-to type, that is const:

int errNumb= 0;
int *const curErr= &errNumb;  // curErr will always point to errNumb
const double pi= 3.14159;
const double *const pip= &pi;  // pip is a const pointer to a cosnt object

The symbol closest to curErr is const, which means that curErr itself will be a const object. The type of that object is formed from the rest of the declarator. the next symbol in the declarator is *, which means that curErr is a const pointer. Finally, the base type of the declaration completes type of curErr, which is a const pointer to an object of type int. Similarly, pip is a const pointer to an object of type const double.

The fact that a pointer is itself const says nothing about whether we can use the pointer to change the underlying object. Whether we can change that object depends entirely on the type to which the pointer points. For example, pip is a const pointer to const. Neither the value of the object addressed by pip nor the address stored in pip can be changed. On the other hand, curErr addresses a plain, nonconst int. We can use curErr to change the value of errNumb:

*pip= 2.72;  // error: pip is a pointers to const
// if the object to which curErr points(i.e., errNumb) is nonzero
if(*curErr)
{
    errorHandler();
    *curErr= 0;  // ok: reset the value of the object to which curErr is bound
}

Note: “C++ Notes” series of blog mainly reference books of C++ Prime is the fifth edition of the Chinese version and English version. My English is very poor, and I don’t want there are some syntax error in blog. So the blogs have lots of words and sentences from the book. I wrote this series in order to consolidate the knowledge of C++, but also in order to improve my poor English. I also hope to help readers. Thank you.、



感谢您的访问,希望对您有所帮助。 欢迎大家关注、收藏以及评论。

我的更多博客文章:NoMasp博客导读


为使本文得到斧正和提问,转载请注明出处:
http://blog.csdn.net/nomasp


posted @ 2015-05-21 12:50  nomasp  阅读(291)  评论(0编辑  收藏  举报