C++指针之防不胜防
我们在使用指针时,经常会出现下面几种错误:
1) 内存分配未成功,却使用了它。
编程新手常犯这种错误,因为他们没有意识到内存分配会不成功。常用解决办法是,在使用内存之前检查指针是否为NULL。如果指针p是函数的参数,那么在函数的入口处用assert(p!=NULL)进行检查。如果是用malloc或new来申请内存,应该用if(p==NULL) 或if(p!=NULL)进行防错处理。
2) 内存分配虽然成功,但是尚未初始化就引用它。
犯这种错误主要有两个起因:一是没有初始化的观念;二是误以为内存的缺省初值全为零,导致引用初值错误(例如数组)。内存的缺省初值究竟是什么并没有统一的标准,尽管有些时候为零值,我们宁可信其无不可信其有。所以无论用何种方式创建数组,都别忘了赋初值,即便是赋零值也不可省略,不要嫌麻烦。
3) 内存分配成功并且已经初始化,但操作越过了内存的边界。
例如在使用数组时经常发生下标“多1”或者“少1”的操作。特别是在for循环语句中,循环次数很容易搞错,导致数组操作越界。
4) 忘记了释放内存,造成内存泄露。
含有这种错误的函数每被调用一次就丢失一块内存。刚开始时系统的内存充足,你看不到错误。终有一次程序突然死掉,系统出现提示:内存耗尽。动态内存的申请与释放必须配对,程序中malloc与free的使用次数一定要相同,否则肯定有错误(new/delete同理)。
5) 释放了内存却继续使用它。 有三种情况: (1)程序中的对象调用关系过于复杂,实在难以搞清楚某个对象究竟是否已经释放了内存,此时应该重新设计数据结构,从根本上解决对象管理的混乱局面。 (2)函数的return语句写错了,注意不要返回指向“栈内存”的“指针”或者“引用”,因为该内存在函数体结束时被自动销毁。 (3)使用free或delete释放了内存后,没有将指针设置为NULL。导致产生“野指针”。
使用指针过程中我们应该遵循下面几条原则:
【规则1】用malloc或new申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存。
【规则2】不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。
【规则3】避免数组或指针的下标越界,特别要当心发生“多1”或者“少1”操作。
【规则4】动态内存的申请与释放必须配对,防止内存泄漏。
【规则5】用free或delete释放了内存之后,立即将指针设置为NULL,防止产生“野指针”。
下面来看一个可能出现野指针的例子:
我们在使用结构体内循环嵌套结构体指针的问题,错误隐蔽。请看如下代码:
//定义一个结构体A,包含一个int变量btypedef struct
{
int b;
}A;//定义一个结构体B,包含一个A结构体指针a和一个int变量c
typedef struct
{
A* a;
int c;
}B;//初始化B结构体指针
void Initialization( B* myB )
{
myB->c=;
}
void main( int argc,char* argv )
{
A myA;
myA.b=;
B* myB;
Initalization( myB );
myB->a->b=;
printf( "the values of c:%d", myB->c );
}
模块1和模块2都是很正常的结构体声明,没有任何问题。而模块3和模块4就涉及指针问题,需要我们慎重考虑,而以上代码在编译器上运行时也会报告段错误。
解决方法:我们在声明类型的指针变量时一定要同时初始化,不能把它变成野指针。模块3和模块4都是同样的问题,指针变量本身申请的内存空间,但其指向那一片的类型地址却没有得到定义,所以我们要为其申请空间并初始化指针变量:
typedef struct
{
int b;
}A;
typedef struct
{
A* a;
int c;
}B;
void Initialization( B* myB )
{
myB->a = malloc(sizeof(A));/*不要忘了初始化*/
myB->c=;
}
void main( int argc,char* argv )
{
A myA;
myA.b=;
B* myB = malloc(sizeof(B));/*使用前要初始化*/
Initalization(myB);
myB->a->b=;
printf( "the values of c:%d", myB->c );
}
这样就不会出现段错误了,你会发现代码能正常运行了。最后别忘了用free(myB).....释放自己在堆中分配的内存,养成良好的习惯。
总结:指针变量是用来存放内存地址的,而其本身也是一个变量,也要在内存中分配地址,而程序员往往把本身要存储的地址当成是以存储的其它类型地址,所以导致访问时其指针变量并没有存储地址,到时访问违规,出现段错误。在我们声明指针变量时,一定要只要它要用来干什么,并在声明时就初始化它。
C++指针之防不胜防的更多相关文章
- NULL指针、零指针、野指针
1.1.空指针 如果 p 是一个指针变量,则 p = 0; p = 0L; p = '\0'; p = 3 - 3; p = 0 * 17;p=(void*)0; 中的任何一种赋值操作之后, p 都成 ...
- [3] 智能指针std::auto_ptr
[1]std::auto_ptr 对于编译器来说,智能指针实质是一个栈对象,而并非指针类型. 智能指针通过构造函数获取堆内存的管理所有权,而在其生命期结束时,再通过析构函数释放由它所管理的堆内存. 所 ...
- 野指针、NULL指针和void*
一.野指针 “野指针”不是NULL指针,是指向“垃圾”内存的指针. “野指针”的成因主要有三种: (1)指针变量没有被初始化.任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱 ...
- 浅谈 “空指针、野指针、void*”
Author: JW. Zhou Date: 2014/7/2 一.空指针(0/NULL) 返回NULL和返回0是完全等价的,因为NULL和0都表示空指针,换句话说:空指针是什么,就是 ...
- (转) 谈C/C++指针精髓
原文:http://www.cnblogs.com/madengwei/archive/2008/02/18/1072410.html [摘要] 指针是C和C++语言编程中最重要的概念之一, ...
- 【C++】智能指针详解(一):智能指针的引入
智能指针是C++中一种利用RAII机制(后面解释),通过对象来管理指针的一种方式. 在C++中,动态开辟的内存需要我们自己去维护,在出函数作用域或程序异常退出之前,我们必须手动释放掉它,否则的话就会引 ...
- 智能指针剖析(上)std::auto_ptr与boost::scoped_ptr
1. 引入 C++语言中的动态内存分配没有自动回收机制,动态开辟的空间需要用户自己来维护,在出函数作用域或者程序正常退出前必须释放掉. 即程序员每次 new 出来的内存都要手动 delete,否则会造 ...
- C语言野指针
本文转载自:http://blog.csdn.net/xwdok/article/details/576497 "野指针"不是NULL指针,是指向"垃圾"内存的 ...
- C++智能指针剖析(上)std::auto_ptr与boost::scoped_ptr
1. 引入 C++语言中的动态内存分配没有自动回收机制,动态开辟的空间需要用户自己来维护,在出函数作用域或者程序正常退出前必须释放掉. 即程序员每次 new 出来的内存都要手动 delete,否则会造 ...
随机推荐
- WCF服务接口多,客户端在引用时出错!报WCF The maximum nametable character count quota (16384) has been exceeded while reading XML data错误
WCF服务接口多,客户端在引用时出错!报WCF The maximum nametable character count quota (16384) has been exceeded while ...
- Ant执行Jmeter工程模版
<?xml version="1.0" encoding="GB2312"?><project name="ant-jmeter-t ...
- 怎么理解Android版本兼容???
程序中设置了minSdkVersion和targetSdkVersion如下: <uses-sdk android:minSdkVersion="8" android:tar ...
- 什么是FOUC?如何避免FOUC?///////////////////////////zzzz
一个新的名词叫做 FOUC 浏览器样式闪烁,之前也听说过一些类似的东西,比如样式突变等等,但这东西竟然有学名的..什么是FOUC(文档样式短暂失效)?如果使用import方法对CSS进行导入,会导致 ...
- Gulp学习指南之CSS合并、压缩与MD5命名及路径替换(转载)
本文转载自: Gulp学习指南之CSS合并.压缩与MD5命名及路径替换
- 理解NDCG
关于NDCG,wiki给点解释很详细,这里我谈谈我的理解. NDCG(Normalized discounted cumulative gain):是用来衡量排序质量的指标. 其中一种计算公式如下: ...
- 编写高性能Web应用程序的10个技巧
这篇文章讨论了: ·一般ASP.NET性能的秘密 ·能提高ASP.NET表现的有用的技巧和窍门 ·在ASP.NET中使用数据库的建议 ·ASP.NET中的缓存和后台处理 使用ASP.NET编写一个We ...
- 操作SSIS之前的准备工作
SSIS的历史概述: 在SQL Server7.0中,微软成立了一个很小的开发团队开发SQL Server中一个非常低调的功能,该功能被称为DTS(数据转换服务),该功能一直被沿用到SQL2000. ...
- postgresql流复制配置
一.配置环境: 示例环境 主机名 IP 角色 系统版本 数据目录 pg版本 db1 192.168.128.128 主库 RedHat5.3 /app/postgreSQL/data 9.1.7 db ...
- oracle 金额格式化
一般金额要显示成 XXX,XXX,XXX.XX的格式,可以这样做: to_char(column, 'FM999,999,999,990.00')