一、概念
指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。
二、运算
假设 ptr 是一个指向地址 1000 的整型指针,是一个 32 位的整数,让我们对该指针执行下列的算术运算:
ptr++
在执行完上述的运算之后,ptr 将指向位置 1004,因为 ptr 每增加一次,它都将指向下一个整数位置,即当前位置往后移 4 个字节。这个运算会在不影响内存位置中实际值的情况下,移动指针到下一个内存位置。如果 ptr 指向一个地址为 1000 的字符,上面的运算会导致指针指向位置 1001,因为下一个字符位置是在 1001。
三、空指针
赋为 NULL 值的指针被称为空指针。 NULL 指针是一个定义在标准库中的值为零的常量。即执行
int *ptr = NULL;
则ptr = 0。
四、与数组
(1)我们喜欢在程序中使用指针代替数组,因为变量指针可以递增,而数组不能递增,因为数组是一个常量指针。
short int height[10]; //int型的数组(short int 每个数据2字节)
cout << "height "<< height << endl
<< "height+1 "<< height + 1 << endl
<< "&height[0] " << &height[0] << endl
<< "&height+1 "<< &height + 1<< endl
<< "height+9 "<< height+9 << endl
<< "height+10 " << height + 10 << endl;
结果如下:
height 0136F900
height+1 0136F902
&height[0] 0136F900
&height+1 0136F914
height+9 0136F912
height+10 0136F914
可以看到:
- height 与 &height[0] 值相等。
- height+1 = height + 2 字节 = height + 1 个 short int 也即 一个数组元素。
- height+9 为 height[] 中最后一个元素的地址,height+10 为该数组结束后的第一个地址。
- &height +1=height+10,即执行 &height+1 的结果是地址跳到整个数组之后第一个地址。
(2)指针和数组并不是完全互换的。例如,请看下面的程序:
1 #include <iostream> 2 3 using namespace std; 4 const int MAX = 3; 5 6 int main () 7 { 8 int var[MAX] = {10, 100, 200}; 9 10 for (int i = 0; i < MAX; i++) 11 { 12 *var = i; // 这是正确的语法 13 var++; // 这是不正确的 14 } 15 return 0; 16 }
把指针运算符 * 应用到 var 上是完全可以的,但修改 var 的值是非法的。这是因为 var 是一个指向数组开头的常量,不能作为左值。
由于一个数组名对应一个指针常量,只要不改变数组的值,仍然可以用指针形式的表达式。例如,下面是一个有效的语句,把 var[2] 赋值为 500:
*(var + 2) = 500;//地址没有改变
再例如:
cout << *(var++) << endl; //编译错误,因为var是数组名(也是数组首元素地址),不是一个变量,不可修改其值
cout << *(var+i) << endl; //编译正确,因为没有对var进行赋值,只是通过与i相加访问变量地址
(3)一维动态数组
定义方式
type* arrayname = new type [size](); // size可以是变量
访问与赋值方式:
for(int i=0;i<size;i++){
*(arrayname+i)=i; // 或是 arrayname[i];
cout<<*(arrayname+i)<<"
";
}
释放数组的方式:
delete [] arrayname;
(4)字符型指针数组
char *names[MAX] 含义为:指针数组,即数组的每个元素都是一个指向 char 类型元素的指针。
这个数组的每个元素被赋值了一个字符串,显然这个元素必然为一个指向 char 类型数组的指针;
简单说,char *names[MAX] 中的元素是指向四个 char 类型数组的指针 names[i]。
1 const char *names[MAX] = {"sun", "bin", "sunbin"}; 2 for (int i = 0; i < MAX; i++) 3 { 4 cout << "Value of names[" << i << "] = ";//输出字符串的值 sun 5 cout << names[i] << endl; 6 cout << "Value of *names[" << i << "] = ";//输出指针所指向字符串的第1个字符 s 7 cout << *names[i] << endl; 8 cout << "Value of *names[" << i << "]+1 = ";//输出ascii码值 116 9 cout << *names[i] + 1 << endl; 10 cout << "Value of *(names[" << i << "]+1) = ";//输出指针所指向字符串的第2个字符 u 11 cout << *(names[i] + 1) << endl; 12 }
int *ptr[3];
由于 C++ 运算符的优先级中,* 小于 [],所以 ptr 先和 [] 结合成为数组,然后再和 int * 结合形成数组的元素类型是 int * 类型,得到一个叫一个数组的元素是指针,简称指针数组。
等价于int *(ptr[3]);
int (*ptr)[3];
这个就不一样了,优先级顺序是 * 小于 (),() 等于 [],() 和 [] 的优先级一样,但是结合顺序是从左到右,所以先是 () 里的 * 和 ptr 结合成为一个指针,然后是 (*ptr) 和 [] 相结合成为一个数组,最后叫一个指针 ptr 指向一个数组,简称数组指针。
(5)函数传参及返回值
1 #include<iostream> 2 3 using namespace std; 4 5 int get(int *p) 6 { 7 *p = 5; 8 return *p; 9 } 10 11 int main() 12 { 13 int a = 0; 14 get(&a); 15 cout << a << endl; 16 return 0; 17 }
1 #include <iostream> 2 #include <ctime> 3 #include <cstdlib> 4 5 using namespace std; 6 7 // 要生成和返回随机数的函数 8 int * getRandom( ) 9 { 10 static int r[10]; 11 12 // 设置种子 13 srand( (unsigned)time( NULL ) ); 14 for (int i = 0; i < 10; ++i) 15 { 16 r[i] = rand(); 17 cout << r[i] << endl; 18 } 19 20 return r; 21 } 22 23 // 要调用上面定义函数的主函数 24 int main () 25 { 26 // 一个指向整数的指针 27 int *p; 28 29 p = getRandom(); 30 for ( int i = 0; i < 10; i++ ) 31 { 32 cout << "*(p + " << i << ") : "; 33 cout << *(p + i) << endl; 34 } 35 36 return 0; 37 }
(6)this指针
在 C++ 中,每一个对象都能通过 this 指针来访问自己的地址。this 指针是所有成员函数的隐含参数。因此,在成员函数内部,它可以用来指向调用对象。
友元函数没有 this 指针,因为友元不是类的成员。只有成员函数才有 this 指针。
静态成员函数没有 this 指针,也不能访问类的 this 指针。
1 class Box{ 2 public: 3 Box(){;} 4 ~Box(){;} 5 Box* get_address() //得到this的地址 6 { 7 return this; 8 } 9 };
this 指针的类型可理解为 Box*。
1 int main(){ 2 3 Box box1; 4 Box box2; 5 // Box* 定义指针p接受对象box的get_address()成员函数的返回值,并打印 6 7 Box* p = box1.get_address(); 8 cout << p << endl; 9 10 p = box2.get_address(); 11 cout << p << endl; 12 13 return 0; 14 }
此时得到两个地址分别为 box1 和 box2 对象的地址。