认识C++指针

简介: 认识C++指针

前言:


 期待已久的指针篇来啦,这篇全都是有关指针的知识,喜欢指针的读者可以大饱眼福^ ^。关于指针的声明和初始化等部分,我在共用、结构里讲过了,需要的读者可以点进去看一下再返回来。


 链接:《共、枚、指1》


1.指针未初始化的危险性

 我们知道指针是存放地址的变量。当我们创建了一个指针的时候,但并没有初始化,在后面我们还对这个未初始化的指针解引用了,就会对内存产生破坏,导致程序挂掉。



  创建指针变量的时候,计算机不会为指针指向的内存单元编号开辟空间。



 当我们用p指针里的地址去找到相应的内存空间并对它进行操作,可不敢这样做,那样是犯法的。故事性理解:就好像你知道了一个旅馆的一个房间地址,但你知道并不代表你拥有这个房间,你来到这个旅馆,没跟馆主说,你径直的冲到这个房间门口,强行打开房间门,里面有小明躺在床上睡觉,你一脚把它踹开,自己躺在床上睡觉,还赖皮的不走了,馆主表示无奈,并报了警。


2.指针与十六进制数字

 我们知道,地址是用十六进制表示的,但数字的十六进制和地址的十六进制的意思是截然不同的,虽然计算机通常把地址当做整数来处理。但我们知道数字是描述数值的,指针描述的是位置。



 计算机把地址当做整数来处理的意思是:指针变量存储的值(也就是地址),就是在按照存储整型的方式存到内存中的,取出来的时候也是按整型取的。


 但我们要记得的是:十六进制数值,和十六进制地址不是一回事就OK。


3.使用new分配内存空间

 使用new运算符在运行阶段开辟堆区空间,开辟的空间大小根据我们给new后面加的数据类型,而且我们需要使用同类型的指针来接收new返回来的地址。

例子:

 指针的大小是固定不变的,不管指针指向什么类型的地址,指针的大小只与平台位数有关。是32位平台就是4字节,64位平台就是8字节。


 这里面pn、pd是用来接收new开辟出来的内存空间的地址,这块内存空间没有名称,只能用指针去访问。而普通变量,内存空间有名称。比如int a = 10;&a是a变量的内存地址,用a这个名称来标记这块空间,就可以直接用a来访问里面的值。


4.使用delete释放内存

 在用new申请内存的时候,当我们不需要用了的时候,必须将这块申请的内存交还给操作系统,否则内存将会越来越少,直到没有多余的内存空间让程序运行起来。

 在C++中,我们使用delete来释放使用new开辟的空间,格式是:delete 指针;(接收new开辟空间返回地址的那个指针),本质上是释放掉new开辟的空间,因为这个接收的指针就是new开辟的地址,所以这么写也是没问题的。


 特别注意的是new和delete是要配套使用的。


delete使用注意事项

delete只能用来释放用new开辟的空间

不能对同一块new开辟的空间释放两次

对空指针使用delete是没事的,相当于delete什么都没做


 我们这里是用delete释放pd,pd指向的那块地址也是new开辟的,因为ps将值赋给了pd,其实delete释放ps也可以,但不要都释放,不然就对同一块new空间释放两次了。


5.使用new来创建动态数组

 静态联编:通过声明创建数组,则在程序被编译时将为它分配内存空间,不管程序最终使不使用数组,它都存在,并占用空间。在编译时给数组分配内存被称为静态离联编。


 而在运行阶段需要数组,则创建数组,不需要就不创建。还能在程序运行时确定数组的长度。这被称为动态联编。这种数组叫做动态数组。  


 使用静态联编,必须在编写程序时指定数组的长度。使用动态联编时,程序可以在运行时确定数组的长度。

  当我们使用new时带上方括号以及数目的时候,也就是在跟new传达开辟数组空间的信号,相应的释放掉数组空间也要给delete加上方括号。用new没有用方括号,delete也不用带。


 补充:对于ANSIC和ISO标准来说,new和delete的格式不匹配的结果是未知的。


总之就是:使用new来创建动态数组的时候,要用对应的格式和new匹配起来,需要补充的一点是这种情况new int[1];,new[]只为一个实体分配内存,用不带[]的delete来释放。看下面代码:

 pd是指向一个double(数组第一个元素)的指针,我们需要负责把数组的元素确定好,因为编译器不能对pd是指向10个double元素中的第一个进行确定。什么意思呢?也就是说当我们忽略数组的元素个数的时候,编译器不知道你这个首元素地址是10个元素大的数组的首元素地址,还是20个元素大的数组的首元素地址,所以不能省略数组元素的个数。


 知道动态数组怎么创建和怎么释放后,我们来讨论如何使用动态数组。


6.使用动态数组

 数组表示法:将指针当做数组名使用即可。



 数组名是一般情况下是首元素地址,数组名的值是不能变的。而指针是变量,可以通过加减来改变所指向的地址。例如parr = parr + 1;,使得parr原本指向第一个元素变成了指向第二个元素。



 parr[0]就是第一个元素。parr[0]是第二个元素是因为parr+1了,指向了第二个元素。把指针当做数组名来使用,并不是就不能用指针的方式来访问数组了,我们知道parr是数组第一个元素的地址,用解引用可以访问到该地址的值,所以*parr和parr[0]是等价的。我们来讲完指针的运算,就会更清晰了。


