天天看点

C++ 指针的算术运算、指针和数组、引用

C++ 指针的算术运算

指针是一个用数值表示的地址。因此,您可以对指针执行算术运算。可以对指针进行四种算术运算:

++

--

+

-

假设

ptr

是一个指向地址

1000

的整型指针,是一个

32

位的整数,让我们对该指针执行下列的算术运算:

在执行完上述的运算之后,

ptr

将指向位置

1004

,因为

ptr

每增加一次,它都将指向下一个整数位置,即当前位置往后移 4 个字节。这个运算会在不影响内存位置中实际值的情况下,移动指针到下一个内存位置。如果

ptr

指向一个地址为

1000

的字符,上面的运算会导致指针指向位置

1001

,因为下一个字符位置是在

1001

递增一个指针

我们喜欢在程序中使用指针代替数组,因为变量指针可以递增,而数组不能递增,因为数组是一个常量指针。下面的程序递增变量指针,以便顺序访问数组中的每一个元素:

实例

#include <iostream>
 
using namespace std;
const int MAX = 3;
 
int main ()
{
   int  var[MAX] = {10, 100, 200};
   int  *ptr;
 
   // 指针中的数组地址
   ptr = var;
   for (int i = 0; i < MAX; i++)
   {
      cout << "Address of var[" << i << "] = ";
      cout << ptr << endl;
 
      cout << "Value of var[" << i << "] = ";
      cout << *ptr << endl;
 
      // 移动到下一个位置
      ptr++;
   }
   return 0;
}
           

当上面的代码被编译和执行时,它会产生下列结果:

Address of var[0] = 0xbfa088b0
Value of var[0] = 10
Address of var[1] = 0xbfa088b4
Value of var[1] = 100
Address of var[2] = 0xbfa088b8
Value of var[2] = 200
           

递减一个指针

同样地,对指针进行递减运算,即把值减去其数据类型的字节数,如下所示:

实例

#include <iostream>
 
using namespace std;
const int MAX = 3;
 
int main ()
{
   int  var[MAX] = {10, 100, 200};
   int  *ptr;
 
   // 指针中最后一个元素的地址
   ptr = &var[MAX-1];
   for (int i = MAX; i > 0; i--)
   {
      cout << "Address of var[" << i << "] = ";
      cout << ptr << endl;
 
      cout << "Value of var[" << i << "] = ";
      cout << *ptr << endl;
 
      // 移动到下一个位置
      ptr--;
   }
   return 0;
}
           

当上面的代码被编译和执行时,它会产生下列结果:

Address of var[3] = 0xbfdb70f8
Value of var[3] = 200
Address of var[2] = 0xbfdb70f4
Value of var[2] = 100
Address of var[1] = 0xbfdb70f0
Value of var[1] = 10
           

指针的比较

指针可以用关系运算符进行比较,如

==

<

>

。如果

p1

p2

指向两个相关的变量,比如同一个数组中的不同元素,则可对

p1

p2

进行大小比较。

下面的程序修改了上面的实例,只要变量指针所指向的地址小于或等于数组的最后一个元素的地址

&var[MAX - 1]

,则把变量指针进行递增:

实例

#include <iostream>
 
using namespace std;
const int MAX = 3;
 
int main ()
{
   int  var[MAX] = {10, 100, 200};
   int  *ptr;
 
   // 指针中第一个元素的地址
   ptr = var;
   int i = 0;
   while ( ptr <= &var[MAX - 1] )
   {
      cout << "Address of var[" << i << "] = ";
      cout << ptr << endl;
 
      cout << "Value of var[" << i << "] = ";
      cout << *ptr << endl;
 
      // 指向上一个位置
      ptr++;
      i++;
   }
   return 0;
}
           

当上面的代码被编译和执行时,它会产生下列结果:

Address of var[0] = 0xbfce42d0
Value of var[0] = 10
Address of var[1] = 0xbfce42d4
Value of var[1] = 100
Address of var[2] = 0xbfce42d8
Value of var[2] = 200
           
#include <iostream>
using namespace std;

