指针:
指针的定义:数据类型+*+变量名;指针可以存储一个变量的地址,通过对这个地址的操作,我们可以实现对变量的操作,具体方法是:*+指针名即可
eg:
#include<iostream>
using namespace std;
int main()
{
int a = 10;
int* p = &a;
cout << *p << endl;//10
*p = 20;
cout << *p << endl;//20
}
通过使用*号可以对我们的指针进行操作,接下来让我们看一下指针的实质是什么:
这里的p存储了我们的a的地址,也就是说,如果你打印p的话,打印出来的的会是a的地址,二者是等价的,如果你想要对p存放的这块地址的位置进行操作的话,使用*号可以找到a并对其进行操作,这就是指针,我们把这个操作称之为解引用;
2:空指针
之所以给出空指针这个概念,是因为指针很强大,也很危险,你想,有一个地址,我们可以访问到这个地址存放的东西,你就算修改也只是修改这个地址存放的东西,但是有了指针就完全不一样了,有了指针,你可以访问任何空间,也就是说,你的内存变得透明了,这对于黑客来说,一个指针就可以篡改你所有的数据;我们把这种指针称为:野指针;
所以我们的c++对于指针做出了很多限制,不如如果一个指针创建出来的时候,你没有给他赋任何值,那么这个指针就是很危险的,这个时候我们应该给它赋空,也就是NULL,这样可以防止这个指针被恶意使用。
当然,被赋予空指针的指针不能被解引用,也不能被赋值。
3:野指针:
一个指针在创建时没有被赋初值,其实就是野指针;
const修饰指针(限制指针的方法)
1:const修饰指针:这样指针的指向可以修改,但指向的值不可修改
#include<iostream>
using namespace std;
int main()
{
int a = 10, b = 20;
const int* p = &a;
cout << *p << endl;
p = &b;
// *p = 30;
cout << *p << endl;
}
被注释掉的那行代码是错误的,因为我们只可以修改指针的指向,但是不可以修改值,以此来让指针只可访问,不可修改;
2:const修饰常量,指针常量,指针指向不可改,值可以改:
#include<iostream>
using namespace std;
int main()
{
int a = 10, b = 20;
int * const p = &a;
cout << *p << endl;
// p = &b;
*p = 30;
cout << *p << endl;
}
与上面相反;
3:const即修饰指针,也修饰常量,这时候指针指向与指向内容的值都不可以修改
#include<iostream>
using namespace std;
int main()
{
int a = 10, b = 20;
const int * const p = &a;
cout << *p << endl;
// p = &b;
// *p = 30;
cout << *p << endl;
}
我注释掉的地方其实都是会报错的,具体的原因就是他会修改指针的指向与值;
4:指针与数组:我们把一个数组赋给指针,其实只是把首地址赋给指针了而已,我们可以通过对指针操作来遍历数组
#include<iostream>
using namespace std;
int main()
{
int arr[5] = { 1,2,3,4,5 };
int* p = arr;
for (int i = 0; i < 5; i++)
{
cout << *p << endl;
p++;
}
}
我们知道,数组是一块连续的空间,那么我们使用指针进行自增其实就是访问下一相邻的内存,也就是顺着数组往下,但是这里有一个问题;
我们知道指针其实是地址,他存的的也不过是一块地址而已,如果你要是使用指针访问到了数组以外的地方,编译器是不会抱错的,甚至直接输出也是不会有问题的
#include<iostream>
using namespace std;
int main()
{
int arr[5] = { 1,2,3,4,5 };
int* p = arr;
for (int i = 0; i < 6; i++)
{
cout << *p << endl;
p++;
}
}
我不敢修改,只敢访问,要是不小心把我内存里的某些东西删掉就不好了...
我的vs2022和dev是都不会报错的。