Pointers

5.1 Pointers

For a type T, *T is the type ‘‘pointer to T.’’  That is, a variable of type *Tcan hold the address of an object of type T. For example:

char  c = ´a´;

char* p = &c;        

or graphically:

Unfortunately, pointers to arrays and pointers to functions need a more complicated notation:

int* pi;                  // pointer to int

char** ppc;           // pointer to pointer to char

int* ap[15];            // array of 15 pointers to ints

int (*fp)(char*);    // pointer to function taking a char* argument; returns an int

int* f(char*);                  // function taking a char* argument; returns a pointer to int

See §4.9.1 for an explanation of the declaration syntax and Appendix A for the complete grammar. The fundamental operation on a pointer is dereferencing, that is, referring to the object pointed to by the pointer.  This operation is also called indirection.  The dereferencing operator is (prefix) unary *.  For example:

char  c = ´a´;

char* p = &c;  // p holds the address of c

char  c2 = *p; // c2 == ’a’

The variable pointed to by p is c, and the value stored in c is ´a´, so the value of *p assigned to c2 is ´a´.It is possible to perform some arithmetic operations on pointers to array elements (§5.3).  Point to functions can be extremely useful; they are discussed in §7.7.

The implementation of pointers is intended to map directly to the addressing mechanisms of the machine on which the program runs.  Most machines can address a byte.  Those that can’t tend to have hardware to extract bytes from words.  On the other hand, few machines can directly address an individual bit. Consequently, the smallest object that can be independently allocated and pointed to using a built-in pointer type is a char.  Note that a bool occupies at least as much space as a char (§4.6).  To store smaller values more compactly, you can use logical operations (§6.2.4) or bit fields in structures (§C.8.1).

5.1.1 Zero

Zero (0) is an int.  Because of standard conversions (§C.6.2.3), 0 can be used as a constant of any integral (§4.1.1), floating-point, pointer, or pointer-to-member type.  The type of zero will be deter-mined by context.  Zero will typically (but not necessarily) be represented by the bit pattern  all- zeros of the appropriate size.No object is allocated with the address 0. Consequently, 0 acts as a pointer literal, indicating that a pointer doesn’t refer to an object.

In C, it has been popular to define a macro NULL to represent the zero  pointer. Because of C++’s tighter type checking, the use of plain 0, rather than any suggested NULL macro, leads to fewer problems. If you feel you must define NULL, use const  int  NULL = 0;

The const qualifier (§5.4) prevents accidental redefinition of NULL and ensures that NULL can be used where a constant is required.

5.1.2 the type of indicators and definition of indicators
     With the type of pointer is that it is the type it points to the type of entity. Such as: a pointer to int type, a point one-dimensional array pointer, a pointer to a pointer type of function, such as.
Pointer variables in the use of a prior statement by a statement of its definition. Statements such as:
       Int * p;
    Defines a pointer to an integer type of variable p. That p is a variable storing the address of plastic variables. Figure 6.4 that the p and i in memory, the map image to the method of p and i said that the logic of the relationship between. Special note should be: the definition of a pointer variable must use the symbol "*", it indicates that the subsequent pointer variable is variable, but do not think "* p" is a pointer variable, pointer variable is p rather than * p.
In the definition of a pointer variable p, the system for this indicator variable assigned a storage unit (typically 2 bytes), use it to store addresses. But this time the pointer variable does not point to determine the plastic variables, because the indicator variables to determine the address did not enter. Is a pointer variable to point to another variable of plastic, plastic variables must be assigned to the pointer variable address. For example:
       Int * p; i = 3;
       p = &i;
     Above defines a pointer variable p and a plastic variable i, i the initial value of 3. But at this point between p and i have no contact. And then the implementation of the assignment "p = &i;", this time on the point p value of i.
Indicator variables can also be defined as the point real, character, and other types of variables, such as:
   float * p;
    char * p;

 

5.2 Arrays

For a type T, T[size] is the type ‘‘array of size elements of type T.’’  The elements are indexed from 0 to size-1.  For example:

