c++快速入门6:指针与引用

了解数据存储

address.cpp

#include <string>
#include <iostream>
using namespace std ;

int main()
{
  int num = 100 ;
  double decimal = 0.0123456789 ;
  string text = "C++ Fun" ;

  cout << "Integer variable starts at: " << &num << endl ;
  cout << "Double variable starts at: " << &decimal << endl ;
  cout << "String variable starts at: " << &text << endl ;

  // Uncomment the lines below to place R-values incorrectly.
  // 200 = num ;
  // 5.5 = decimal ;
  // "Bad assignments" = text ;

  return 0 ;
}

用指针获取数值

指针存储其他变量的内存地址的变量。指针变量的声明方式与其他变量的声明方式相同,但数据类型以 "*"字符为后缀,指针的数据类型必须与它所指向的变量的数据类型相匹配。

指针变量的初始化是通过使用&引用操作符,将变量的内存地址分配给它。赋值可以在声明语句中进行,也可以在声明之后的单独语句中进行。仅仅通过它的名字来引用指针变量将简单地显示出它所包含的内存地址。

deref.cpp

#include <iostream>
using namespace std ;

int main()
{
  // Declare and initialize regular variables.
  int a = 8, b = 16 ;

  // Declare and initialize pointer variables
  // with reference addresses.
  int* aPtr = &a ;

  int* bPtr ;
  bPtr = &b ;

  // Output address of pointers...
  cout << "Addresses of pointers..." << endl ;
  cout << "aPtr: " << &aPtr << endl ;
  cout << "bPtr: " << &bPtr << endl << endl ;

  // Output addresses stored in pointers.
  cout << "Values in pointers..." << endl ;
  cout << "aPtr: " << aPtr << endl ;
  cout << "bPtr: " << bPtr << endl << endl ;

  // Output deferenced values pointed to.
  cout << "Values in addresses pointed to..." << endl ;
  cout << "a: " << *aPtr << endl ;
  cout << "b: " << *bPtr << endl << endl ;

  return 0 ;
}

指针运算

++增量运算符或--减量运算符会将指针移动到该数据类型的下一或上一地址--数据类型越大,跳跃就越大。使用+=和-=运算符可以实现更大的跳跃。

point.cpp

#include <iostream>
using namespace std ;

int main()
{
  int nums[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } ;

  // Pointer assigns address of element zero.
  int* ptr = nums ;

  cout << endl << "ptr at: " << ptr << " gets: " << *ptr ;

  // Increment to element one.
  ptr++ ;
  cout << endl << "ptr at:\t" << ptr << " gets: " << *ptr  ;

  // Increment again to element two.
  ptr++ ;
  cout << endl << "ptr at: " << ptr << " gets: " << *ptr ;

  // Decrement again to element zero.
  ptr -= 2 ;
  cout << endl << "ptr at: " << ptr << " gets: " << *ptr ;
  
  // (Added for formatting.)
  cout << endl ;

  for( int i = 0 ; i < 10 ; i++ )
  {
    cout << endl << "Element: " << i ;
    cout << "    Value: " << *ptr ;
    ptr++ ;
  }

  // (Added for formatting).
  cout << endl << endl ;

  return 0 ;
}

函数传址

指针被传递给函数时,它们的数据被 "通过引用 "传递--这样函数就在原始值上操作。

#include <iostream>
using namespace std ;

void writeOutput( int* ) ; // Prototypes.
void computeTriple( int* ) ;

int main()
{
  int num = 5 ; // Regular declaration.

  int* ptr = &num ; // Data pointer declaration.
  writeOutput( ptr ) ;

  *ptr += 15 ;      // Change the pointed value.
  writeOutput( ptr ) ;

  computeTriple( ptr ) ; // Change the pointed value.
  writeOutput( ptr ) ;

  return 0 ;
}

void writeOutput( int* value )
{
  cout << "Current value: " << *value << endl ;
}

void computeTriple( int* value)
{
  *value *= 3 ;
}

数组与指针

arrptr.cpp

#include <iostream>
using namespace std ;

