C++ 全面刨析使用指针方法 _new _delete

指针
 1 #include<iostream>
 2 using namespace std;
 3 int main() {
 4         int avr = 8;
 5         int* pn;//声明       int* pn = &avr;//初始化
 6         pn = &avr;
 7         cout << *pn << endl;
 8         cout << pn << endl;
 9         system("pause");
10         return 0;
11 }

指针的危险:

int* pn;
*pn=2;
指针指向的是地址,初始化一定要有初始化确定的地址,否则,指针可能指向任何位置;
new
对 指针 的 工作 方式 有 一定 了解 后, 来 看看 它 如何 实现 在 程序 运行时 分配 内存。 前面 我们 都将 指针 初始 化为 变量 的 地址; 变量 是在 编译 时 分配 的 有名称 的 内存, 而 指针 只是 为 可以 通过 名称 直接 访问 的 内存 提供 了 一个 别名。 指针 真正 的 用武之地 在于, 在 运行 阶段 分配 未 命名 的 内存 以 存储 值。 在 这种 情况下, 只能 通过 指针 来访 问 内存。 在 C 语言 中, 可 以用 库 函数 malloc( )来 分配 内存; 在 C++ 中 仍然 可以 这样做, 但 C++ 还有 更好 的 方法— new 运算符。
 1 #include<iostream>
 2 using namespace std;
 3 int main(){
 4    int var =8;
 5    int* pn = new int;//new 一块int 类型的空间
 6    *pn = 8;
 7    cout<<"var value = "<<var<<endl;
 8    cout<<"var adrr"<<&var<<endl;
 9    cout<<"*pn value = "<<*pn<<endl;
10    cout<<"pn adrr"<<pn<<endl;
11    delete pn;
12 }

delete

delete 运算符,它使得在使用完内存后,能够将其归还给内存池,这是通向最有效地 使用 内存 的 关键 一步。 归还 或 释放( free) 的 内存可供程序的其他部分使用。使用 delete 时, 后面要加上指向内存 的 指针
这将释放pn指向的内存,但不会删除指针pn本身。 例如,可以将ps重新指向另一个新分配的内存块。 一定要配对地使用new和 delete;否则将发生内存泄漏( memory leak),也就是说,被分配的内存再也无法使用了。 如果内存泄漏严重, 则程序将由于不断 寻找 更多 内存 而 终止。 不要 尝试 释放 已经 释放 的 内存 块, C++ 标准 指出, 这样做的结果将是不确定的, 这 意味着什么情况 都 可能发生。 另外,不能使用delete来释放声明变量所获得的内存:
警告: 只能 用 delete 来 释放 使用 new 分配 的 内存。 然而, 对空 指针 使用 delete 是 安全 的。 注意, 使用 delete 的 关键 在于, 将它 用于 new 分配 的 内存。 这 并不 意味着要使用于 new 的指针, 而是用于 new的地址:
int* pn = new int;
int a=10;
int *pt = &a;
delete ps;//正确
delete ps;//错误 二次释放
delete pt;//错误;
/////////////////////////////////////////////////
int *pn = new int ;
int *pt= pn;
delete pt;
一般来说, 不要创建 两个指向同一个内存块的指针, 因为这将增加错误地删除同一个 内存块两次的可能性。 但稍后您会 看到 ,对于返回指针的函数, 使用另一个指针确实 有道理。
new 动态数组
在 C++ 中, 创建动态数组很容易; 只要将数组的元素类型和元素数目告诉new即可。 必须在类型名后加上方括号, 其中包含元素数目。 例如, 要创建一个包含10个int元素的数组,可以这样做:
int* arr = new int[10];获取1个int 内存块 
 new 运算符返回第一个元素的地址。 在这个例子中, 该地址被赋给指针arr。 当程序使用完new分配的内存块时, 使用delete释放它们。 然而,对于使用new创建的数组, 应使用另一种格式的 delete 来 释放: 
delete [] arr;
方括号告诉程序, 应释放整个数组, 而不仅仅是指针指向的元素。
请注意delete和指针之间的方括号。 如果使用new时, 不带方括号, 则使用 delete 时, 也不应带方括号。 如果使用 new 时带方括号, 则使用 delete 时也应带方括号。
注意:
使用 new和delete时,应遵守以下规则。 
1、不要使用delete来释放不是new分配的内存。 
2、不要使用 delete 释放同一个内存块两次。
3、如果 使用 new [ ]为数组分配内存, 则应使用delete [ ]来释放。 
4、如果使用new为 一个实体分配内存, 则应使用delete( 没有方括号)来释放。 
5、对空指针应用delete是安全的。
arrnew:
 1 #include<iostream>
 2 using namespace std;
 3 int main(){
 4    double* p3 = new double [3];
 5    p3[0]= 0.5;
 6    p3[1]= 0.7;
 7    p3[2]= 0.9;
 8  
 9    cout<<"p3[0] value = "<<p3[0]<<endl;
10    cout<<"p3+1 value = "<<*(p3+1)<<endl;
11    p3 = p3+1;
12    cout<<"p3[0] value = "<<p3[0]<<endl;
13   // delete [] p3;//释放的是p3+1的地址   多以会有错误
14   p3 = p3-1;
15   delete [] p3;
16    return 0;
17 }

 

 
 