float  v[3];   // an array of three floats: v[0], v[1], v[2]

char* a[32];    // an array of 32 pointers to char: a[0] .. a[31

The number of elements of the array, the array bound, must be a constant expression (§C.5).  If you need variable bounds, use a vector (§3.7.1, §16.3).  For example:

void  f(int  i)

{

int  v1[i];            // error: array size not a constant expression

vector<int> v2(i);  // ok

}

Multidimensional arrays are represented as arrays of arrays.  For example:int  d2[10][20]; // d2 is an array of 10 arrays of 20 integers Using comma notation as used for array bounds in some other languages gives compile-time errors because comma (,)  is a sequencing operator (§6.2.2) and is not allowed in constant expressions

(§C.5).  For example, try this: int  bad[5,2];    // error: comma not allowed in a constant expression

Multidimensional arrays are described in §C.7.  They are best avoided outside low-level code.

5.2.1Array Initializers

An array can be initialized by a list of values.  For example:

int  v1[] = { 1, 2, 3, 4 };

char  v2[] = { ´a´, ´b´, ´c´, 0 };

When an array is declared without a specific size, but with an initializer list, the size is calculated by counting the elements of the initializer list.  Consequently,  v1 and  v2 are of type  int[4] and char[4], respectively.  If a size is explicitly specified, it is an error to give surplus elements in an initializer list.  For example:

char  v3[2] = { ´a´, ´b´, 0 };          // error: too many initializers char  

v4[3] = { ´a´, ´b´, 0 };                      // ok

If  the  initializer  supplies  too  few  elements,  0  is  assumed  for  the  remaining  array  elements.   For example:

int  v5[8] = { 1, 2, 3, 4 };

is equivalent to

int  v5[] = { 1, 2, 3, 4 , 0, 0, 0, 0 };

Note that there is no array assignment to match the initialization:

void  f()

{

v4 = { ´c´, ´d´, 0 }; // error: no array assignment

}

When you need such assignments, use a vector (§16.3) or a valarray (§22.4) instead. An array of characters can be conveniently initialized by a string literal (§5.2.2)

5.2.2  String Literals

A string literal is a character sequence enclosed within double quotes:"this  is  a  string" A string literal contains one more character than it appears to have; it is terminated by the null char- acter ´/0´, with the value 0.  For example:

sizeof("Bohr")==5

The type of a string literal is ‘‘array of the appropriate number of const characters,’’ so "Bohr" is of type const char[5].

A string literal can be assigned to a char*.  This is allowed because in previous definitions of C and C++ , the type of a string literal was char*.  Allowing the assignment of a string literal to a char* ensures that millions of lines of C and C++ remain valid.  It is, however, an error to try to modify a string literal through such a pointer:

void  f()

{

char* p = "Plato";

p[4] = ´e´;               // error: assignment to const; result is undefined

}

This kind of error cannot in general be caught until run-time, and implementations differ in their enforcement of this rule.  Having string literals constant not only is obvious, but also allows imple- mentations to do significant optimizations in the way string literals are stored and accessed.

If we want a string that we are guaranteed to be able to modify, we must copy the characters into an array:

void  f()

{

char  p[] = "Zeno";      // p is an array of 5 char

p[0] = ´R´;                     // ok

}

A string literal is statically allocated so that it is safe to return one from a function.  For example:

const  char* errormessage(int  i)

{

// ...

return "range  error";

}

The memory holding range error will not go away after a call of errormessage().Whether two identical character literals are allocated as one is implementation-defined (§C.1).For example:

const  char* p = "Heraclitus";

const  char* q = "Heraclitus";

void  g()

{

if (p == q) cout << "one!/n";  // result is implementation-defined

// ...

}

Note  that  == compares  addresses  (pointer  values)  when  applied  to  pointers,  and  not  the  values pointed to.

The empty string is written as a pair of adjacent double quotes,   "", (and has the type  const char[1]).