7.指针运算

 在C和C++中数组和指针基本是等价的。等价的原因不只是因为C和C++内部都使用指针来处理数组,也在于指针算术。


 将一个整数加1,其值将增加1,但指针增加1,它的值增加的大小取决于指针的类型。



 i的值增加1,这我们都理解。指针的值从E8变到EC(十六进制 C是12),增加了4,恰好是一个整型的大小,所以指针的加减运算是让指针变量跳过n个指针类型,值也相应加减n个指针类型的大小。例子:double df = 3.14;double* pd = &df;pd+1;pd的值将增加8。


 加油加油,再看一个就结束啦!坚持。

 在这里面,我们将wages(数组名)给double类型的指针初始化,可行的原因正是因为数组名是首元素的地址,数组的元素是double类型的,double类型的地址给double指针初始化那再合理不过了。


 pd在加1前,打印的值是A8,加一后是B0,增加了8。因为pd跳过了一个double类型(占8个字节)。有些读者可能就要问了,为什么让值增加8呢?其实是因为,每个地址编号对应的内存单元占一个字节。第一个元素占8个字节也就是8个编号,而指针指向头个内存单元。A8是第一个元素的头个字节,还有A9,AA一直到AF,算上A8是8个字节。然后指针加一指向下一个元素,而数组又是连续存储元素的,紧接着指针就指向了B0,这就是为什么会加8的原因。


 来到20、21行,这里就是指针访问和数组表示的关系。我们已经知道数组是首元素地址了,stacks[0]就相当于*(stacks+0),stacks加0还是首地址,解引用就是首个元素。


 也就是假设:在这里我们用指针ps来接收stacks,就可以用这些操作,*ps就是首元素,*(ps+1)是指针指向首元素的下一个元素后解引用得到第二个元素,ps[0]是*(ps+0),ps[1]是*(ps+1)。


 数组名的意思:在最后sizeof(wages),wages不是数组首元素地址的意思,而是整个数组的意思。wages每个元素8字节,数组有三个元素,就是24字节。


数组名

&arr

整个数组的地址

arr

数组首元素地址

sizeof(arr)

整个数组的大小

 一般情况下数组名都是首元素地址,有且仅有两种情况是值整个数组,单纯&arr和单纯sizeof(arr),加单纯的意思就是说只能是这种形式下的数组名才指整个数组。sizeof(arr+1),这里的arr就是一般情况了。


 到这里指针的大部分基本知识就讲完啦,还有指针与字符串、指针与类型的组合等,我们下节再讲。最重要的是对使用要熟练使用指针解决问题。


 希望读者读完有所收获,如果本篇博客有内容上的错误或排版、内容分布不合理,请评论跟博主讲!


 求点赞,求点赞,求点赞!你的点赞是我更新的动力^ ^。

相关文章
|
12天前
|
存储 安全 编译器
在 C++中,引用和指针的区别
在C++中,引用和指针都是用于间接访问对象的工具,但它们有显著区别。引用是对象的别名,必须在定义时初始化且不可重新绑定;指针是一个变量,可以指向不同对象,也可为空。引用更安全,指针更灵活。
|
30天前
|
存储 C++
c++的指针完整教程
本文提供了一个全面的C++指针教程,包括指针的声明与初始化、访问指针指向的值、指针运算、指针与函数的关系、动态内存分配,以及不同类型指针(如一级指针、二级指针、整型指针、字符指针、数组指针、函数指针、成员指针、void指针)的介绍,还提到了不同位数机器上指针大小的差异。
28 1
|
1月前
|
存储 编译器 C语言
C++入门2——类与对象1(类的定义和this指针)
C++入门2——类与对象1(类的定义和this指针)
22 2
|
1月前
|
存储 安全 编译器
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(一)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
|
1月前
|
存储 C++ 索引
C++函数指针详解
【10月更文挑战第3天】本文介绍了C++中的函数指针概念、定义与应用。函数指针是一种指向函数的特殊指针,其类型取决于函数的返回值与参数类型。定义函数指针需指定返回类型和参数列表,如 `int (*funcPtr)(int, int);`。通过赋值函数名给指针,即可调用该函数,支持两种调用格式:`(*funcPtr)(参数)` 和 `funcPtr(参数)`。函数指针还可作为参数传递给其他函数,增强程序灵活性。此外,也可创建函数指针数组,存储多个函数指针。
|
2月前
|
编译器 C++
【C++核心】指针和引用案例详解
这篇文章详细讲解了C++中指针和引用的概念、使用场景和操作技巧,包括指针的定义、指针与数组、指针与函数的关系,以及引用的基本使用、注意事项和作为函数参数和返回值的用法。
35 3
|
1月前
|
算法 C++
【算法】双指针+二分(C/C++
【算法】双指针+二分(C/C++
|
1月前
|
存储 编译器 程序员
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(二)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
|
2月前
|
C++
C++(十八)Smart Pointer 智能指针简介
智能指针是C++中用于管理动态分配内存的一种机制,通过自动释放不再使用的内存来防止内存泄漏。`auto_ptr`是早期的一种实现,但已被`shared_ptr`和`weak_ptr`取代。这些智能指针基于RAII(Resource Acquisition Is Initialization)原则,即资源获取即初始化。RAII确保对象在其生命周期结束时自动释放资源。通过重载`*`和`->`运算符,可以方便地访问和操作智能指针所指向的对象。
|
2月前
|
C++
C++(九)this指针
`this`指针是系统在创建对象时默认生成的,用于指向当前对象,便于使用。其特性包括:指向当前对象,适用于所有成员函数但不适用于初始化列表;作为隐含参数传递,不影响对象大小;类型为`ClassName* const`,指向不可变。`this`的作用在于避免参数与成员变量重名,并支持多重串联调用。例如,在`Stu`类中,通过`this->name`和`this->age`明确区分局部变量与成员变量,同时支持链式调用如`s.growUp().growUp()`。