C++知识点累积(六)(指针)

本文详细介绍了C++中的指针,包括指针的基本操作、*pa++和(*pa)++的区别、常量指针与指针常量的特性,以及指针与数组的关系。此外,还讲解了动态内存管理,如malloc、calloc、realloc、memcpy、memset和free函数的使用。最后,提到了C++中的引用、智能指针std::unique_ptr和std::shared_ptr,以及字符处理中的字符串操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

**

2020-10-15 C++知识点累积(六)

**
**

一、指针

**

#include <iostream>

int main()
{
	int a{ 5200 };
	std::cout <<"a的值:"<< a<<std::endl;
	int* pa = &a;
	std::cout <<"pa的值:" <<pa<<"\n*pa的值:"<<*pa << std::endl;
	*pa = 500;
	std::cout << "a的值:" << a <<"\n*pa的值:"<<*pa<<"\n&a的值:"<<&a<< std::endl;
	(*pa)++;
	std::cout << "a的值:" << a << "\n*pa的值:" << *pa << "\n&a的值:" << &a << std::endl;
}

结果:
在这里插入图片描述

int* pa pa是int类型的指针
int* pa=&a 是把a的地址赋值给pa
*pa=500 是改变地址内的值,因为a的地址和pa的地址一样,所以a的值也改变了
pa=a的地址
*pa=a的值
&a=a的地址
(*pa)++使用运算符需要把*pa括起来表示一个整体
**

*pa++和(*pa)++区别

**
指针+1的时候 数值的变化是+1*指针类型的大小
如:

#include <iostream>


 int main() {
	 int a[5]{ 1001,2001,3001,4001,5001 };
	 int* pa{ &a[0] };
	 std::cout << ++(*pa) << std::endl;
	 std::cout << pa << std::endl;
	 *pa++;
	 std::cout << *pa << std::endl;
	 std::cout << pa << std::endl;
	 return 0;
}

结果:
在这里插入图片描述
pa++前和pa++后地址差4,因为1*4(int为4个字节)

**

常量指针和指针常量

**

#include <iostream>

 int main() {
	 //常量指针(const 变量类型* 变量名)
	 const int a{ 10001 };
	 int b{ 10002 };
	 const int* ptrA{&b};
	 std::cout << "ptrA:" << *ptrA<<std::endl;
	 ptrA = &a;
	 std::cout <<"ptrA:"<<*ptrA << std::endl;
	 //指针常量(变量类型* const 变量名)
	 int* const ptrB{ &b };
	 std::cout << "ptrB:" << *ptrB << std::endl;
	 *ptrB = -1;
	 std::cout << "ptrB:" << *ptrB << std::endl;
	 return 0;
	 //指向常量的常量指针(const 变量类型* const 变量名)
	 const int* const ptrC{&b};
	 std::cout << "ptrC:" << *ptrC<< std::endl;
}

结果:
在这里插入图片描述
在第一次赋值之后:
常量指针能改变指针的指向,不能改变指针地址里的值;
指针常量能改变指针地址里的值,不能改变指针的指向;
指向常量的常量指针既不能改变指针的指向,也不能改变指针地址里的值

**

指针与数组

**

#include <iostream>

 int main() {
	 int a[5];
	 int* ptr{ a };
	 a[0] = 5;
	 a[2] = 10;
	 std::cout << a[0]<< "\n";
	 std::cout << *(ptr + 2)<<"\n";
	 std::cout << ptr[0];
	 return 0;
}

结果:
在这里插入图片描述
a[0]的地址为a的地址偏移0个位子,所以a其实是一个数组的起始地址;
ptr指向a的地址,所以ptr也可以像a一样控制数组,如ptr[0],ptr[1];(ptr[1]==a[1])
ptr也可以*(ptr+2),等同于a[2];
多维数组也一样如:int a[2][2]{},a[1][1]==ptrA[3];
结论:
在这里插入图片描述
**

指针数组和数组指针

**
在这里插入图片描述

#include <iostream>

void main() {
	int a[2][5]{};
	a[0][2] = 1001;
	int* ptrB[5]{&a[0][0],&a[0][1] ,&a[0][2] ,&a[0][3] ,&a[0][4] };//指针数组代表能存五个int类型的指针的数`在这里插入代码片`组(本质上是数组)
	int(* ptrC)[5]{ a };//数组指针代表指向int[5]的数组(本质上是指针)
	std::cout << *ptrB[2] <<std::endl;
	std::cout << ptrC[0][2] << std::endl;
}