创建动态结构
struct student{
    char name[20];
    float age;
    double high;
};
int main(){
 
    student * stu01 = new student;//创建动态结构体
    cout<<"please input name :";
    cin.get(stu01->name,20);//指针方法调用成员
    cout<<"please input age :";
    cin>>stu01->age;
    cout<<"please input high :";
    cin>>(*stu01).high;//对象方法调用
    cout<<"name: "<<(*stu01).name<<endl;
    cout<<"age: "<<stu01->age<<endl;
    cout<<"high: "<<stu01->high<<endl;
 
    return 0;
}
指针函数---读取键盘字符
定义了一个函数getname( ), 该函数返回一个指向输入字符串的指针。 函数将输入读入到一个大型的临时数组 中,然后 使用 new [ ]创建一个刚好能够存储该输入字符串的内存块,并返回一个指向该内存块的指针。 对于读取大量字符串的程序,这种方法可以节省大量内存。
int main(){
    char *name;
    name = getname();//读取键盘字符
    cout<<name<<" at "<<(int *)name<<"\n";
    delete [] name//释放内存空间
 
    name = getname();//再次读取键盘字符
    cout<<name<<" at "<<(int *)name<<"\n";
    delete [] name;//释放内存空间
   //可以反复进行读取与操作,节省大量内存空间
    return 0;
 
}
char *getname(){//指针数组
     char temp[10];
     cout<<"please input string :";
     cin>>temp;
     char * pn = new char[strlen(temp)+1];
     strcpy(pn,temp);
     return pn;//返回指针
}
3. 动态存储 
new和delete运算符提供了一种比自动变量和静态变量更灵活的方法。 它们管理了一个内存池,这在C++中被称为自由存储空间( free store)或 堆( heap)。 该内存池同用于静态变量和自动变量的内存是分开的。 程序表明, new 和 delete 让 您 能够在一个函数中分配 内存, 而在 另一个 函数中释放它。 因此,数据的生命周期不完全受程序或函数的生存时间控制。 与使用常规变量相比,使用 new 和 delete 让 程序员 对 程序 如何 使用 内存 有 更大 的 控制 权。 然而, 内存管理也更复杂了。 在栈中, 自动添加和删除机制使得占用的内存总是连续的, 但 new 和 delete 的 相互 影响 可能 导致 占用 的 自由 存储 区 不连续, 这使 得 跟踪 新 分配 内存 的 位置 更 困难。 栈、堆和内存泄漏如果使用new运算符在自由存储空间( 或 堆)上创建变量后, 没有调用 delete, 将发生什么情况呢? 如果没有 调用 delete, 则 即使 包含 指针 的 内存 由于 作用域 规则和对象生命周期的原因而被 释放, 在自由存储空间上动态分配的变量或结构也将继续存在。 实际上,将会无法访问自由存储空间中的结构, 因为指向这些内存的指针无效。 这将导致内存 泄漏。 被 泄漏 的 内存 将在程序的整个生命周期内都不可使用; 这些内存被分配出去, 但无法收回。 极端情况( 不过不常见)是, 内存 泄漏 可能 会 非常 严重, 以致 于 应用 程序 可用 的 内存 被 耗尽, 出现 内存 耗尽 错误, 导致 程序 崩溃。 另外, 这种 泄漏 还会 给 一些 操作系统 或在 相同 的 内存 空间 中 运行 的 应用 程序 带来 负面 影响, 导致 它们 崩溃。 即使 是最 好的 程序员 和 软件 公司, 也可能 导致 内存 泄漏。 要 避免 内存 泄漏, 最好 是 养成 这样 一种 习惯, 即 同时 使用 new 和 delete 运算符, 在 自由 存储 空间 上 动态 分配 内存, 随后 便 释放 它。 C++ 智能 指针 有助于 自动 完成 这种 任务, 这 将 在 第 16 章 介绍。 注意: 指针 是 功能 最强 大的 C++ 工具 之一, 但也 最 危险, 因为 它们 允许 执行 对 计算机 不友好 的 操作, 如 使用 未经 初始化 的 指针 来访 问 内存 或者 试图 释放 同一个 内存 块 两次。
 
posted @ 2019-12-08 14:53  小猫王  阅读(461)  评论(0编辑  收藏  举报