1 什么是指针

指针是存储内存地址的变量
与所有变量一样,指针也占用内存空间,其特殊之处在于,指针包含的值为内存地址,因此,指针是指向内存单元的特殊变量

内存单元通常使用十六进制表示法

1.1 声明指针

和其它变量一样,指针在使用前也需要声明。通常将指针声明为指向特定的类型,如int,这意味着指针变量包含的地址对应的内存单元存储了一个整数;也可将指针声明为指向一个内存块,这种指针被称为void指针
格式:

PointedType* PointerVariableName

可将指针初始化为NULL,NULL是一个可检查的值,且不会是内存地址

1.2 使用引用运算符&获取变量地址

1.3 使用解引用运算符 * 访问指向的数据

1.4 将sizeof()作用于指针

指针是包含内存地址的变量,所以不管其指向哪种类型的变量,内容都是一个地址。因此,将sizeof()作用于指针时,结果取决于编译程序时使用的编译器和针对的操作系统,与指针指向的变量类型无关

2 动态内存分配

2.1 使用new和delete动态分配内存和释放内存

使用new分配新的内存块,成功则返回一个指向分配内存的指针,否则触发异常。使用new时,需要指定要为哪种数据类型分配内存

Type* Pointer=new Type; 

Type* Pointer=new Type[numElements]; //指定为多个元素分配内存

new表示请求分配内存,并不能保证分配总能得到满足,取决于系统状态机内存资源的可用性

释放内存使用delete

delete Pointer

delete[] Pointer 

new[...]分配的内存块,需使用delete[]释放;使用new为单个元素分配的内存,需使用delete释放
不再使用分配的内存后,如果不释放它们,这些内存仍被预留并分配给应用程序。这将减少可供其它应用程序使用的系统内存量,甚至降低应用程序的执行速度,这被称为内存泄漏。

delete只能用于new返回的且未使用delete释放的指针,而不能将其用于任何包含地址的指针

2.2 对指针使用自加++自减--运算符

对指针使用自加++自减--运算符,编译器将会指向内存块相邻的值(同时假定该值类型与前一个值类型相同),而不是相邻字节
示例:

#include <iostream>
using namespace std;

int main()
{
   cout << "How many integers you wish to enter? ";
   int numEntries = 0;
   cin >> numEntries;
   int* pointsToInts = new int [numEntries];

   cout << "Allocated for " << numEntries << " integers" << endl;
   for(int counter = 0; counter < numEntries; ++counter)
   {
      cout << "Enter number "<< counter << ": ";
      cin >> *(pointsToInts + counter); 
   }
   cout << "Displaying all numbers entered: " << endl;
   for(int counter = 0; counter < numEntries; ++counter)
      cout << *(pointsToInts++) << " ";

   cout << endl;
   // return pointer to initial position

   pointsToInts -= numEntries;
   // done with using memory? release 

   delete[] pointsToInts;
   return 0;
}

调用delete[]释放内存时,必须指定分配内存时new返回的指针地址。这个值存储在pointsToInts中,但后面修改了pointsToInts的值,所以在使用delete前使用-=让pointsToInts重新指向原来地址(很不方便啊。。。)

2.3 const指针

指针也是变量,因此可将关键字const用于指针。const指针有如下三种:

常量指针(顶层const)

指针变量存储的地址(所指向的变量的地址)是常量,不可修改,但可修改指针指向的变量的值
image

示例:

int daysInMonth=30; //一个月有多少天
int* const pDaysInMonth=&daysInMonth;  
*pDaysInMonth=31; //可以修改指向的数据
int daysInLunarMonth=28;
pDaysInMonth=&daysInLunarMonth; //错误,不可让指针指向另一个地址

指向常量的指针(底层const)

指针指向的内容是常量,不能修改,但可以修改指针存储的地址,即指针可以指向其它地方
image
在C++ Primer中,又说可以修改指针指向的变量(p56),只是它以为它指向的是常量
虚线表示可选的指向地址
声明示例:

const int* pointsToInt;

指针包含的地址以及它指向的值都是常量,不能修改
image

声明示例:

const int* const pHourInDay;

函数参数应该声明为第三张const,以确保函数不会修改指针指向的值

2.4 数组与指针

数组变量是指向其第一个元素的指针

3 使用指针常犯的错误

3.1 内存泄露

确保程序释放其分配的所有内存

3.2 指针指向无效的内存单元

使用运算符 * 对指针解引用以访问指向的值时,务必确保指针指向了有效的内存单元,否则程序要么崩溃、要么发生不可预测的行为

3.3 悬浮指针

初始化指针或释放指针后都应将其设置为NULL,并在使用运算符 * 对指针解引用前检查它是否有效(将其与NULL比较)

3.4 检查使用new发出的分配请求是否得到满足

除非请求分配的内存量特别大或系统处于临界状态,可供使用的内存很少,否则new的请求一般都能成功。但还是有许多情况内存分配不一定成功,C++有两种确认指针有效的方法:

  • 默认方法使用异常,即如果内存分配失败,将触发std::bad_alloc异常,这将导致程序中断,除非提供了异常处理程序,否则程序将崩溃并显示“异常未处理”的消息
  • 第二张方法使用new变种new(nothrow),在内存分配失败时不引发异常,而返回NULL,让程序员在使用指针前检查其有效性

4 引用是什么

引用是变量的别名。声明引用时,需将其初始化为一个变量,因此引用只是另一种访问相应变量存储的数据的方式
引用声明需使用引用运算符&,格式:

VarType original=Value;
VarType& ReferenceVariable=original;

示例程序:

#include <iostream>

using namespace std;

int main()
{
   int original = 30;
   cout << "original = " << original << endl;
   cout << "original is at address: " << hex << &original << endl;

   int& ref1 = original;
   cout << "ref1 is at address: " << hex << &ref1 << endl;

   int& ref2 = ref1;
   cout << "ref2 is at address: " << hex << &ref2 << endl;
   cout << "Therefore, ref2 = " << dec << ref2 << endl;

   return 0;
}

输出:

original = 30
original is at address: 0x7ffde6e23cb4
ref1 is at address: 0x7ffde6e23cb4
ref2 is at address: 0x7ffde6e23cb4
Therefore, ref2 = 30

输出表明,无论将引用初始化为变量还是其它引用,它都将指向相应变量所在的内存单元

4.1 引用的作用

  • 函数编写
    之前的函数编写传参过程,一般直接使用变量,这将产生较大的复制开销。引用可以直接使用调用者栈中的数据,从而避免复制操作。(和指针有什么区别呢??)

程序示例:

#include <iostream>

using namespace std;

void GetSquare(int& number){
   number *= number;
}

int main()
{
   cout << "Enter a number you wish to square: ";
   int number = 0;
   cin >> number;

   GetSquare(number);
   cout << "Square is: " << number << endl;

   return 0;
}

4.2 const引用

posted on 2024-05-10 12:26  房东的猫hhhh  阅读(3)  评论(0编辑  收藏  举报