new与指针

19 篇文章 2 订阅

原地址:https://mp.csdn.net/postedit

使用new 来分配内存
之前是使用以下模式来分配指针的地址:

int fellow;
int* pt = &fellow;

变量fellow 是在编译时分配的有名称的内存,而指针只是为了可以通过名称直接访问的内存提供了一个别名。 
而指针的真正的用武之地在于,在运行阶段分配内存名的内存以存储值。这种情况只能使用指针来访问内存。 
例如:

int* pt = new int;

在这里,new 会在这里寻找一个适合int 类型长度正确的内存块,并返回该内存块的地址给指针pt。

int nights = 1001;
int* pt = new int;
*pt = 1001;

在上面的例子,因为pt以及分配了内存,所以可以使*pt = 1001。因为此时已经知道指针pt 所存储的地址。

内存被耗尽? 
计算机可能会由于没有足够的内存而无法满足new的请求。在这种情况下,new通常会引发异常—一种将在第15章讨论的错误处理技术;而在较老的实现中,new 将返回0 。在C++中,值为0的指针被成为空指针(null pointer)。C++确保空指针不会指向有效的数据,因此它常被用来表示运算符或函数失败(如果成功,它们将返回一个有用的指针)。将在第6章讨论的if语句可帮助您处理这种问题;就目前而言,您只需如下要点:C++提供了检测并处理内存分配失败的工具。

使用delete释放内存
当需要内存的时候,我们可以使用new来请求内存。当使用完内存的时候,我们需要将内存归还给内存池,使用delete 运算符来释放。归还或释放(free)的内存可供程序的其他部分使用。

int* ps = new int;  //allocate memory with new
...                  //use the memory
deletes ps;         //free memory with delete when done

这里释放了指针ps的所分配的内存,但是不会删除ps变量。 
这里new和delete一定是配对使用的。否则会发送内存泄露(memory leak),会占用内存,是内存无法使用,积累下来,会造成内存不够而使程序终止。

第一,不能用delete来释放已经释放的内存块,即指针,C++标准指出,这样做的结果将是不正确的,意味着everything will happen。
int* ps = new int;   //ok 
delete ps;           //ok
delete ps;           //not ok now

第二,不能使用delete来释放声明变量所获得的内存的指针;
int jugs = 5;       //ok
int* pi = &jugs;    //ok
delete pi;          //not allowed,memory not allocated by new

警告:只能用delete来释放使用new分配的内存。然而,对空指针使用delete是安全的。

new与数组
如果使用new和delete是分配和释放一个值,则是简单的运用一个内存块。 
但是对于大型数据(如数组,字符串和结构),才是new真正的用武之地。

使用new是运行阶段需要数组,则创建它;如果不需要,则不创建。还可以在程序运行时选择数组的长度。这被称为动态编程(dynamic binding),意味着数组是在程序运行时创建的。这种数组叫作动态数组(dynamic array)。

使用new创建动态数组
需要将数组的元素类型和元素数目告诉new即可。必须在等号右边类型名后加上方括号,其中包含元素数目。 
例如,要创建 一个包含10个int元素的数组:

int* psome = new int [10];  //get a block of 10 ints

运算符new会返回第一个元素的地址给指针psome。 
使用完new分配的内存块时,也应该使用delete来释放它们。

delete[] psome;             //free a dynamic array

使用new和delete的,应遵守以下规则:

不要使用delete来释放不是new分配的内存;
不要使用delete释放同一个内存块两次;
如果使用new[]为数组分配内存,则应使用delete[]来释放;
如果使用new为一个实体分配内存,则应使用delete(没有方括号)来释放;
对空指针应用delete是安全的。
对于new分配的动态数组,psome是指向一个int(数组第一个元素)的指针。然而编译器不能对psome是指向10个整数中的第一个进行跟踪其他的元素,所以需要让程序知道跟踪元素的数目,因此在编写程序的时候,需要写明数组元素的数目。 
实际上,程序在确定跟踪的分配的内存量之后,也方便最后使用delete[]运算符时能够正确地释放内存。 
为数组分配内存的通用格式如下:

type_name* pointer_name = new type_name [num_elements];
1
使用new运算符可以确保内存块足以存储num_elements个类型为type_name的元素,而pointer_name指向第一个元素。

使用动态数组
new语句提供了识别内存块中每个元素所需要的全部信息; 
而且,只要将指针当作数组名使用,就可以知道其他元素的数值(数值和指针基本等价时C和C++的优点之一)。 
通过以下例子:

double* p3 = new double [3];    //space for 3 doubles
p3[0] = 0.2;                    //treat p3 like an array name
p3[1] = 0.5;
p3[2] = 0.8;

cout << "p3[1] is "<<p3[1]<<".\n";
p3 = p3 + 1;                    //increment the pointer
cout << "Now p3[1] is "<<p3[1]<<" and ";
cout << "p3[1] is "<<p3[1]<<".\n";

p3 = p3 - 1;                    //point back to begining
deleta[] p3;                    //free the memory

return 0;

下面是程序的输出结果:

p3[1] is 0.5.
Now p3[0] is 0.5 and p3[1] is 0.8.

程序将指针p3当做数组名来使用,从而可以知道其他数组元素的值;
当p3 = p3 + 1,已经将指针p3由指向p3[0]变成指向p3[1],由此可知,new提供了识别内存块中每个元素所需要的全部信息,同时将指针变量加1后,其增加的值等于指向的类型占用的字节数;
经过p3 = p3 - 1,需要将指针p3返回原来的值,从而方便delete[]的释放内存提供正确的值。
short stacks[3] = {3,2,1};
cout << "access two elements with array notation\n";
cout << "stacks[0] = " << stacks[0]
    << ", stacks[1] = " << stacks[1] << endl;
cout << "access two element with pointer notation\n";
cout << "*stacks = " << *stacks
    << ", *(stacks + 1) = " << *(stacks + 1) << endl;

结果是:

access two elements with array notation
stacks[0] = 3, stacks[1] = 2
access two element with pointer notation
*stacks = 3, *(stacks + 1) = 2

C++编译器将该表达式看作是*(stacks + 1),这意味着先计算数组第2个元素的地址,然后找到存储在那里的值。最后的结果便是stacks[1]的含义(运算符优先使用括号,如果不使用括号,将给*stacks加1,而不是给stacks+1);
同时*(stecks+1)和stacks[1]是等价的。
关于数组名和指针对于运算的区别 
例如都可以进行以下执行: 
arraymame[i] becomes *(arrayname + i); 
pointername[i] becomes *(pointername + i); 
但是数组无法像指针一样执行下面的算法,因为数组名是一个常量: 
pointername = pointername + 1; //valid 
arrayname = arrayname + 1; //not allowed 
当使用sizeof时,求指针pw,得到指针的长度,求数组名wages,得到的是数组的长度 
24 = size of wages array << displaying sizeof wages 
4 = size of pw pointer << displaying sizeof pw 
这种情况下,C++不会将数组名解释为地址。

在之前,给数组声明指针,都是数组名直接是地址,或者对首个数组的值取地址,如果对数组取地址应该怎么取:

short (*pas)[20] = &tell;   //pas points to array of 20 shorts

此处是将pas和*先 进行结合,&tell是一个指向包含20个元素的short的数组。pas被设置为&tell,因此*pas与tell等价,因此(*pas)[0]为tell数组的第一个元素。

#include<iostream>

int main()
{
    using namespace std;
    short tell[10] = { 1,2,3,4,5,6,7,8,9,10 };
    short* ps = tell;
    cout << "The ps is "<<ps << endl;
    cout << "The tell is " << tell << endl;
    cout << "The tell+1 is " << tell+1 << endl;
    cout << "The &tell is " << &tell << endl;
    cout << "The &tell+1 is " << &tell+1 << endl;

    cin.get();
    return 0;
}

输出结果是:

The ps is 0053FD9C
The tell is 0053FD9C
The tell+1 is 0053FD9E
The &tell is 0053FD9C
The &tell+1 is 0053FDB0

指针和字符串
请看以下代码:

char flower[10] = "rose";
cout << flower <<"s are red\n";

由前面所知,数组名是第一个元素的地址,所以语句中flower是包含字符r的char元素的地址。cout对象认为char的地址是字符串的地址,因此它打印该地址处的字符,然后会继续打印后面的字符,直到遇到空字符(\0)为止。 
因此,在这里需要记住的一点是,flower是一个char的地址,而不是一个数组名。

如果需要将一个数组的地址赋值给一个指针且使用同样的内存单元和字符串,则使用=运算符,如果是需要将字符串赋值给一个指针且同时分配新的内存,则使用strcpy()或strncpy(),例如:

char animal[20] = "bear";
char* ps;

ps = animal;        //set ps to point to string

ps = new char[strlen(animal) + 1];      //get new storage
strcpy(ps,animal);                      //copy string to new storage

注意:经常需要将字符串放到数组中。初始化数组时,请使用=运算符;否则应使用strcpy()或strncpy()。
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值