当时春风念作曾

指针和自由存储空间

1)计算机程序在存储数据时必须跟踪的基本属性:
*信息存储在何处;
*存储的值为多少;
*存储信息的类型;

2)指针声明必须指定指针指向的数据类型。(指针变量不仅仅是指针,而且是指向特定类型的指针)
int * ptr;
ptr是指针,*ptr时int。
int* ptr; 这里强调:int*是一种类型(复合类型)——指向int的指针。

3)指针的危险:
C++创建指针时,计算机将分配用来存储地址的内存,但不会分配用来存储指针所指向的数据的内存。

4)使用new来分配内存。
<1>指针的真正用武之地在于,在运行阶段分配未命名内存以存储值。在这种情况下,只能使用指针来访问内存。c语言中,可以用库函数malloc()来分配内存。在C++中——new运算符。
<2>示例:
int * pn= new int; //pn指向一个“数据对象”。为数据项分配的内存块。
int * pt = new int;
* pt = 101; //有了指针pt,可以像变量一样使用*pt。
<3>地址本身只是指出了对象存储地址的开始,而没有指出其类型(使用的字节数)。
<4>new分配的内存块通常与常规变量声明分配的内存块不同,变量和指针的值都存储在栈(stack)的内存区域,而new从被称为堆(heap)或自由存储区(free store)的内存区域分配内存。

5)使用delete释放内存。(配对的使用new和delete)
<1>int * ps = new int;
。。。
delete ps;
释放ps所指向的内存,但不会删除指针ps本身。
<2>只能用delete释放new分配的内存,但对空指针NULL使用delete是安全的,不能用delete释放声明变量所获取的内存。不能使用delete来释放一个内存块两次及以上。

6)使用new来创建动态数组。
在编译时给数组分配内存被称为静态联编(static binding),意味着数组是在编译时加入到程序中的。但使用new时,如果运行阶段需要数组,则创建它;如果不需要,则不创建。还可以在运行时选择数组的长度。称为动态联编(dynamic binding),即数组全在程序运行时创建的。这种数据称为动态数组(dynamic array)。
int * psome = new int [10];
对于new创建的数组,用另一种格式的delete来释放:
delete [] psome; //free a dynamic array.

7)使用动态数组。
int * psome = new int [10];
把指针当作数组名使用即可,对于第一个元素可以使用psome[0],而不是*psome,对第二个元素,可以使用psome[1],一次类推。(c和C++内部都使用指针来处理数组,数组和指针等价)。

#include<iostream>

using namespace std;

int main()
{
    double * p1 = new double [3];
    p1[0] = 1.23;           //treat p1 like an array name
    p1[1] = 2.34;
    p1[2] = 3.45;

    cout<<"p1[1] = "<<p1[1]<<endl;

    p1 = p1 + 1;            //increment the pointer

    cout<<"NEW p1[0] = "<<p1[0]<<endl;
    cout<<"p1[1] = "<<p1[1]<<endl;
    //cout<<"p1[2] = "<<p1[2]<<endl;

    p1 = p1 - 1;            //point back to begining

    cout<<"p1[2] = "<<p1[2]<<endl;

    delete [] p1;           //free the memory

    return 0;
}

指针、数组和指针运算

1)指针和数组基本等价的原因是指针运算(pointer arithmetic)和C++内部处理数组的方式。
*在多数情况下,C++将数组名解释为数组的一个元素的地址。
*将指针变量加1后,其增加量的值等于指向的类型占用的字节数。
*两者区别: 可以修改指针的值,而数组名是常量。
对数组用sizeof运算得到是整个数组的长度,而对应指针 用 sizeof 得到指针的长度。

2)指针小结
<1>指针的声明
TypeName * pointerName;
<2>给指针赋值:对变量名应用&运算符,来获取被命名的内存的地址,new运算符返回未命名的内存地址。
double * pn;
double * pa;
char * pc;
double db=1.23;
pn=&db;
pc=new char;
pa=new double[30];
<3>对指针解除引用:
意味着获得指针指向的值。
<4>区分指针和指针所指向的值
<5>数组名
<6>指针算术
仅当两个指针指向同一个数组,才有意义,得到的是两个元素的间隔。
<7>数组的动态联编和静态联编
<8>数组表示法和指针表示法——???

(3)指针和字符串

#include<iostream>
#include<cstring>       //declare strlen() , strcpy

using namespace std;

int main()
{
    int dt[3]={1,2,3};
    const int * pi=dt;
    char animal[20]="bear";
    const char * bird="wren";
    char * ps;

    //一般来说,给cout提供一个指针,他将打印地址(int*),
    //但如果指针为char*,则cout显示指向的字符串
    cout<<pi<<endl;
    cout<<animal<<" and "<<bird<<endl;

    cout<<"Please enter a kind of animal: ";
    cin>>animal;

    //animal 复制在给 ps 不会复制字符串,
    //而只是复制地址,因此指向相同的地址单元和字符串
    ps=animal;

    cout<<"Before using strcpy():\n";
    cout<<animal<<" at "<<(int*) animal<<endl;
    cout<<ps<<" at "<<(int*) ps<<endl;

    //获得字符串副本
    ps=new char[strlen(animal)+1];      //get a new storage
    //strcpy()接受两个参数,第一个为目标地址,第二个为要复制的字符串地址
    strcpy(ps,animal);                  //copy string to new storage
    cout<<"After using strcpy():\n";
    cout<<animal<<" at "<<(int*) animal<<endl;
    cout<<ps<<" at "<<(int*) ps<<endl;

    delete [] ps;

    return 0;
}

