C++的指针详解
指针的定义
int a =10
int* p;
p = &a;
指针所占内存空间
空指针和野指针
const 修饰指针
接下来就是指针和数组,函数的关系
指针和数组
指针和函数
**
接下来是指针的高级内容理解
**
指针变量,保存另外一个变量在内存中的位置
64位和32位,指针的大小不同,64位占8个字节 32位4个字节(指针的大小不分类型***)
*在变量初始化的时候代表这个变量为指针
在初始化之后,并在指针前面,表示从该地址中获取数值
int a = 10;
int p = &a;
cout << *p << endl;
*p += 5;
cout << a << endl;
指针与数组之间的关系
数组内存连续
数组的名字就是连续地址中的首地址
同一个数组可以进行运算
-
- ++ – -= += > >= < <= == !=
int arr[10] = { 11,22,33,44,55,66,77,88,99,1 };
int* p1 = &arr[0];
int* p2 = &arr[4];
//比较的是在数组的索引大小,而不是对应的数值
if (p2 > p1)
{
cout <<*p2<<"yes" << endl;
}
for (int i = 0;i < 10;i++, p1++)
{
*p1 = 10;
}
for (int i = 0;i < 10;i++)
{
cout << arr[i] << endl;
}
//空指针初始化0 NULL nullptr
int* p = nullptr;
int myStrLen(const char *s)
{
const char* p = s;
int num = 0;
while (*p != '\0')
{
p++;
num++;
}
return num;
}
void myCopy(char *p1, const char *p2)
{
while (*p2 != '\0')
{
*p1 = *p2;
p1++, p2++;
}
*p1 = '\0';
}
指针的动态创建
先有一个创建好的变量或者数组,然后指针保存它的地址
指针也能动态的在内存中创建出变量,并赋值
创建方案()为值变量,[]为数组的创建
如果指针创建的是数组或者保存数组的地址的话,指针可以当成数组来用
指针通过new创建的变量保存在堆内存,堆区,动态内存都是指使用new关键字在堆区,
开辟一块空间。必须手动释放。
New 返回的是该类型的指针
局部变量保存在栈内存,过了域(例如main的{}或者for的{})自动释放
函数外面写的变量叫全局变量,全局变量和静态变量存在全局内存区域,程序关闭自动删除
释放指针new的内存 delete 指针(删除变量) 或者 delete[] 指针(删除数组);
/* int* p = new int(5);
cout << *p << endl;*/
int* p = new int[5] {1, 2, 3, 4, 5};
cout << *p << endl;
//p += 2;
//cout << p[3] << endl;
使用不当导致的错误,使程序崩溃的多种情况
//1.new的变量才能delete 一个new对应一个delete
int a = 10;
int* p = &a;
delete p;
//2
Int* p = new int(0);
Int a = 10;
P = &a;
delete p
//3.内存泄漏
Int* p = new int(0);
Int a = 10;
P=&a;
P=new int(2);
delete p;
//4.删除空指针不会出错
Int *p = nullptr;
delete p;
//大程序一般使用完删除,立即设置为空,避免误删出错,空指针删除不报错
//数组初始化不赋值,无法访问
指针与函数之间的关系
//函数指针,还叫委托,也叫代理,还叫单播
int(*pfun)(int, int);
pfun = addNumber;
int n = pfun(2, 3);
cout << n << endl;
pfun = multiNumber;
n = pfun(2, 3);
cout << n << endl;
//函数指针做参数
int addNumber(int a, int b)
{
return a + b;
}
int multiNumber(int a, int b)
{
return a * b;
}
void printNumber(int(*p)(int, int), int a, int b)
{
int n = p(a, b);
cout << n << endl;
}
//void show(int a) {} void(*p)(int);
Int main()
{
//委托,代理,单播,函数指针
//函数名作为参数
printNumber(addNumber, 3, 5);
printNumber(multiNumber, 3, 5);
//事件, 多播
//函数指针数组存函数名,然后for依次调用
int(*p[2])(int, int);
p[0] = addNumber;
p[1] = multiNumber;
for (int i = 0;i < 2;i++)
{
cout << p[i](3, 5) << endl;
}
}
int* show()
{
//三种方法处理栈区释放的问题
//堆区开辟
//变成静态
//变成全局
//int n = 100;
Int * p = new int(100);
return &n;
}
//指针函数,函数的返回值是一个指针
int n = *show();
cout << *n << endl;
//这时候要把返回值开辟在堆区,
//或者定义成全局变量
//或者加static变成静态变量
否则容易出现地址找不到的问题
int *n = show();
Cout<< *n<< endl;
//函数的参数传递有3种方案
//传值
//传址
//引用
//错误
void creatString(char* s)
{
//s = new char[100];
s = new char[100];
}
char* p = nullptr;
creatString(p);
strcpy(p, "helloworld");
cout << p << endl;
//上面的p指针为空,然后将空指针地址传给到函数内,并没有开辟空间,创建变量
,我们需要把指针指向的地址传过去,然后修改为指向*s的地址,开辟了空间就可以拷贝字符了。
void creatString(char** s)
{
//s = new char[100];
*s = new char[100];
}
char* p = nullptr;
creatString(&p);
strcpy(p, "helloworld");
cout << p << endl;
//常量
const int a = 10;
// ***引用与指针之间的区别
//1.引用初始化必须要赋值,不能是空引用,指针可以是空指针
//2.引用的东西必须是地址的,指针可以自己直接创建(创建的是在堆内存new)
//3.引用的字节大小和被引用的东西有关,指针大小由系统位数决定
//4.引用初始化后引用的地址不能再改变(引用的底层是利用的指针常量来实现的)
// ,指针保存的地址可以改。
int a = 10;
int b = 3;
int& ref = a;
ref += 5;
cout << a << endl;
int& ref = a;
ref = b;
int* p = &a;
p = &b;
//*****
//常量指针,const往右看有星号,就是常量指针,const修饰的是p,
// 所以以下代码中出现p=就为错(不能改值,可以改方向)
// 指针常量
// const修饰的是p,所以代码中出现p=就为错
//(引用的底层是利用的指针常量来实现的)
// 常量指针常量
// const既修饰*p,const也修饰p,所以值和方向都不能改了
Const int * const p =&a;
/int a = 10;
int b = 20;
const int p1 = &a;
p1 = &b;
int const* p2 = &a;*/
//预编译
//带有#的,编译器会提前帮我们把代码编译一下,看一下执行的顺序和代码中是否有错误等
//预编译中的判断
//宏定义–实现完全的取代效果
cout << AA << endl;
//我们在使用的时候一定要记得是替换,不是做计算