new和delete

2023-10-11 21:13:40 浏览数 (1)

在C 语言中,我们可以通过malloc分配堆上的内存,但是C 时使用new来分配内存

代码语言:javascript复制
int *x = new int;

上述代码为指针变量x申请了一块大小为四字节的内存,并用指针变量指向了这块内存。 注意区分将变量地址赋给指针变量的情况,如int*x = &q;第二种情况可以通过q访问这个变量内存的值,而第一种只能通过指针变量访问,格式如下: typename * ponitername = new typename;

代码语言:javascript复制
#include<iostream>
using namespace std;
int main()
{
    
    int* Pnights = new int;
    *Pnights = 1001;
    cout << "int"
        << "value = " << *Pnights << " :location " << Pnights << endl;
    double* pdouble = new double;
    *pdouble = 1000000000001;
    cout << "double"
        << "value = " << *pdouble << " :location " << pdouble << endl;
    //验证一下这几个类型的大小
    cout << "sizeof(Pnights) = " << sizeof(Pnights) << endl;
    cout << "sizeof(*Pnights) = " << sizeof(*Pnights) << endl;
    cout << "sizeof(pdouble) = " << sizeof(pdouble) << endl;
    cout << "sizeof(*pdouble) = " << sizeof(*pdouble) << endl;
}

该程序为int和double申请了内存区域,指针指向了两个内存空间用来访问这一块内存,这两个地址都是占4个字节的指针,而我们申明了申请内存空间的类型,所以我们可以知道*Pnights和*pdouble分别是4字节和8字节。

delete释放内存

我们申请完的地址,在程序退出之前是不会释放占用的,跟栈区的变量有差别,我们使用delete,可以将用完的内存还给内存池,C语言使用free而在C 中用的是delete释放

代码语言:javascript复制
int*p = new int;
delete p;

我们这样只是释放了内存空间,指针还是存在的,可以用ps重新指向一块新的内存,如果不配对使用new和delete,会发生内存泄漏。 delete只能用来释放new出来的内存空间,但是对于空指针用delete也是安全的,但也是无意义的。

使用new来创建动态数组

我们平时要申请一个简单变量,在栈上管理内存肯定比堆上要方便,但是对于大型数据(数组 字符串和结构),用new更加合适。如果通过声明来创建数组,则程序在编译时就为数组分配了内存空间,数组一直存在,内存也一直在占用,这种分配内存的方式叫静态联编。如果new,在运行时,如果需要数组,则会创建,不需要则不创建。此外还可以选择创建数组的长度,这被成为动态联编,这种数组也被称为动态数组。静态联编必须在编写程序的时候就确定数组的长度,而动态联编,在运行时确定数组长度。 比如要创建一个10个int的数组 int * p = new int[10]; 然后返回创建内存块的地址给指针变量p,对于数组的释放delete [] p; 搭配规则:

不要用delete释放不是new创建的内存

不要使用delete释放一块内存两次

涉及动态数组的创建,应该用delete[]释放,如果是为实体分配内存,则需要用delete来释放。

动态数组

type_name* poniter_name = new type_name[num_elements]; poniter_name指向了数组的第一个元素地址,同时我们也可以用数组名表示元素第一个的地址。

动态数组的遍历

跟一般数组遍历方法是一样的,需要明确的是,数组名是指针常量不能修改其指向,因此用数组名进行遍历是错误的,我们这里有一个指向数组的指针,就可以用这个指针变量来遍历这个数组。

代码语言:javascript复制
#include<iostream>
using namespace std;
int main()
{

 double* x = new double[10];
 x[0] = 1.0;
 x[1] = 2.0;
 x[2] = 3.0;
 cout << "x[0] = " << x[0] << endl;
 x  ;
 cout << "x[0] = " << x[0] << endl;
 x--;
 cout << "x[0] = " << x[0] << endl;
 delete[]x;
 return 0;
}

指针算数

指针和数组等价的原因在于指针算数和C 内部处理数组的方式。指针变量 1,增加的量等于它指向类型的字节数。

代码语言:javascript复制
#include<iostream>
using namespace std;
int main()
{
 

 double wages[3] = { 1000.0,2000.0,3000.0 };
 short stacks[3] = { 3,2,1 };
 double* Pwages = wages;
 short* Pstacks = &stacks[0];
 cout << "Pwages = " << Pwages << " *Pwages = " << *Pwages<<endl;
 Pwages  ;
 cout << "Pwages = " << Pwages << " *Pwages = " << *Pwages << endl;
 cout << "Pstacks = " << Pstacks << " *Pstacks = " << *Pstacks << endl;
 Pstacks  ;
 cout << "Pstacks = " << Pstacks << " *Pstacks = " << *Pstacks << endl;
 cout << " stacks[0] = " << stacks[0] << endl;
 cout << " stacks[1] = " << stacks[0] << endl;
 cout << "*stacks = " << *stacks << ",*(stacks 1) = " << *(stacks   1) << endl;
 cout << sizeof(wages) << " = size of wages arry" << endl;
 cout << sizeof(Pwages) << " = size of poniter Pstacks "<<endl;

}

这些内容我前面C语言笔记大部分都有,不再过度赘述。 数组名表示法 arryname[i] = *(arryname i) 指针表示法 ponitername[i] = *(ponitername i) 因此在很多情况下,可以用相同的方式使用指针名和数组名,对于他们,可以使用数组方括号表示,也可以解引用,区别是指针可以被修改,而数组名无法修改

代码语言:javascript复制
short tell[10];
cout<<&tell[0];
cout<<tell;

从输出结果来看&telltell是一样的,但是概念上,&tell表示这个20字节的内存块的首地址,tell表示2字节内存块地址。tell i表示tell地址 2,&tell i ,则表示地址 20 tell相当于short指针 &tell相当于指向了包含10个元素的short数组 当然我们也可以用二维数组指针指向数组首地址 我们把一维的short数组看成0行但是有20列的数组集合,也就是short (*P)[10] 表示里面有,我们之前也说过二维数组,(*P)表示每个一维数组(也就是每个数组首地址)。这里也为了区分&tell和tell的区别

代码语言:javascript复制
 short tell[10] = {1,2,3,4,5,6,7,8,9,10};
 cout << "tell = " << tell << endl;
 cout << "&tell = " << &tell << endl;
 short(*p)[10] = &tell;
 cout << "(*p)[1] = " << (*p)[2] << endl;
 short* pptell = tell;
 cout << "*(p 2) = " << *(pptell  2) << endl;

0 人点赞