结果:
在这里插入图片描述
**

动态内存

**
C语言动态内存分配(c++也可以用)
malloc

功能:分配内存空间
格式:void* malloc(size_t size)
size代表分配的内存大小,返回值是内存分配的地址,如果分配失败则返回0
示例:

#include <iostream>
#include <string>
void main() {
	int* a = (int*)malloc(10 * sizeof(int));//分配了10个int类型的大小(10*4)返回的为10个int内存空间的起始地址(类似于数组)
	int* b = (int*)malloc(999999999 * sizeof(int));//分配了10个int类型的大小(10*4)返回的为10个int内存空间的起始地址(类似于数组)
	if (a == 0)
	{
		std::cout << "分配内存失败";
	}
	if (b == 0)
	{
		std::cout << "分配内存失败";//b内存分配失败原因为分配的空间超过了可分配空间最大值(32位最大值为4GB)
	}
}

代码中a成功分配内存空间10*4字节大小,b分配内存空间失败

calloc
功能:分配内存空间
格式:void* calloc(size_t count,size_t size)
count代表分配的个数,size表示每个个数分配的大小,返回值与malloc一样,分配失败返回值也和malloc一样
malloc和calloc的区别
calloc会将分配好的内存区域的值设置为0,而malloc不会处理内存空间内的值,但是malloc会比calloc运行效率高

#include <iostream>

int main()
{
	int* pm = (int*)malloc(10*sizeof(int));
	int* p = (int*)calloc(10,sizeof(int));
	std::cout << pm[0] << std::endl;
	std::cout << p[0] << std::endl;
}

结果:在这里插入图片描述
realloc
功能:重新分配内存空间
格式:void* realloc(void* _Block,size_t _Size)
_Block代表需要重新被分配的内存,_Size是重新分配的内存大小,返回值和malloc一样

#include <iostream>

int main()
{
	int* p = (int*)malloc(10*sizeof(int));
	std::cout << p[0] << std::endl;
	p=(int*)realloc(p,100*sizeof(int));
}

memcpy
功能:复制内存
格式:void* memcpy(void* _Dst,const Void* _Src,size_t _Size)
把_Sre区域的内存复制到_Det的区域,_Size需要复制的长度(可以复制_Sre部分内存区域到_Det,但是不要复制超出_Sre的内存区域)

#include<iostream>

int main() {
	int a[2]{8,9};
	int* b=new int[2];
	memcpy(b, a, 8);
	std::cout << a[0] << std::endl;
	std::cout << a[1] << std::endl;
	std::cout << b[0] << std::endl;
	std::cout << b[1] << std::endl;
}

结果:
在这里插入图片描述
memset
功能:设置内存
格式:void* memset(void* _Dst,int val,size_t _Size)
_Dst代表设置内存的地址,val表示设置内存的值,_Size需要设置的长度(字节)
memset可以将指定内存区域每一个字节的值都设置为val,所以只能设置为一个字节大小的东西

#include <iostream>
int main()
{
	int a[5]{ 1,2,3,4,5 };
	int* b = new int[5];
	memset(b, 0x0, 5 * sizeof(int));
	for (int i = 0; i < 5; i++)//设置未超过一个字节的值
	{
		std::cout <<std::hex << b[i] << std::endl;
	}
	std::cout << "---------------------------------" << std::endl;
	memset(b, 0x12345, 5 * sizeof(int));//设置超过一个字节的值,会截取最后两位,因为一个字节最大0xFF
	for (int i = 0; i < 5; i++)
	{
		std::cout << std::hex << b[i] << std::endl;//每次显示4个字节的值(int为4字节)
	}
}

结果:
在这里插入图片描述

free
功能:释放内存
格式:void free(void* _Block)
_Block表示需要释放的内存

#include <iostream>

int main()
{
	int* p = (int*)malloc(10*sizeof(int));
	std::cout << p[0] << std::endl;
	p=(int*)realloc(p,100*sizeof(int));
	free(p);
	p=0;
}

