有关C++指针与安全阐述
Posted IT科技股
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了有关C++指针与安全阐述相关的知识,希望对你有一定的参考价值。
**文件目录**
# 一、内存的分配方式
## 1、堆与栈
在程序中定义一个变量,他的值会被放入内存中,如果没有申请动态分配,它的值将会被放入栈中。栈中的变量所属的内存大小是无法改变的,他们的产生与消亡也与变量定义的位置和存储方式有关.堆是一种与栈相对应的动态分配方式的内存。当我们申请使用动态分配方式存储某个变量时,这个变量就会被放入堆中,根据需要,这个变量的内存大小可以发生改变,内存申请和销毁的时机则由编程者来操作。
## 2、关键字new与dalete
在获取变量之前,编译器并没有获取到变量的名称,而只是具有指向该变量的指针。这时申请变量的堆内存即是申请自身指向堆。new是c++语言中申请动态内存的关键字,形如:
int* PI=new int;
这样,PI指针就申请了动态方式,使用它在堆内申请内存存储int型的值。
***例;动态分配空间***
using namespace std;
int main(){
int* PI1=NULL;
PI1=new int; //申请动态分配
*PI=111;//动态分配内存存储的内容变成111的整型变量
cout<<"PI内存的内容"<<*PI<<",PI所指向的地址"<<PI1<<endl;
int* PI2;
//*PI2=222; //直接赋值会导致错误!!!
int k; //栈中的变量
PI2=&k; //分配栈内存
*PI2=222; //分配内存后方可赋值
cout<<"PI内存的内容"<<*PI2<<",PI所指向的地址"<<PI2<<endl;
return 0;
}
动态分配方式虽然很灵活,但是也带来了新的问题。当申请一块堆内存后,系统不会在程序执行时依据情况自动销毁它,若想释放该内存空间,则需要使用关键字delete。
***例:动态内存的销毁***
#include"stdafx.h"
#include<iostrteam>
using std::cout;
using std::endl;
int* newPointerGet(int* p1){
int k1=55;
p1=new int ;
*p1=k1;
return p1;
}
int* PointerGet(int *p2){
int k2=55;
p2=&k2;
return p2;
}
int main(){
cout<<"输出函数各自返回指针所指向的内存的值"<<endl;
int* p=NHLL;
p=newPointerGet(p);
int* i=NULL;
i=PointerGet(i);
cout<<"newGet:"<<*P<<",get:"<<*i<<endl;
cout<<"i所指向的内存没有被立即销毁,执行一个输出语句后:”<<endl;
cout<<"newGet:"<<*P<<",get:"<<*i<<endl;
delete p;
cout<<"销毁堆内存后:"<<endl;
cout<<"*p:"<<*p<<endl;
return 0;
}
# 内存安全
指针是c++提供的强大而又灵活的工具,如何安全地使用它们是编程者必须掌握的技能之一。前面我们已讨论过指针所指向内存的销毁问题,当一块内存被销毁时,该区域不可复用。若有指针指向该区域,则需要该指针置为空值(NULL)或者之相未被销毁的内存。
内存销毁实质上是系统判定该内存不是编程人员正常使用的空间,系统也会将他分配给别的任务,若擅自使用被销毁内存的指针更改该内存的数据,则可能会造成意想不到的后果。
***例:被销毁的内存***
using std::cout;
using std::endl;
int* sum(int a,int b){
int* ps=NULL;
int c=a+b;
ps=&c;
return ps;
}
int main(){
int* pi=NULL;
int k1=3;
int k2=5;
pi=sum(k1,k2);
cout<<"*pi的值:"<<*pi<<endl;
cout<<"也许*pi还保留着i的值,但它已经被程序认定为销毁"<<endl;
cout<<"*pi的值:"<<*pi<<endl;
cout<<"尝试修改*pi"<<endl;
*pi=3;
for(int i=0;i<3;i++){
cout<<"修改被销毁的内存后*pi的值:"<<*pi<<endl;
}
}
于此相对应的另一个安全问题是内存泄漏。如我们所知,在申请动态分配内存后,系统不会主动销毁该堆内存,而需要编程者使用delete关键字通知系统销毁。如果不这样做,系统将浪费很多资源,是程序执行时变得臃肿,如只需占用数十MB内存的程序可能为此占用上百MB的内存。可见,回收堆内存空间是很有必要的。销毁内存时,需要保留指向该堆内存的指针。当没有指针指向一块没被回收的堆内存时,此块内存犹如丢失一般,我们称之为内存
***例:丢失的内存***
//******这是一个反例,它会造成内存泄漏**********//
using namespace std;
int main(){
float* pf=NULL;
pf=new float;
*pf=4.321f;
float f2=5.321f;
cout<<"pf指向的地址"<<pf<<endl;
cout<<"*pf的值:"<<*pf<<endl;
pf=&pf;
cout>>"pf指向了f2的地址:"<<pf<<endl;
if(*pf>5){
cout<<"*pf的值:"<<*pf<<endl;
}
return 0;
}
程序中动态分配的内存开始有pf指向,当pf改变指向后,此块内存就再也无法回收了。
一般情况下,我们无法通过调试程序发现内存泄漏。所以,使用动态分配时一定要注意形成良好习惯
***例:回收动态内存的一般处理步骤***
void swap(int* a,int* b){
int temp=*a;
*a=*b;
*b=temp;
}
int main(){
int* pi=new int;
*pi=3;
int k=5;
swap(pi,&k);
std::cout<<"*pi:"<<*pi<<std::end; //使用std命名空间
std::cout<<"k:"<<k<<std::endl;
delete pi; //回收动态内存
pi=NULL; //将pi置空,防止使用已销毁的内存。不可与上一语句颠倒,否者将造成内存泄漏
return 0;
}
以上是关于有关C++指针与安全阐述的主要内容,如果未能解决你的问题,请参考以下文章