strncpy()含有三个参数:
char food[20];
strncpy(food,”a picnic basket filled with many goodies”,19);
food[19]=’\0’;
这样最多复制19个字符到数组中,最后一个元素设置为空字符。

4)使用new创建动态结构
<1>访问成员:
*使用箭头运算符(->);
*如果ps为指向结构的指针,则 *ps就是被指向的值——结构体本身,( *ps ).price.

#include<iostream>

using namespace std;

struct inflatable
{
    char name[20];
    float volume;
    double price;
};

int main()
{
    inflatable * ps = new inflatable;
    cout<<"Enter the name of inflatable iten : ";
    cin.get(ps->name,20);           //method 1 for member access
    cout<<"Enter the volume in cubic feet : ";
    cin>>(*ps).volume;              //method 2
    cout<<"Enter the price : $";
    cin>>ps->price;

    cout<<endl;

    cout<<"NAME is : "<<ps->name<<endl;
    cout<<"VOLUME is "<<(*ps).volume<<endl;
    cout<<"PRICE is : "<<ps->price<<endl;

    delete ps;

    return 0;

}

<2>使用new和delete的示例:

#include<iostream>
#include<cstring>

using namespace std;

char * getname(void);

int main()
{
    char * name;    //creat a pointer but no storage

    name=getname();
    cout<<name<<" at "<<(int *) name<<endl;
    delete [] name;     //memory freed

    name=getname();     //reuse freed memory
    cout<<name<<" at "<<(int *) name<<endl;
    delete [] name;     //memory freed again


    return 0;
}

char * getname()        //return pointer to new string
{
    char temp[80];
    cout<<"Please input last name: ";
    cin>>temp;
    char * pn=new char[strlen(temp)+1];
    strcpy(pn,temp);        //copy string into smaller space

    return pn;      // temp lost when function ends
}

自动存储、静态存储和动态存储
根据用于内存的方法,C++有三种管理数据的方式:自动存储、静态存储和动态存储(自由存储空间或堆),C++11新增第四种类型——线程存储。
<1>.自动存储:
在函数内部定义的常规变量使用自动存储空间,被称为自动变量(automatic variable),意味着它们在所属的函数被调用时产生,该函数结束时灭亡。如上例,temp数组仅当getname()函数活动时存在,程序控制权回到main函数时,temp使用的内存将自动释放。
实际上,自动变量是一个局部变量,其作用域包含它的代码块。
自动变量通长存储在栈中,先进后出(LIFO),程序执行的过程中,栈将不断地放大缩小。
<2>静态存储
静态存储是整个程序执行期间都存在的存储方式。变量使用静态存储有两种方式:一种为在函数外面定义它;另一种是在声明变量时使用static:
static double free=56.23;

静态存储和动态存储关键在于:这些方法严格的限制了变量的寿命。变量存在于整个周期为(静态变量),只存在于特定函数为(自动变量)。

<3>动态存储
new和delete提供了一种更灵活的方法。它们只管理一个内存池,在C++中被称为自由存储空间(free store)或堆(heap)。该内存池中的静态变量和动态变量是分开的,在上面的程序例子中表明,new和delete可以让程序员在一个函数中分配内存,在另一个函数中释放内存。则,数据的生命周期不完全受程序或者函数控制。

**注意:栈、堆和内存泄漏!!!

5)类型组合

6)数组的替代品
<1>模板类vector:类似于string类,也是一种动态数组。
声明一个名为vt的vector对象,可存储n_elem个类型为typename的元素。
vector vt(n_elem);
<2>模板类array (C++11)
使用栈(静态内存分配),不是自由存储区。
要包含头文件array(#include)。
array

#include<iostream>
#include<vector>
//#include<array>

using namespace std;

int main()
{
    double a1[4]={1.23,2.89,3.45,5.79894};

    vector<double> a2(4);
    a2[0]=1.234;
    a2.at(1)=5.56;
    a2[2]=2.345;
    a2[3]=4.988;
    a2[-3]=45.56;

    /*array<double,4> a3={9.87,8.76,7.65,6.54321};
    array<double,4> a4;
    a4=a3;*/

    cout<<"a1[2]= "<<a1[2]<<" at "<<&a1[2]<<endl;
    cout<<"a2[2]= "<<a2[2]<<" at "<<&a2[2]<<endl;
    //cout<<"a3[2]= "<<a3[2]<<" at "<<&a3[2]<<endl;
    //cout<<"a4[2]= "<<a4[2]<<" at "<<&a4[2]<<endl;

    a1[-2]=12.34;
    cout<<"a1[-2]="<<a1[-2]<<" at "<<&a1[-2]<<endl;
    cout<<"a2[-3]="<<a2[-3]<<" at "<<&a2[-3]<<endl;

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值