int main()
{
    int  var[5] = {1,2,3,4,5};   // 实际变量的声明
    int  *ip;        
    // 指针变量的声明  
    int  *ip_1;

    //ip = &var;
    //指针指向数组的时候不用 “&”取址符
    //ip = &var[2]
    //指针指向数组某一元素时要用 “&”取址符
    ip = var; 
    // 在指针变量中存储 var 的地址
    ip_1 = &var[2];
    // 在指针变量中存储 var[2] 的地址
    cout << "Value of var variable: ";
    cout << var << endl;

    // 输出在指针变量中存储的地址
    cout << "Address stored in ip variable: ";
    cout << ip << endl;

    // 访问指针中地址的值    
    cout << "Value of *ip variable: ";
    *ip = 30;
    cout << *ip << endl;
    cout << "\t" << var << endl;

    // 打印指针指向数组的某一元素的值  
    cout << "Value of *ip_1 variable:";
    cout << *ip_1 << endl;


    system("pause"); 
    return 0;
}
           

& 并不是不能用在数组名上,只是用在数组名和数组名

[i]

有所区别

int height[10];//int型的数组
cout << &height << endl;//&用在数组名上
cout << &height[0] << endl;//&用在数组第一个元素上
           

上面

&height[0]

就是取得是数组第一个元素的地址,假设地址为 1000;

&height

是直接对数组名进行取地址,这个时候就是取得是 height 整个数组的地址,指向包含 10 个元素的 int 型数组,地址范围为 1000~1036;

我们知道

height

等价于

&height[0]

height+1

会将地址加 4 个字节;但

&height+1

就是将地址增加 10*4 个字节。

C++ 引用

引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字。一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。

C++ 引用 vs 指针

引用很容易与指针混淆,它们之间有三个主要的不同:

  • 不存在空引用。引用必须连接到一块合法的内存。
  • 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
  • 引用必须在创建时被初始化。指针可以在任何时间被初始化。

C++ 中创建引用

试想变量名称是变量附属在内存位置中的标签,您可以把引用当成是变量附属在内存位置中的第二个标签。因此,您可以通过原始变量名称或引用来访问变量的内容。例如:

我们可以为 i 声明引用变量,如下所示:

int&  r = i;
double& s = d;
           

在这些声明中,

&

读作引用。因此,第一个声明可以读作 “r 是一个初始化为 i 的整型引用”,第二个声明可以读作 “s 是一个初始化为 d 的 double 型引用”。下面的实例使用了 int 和 double 引用:

实例

#include <iostream>
 
using namespace std;
 
int main ()
{
   // 声明简单的变量
   int    i;
   double d;
 
   // 声明引用变量
   int&    r = i;
   double& s = d;
   
   i = 5;
   cout << "Value of i : " << i << endl;
   cout << "Value of i reference : " << r  << endl;
 
   d = 11.7;
   cout << "Value of d : " << d << endl;
   cout << "Value of d reference : " << s  << endl;
   
   return 0;
}
           

当上面的代码被编译和执行时,它会产生下列结果:

Value of i : 5
Value of i reference : 5
Value of d : 11.7
Value of d reference : 11.7
           

int& r = i

; 和

int r = i

; 不同之处是内存的分配,后者会再开辟一个内存空间

#include <iostream>
 
using namespace std;
 
int main ()
{
   int i;
   int& r = i;
   i = 5;
   cout << "Value of i : " << i << endl;
   cout << "Value of i reference : " << r  << endl;
   cout << "Addr of i: " << &i << endl;
   cout << "Addr of r: " << &r << endl;
   
   int x;
   int y = x;
   x = 6;
   cout << "Value of x : " << x << endl;
   cout << "Value of y : " << y  << endl;
   cout << "Addr of x: " << &x << endl;
   cout << "Addr of y: " << &y << endl;
 
   return 0;
}
           

输出结果:

Value of i : 5
Value of i reference : 5
Addr of i: 0x7fff59cda988
Addr of r: 0x7fff59cda988
Value of x : 6
Value of y : 32767
Addr of x: 0x7fff59cda97c
Addr of y: 0x7fff59cda978
           
  1. 引用必须在声明时将其初始化,不能先声明后赋值。
#include <iostream>

using namespace std;

int main()
{
  int rats = 10;
  
  //声明引用,旦未初始化
  int &rodents;

  rodents = rats;

  return 0;
}
           

上述代码编译时会报以下错误:

error: ‘rodents’ declared as reference but not initialized
           

错误:’

rodents

’ 声明为引用但未初始化。

  1. 引用更接近

    const

    指针,必须在创建时进行初始化,一旦引用和某个变量关联起来,该引用就会一直指向该变量。
int rats = 10;
int &rodents = rats;
           

上面代码实际上是下述代码的伪装表示:

int rats = 10;
int * const pr = &rats;
           

例子:

#include <iostream>

using namespace std;

int main()
{
  int rats = 100;
  int &rodent = rats;

  cout << "rats = "<<rats<<", rosent = "<<rodent<<endl;
  cout << "rats address = "<<&rats<<endl;
  cout << "rosent address = "<<&rodent<<endl;

  cout <<"==================================="<<endl;
  int bunnies = 50;
  rodent = bunnies;

  cout << "rats = "<<rats<<", rosent = "<<rodent<<", bunnies = "<<bunnies<<endl;
  cout << "rats address = "<<&rats<<endl;
  cout << "rosent address = "<<&rodent<<endl;
  cout << "bunniess address = "<<&bunnies<<endl;

  return 0;
}
           

输出结果:

rats = 100, rosent = 100
rats address = 0xbfce21e4
rosent address = 0xbfce21e4
===================================
rats = 50, rosent = 50, bunnies = 50
rats address = 0xbfce21e4
rosent address = 0xbfce21e4
bunniess address = 0xbfce21e8
           

从结果可以看出,虽然在调用

rodent = bunnies

; 后引用

rosent

的值变为 50,但是 rosent 所指向的地址空间还是指向了 rats,没有发生改变,说明

rodent = bunnies

; 只是将 bunnies 的值赋值给引用 rodent 所指向的变量,没有改变引用的指向。

C++ 把引用作为参数

下面的实例使用了引用来实现引用调用函数。

实例

#include <iostream>
using namespace std;
 
// 函数声明
void swap(int& x, int& y);
 
int main ()
{
   // 局部变量声明
   int a = 100;
   int b = 200;
 
   cout << "交换前,a 的值:" << a << endl;
   cout << "交换前,b 的值:" << b << endl;
 
   /* 调用函数来交换值 */
   swap(a, b);
 
   cout << "交换后,a 的值:" << a << endl;
   cout << "交换后,b 的值:" << b << endl;
 
   return 0;
}
 
// 函数定义
void swap(int& x, int& y)
{
   int temp;
   temp = x; /* 保存地址 x 的值 */
   x = y;    /* 把 y 赋值给 x */
   y = temp; /* 把 x 赋值给 y  */
  
   return;
}
           

当上面的代码被编译和执行时,它会产生下列结果:

交换前,a 的值: 100
交换前,b 的值: 200
交换后,a 的值: 200
交换后,b 的值: 100
           
引用作为函数参数

C++之所以增加引用类型, 主要是把它作为函数参数,以扩充函数传递数据的功能。

C++ 函数传参:

  • (1)将变量名作为实参和形参。这时传给形参的是变量的值,传递是单向的。如果在执行函数期间形参的值发生变化,并不传回给实参。因为在调用函数时,形参和实参不是同一个存储单元。// 同 c
  • (2) 传递变量的指针。形参是指针变量,实参是一个变量的地址,调用函数时,形参(指针变量)指向实参变量单元。这种通过形参指针可以改变实参的值。// 同 c
  • (3) C++提供了传递变量的引用。形参是引用变量,和实参是一个变量,调用函数时,形参(引用变量)指向实参变量单元。这种通过形参引用可以改变实参的值。
以引用作为参数的函数,可以把变量传入,但不能传入常量。
#include <iostream>
using namespace std;

int hls(int& a1, int& a2, int& b1, int& b2) //定义行列式函数
{
   int temp;
   temp=a1*b2-a2*b1;
   return temp;
}

int main()
{
   int x1=11; int x2=9;
   int y1=15; int y2=14;  //定义矩阵
   int result;  //行列式运算结果
   result=hls(x1,x2,y1,y2);   //result=hls(11,9,15,14)会报错
   cout << result << endl;
   return 0;
}
           

继续阅读