1. 声明和初始化指针
指针储存的是地址。
比如:int * testPointer;
这里testPointer 为int*类型的值,存储内存地址。
*testPointer为int类型的值,代表当前内存地址存储的值。
int main{
int testPointer = 5;
int *p = &testPointer;
cout<<p<<endl; //内存地址 0x30dd69a88 不同机器地址可能不同
cout<<*p<<endl; //内存存储的值 5
}
注意: C++在创建指针的时候,计算机会分配用于存储地址的内容,但不会分配用来存储指针所指向的数据的内存,所以在对指针应用解除运算符*之前,一定要将指针初始化为一个确定是适当的地址。
如下图所示,当*p直接赋值时,由于没有具体的地址指向,程序运行时会出问题。
如果需要将数字值作为地址来使用,需要通过强制转换类型将数字转换为适当的地址类型,用于指定模块内存指针。
int main(){
int *p;
p = (int *) 0xB8000000;
cout<<p<<endl; //内存地址 0xb8000000
}
2. new / delete
指针初始化为变量的地址时由于变量是在编译分配的有名称的内存,而指针就是为可能通过名称访问的内存提供的一个别名。
指针可以在运行阶段分配未命名的内存以存储值(通过new分配),这种情况下只能通过指针来访问内存。
int main(){
int testPointer = 5;
int *p = &testPointer;
int * testPointer1 = new int;
cout<<p<<endl; //内存地址 0xb8000000
cout<<&testPointer<<endl; //使用变量取地址和指针值一样
cout<<testPointer1<<endl; //只能使用指针
}
常规变量分配内存 | new 分配内存 | |
分配时间 | 编译时分配 | 运行时 |
名称 | 内存有名字,可通过名字访问 | 没有名字,只能通过指针访问 |
分配位置 | 栈内存 | 堆内存 |
使用new申请的内存,一定要通过delete释放,否则将发生内存泄漏 。
使用delete的规则:
- 不能释放已经释放的内存块。
- 不能使用delete来释放变量所获的的内存。
- 空指针delete是安全的。
- 如果使用new[] 为数组分配内存,要用delete[] 释放。
- 如果使用new为一个实体分配内存,则使用delete释放。
3. 指针和数组
在大多数情况下,C++将数组名解释为数组第一个元素的地址。
int main()
{
int test[3] = {1, 3, 4};
cout<<test<<endl;
cout<<&test<<endl;
cout<<test+1<<endl;
cout<<&test+1<<endl;
cout<<0x304c66a90 - 0x304c66a8c<<endl;//4
cout<<0x304c66a98 - 0x304c66a8c<<endl;//8
}
⬆️代码运行结果如下:可以看出,指针变量加1,其增加的值等于指向的类型占用的字节数。而&test代表一个12字节的内存块地址,当&test+1时,增加的时该数组对应的内存块值。
0x30465ca8c
0x30465ca8c
0x30465ca90
0x30465ca98
4
12
很多情况下,可以用相同的方式使用数组名和指针名,但他们也有区别:
- 可以修改指针的值,但数组的名是常量是不允许的
- 对数组使用sizeof得到的是数组的长度,而对指针使用sizeof得到的是指针的长度,而不是指针指向的数组的长度
4. 指针和字符串
在cout和多数c++表达式中,char数组名,char指针,以及用引号表示的字符串常量都被解释为字符串第一个字符的地址。
int main()
{
int test[3] = {1, 3, 4};
cout<<test<<endl;
char str[10] = "test";
cout<<str<<endl;
}
0x3096a7a8c
test
Process finished with exit code 0
待续~~