内存管理:new和delete

本文详细介绍了 C++ 中的指针概念及其在内存管理中的应用,包括 new 和 delete 的使用方法,以及如何利用指针进行对象创建、链表实现和排序算法等高级主题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++ 指针(二)--c++

一、内存管理:new和delete

1、new操作符:从操作系统获得内存块,并返回该内存块的首地址。

      delete操作符:将new申请的内存返还给操作系统。

开始一个简单的例子:

?
#include <iostream>
#include<cstring>
using namespace std;
int main()
{
     char * str= "it is a good job!" ;
     int len= strlen (str);
     char * ptr= new char [len+1];
     strcpy (ptr,str);
     //ptr=str;  //错误,这样是ptr和str都指向字符串。这里ptr和str应该指向不同的地址。
     cout<< "ptr=" <<ptr<<endl;
     delete [] ptr;
     return 0;
}
1) new格式:
char* ptr = new char [len+1]
 

指针

=

关键字

变量的数据类型

char类型变量的数目(方括号)

         new和malloc:new方法可以返回适当的数据类型的指针;而malloc返回的指针是void类型的指针,必须强制转化才能转化成适当的数据类型指针。
C中的realloc函数可以改变已分配内存空间的大小。C++中没有这样的函数,只能通过new重新申请一个更大或者更小的空间。
2) delete格式:delete【】 要删除的指针
如果new创建的是一个简单的对象,则在删除的时候可不加方括号,如果是数组就必须加括号。

2.使用new的类

?
#include<iostream>
using namespace std;
class String
{
public :
     String( char * s)
     {
         int len= strlen (s);
         str= new char [len+1];
         strcpy (str,s);
     }
     ~String()
     {
         cout<< "where?" <<endl;
         delete [] str;
     }
     void display()
     {
         cout<<str<<endl;
     }
private :
     char * str;
};
int main()
{
     String str= "hello! word!" ;
     str.display();
     return 0;  
}

1)在构造函数中使用new获得内存空间。

2)既然使用new来分配内存空间,因而析构函数也变得很重要。(因为在创建对象的时分配了内存空间,则当这些对象不再需要时就很有必要释放这些空间)。析构函数在对象销毁时自动调用的例程,所以放入delete恰好。

问题:如果一个类的两个对象执行了s1=s2这样的操作(即出现两个对象的指针指向同一个内存地址),而此时一个对象被删除(如含有其中一个对象的调用函数结束后返回时),这样申请的内存地址被收回,这样就导致另一个对象的是一个无效的指针了。

    这个错误一定要重视,因为很容易疏忽。怎样才能写一个更聪明的析构函数呢??   后面揭晓…

二、对象与指针

1、对象指针

有时在程序的编写时并不知道需要创建多少个对象。当出现这中情况时,就可以在程序运行中使用new来穿件对象。这里,new返回的是一个指向未命名对象的指针。

例子:

?
#include<iostream>
using namespace std;
class Distance
{
public :
     void getdist();
     void showdist();
private :
     int feet;
     float inches;
};
void Distance::getdist()
{
     cout<< "Enter the feet:" ; cin>>feet;
     cout<< "Enter the inches:" ;cin>>inches;
}
void Distance::showdist()
{
     cout<< "The feet:" <<feet<<endl;
     cout<< "The inches:" <<inches<<endl;
}
int main()
{
     Distance dd;
     dd.getdist();
     dd.showdist();
     Distance* ptr= new Distance; // pointer to Distance,points to new Distance object
     ptr->getdist();  //这里如果是点运算符就会出错
     ptr->showdist(); //因为点运算符要求它的左运算符是一个变量,而ptr为一个指针。
     return 0;
}

上面标注的地方除了用成员访问运算符(->)表示之外,我们还可以这样(*ptr).getdist(); //ok,but inelegant (圆括号是必须的,因为点运算符的优先级比间接引用运算符要高).

2、对象指针数组

?
Distance* distptr[100];
distptr[j]= new Distance;
//*(distptr+j)=new Distance;
distptr->getdist();
distptr->showdist();

