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
- 引用必须在声明时将其初始化,不能先声明后赋值。
#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
’ 声明为引用但未初始化。
- 引用更接近
指针,必须在创建时进行初始化,一旦引用和某个变量关联起来,该引用就会一直指向该变量。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;
}