释放内存每个内存只能释放一次,一般释放完会把指针赋为0,防止出现悬挂指针问题

C++动态内存分配
new
功能:分配内存
格式:数据类型* 变量名 = new 数据类型

int* pa = new int//只分配了一个int类型的内存空间

数据类型* 变量名 = new 数据类型[数量]

int* pa = new int[5]//分配一段能存放5个int变量类型的内存空间

数据类型* 变量名 = new 数据类型(数据)

int* pa = new int(5)//分配一个int类型的内存空间,并赋值5

数据类型* 变量名 = new 数据类型{数据}

int* pa = new int{5}//分配一个int类型的内存空间,并赋值5

delete
功能:释放内存
格式:如果内存分配的是用new则用delete+需要释放的内存

delete pa;

如果分配内存用的是new[]则用delete[]+需要释放的内存

delete[] pa;

例子:

#include <iostream>

int main()
{
	int* p = new int;
	std::cout << p[0] << std::endl;
	delete p;
	p=new int[5];
	delete[] p;
}

**

引用

**
引用的概念
引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字。一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。
引用 vs 指针
引用很容易与指针混淆,它们之间有三个主要的不同:
1.不存在空引用。引用必须连接到一块合法的内存。
2.一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
3.引用必须在创建时被初始化。指针可以在任何时间被初始化。
引用的作用
假如变量名称是变量附属在内存位置中的标签,可以把引用当成是变量附属在内存位置中的第二个标签。因此,您可以通过原始变量名称或引用来访问变量的内容
例如:

#include <iostream>
int main()
{
	int i = 999;
	int& li = i;
	li++;
	std::cout << i << std::endl;
	std::cout << li << std::endl;
}

结果:
在这里插入图片描述
改变引用变量li的值,i的值也会发生变化,并且引用变量的地址和被引用变量的地址相同,引用变量无法二次改变引用

智能指针

**

std::unique_ptr:唯一智能指针

**
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
实例:

#include <iostream>

int main()
{
	int* ptr = new int{6};
	std::unique_ptr<int> a{ std::make_unique<int>(5)};//给指针a赋值5
	std::unique_ptr<int[]> b{ std::make_unique<int[]>(5) }; //给指针数组b分配5个元素
	std::unique_ptr<int[]> bCopy{ std::make_unique<int[]>(5) };
	b[1] = 500;
	std::cout << "a的地址:" <<a << "   " << "a的值:" << *a<<std::endl;
	std::cout << "b的地址:" << b << "   " << "b[1]的值:" << b[1] << std::endl;
	std::cout << "bCopy的地址:" << bCopy << "   " << "bCopy[1]的值:" << bCopy[1] << std::endl;
	std::cout << "ptr的地址:" << ptr << "   " << "ptr的值:" << *ptr << std::endl;
	ptr=a.get();//get()的功能是获取a的指针
	a.reset();//reset()的功能是释放内存空间,并且把a设为nullptr
	std::cout << "Get后ptr的地址:" << ptr << "   " << "Get后ptr的值:" << *ptr << std::endl;
	std::cout << "reset后a的地址:" << a << "   " << "reset后a的值:" << *a << std::endl;
	bCopy=std::move(b);//把b指针转移给bCopy
	std::cout << "Move后bCopy的地址:" << bCopy << "   " << "Move后bCopy[1]的值:" << bCopy[1] << std::endl;
	ptr=bCopy.release();//release的功能是获取bCopy的指针,并且把bCopy设为nullptr,但是不释放其内存
	std::cout << "release后bCopy的地址:" << bCopy << "   " << "release后bCopy的值:" << bCopy << std::endl;
	std::cout << "release后ptr的地址:" << ptr << "   " << "release后ptr的值:" << ptr << std::endl;
}

注意:智能指针具有唯一性,不能将两个智能指针存放同一个内存地址

**

std::shared_ptr:共享智能指针

**
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

**

字符处理(字符串)

**
char声明字符串

char str[6]{"Hello"};//==>'H','e','l','l','o','\0'
const char* strA{ "Hello" };
char *strB = new char[6]{ "Hello" };

因为字符串以\0结尾,所以声明初始化数组数量要+1

strlen()
功能:获取字符串长度
用法:strlen(const char* str);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值