注意:数组表示法distptr[j]等价于指正表示法*(distptr+j),由于是指针数组,上面两种表示的方法的元素还是指针(指向对象的指针)

          distptr->getdist(); 表示执行了由数组distptr的第j个元素 所指向的Distance对象的成员函数。

三、链表

链表提供了一种不使用数组但更为灵活的存储系统,每个数据项都是按照需要通过new来获取的,且数据之间是通过指针链接起来的。

单个数据项之间并不需要和数组元素一样在内存中相邻分配,相反他们可以分散到任何地方。

例子:

?
#include <iostream>
using namespace std;
struct link
{
     int data;     //表示对象的单个数据项
     link* next;   //指向下一个链接项
};
class linklist
{
public :
     linklist():first(NULL) {}
     void addlist( int d);   //增加链接项
     void display();        //显示链接内容
private :
     link* first;
};
void linklist::addlist( int d)  //增加链接项
{
     link* newptr= new link; //创建一个新的link结构类型
     newptr->data=d;        //将参数的值传递给结构变量data 
     newptr->next=first;    //指针next指向first指向的任何地址(在这里是链表头)
     first=newptr;          //将指针first指向这个新的链接项
}
void linklist::display()
{
     link* nowptr=first;
     while (nowptr!=NULL)
     {
         cout<<nowptr->data<<endl;
         nowptr=nowptr->next;  //指针移动到下一个链表的地址
     }
}
int main()
{
     linklist ll;
     ll.addlist(22);
     ll.addlist(33);
     ll.addlist(44);
     ll.display();
     return 0;
}

注意:在使用link结构的时候含有一个指向同类型结构的指针。同样的在类中也可以这么使用:

?
class sampleclass
{
     sampleclass* ptr;   //this is fine!
     sampleclass obj;    //can't do this!!
};

但是这里要特别注意:虽然类中可以包含一个指向同类型对象的一个指针,但不能包含一个同类的对象。

四、指向指针的指针

看个例子:

?
#include<iostream>
#include <string>
using namespace std;
class person
{
public :
     void SetName()
     {
         cout<< "Enter name:" ; cin>>name;
     }
     void PrintfName()
     {
         cout<<name;
     }
     string GetName()
     {
         return name;
     }
private :
     string name;
};
int main()
{
     void bsort(person**, int );     //排序
     person* perptr[100];
     int n=0;
     char ch;
     do
     {
         *(perptr+n)= new person;
         (*(perptr+n))->SetName();
         n++;
         cout<< "Enter another?" ;
         cin>>ch;
     } while (ch== 'y' );
     cout<< "姓名排序前:" ;
     for ( int j=0;j<n;j++)
     {
         perptr[j]->PrintfName();
         cout<< " " ;
     }
     bsort(perptr,n);
     cout<< "\n姓名排序后:" ;
     for ( int j=0;j<n;j++)
     {
         perptr[j]->PrintfName();
         cout<< " " ;
     }
     cout<<endl;
     return 0;
}
void bsort(person** ptr, int n)  //排序
{
     void order(person**,person**);
     int j,k;
     for (j=0;j<n-1;j++)
         for (k=j+1;k<n;k++)
             order(ptr+j,ptr+k);
}
void order(person** ptr1,person** ptr2)  //比较
{
     if ((*ptr1)->GetName()>(*ptr2)->GetName()))
     {
         person* tem;
         tem=*ptr1;
         *ptr1=*ptr2;
         *ptr2=tem;
     }
}

1)注意到数据类型person**,表示这些参数被用来传递perptr指针数组的地址。本身perptr数组中存的就是指针,因此指针数组的地址是一个指向指针的指针。

2)因为数组perptr包含的是指针,因而:perptr[j]->PrintfName();  表示执行perptr数组的j号元素所指向的对象的PrintfName()成员函数。

3)(*ptr1)->GetName();

其中ptr1是一个指向指针的指针,因此(*ptr1)表示指针数组的元素。总体意思就是执行perptr数组的元素(*ptr1)所指向的对象的PrintfName()成员函数。

分类:  c+
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值