1.使用new和delete
- 不要使用delete来释放不是new分配的内存。
- 不要使用delete释放同一块内存两次。
- 如果使用new[]为数组分配内存,则应使用delete[]释放。
- 如果使用new为一个实体分配内存,则应使用delete(没有方括号)来释放。
- 对空指针应用delete是安全的。
2.指针小结
2.1声明指针
要声明特定类型的指针,使用下列格式:
typeName * pointerName;
2.2给指针赋值
应将内存地址给指针。可以对变量名应用&运算符,来获得被命名的内存地址,new运算符返回未命名的内存地址。
double * pn; //pn can point to a double value
double * pa; //so can pa
char * pc; //pc can point to a char value
double bubble = 3.2;
pn = &bubble; //assign address of bubble to pn
pc = new char; //assign address of newly allocated char memory to pc
pa = new double[30]; //assign address of lst element of array of 30 double to pa
2.3对指针解除引用
对指针解除引用意味着获得指针指向的值(运算符变成为间接值或解除引用运算符),对指针解除引用来解除引用。因此,如果像上面的例子那样,pn是指bubble的指针,则*pn是指向的值。及3.2。
cout << *pn; //print the value of bubble
*pc ='s'; //place 's' into the memory location whose adress is pc
另一种对指针解除引用的方法是使用数组表示法,例如pm[0]与*pn是一样的。但绝对不要对未被初始化为适当地址的指针解除引用。
2.4区分指针和指针
如果pt是指向int的指针,则*pt不是指向int的指针,而是完全等同于一个int类型变量。pt才是指针。
int * pt =new int; //assigns an address to the pointer pt
*pt = 5; //stores the value 5 at that address
2.5数组名
在多数情况下,c++将数组名视为数组的第一个元素的地址。
int tacos[10]; //now tacos is the same as &tacos[0]
一种例外情况是,是将sizeof运算于数组名用时,此时将返回整个数组的长度(单位位字节)
2.6指针算术
c++允许指针和整数相加。
加一的结果等于原来地址值加上指向对象占用的总字节数。
还可以将一个指针减去另外一个指针,获得两个指针的差,该差是一个整数,得到的正是两个元素的间隔。
注:仅当两个指针指向同一个数组(也可以指向超出结尾的的一个位置)时,这种运算才有意义
int tacos[10]={1,2,3,4,6,7,9,8,10};
int * pt = tacos; //suppose pt and pt and tacos are the adress 3000
pt = pt+1; //now pt is 3004 if an int is 4 bytes
int * pe = &tacos[9]; //pe is 3036 if an int is 4 butes
pe = pe-1; //now pe is 3032,the address of tacos[8]
int diff = pe-pt; //diff is 7,the speaaration between tacos[8] and tacos[1]
2.7数组的动态联编和静态联编
使用数组声明来创建数组的时候,将采用静态联编,即数组的长度在编译的时候设置。
int tacos[10]; //static binding,size fixed at complie time
使用new[]运算符创建数组时,将采用静态联编(动态数组),即将在运行时为数组分配空间,其长度也将在运行时设置。使用完这种数组后,应使用delete[]释放其占用的内存。
int size;
cin>>size;
int *pz = new int [size]; //dynamic binding,size set at run time
...
delete [] pz;
2.8数组表示法和指针表示法
使用方括号的数组表示法等同于对指针解除引用:
tacos[0] means *tacos means the value at address tacos
tacos[3] means *(tacos+3) means the value at address tacos+3
数组名和指针变量都是如此,因此对于指针和数组名,既可以使用指针表示法,也可以使用数组表示法。
int *pt = new int [10] //pt points to block of 10 ints
*pt =5; //set element number 0 to 5
pt[0]=6; //reset element number 0 to 6
pt[9]=44; //set element number 9 to 44
int coats[10];
*(coats+4)=12; //set coats[4] to 12
3指针和字符串
在cout和多数c++表达式中,char数组名、char指针以及用引号括起来的字符常量都被解释为字符串第一个字符的地址。cout对象认为其为字符串地址,因此它打印该地址处的字符,然后继续打印后面的字符,直到遇到空字符(\0)为止。
4.自动存储、静态存储和动态存储
根据用于分配内存的方法,c++有三种管理内存的方式:自动存储、静态存储和动态存储(有时也叫自由存储空间或堆)
4.1自动存储
在函数内部定义的常规变量使用自动存储空间,被称为自动变量,在所属函数被调用时自动产生,在该函数结束时消亡。
自动变量通常存储在栈中。(这意味着在执行代码的时候,其中的变量依次加入到栈中,而在离开代码块时,将按反方向释放这些变量,即后进先出FILO)。
4.2静态存储
静态存储是整个程序执行期间都存在的存储方式。使变量成为静态变量的方式有两种:
-
在函数外定义它
-
在声明变量时使用static
自动存储和静态存储的关键在于:这些方法严格的限制了变量的寿命。对于静态变量存在于程序的整个生命周期,自动变量存在与特定函数被执行的时间周期内。
4.3动态存储
new和delete运算符提供了一种比自动变量和静态变量更灵活的方法。它们管理一个内存池,一般称为自由存储空间(free store)或堆(heap)。