int main()
{
  // Variables to store "strings".
  char letters[8] = { 'C','+','+',' ', 'F','u','n', '\0' } ;
  const char* text = "C++ Fun" ;

  // Pointers to arrays of characters - ie. strings.
  const char* term = "Element:" ;
  const char* lang = "C++" ;

  // Pointers to arrays of strings.
  const char* ap1[3] = { "Great  ", "Program", "Code   " } ;
  // Assigning char pointer to first element.
  const char* ap2[3] = { lang, "is ", "Fun" } ;

  // Pointers to arrays of pointers.
  const char* ap3[3] = { ap2[0], ap2[1], ap1[0] } ;
  const char* ap4[3] = { ap1[2], ap2[1], ap2[2] } ;

  // Output the variables.
  cout << letters << endl ;
  cout << text << endl ;

  // Output the elements of each array.
  for ( int i = 0; i < 3 ; i++)
  {
    cout << term << i << "   " ;

    cout << ap1[i] << "   " ;
    cout << ap2[i] << "   " ;
    cout << ap3[i] << "   " ;
    cout << ap4[i] << endl ;
  }
  return 0 ;
}

引用

引用是变量或对象的别名,它必须在其声明中被初始化。

注意,&引用操作符的目的是与上下文相关的,所以当它作为L值使用时,在=操作符的左边声明引用,否则当它作为R值使用时,返回内存地址。

引用是其关联项的真正别名,查询其内存地址会返回其关联项的地址--没有办法发现引用本身的地址。

ref.cpp

#include <iostream>
using namespace std ;

int main()
{
  int num ;
  
  int &rNum = num ;

  rNum = 400 ;

  cout << "Value direct: " << num << endl ;
  cout << "Value via reference: " << rNum << endl ;

  cout << "Address direct: " << &num << endl ;
  cout << "Address via reference: " << &rNum << endl ;

  rNum *= 2 ;

  cout << "Value direct: " << num << endl ;
  cout << "Value via reference: " << rNum << endl ;

  return 0 ;
}

引用传递给函数

引用可以像指针一样,作为参数传递给函数。

fnref.cpp

#include <iostream>
using namespace std ;

void writeOutput( int& ) ; // Prototypes.
void computeTriple( int& ) ;

int main()
{
  int num = 5 ; // Regular declaration.

  int& ref = num ; // Reference declaration.
  writeOutput( ref ) ;

  ref += 15 ; // Change the referenced value.
  writeOutput( ref ) ;

  computeTriple( ref ) ; // Change the referenced value.
  writeOutput( ref ) ;

  return 0 ;
}

void writeOutput( int& value )
{
  cout << "Current value: " << value << endl ;
}

void computeTriple( int& value)
{
  value *= 3 ;
}

指针和引用的比较

指针和引用都可以用来引用变量的值,并通过引用而不是通过值将它们传递给函数。从技术上讲,通过引用传递比通过值传递更有效,所以要鼓励使用指针和引用。

引用必须在声明中被初始化,指针比引用更灵活,甚至可以指向函数。

pref.cpp

#include <iostream>
using namespace std ;

inline void add( int& a, int* b )
{
  cout << "Total: " << ( a + *b ) << endl ;
}

int main()
{
  int num = 100 , sum = 500 ;
  int& rNum = num ; // Reference declaration.
  int* ptr = &num ; // Pointer declaration.
  void (* fn) ( int& a, int* b ) = add  ; // Function pointer declaration.

  cout << "Reference: " << rNum << endl ; // Output via reference.  
  cout << "Pointer: " << *ptr << endl ; // Output via pointer.

  ptr = &sum ; // Reassign pointer.
  cout << "Pointer now: " << *ptr << endl ; // Output different value via pointer.
  fn( rNum, ptr ) ; // Output via function pointer. (Note: NOT directly with add(rNum,ptr); as listed in the book.)

  return 0 ;
}

C语言程序员倾向于把&和*字符放在变量名之前,但在C++中通常把它们放在数据类型之后。

推荐阅读更多精彩内容