一、指针基础:
①指针的两种理解方法:
int* p = nullptr;
C-style: int *p; //指向int的指针p
C++-style: int* p; //int*型数据p
②指针算数:
1>减法:
同类型指针做减法时,得到这两个指针的间距,间距为整数(个单位距离);
int array_name[5] = {1,2,3,4,5};
int* p_a0 = &array_name[0];
int* p_a4 = &array_name[4];
int c = p_a4 - p_a0; //得到p_a4与p_a0的间距,该间距是一个整数
//一般来说,指针减法运算只在同一数组范围内有实用意义;
2>加法:
指针只能与整数做加法,两个指针(即使为同类型)之间不可直接做加法;
int array_name[5] = {1,2,3,4,5};
int* p_a0 = &array_name[0];
int* p_a4 = &array_name[3];
p_a0 = p_a0 + 1; //可行
p_a3 = p_a3 + 1; //可行
int p_n = p_a0 + p_a3; //不可行
二、指针与数组名:
int array_name[SIZE]; //数组名
int* p_array = new int[SIZE]; //指针操作的数组
//正如操作new得到的heap区内存一样,指针的一个很重要的用途是,直接操作没有命名的内存(块)
①共同点:
1>都可以使用[ ]下标方法或*解除引用访问数组元素:
array_name[i]; //同*(array_name + i)
p_array[i]; //同*(p_array + i)
//下标方法访问数组元素既然被解释为*(p_array + i),会不会导致指针实际位置移动呢?
#include "stdafx.h"
#include<iostream>
int main()
{
//
using std::cout;
using std::endl;
//
int*p = new int[3];
p[0] = 1;
cout << "\t" << p[0] << "p:" << (void*)p << endl;
p[1] = 2;
cout << "\t" << p[1] << "p:" << (void*)p << endl;
p[2] = 3;
cout << "\t" << p[2] << "p:" << (void*)p << endl;
//
cout << *p << endl;
delete []p;
//
system("pause"); //结论:对指针的类数组操作p[1],p[2],p[3]并不会导致指针实际移动
return 0;
}
2>绝大部分情况下,都表示地址:
array_name和p_array都被解释为指针首元素的地址;
std::cout << array_name << std::endl;
std::cout << p_array << std::endl;
//输出结果都是数组首元素地址
//特殊的,对于char*和char[],二者都将输出整个字符串
②区别:
1>数组名的行为更接近const指针。数组名是常量,而(非const)指针可以修改指向;
array_name++; //不允许
p_array++; //允许
//array_name与&array_name的区别:
#include "stdafx.h"
#include<iostream>
int main()
{
//
using std::cout;
using std::endl;
//
int array_name[5] = { 1,2,3,4,5 };
cout << "\t" << "array_name:" << array_name << endl;
cout << "\t" << "&array_name:" << &array_name << endl; //输出结果数值一致
//
system("pause");
return 0;
}
//但事实上只是数值上一致:array_name被解释为首元素地址,跳转单位为1个int;((array_name+1)跳转4byte)
&array_name被解释为整个数组的地址,跳转单位为5个int;((&array+1)跳转20byte)
2>sizeof的结果不同:
sizeof(array_name); //数组大小
sizeof(p_array); //指针大小
三、智能指针:
智能指针是一类模板类,在头文件<memory>中被声明。
智能指针被提出的目的是简化new和delete的使用。
现有的三种智能指针模板类:
①auto_ptr<>:
auto_ptr<>是三种智能指针中最老式的版本,功能不完善,不能够处理所有权(ownership)问题:
auto_ptr<string> p1 = auto_ptr<string>(new string("some words"));
auto_ptr<string> p2 = p1; //p1指向的字符串所有权转交给p2,p1不再指向该字符串
此时p1为NULL,这导致指针不可再用。
另外,auto_ptr<>只能管理使用new分配的内存,而不能用于管理使用new[]分配的内存。
②shared_ptr<>:
shared_ptr<>是稍优于auto_ptr<>的版本,在所有权问题上进行了改善:
shared_ptr<string> p1 = shared_ptr<string>(new string("some words"));
shared_ptr<string> p2 = p1; //引用计数+1,p1和p2都指向同一个字符串
shared_ptr<>使用引用计数,在计数降至1之前将不会调用带有delete的析构函数,以此避免所有权矛盾。
和auto_ptr<>一样,shared_ptr<>也只能管理使用new分配的内存,而不能用于管理使用new[]分配的内存。
③unique_ptr<>:
unique_ptr<>不允许非临时的所有权的转让:
unique_ptr<string> p1 = unique_ptr<string>(new string("some words"));
unique_ptr<string> p2 = p1; //不允许这样的赋值
和auto_ptr<>以及shared_ptr<>不同,unique_ptr既可用于管理new又可用于new[]分配的内存。