The  backslash  convention  for  representing  nongraphic  characters  (§C.3.2)  can  also  be  used within a string.  This makes it possible to represent the double quote (") and the escape character backslash (  /) within a string.  The most common such character by far is the newline character,

´/n´.  For example:

cout<<"beep  at  end  of  message/a/n";

The escape character ´/a´ is the ASCII character BEL (also known as alert), which causes some kind of sound to be emitted.It is not possible to have a ‘‘real’’ newline in a string:"this  is  not  a  string but  a  syntax  error"

Long strings can be broken by whitespace to make the program text neater.

The compiler will concatenate adjacent strings, so alpha could equivalently have been initialized by the single string:

"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

It is possible to have the null character in a string, but most programs will not suspect that there are characters after it.  For example, the string "Jens/000Munk" will be treated as "Jens" by stan- dard library functions such as strcpy() and strlen(); see §20.4.1.

5.3 Pointers into Arrays

In C++, pointers and arrays are closely related.  The name of an array can be used as a pointer to its initial element.  For example:

int  v[] = { 1, 2, 3, 4 };

int* p1 = v;            // pointer to initial element (implicit conversion)

int* p2 = &v[0];     // pointer to initial element

int* p3 = &v[4];     // pointer to one beyond last element

or graphically:Taking  a  pointer  to  the  element  one  beyond  the  end  of  an  array  is  guaranteed  to  work. This  is important for many algorithms (§2.7.2, §18.3).  However, since such a pointer does not in fact point to  an  element  of  the  array,  it  may  not  be  used  for  reading  or  writing.   The  result  of  taking  the address  of  the  element  before  the  initial  element  is  undefined  and  should  be  avoided. On  some machine architectures, arrays are often allocated on machine addressing boundaries, so ‘‘one before the initial element’’ simply doesn’t make sense.

The implicit conversion of an array name to a pointer to the initial element of the array is exten- sively used in function calls in C-style code.  For example:

extern "C" int  strlen(const  char*); // from string.h

void  f()

{

char  v[] = "Annemarie";

char* p = v;    // implicit conversion of char[] to char*

strlen(p);

strlen(v);        // implicit conversion of char[] to char*

v = p;             // error: cannot assign to array

}

The same value is passed to the standard library function strlen() in both calls.  The snag is that it is impossible to avoid the implicit conversion.  In other words, there is no way of declaring a function so that the array v is copied when the function is called. Fortunately, there is no implicit or explicit conversion from a pointer to an array.

The implicit conversion of the array argument to a pointer means that the size of the array is lost to the called function. However, the called function must somehow determine the size to perform a meaningful operation. Like  other  C  standard  library  functions  taking  pointers  to  characters, strlen() relies on zero to indicate end-of-string; strlen(p) returns the number of characters up to and  not  including  the  terminating  0.   This  is  all  pretty  low-level.   The  standard  library  vector (§16.3) and string (Chapter 20) don’t suffer from this problem.

5.3.1  Navigating Arrays

Efficient and elegant access to arrays (and similar data structures) is the key to many algorithms (see §3.8, Chapter 18). Access can be achieved either through a pointer to an array plus an index or through a pointer to an element. For example, traversing a character string using an index,

void  fi(char  v[])

{

for (int  i = 0; v[i]!=0; i++) use(v[i]);

}

is equivalent to a traversal using a pointer:

void  fp(char  v[])

{

for (char* p = v; *p!=0; p++) use(*p);

}

The prefix * operator dereferences a pointer so that *p is the character pointed to by  p,and ++ increments the pointer so that it refers to the next element of the array.

There is no inherent reason why one version should be faster than the other.  With modern com- pilers, identical  code  should  be  generated  for  both  examples  (see  §5.9[8]). Programmers  can choose between the versions on logical and aesthetic grounds.

The result of applying the arithmetic operators +, -, ++, or -- to pointers depends on the type of  the  object  pointed  to.  When  an  arithmetic  operator  is  applied  to  a pointer  p of type  T*,  p is assumed to point to an element of an array of objects of type T; p+1 points to the next element of that array, and p-1 points to the previous element.  This implies that the integer value of p+1 will be sizeof(T) larger than the integer value of p.  For example, executing

using a default hexadecimal notation for pointer values.  This shows that on my implementation,sizeof(short) is 2 and sizeof(int) is 4.

Subtraction of pointers is defined only when both pointers point to elements of the same array(although the language has no fast way of ensuring that is the case).  When subtracting one pointer from another, the result is the number of array elements between the two pointers (an integer).  One can add an integer to a pointer or subtract an integer from a pointer; in both cases, the result is a pointer value.  If that value does not point to an element of the same array as the original pointer or one beyond, the result of using that value is undefined.  For example:

void  f()

{

int  v1[10];

int  v2[10];

int  i1 = &v1[5]-&v1[3]; // i1 = 2

int  i2 = &v1[5]-&v2[3]; // result undefined     

int* p1 = v2+2;             // p1 = &v2[2]

int* p2 = v2-2;              // *p2 undefined

}

Complicated pointer arithmetic is usually unnecessary and often best avoided.  Addition of pointers makes no sense and is not allowed.Arrays are not self-describing because the number of elements of an array is not guaranteed to be stored with the array.  This implies that to traverse an array that does not contain a terminator the way character strings do, we must somehow supply the number of elements.  For example:

void  fp(char  v[], unsigned  int  size)

{

for (int  i=0; i<size; i++) use(v[i]);

const  int  N = 7;

char  v2[N];

for (int  i=0; i<N; i++) use(v2[i]);

}

Note  that  most  C++  implementations  offer  no  range  checking  for  arrays.   This  array  concept  is inherently low-level.  A more advanced notion of arrays can be provided through the use of classes; see §3.7.1.

5.4 Constants

C++ offers the concept of a user-defined constant, a const, to express the notion that a value doesn’t change directly.  This is useful in several contexts.  For example, many objects don’t actually have their values changed after initialization, symbolic constants lead to more maintainable code than do literals embedded directly in code, pointers are often read through but never written through, and most function parameters are read but not written to.The keyword const can be added to the declaration of an object to make the object declared a constant.  Because it cannot be assigned to, a constant must be initialized.  For example:

const  int  model = 90;          // model is a const const  int  v[] = { 1, 2, 3, 4 };                                                  // v[i] is a const

const  int  x;                         // error: no initializer

Declaring something const ensures that its value will not change within its scope:

void  f()

{

model = 200; // error

v[2]++;         // error

}

Note that const modifies a type; that is, it restricts the ways in which an object can be used, rather than specifying how the constant is to be allocated.  For example:

void  g(const  X* p)

{

// can’t modify *p here

}

void  h()

{

X  val; // val can be modified

g(&val);

// ...

}

Depending on how smart it is, a compiler can take advantage of an object being a constant in sev-

eral ways.  For example, the initializer for a constant is often (but not always) a constant expression

(§C.5); if it is, it can be evaluated at compile time.  Further, if the compiler knows every use of the const, it need not allocate space to hold it.  For example:

const  int  c1 = 1;

const  int  c2 = 2;

const  int  c3 = myf(3);   // don’t know the value of c3 at compile time

extern  const  int  c4;      // don’t know the value of c4 at compile time

const  int* p = &c2;    // need to allocate space for c2

Given this, the compiler knows the values of c1 and c2 so that they can be used in constant expres- sions.  Because the values of c3 and c4 are not known at compile time (using only the information available in this compilation unit; see §9.1), storage must be allocated for c3 and c4.  Because the address of  c2 is taken (and presumably used somewhere), storage must be allocated for  c2.  The simple and common case is the one in which the value of the constant is known at compile time and no storage needs to be allocated; c1 is an example of that.  The keyword extern indicates that c4 is defined elsewhere (§9.2).

It is typically necessary to allocate store for an array of constants because the compiler cannot,in  general,  figure  out  which  elements  of  the  array  are  referred  to  in  expressions.   On  many machines, however, efficiency improvements can be achieved even in this case by placing arrays of constants in read-only storage.

Common uses for consts are as array bounds and case labels.  For example: Enumerators (§4.8) are often an alternative to consts in such cases.The way const can be used with class member functions is discussed in §10.2.6 and §10.2.7. Symbolic  constants  should  be  used  systematically  to  avoid  ‘‘magic  numbers’’  in  code. If  a numeric constant, such as an array bound, is repeated in code, it becomes hard to revise that code because every occurrence of that constant must be changed to make a correct update.  Using a sym- bolic constant instead localizes information.  Usually, a numeric constant represents an assumption about the program.  For example, 4 may represent the number of bytes in an integer, 128 the num- ber of characters needed to buffer input, and 6.24 the exchange factor between Danish kroner and U.S. dollars.  Left as numeric constants in the code, these values are hard for a maintainer to spot and understand.  Often, such numeric values go unnoticed and become errors when a program is ported or when some other change violates the assumptions they represent.  Representing assump- tions as well-commented symbolic constants minimizes such maintenance problems.

5.4.1 Pointer and the volume indicator
        Address storage area as if looking for signs, in the programming language known as the pointer. Can also say that an address point to a program entity storage space. Usually through the variable name or address to visit a program storage means entities referred to as "direct access" approach (in fact, through the variable names is to visit the address to visit).

    There is also a "indirect access" approach is to address a variable on another variable. Another unit in the memory to set up a number of variables: pa, pb, pc, pd, pe, pf, respectively, used to store variables a, b, c, d, e, f address. If you want a value, you can first visit the variables pa, to be pa of the value of 1010 (which the value of a variable), and then find it through the address of 1010 point to the value of the memory cell. That the address stored in a variable, and then through the first variable to identify the address of the value (an address), in this address to find the ultimate way to access variables, known as the "indirect access." Need to show that the variables stored address is a special variable, it can only be used to store addresses and can not be used to store other types of data need to be defined specifically.
       Need to explain: "pointer" is the word that the image of the guidelines visit the relationship between variables, not in memory as the clock is really like a needle in the mobile. In fact, it only stored the address of a variable only.

5.4.2  Pointers and Constants

When using a pointer, two objects are involved: the pointer itself and the object pointed to.  ‘‘Pre- fixing’’ a declaration of a pointer with const makes the object, but not the pointer, a constant.  To declare a pointer itself, rather than  the  object  pointed  to,  to  be  a  constant,  we  use  the  declarator operator *const instead of plain *. For example:

void  f1(char* p)

{

char  s[] = "Gorm";

const  char* pc = s;            // pointer to constant

pc[3] = ´g´;                           // error: pc points to constant

pc = p;                                 // ok

char *const  cp = s;           // constant pointer cp[3] = ´a´;  // ok

cp = p;                                 // error: cp is constant

const  char *const  cpc = s;       // const pointer to const

cpc[3] = ´a´;                         // error: cpc points to constant

cpc = p;                               // error: cpc is constant

}

The  declarator  operator  that  makes  a  pointer  constant  is  *const.   There  is  no  const* declarator operator, so a const appearing before the * is taken to be part of the base type.  For example:

char *const  cp; const pointer to char char  const* pc;       // pointer to const char const  char* pc2;      pointer to const char

Some  people  find  it  helpful  to  read  such  declarations  right-to-left.   For  example,  cp  is  a  const pointer to a char’’ and pc2 is a pointer to a char const.’’

An object that is a constant when accessed through one pointer may be variable when accessed in other ways.  This is particularly useful for function arguments.  By declaring a pointer argument

const, the function is prohibited from modifying the object pointed to.  For example:char* strcpy(char* p, const  char* q); // cannot modify *q

You can assign the address of a variable to a pointer to constant because no harm can come from that.  However, the address of a constant cannot be assigned to an unrestricted pointer because this would allow the object’s value to be changed.  For example:

void  f4()

{

int  a = 1;

const  int  c = 2;

const  int* p1 = &c;  // ok

const  int* p2 = &a; // ok

int* p3 = &c;         // error: initialization of int* with const int*

*p3 = 7;                 // try to change the value of c

}

It is possible to explicitly remove the restrictions on a pointer to const by explicit type conversion(§10.2.7.1 and §15.4.2.1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值