书接上文
简单了解一下C++指针
其实指针应该也是属于复合类型,对于C++来说是比较重要的知识点,所以打算拆开记录;简单来说,指针是一个变量,其存储的是值的地址,而不是值的本身;我们应该怎样取到一个变量的内存地址呢?通过“&”符号获取;我们说地址是一个指定的值,而实际值则为派生值,当我们知道一个派生值的地址时,我们可以通过“*”符号进行获取派生值。
使用指针和初始化指针
通过“”声明一个指向int的指针,然后通过“&”取址符进行赋值,赋值后也就是int是指向这个内存地址的,然后通过“*”对int *类型“解除引用”获得间接值。 代码:
using namespace std;
#include <iostream>
int main()
{
// 声明一个值
int trueVal = 5;
// 声明一个指向int的指针类型,用于接收trueVal的内存地址
int* val;
// val = &trueVal的内存地址
val = &trueVal;
// 打印出val的内存地址
cout<< val<<endl;
// 打印出val的内存地址中的派生值
cout<< *val << endl;
}
运行截图:
指针的危险
C++创建指针时,计算机会给指针分配存储地址的内存,但不会分配指针指向某个数据的内存;数据的内存需要我们独立的去分配,这很重要!!!如果通过解除引用指针之前,没有给指针一个切确的地址,那么就会有空指针报错;所以我们在“”解除引用指针时,确保此时指针已经赋予一个切确的地址。 代码:
using namespace std;
#include <iostream>
int main()
{
int a = 0;
// 错误师范,请勿模仿!!!
// 声明一个error的指针,但指向哪个内存地址,我们不做处理,此时这个指针已经被C++分配了内存了
int* error = &a; // 假设a是一个不知道的地址,我们不清楚error是指向哪个地址的
* error = 1; // 此时给*error赋值,我们就不知道把哪个地址的值给覆盖了
cout<<a<<endl;// 输出1
}
运行截图:
指针与数字
指针打印出来的是内存地址,如果直接赋值一个整数或者16进制的整数编译器会报错的,但是能通过int*强转一个电脑上16进制的内存地址进行赋值。强烈不推荐这么搞,知道一下就好... 代码:
using namespace std;
#include <iostream>
int main()
{
// 一个非常变态的做法,0x5ffe14是我电脑上的一段内存地址,可以通过强转的形式给指针赋值内存地址,后续给他进行解除引用,也是能够往内存里写值的
int* b = (int *)0x5ffe14;
*b = INT_MAX;
cout << *b << endl;
}
运行截图:
new分配内存和delete释放内存
有过编程经验的小伙伴对于“new”关键字的使用并不陌生,在C语言中,可以通过库函数malloc来进行内存分配,在C++中任然可以这么做,但推荐更好的new关键字的使用,通过new出来的内存是在堆上分配的内存,不需要用时需要及时的通过“delete”清理;不要重复的去释放一个内存块会带来不确定的因素;delete对空指针来说是安全的。 代码:
using namespace std;
#include <iostream>
int main()
{
// 使用new关键字分配int内存
int* ps = new int;
*ps = 5;
cout << *ps << endl;
// 回收new关键字分配的堆外内存,但不会回收ps的指针内存,因为指针属于栈上分配的内存
delete ps;
// 不要重复释放同一个内存块,这个结果是不确定的,不知道会发生什么神奇的事情
// delete ps;
cout << *ps << endl;
}
代码截图;
通过new创建动态数组
在没有学会new之前,我们创建数组都是需要提前知道数据的长度的,有时候并不能准确的预测出动态数据的长度到底是多少?分配多了就浪费内存,分配少了就出现溢出的情况;现在我们学到了new关键字,可以在动态的时候创建数组;“delete”数组时需要带上“[]”,表示移除整个数组;数组与指针基本等价,访问的过程中不需要带上“*”。 代码:
using namespace std;
#include <iostream>
int main()
{
int* array = new int[10];
array[0] = 1;
array[1] = 2;
cout << array[0] << endl;
cout << array[1] << endl;
delete [] array;
}
代码截图:
指针算数
数组基本等价于指针原因在于指针算数,在整数中,如果整数等于1,然后+1会等于2,在指针中+1表示的是类型的字节数,如果int指针+1,表示原本指针指向4字节,+1后执行后面的4字节;跟数组的连续分配内存一样,其实指针+1就是下标+1。
代码:
using namespace std;
#include <iostream>
int main()
{
// 定义了1,2,3三个数,下标分别表示0,1,2
int* array = new int[10]{1,2,3};
// 取下标0的地址+1,得到2的地址
int* array1 = &array[0] + 1;
// 输出2
cout << *array1 << endl;
delete[] array;
}
运行截图:
通过new创建动态结构
通过new创建的结构,有一个比较棘手的问题,那就是访问成员变量,由于之前是具体的结构体类型,现在是指针,C++准备了“指针->成员变量”的形式进行访问,或者通过“*指针”解除引用进行访问。 代码:
using namespace std;
#include <iostream>
struct student
{
string name;
int age;
};
int main()
{
student* st = new student;
st->name = "Joh";
st->age = 18;
cout<<"Name: "<<st->name<<endl;
cout<<"Age: "<<(*st).age<<endl;
}
运行结果: