指针是一个变量,其存储的值是地址,而不是值本身。(有点类似于组成原理里面的变址寻址)
在讨论指针之前,我们先来看看如何寻找常规变量的地址。只需对变量引用取地址符(&)就行了。
如下面一段代码:
#include <iostream>
using namespace std;
int main()
{
int dounts=6;
double cpus=5.6;
cout<<"dounts = "<<dounts<<", address is "<<&dounts<<endl;
cout<<"cpus = "<<cpus<<", address is "<<&cpus<<endl;
return 0;
}
*运算符被称为间接值或者解除引用运算符。将其用于指针,便可以得到该地址存储的值。
duck变量为int型变量,其分配的地址是1000,里面存储的值是12,而birding是一个int型指针变量它本身的地址是1006,而在它里面存储的值duck的地址1000。
所谓指针指的是存储的其他变量的地址。
指针的声明和初始化
int *ptr;//声明一个int型指针
*两边的空格是可选的。
传统上,C程序员使用这种格式。
int *ptr;//强调*ptr是一个int类型
C++程序员通常使用下面这种方式
int* ptr;
强调int*之一中指向int类型的指针。在哪里添加空格对于编译器没有区别。
注意:
int *p1, p2;表示的是创建一个int类型指针p1和一个变量p2。如果要声明两个变量,应该这样做:int *p1, *p2。
指针的初始化
#include <iostream>
using namespace std;
int main()
{
int a=3;
int *b;
b=&a;
cout<<"a = "<<a<<" at "<<&a<<endl;//&a表示a的地址
cout<<"*b = "<<*b<<endl;//<span style="font-family: Arial, Helvetica, sans-serif;">*b 表示b里面存储的地址所指向的位置存储的值,即a的值</span>
cout<<"the value of b is "<< b<<" at "<<&b<<endl;//b表示的是b里面存储的值,即a的地址
return 0;
}
从运行结果可以证明上面的图的正确性。
注意:C++在创建指针的时候,计算机将会分配用来存储地址的内存,但不会分配用来存储指针所指向的数据的内存。
如下所示:
int *a;
*a=2333;
上面这段代码并没有为2333分配内存,而是将其随机存放在一个位置,有可能是空闲位置,有可能是一个已经存放了数据的位置从而造成数据损坏。
使用new申请内存
int * pn=new int;
new int 告诉计算机程序要申请一块int类型的内存,new运算符根据类型判断需要多少字节的内存。找到内存之后将地址传回pn。
还可以使用变量直接赋值。
int higgens;
int * pt=&higgens;
申请数组
以申请int类型的数组为例:
int * psome=new int[20];//执行这句的时候,计算机会申请10个int型的连续存储内存,并将首地址返回。
#include <iostream>
using namespace std;
int main()
{
int nights = 1001;
int * pt = new int; //C-style
*pt = 1001;
cout << nights << ",location " << &nights << endl;
cout << "int value " << (*pt) << "location " << pt << endl;
double * pd=new double;
*pd = 10001;
cout << "value = " << *pd << " location " << pd << endl; //show the location of pd;
cout << "location of pointer pd " << &pd << endl;
cout << "size of pt " << sizeof(pt) << endl;//显示申请的地址的大小
cout << "sizeof *pt " << sizeof(*pt) << endl;//显示存储的地址里面的值的大小
cout << "size of pd " << sizeof(pd) << endl;
cout << "size of *pd " << sizeof(*pd) << endl;
/*
不初始化的话pp里面存的就是未知地址,可能会造成数据损坏、
*/
double *pp;
cout<<"pp at "<<&pp<<endl;
// *pp=3; //错误的用法
// cout<<pp<<endl;
pp=new double();
cout<<"*pp at "<<pp<<endl;
return 0;
}
一半常规变量申请的内存是在栈中的,随着函数的生命周期的结束会自动被回收。但是new申请的内存在堆(heap)或自由存储区中,用完之后必须被回收。不然会造成内存的泄露。所以这里我们需要使用delete来回收new申请的内存。
delete的用法
int *ps=new int;
delete ps;
int jugs=5;
int *pi=&jugs;
delete pi;//wrong
delete只能用来回收new申请的动态内存,所以第二种用法无效。
删除数组的用法和上面的类似
int *a=new int[10];
delete []a;
1.delete只能用来释放new分配的内存
2.不要使用delete对同一个内存释放两次
3.new和delete应该成对出现。
4.对空指针使用delete是安全的。
delete删除的是new申请的内存里面的值,而不是指针本身。
#include<iostream>
using namespace std;
int main()
{
int a=3;
int *b=&a;
int *c=new int();
int *d=c;
*c=123;
cout<<"a = "<<a<<", the address of a is "<<&a<<endl;
cout<<*b<<" at "<<b<<",the address of b is "<<&b<<endl;
cout<<"*c = "<<*c<<",the address stored in c is "<<c<<" and the address of c is "<<&c<<endl;
cout<<"*d = "<<*d<<",and the address stored in d is "<<d<<",the address of d is "<<&d<<endl;
delete c;//回收内存
//delete d; 加上之后影响不大
cout<<*c<<",the address in c is "<<c<<",and c's address is "<<&c<<endl;
cout<<*d<<",the address in c is "<<d<<",and c's address is "<<&d<<endl;
return 0;
}
从上面的例子可以看出指针c和d是两个不同的指针,但是他们指向的同一块内存。delete删除的只是申请的内存里面的值,而对指针本身的地址以及指针存储的地址并没有影响。系统会为a,b,c,d都分配一个地址,但是b存储的是a的地址,c,d存储的是123在堆里面的地址。delete也就是将123莫抹去,是该块内存显示为未用。