4.7 指针和自由存储空间
计算机程序在存储数据时必须跟踪的3种基本属性。
信息存储在何处
存储的值为多少
存储的信息是什么类型
指针是一个变量,其存储的值是值的地址。
使用常规变量时,值是指定的量,而地址为派生量。指针的策略完全不同,它是c++内存管理的核心,其处理存储数据的策略为:将地址视为指定的量,而将值视为派生量。
指针名表示的是地址,*运算符被称为间接值或解除引用运算符,可以得到该地址存储的值。
#include <iostream>
int main()
{
using namespace std;
int updates = 6;
int *p_updates;
p_updates = &updates;
cout<< "Value : updates = "<< updates<<", *updates = "<< *p_updates << endl;
cout << "Address : &updates = "<< &updates <<" ,p_updates = "<<p_updates<<endl;
cout << "now the update is : "<< *p_updates+1 <<endl;
return 0;
}
4.7.1 声明和初始化指针
计算机需要跟踪指针指向的值的类型。
int *p_updates;
这表明,p_updates的类型为 int。由于运算符只用于指针,因此p_updates变量本身必须是指针。p_updates是指针,*p_updates是int
连续声明两个指针:
int *p1, p2;//表明p1是指针,p2是int
double *p4, *p3;//两个都是指针
上面的p1和p3是不同类型的指针,指向int型的指针和指向double型的指针。
指针可以初始化,初始化的是指针(地址)而不是它指向的值。
int Jack = 10;
int *p = &Jack;
4.7.2 指针的危险
创建指针时一定要将指针的值初始化,否则指针(位置)是随机的,万一随机到系统很重要的地方,你一赋值系统崩了呢。
警告: 在对指针进行操作之前,要将指针初始化为一个确定的、适当的地址。
4.7.3 指针和数字
指针(地址)虽然是数字,但和数字类型完全是两种类型,指针不能参与数学运算,是独特的。
4.7.4 使用new来分配内存
在运行阶段为一个int值分配未命名的内存,并使用指针来访问这个值。
int *p = new int;
int higgens;
int *pt = &higgens;
new找到一个长度为len(int)的内存块,并返回该内存块的地址,由指针变量p来接收该内存地址。
#include <iostream>
int main()
{
using namespace std;
int nights = 1001;
int *pt = new int;
*pt = 1001;
cout << "nights value = ";
cout << nights << ":location "<<&nights<<endl;
cout <<"int ";
cout <<"value = "<<*pt<<": location = "<<pt<<endl;
double *pd = new double;
*pd = 1000001.0;
cin.get();
cin.get();
return 0;
}
new分配的内存块与常规变量声明分配的内存块不用,变量nights的值存储在称为栈(stack)的内存区域,而new从堆(heap)或自由存储区(free store)的内存区域分配内存。
4.7.5 使用delete释放内存
可以使用delete来释放用new申请的内存,要配对使用,否则delete掉的是那块区域无法了解。
4.7.6 使用new来创建动态数组
对于大型数据(数组、字符串、结构),应使用new。假如要编写一个程序,它是否需要数组取决于运行时用户提供的信息。
如果通过声明来创建数组,则在程序被 编译 时为它分配内存空间,不管程序最终是否使用数组,数组都在那里,它占用了内存。这种分配内存的方法称为“静态联编”,意味着数组是在编译时加入到程序中的。
当使用new时,如果在运行阶段需要数组,则创建它;如果不需要则不创建。还可以在程序运行时选择数组的长度,这被称为“动态联编”,这种数组叫作动态数组。
使用静态联编时必须指定数组的长度,使用动态联编时,程序将在运行时确定数组的长度。
1 使用new来创建动态数组
int *psome = new int[10];
delete [] psome;//标准格式,不要乱混用
2 使用动态数组
#include <iostream>
int main()
{
using namespace std;
double *p3 = new double[3];
p3[0] = 0.2;
p3[1] = 0.3;
p3[2] = 0.8;
cout << "p3[1] is "<< p3[1]<<" .\n";
p3 = p3+1;
cout <<"now p3[0] is "<<p3[0]<<" .\n";//p3移动了一位,p3[0]已经变了
p3 = p3-1;
delete []p3;
cin.get();
cin.get();
return 0;
}
delete的是new申请的地址,所以p3 = p3-1;
4.8 指针、数组和指针算术
指针和数组基本等价的原因在于指针运算和c++内部处理数组的方式。指针变量增加1,增加的量是它指向的类型的字节数。c++将数组名解释为地址。
#include <iostream>
int main()
{
using namespace std;
double wages[3] = {1000.0, 2000.0, 3000.0};
short stacks[3] = {1,2,3};
double *pw = wages;
short *ps = &stacks[0];
cout <<"pw= "<<pw<<" ,*pw= "<<*pw<<endl;
pw = pw+1;
cout << "add 1 to pw"<<endl;
cout <<"pw= "<<pw<<" ,*pw= "<<*pw<<endl;
cout <<"ps= "<<ps<<" ,*ps= "<<*ps<<endl;
ps = ps+1;
cout << "add 1 to ps"<<endl;
cout <<"ps= "<<ps<<" ,*ps= "<<*ps<<endl;
cout << "Array_way"<<endl;
cout <<"stacks[0]= "<<stacks[0]<<", stacks[1]= "<<stacks[1]<<endl;
cout << "Point_way"<<endl;
cout <<"*stacks= "<<*stacks<<", *(stacks+1)= "<<*(stacks+1)<<endl;
cout << "sizeof(wages) array: "<< sizeof(wages)<<endl;
cout << "sizeof(pw) point: " << sizeof(pw) <<endl;
return 0 ;
}
4.8.1 程序说明
数组名解释为数组第一个元素的地址。
4.8.2 指针和字符串
char flower[10]="rose";
cout <<flower<< "s are red\n";
flower是数组名,是第一元素‘r’的地址,可以作为地址参数传递给cout来显示。
c++中,char数组名,char指针以及用引号括起的字符串常量被解释为字符串第一个字符的地址。
以下是一个example:
#include <iostream>
#include <cstring>//可以使用char型的函数,不能调用string类
int main()
{
using namespace std;
char animal[20] = "bear";
const char *bird = "wren";
char *ps;//uninitialized
cout<<animal<<" and ";
cout << bird<<"\n";
//cout << ps <<" \n";// may display garbage, may cause a crash
cout <<"Enter a kind of animal: ";
cin >> animal;
//cin>>ps;//Too horrible a blunder to try;可能乱了地址
ps = animal;//animal是字符数组地址
cout << ps << "!\n";
cout << "Before using strcpy():\n";
cout<<animal << " at "<< (int*)animal<<endl;
cout << ps<<" at "<<(int*)ps <<endl;
ps = new char[strlen(animal)+1];
strcpy(ps,animal);
cout<<"After using strcpy():\n";
cout<<animal<<" at "<<(int*)ps<<endl;
delete []ps;
return 0;
}