首页 > 其他分享 >第8章 指针和引用

第8章 指针和引用

时间:2024-05-10 12:33:33浏览次数:14  
标签:变量 指向 int 内存 new 指针 引用

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指针有如下三种:

  • 指针变量存储的地址是常量,不可修改,但可修改指针指向的数据
    image

示例:

int daysInMonth=30; //一个月有多少天
int* const pDaysInMonth=&daysInMonth;  
*pDaysInMonth=31; //可以修改指向的数据
int daysInLunarMonth=28;
pDaysInMonth=&daysInLunarMonth; //错误,不可让指针指向另一个地址
  • 指针指向的数据是常量,不能修改,但可以修改指针包含的地址(指针是一个存储地址的变量),即指针可以指向其它地方
    image

虚线表示可选的指向地址
声明示例:

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引用

标签:变量,指向,int,内存,new,指针,引用
From: https://www.cnblogs.com/xdhisgood-xy/p/18183166

相关文章

  • ansible02-ansible变量的定义与引用
    4.1ansible变量的定义与引用playbook中变量的定义变量名只能由数字、字母、下划线组成,且只能由字母开头变量的来源(1)setup模块中的所有变量都可以直接调用(2)在/etc/ansible/hosts中定义- 普通变量:主机组中主机单独定义,优先级高于公共变量- 公共变量:也称组变量,针对主......
  • WPF 引用类库中的图片在设计器的时候显示,运行起来不显示
    我这边是建立了一个类库,然后把所有静态资源放在该类库中,然后主项目添加该项目引用,然后图片死活不显示  1.图片属性设置为资源2.主项目添加该项目引用操作都试过了,就是死活不显示,然后问了别人,让我删除类库重新建一个试试,然后试了下,诶,好像确实可以了,突然想起一个小细节,我......
  • C++ const常量指针
    const常量指针const是C++关键字,译为常量,const指针即为常量指针。分为三类指向const的指针const指针指向const的const指针指向const的指针表示指向区域的数据是不可变的,但是可以更换指向语法(将const卸载*之前):const数据类型*指针名数据类型const*指针名......
  • 【java】Java之关于基本数据类型和引用数据类型的存放位置
    1、基本数据类型存放在哪?基本类型的变量存在栈里或者堆里不是由"大小可知,生存期可知"就能确定了。关键是上下文。比如:123voidmethod(){    inta=3;}这自然是存在栈里的。局部方法嘛。而:123classTest{    inta=3;}......
  • 如何判断一个js对象是否存在循环引用
    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助一、背景在前端JSON.stringfy是我们常用的一个方法,可以将一个对象序列化。例如将如下对象序列化constperson={name:'kalory',age:18}JSON.stringfy(person)//结果'{"name":"kalory","age":18}'将一......
  • 引用
    左值 右值  (纯右值,将亡值)       可以在等号左边只能在等号右边能够取到地址不能取地址具名不具名1.变量名2.返回左值引用的函数3.解引用  (*this)4.++i是左值5.声明出来的左值引用6.右值引用1.返回非引用类型的函数调用(intf......
  • 06. C语言指针
    【指针】C语言使用数据名调用数据,数据名相当于C语言的直接寻址,直接寻址只能调用固定数据,而指针是间接寻址,指针存储了另一个数据的地址,使用指针调用数据时首先取指针存储的内存地址,之后使用此地址调用数据,使用间接寻址有如下几点优势:1.统一数据的调用方式,因为指针是调用数据的中间......
  • C#配置程序引用的dll的位置
    在C#程序的App.config配置第三方dll的位置,使得C#程序可以自动加载子目录下的dll。参考博客:https://blog.csdn.net/qq_43307934/article/details/117805106<runtime><assemblyBindingxmlns="urn:schemas-microsoft-com:asm.v1"><probingprivatePath="bin;bin......
  • 内联函数、引用、汇编
    内联函数内联函数是一种特殊的C++函数,编译器会将它的代码直接插入到调用它的位置,而不是像普通函数那样进行函数调用。这可以减少函数调用的开销,从而提高性能。#include<iostream>usingnamespacestd;intfunc(intv1,intv2){ returnv1+v2;}inlineintfunc1......
  • 指针实现字符串匹配
    #include<stdio.h>voidcomp(char*sub,char*str){inti=0,j=0;//通过子串指针移动的次数等于字串的长度,实现匹配成功与否//下面代码是直接使用子串和主串是否同时用完子串长度的循环实现while(*str){for(i=0;*(sub+i)==*(str+i);i++)//判断子串......