C++程序从问题到程序

C++调试过程中最麻烦的问题—运行时错误_C语言中文网
&&/&&&&/&&&&/&&
在调试过程中,运行时错误是最麻烦的问题。因为编译错误可以由编译器检查出来,而大多数编译器对运行时错误却无能为力。查错和纠错的工作完全由用户自己来完成。
运行时错误还分为两种:
一种是由于考虑不周或输入错误导致程序异常(Exception),比如数组越界访问,除数为零,堆栈溢出等等。
另一种是由于程序设计思路的错误导致程序异常或难以得到预期的效果。
对于第一类运行时错误,我们不需要重新设计解决问题的思路,认为当前算法是可行的、有效的。我们只需要找出输入的错误或考虑临界情况的处理方法即可。对于第二类运行时错误,不得不遗憾地说,一切都要从头再来。
见识运行时错误
由于编译器无法发现运行时错误,这些错误往往是在程序运行时以五花八门的形式表现出来。下面就是典型的几种因运行时错误引起的问题:
(1)WindowsXP错误报告
(2)内存不能为Read/Written
(3)非法操作
(4)Debug错误
查找错误点
语法错误的位置能很快地被编译器找到,而运行时错误的位置却很难被我们发现。即使我们一条条地检查语句,也未必能检查出什么。所以,在这里要介绍一种查找导致运行时错误的语句的方法。
我们知道,带有运行时错误的程序是可以运行的。当它运行到一个产生错误的语句时,就提示出错了。根据这个特点,我们可以用输出语句来判断程序的运行流程。下面就让我们来看一段有运行时错误的程序:(程序11.4)
#include &iostream&
int main()
& &char a[5],b[5];
& &int alen=0,blen=0;//记录字符串a和b的长度
& &cin &&a &&b;
& &for (int i=0;a[i]!='\0' && b[i]!='\0';i++)//计算字符串的长度
& & & if (a[i]!='\0')
& & & & &alen++;
& & & if (b[i]!='\0')
& & & & &blen++;
& &char *c=new char[alen+blen];//申请堆内存,存放连接后的字符串
& &for (i=0;i&=alen+i++)//把字符串a和b连接复制到字符串c
& & & if (i&alen)
& & & & &c[i]=a[i];
& & & else
& & & & &c[i]=b[i-alen];
& &cout &&c &&
& &delete []//释放堆内存
& &return 0;
运行结果:
TomatoStudio
udioTomat  葺葺葺葺癅
在程序运行结束之前,提示Debug Error,它属于一种运行时错误。而且根据输出的一些内容,发现程序也没有达到连接字符串的目的。所以我们让程序输出更多信息,查找错误原因。首先在计算字符串a和b的长度后,输出他们的长度,即在第一个for语句后添加一句cout &&&alen=& &&alen &&&blen=& &&blen &&。
运行结果:
TomatoStudio
alen=4blen=4
udioTomat  葺葺葺葺癅
OOTTMA字符串长为6,TomatoStudio字符串长为12。根据程序运行结果,我们发现计算出的字符串长度有问题。所以我们必须检查实现该功能的语句。另外,由字符串长度我们可以想到申请空间是否足够的问题。发现数组的空间只能存放5个字符,而现在两个字符串都已经超过这个限制。于是把数组空间扩大,该作char a[20],b[20];。
运行结果:
TomatoStudio
alen=6blen=6
OOTTMATomatoS  葺葺癅
发现字符串a的长度已经正确,可是字符串b的长度为什么不对呢?经过多次尝试,我们发现,正确的字符串长度总是较短的字符串。所以我们想到检查循环继续的条件是否正确,如果过早地终止循环,就会导致这种情况。果然,a[i]!='\0' && b[i]!='\0'意味着只要有一个字符串结束,那么长度计算就结束了,故把&&改成||。
运行结果:
TomatoStudio
alen=35blen=41
这么一改,居然两个长度全都错了。我们不禁要思考为什么会这样了:用一个for语句来计算两个字符串的长度,当循环变量越过任一个字符串的结尾符以后又误认为它没有结束,所以输出的长度远远长于字符串的实际长度。我们把计算字符串长度用两个for语句来实现。即程序被改写成这样:
#include &iostream&
int main()
& &char a[20],b[20];
& &cin &&a &&b;
& &for (int alen=0;a[alen]!='\0';alen++);//计算字符串a的长度
& & & for (int blen=0;b[blen]!='\0';blen++);//计算字符串b的长度
& & & & &cout &&&alen=& &&alen &&&blen=& &&blen &&
& &char *c=new char[alen+blen];
& &for (int i=0;i&=alen+i++)
& & &if (i&alen)
& & & & c[i]=a[i];
& & & else
& & & & c[i]=b[i-alen];
& &cout &&c &&
& &delete []
& &return 0;
运行结果:
TomatoStudio
alen=6blen=12
OOTTMATomatoStudio
现在两个字符串的长度都正确了,输出的内容也实现了字符串的连接,但是Debug Error仍然存在。继续检查,发现剩下的语句和申请的堆内存空间字符串c有关了。于是先检查c是否有越界访问。根据c申请的空间大小,发现for语句中循环继续的条件有错误,导致越界访问,把它改成i&alen+。
运行结果:
TomatoStudio
alen=6blen=12
OOTTMATomatoStudio  @
Debug Error已经没有了,看来造成这个错误的原因就是越界了。但是现在输出的字符串后面有乱码,可能是结尾符被忽略了。检查程序,发现alen+blen是两字符串长度,但是没有考虑结尾符,所以要给字符串c增加一个字符的空间。程序改写成如下:
#include &iostream&
int main()
& &char a[20],b[20];
& &cin &&a &&b;
& &for (int alen=0;a[alen]!='\0';alen++);
& & & for (int blen=0;b[blen]!='\0';blen++);
& & & & &//cout &&&alen=& &&alen &&&blen=& &&blen &&
& & & & &char *c=new char[alen+blen+1];
& &for (int i=0;i&alen+blen+1;i++)
& & & if (i&alen)
& & & & &c[i]=a[i];
& & & else
& & & & &c[i]=b[i-alen];
& &cout &&c &&
& &delete []
& &return 0;
运行结果:
TomatoStudio
OOTTMATomatoStudio
至此,程序修改完成。在目前的测试数据下,不再出现运行时错误,并且也能实现字符串连接的功能。
推荐文章 TOP10当前位置:&&编程语言>
c/c++服务器程序内存泄露问题分析及解决
&&&&发布时间:&&
&&&&本文导语:&
对于一个c/c++程序员来说,内存泄漏是一个常见的也是令人头疼的问题。已经有许多技术被研究出来以应对这个问题,比如 Smart Pointer,Garbage Collection等。Smart Pointer技术比较成熟,STL中已经包含支持Smart Pointer的class,...
对于一个c/来说,是一个常见的也是令人头疼的问题。已经有许多被研究出来以应对这个问题,比如 smart , 等。smart pointer技术比较成熟,中已经包含支持smart pointer的,但是它的使用似乎并不广泛,而且它也不能解决所有的问题;garbage collection技术在中已经比较成熟,但是在c/c++领域的发展并不顺畅,虽然很早就有人在c++中也的支持。现实世界就是这样的,作为一个c/c++程序员,内存泄漏是你心中永远的痛。不过好在现在有许多能够帮助我们验证内存泄漏的,找出发生问题的代码。1.内存泄漏的定义    一般我们常说的内存泄漏是指堆内存的泄漏。堆内存是指从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定),使用完后必须显示释放的内存。应用程序一般使用,,等从堆中分配到一块内存,使用完后,程序必须负责相应的调用或释放该 内存块,否则,这块内存就不能被再次使用,我们就说这块内存泄漏了。以下这段演示了堆内存发生泄漏的情形:void MyFunction(int nSize)
 char* p= new char[nSize];
 if( !GetStringFrom( p, nSize ) ){
  MessageBox(“Error”);
 …//using the
}当函数GetStringFrom()返回零的时候,p的就不会被释放。这是一种常见的发生内存泄漏的情形。程序在入口处分配内存,在出口处释放内存,但是c函数可以在任何地方,所以一旦有某个出口处没有释放应该释放的内存,就会发生内存泄漏。  广义的说,内存泄漏不仅仅包含内存的泄漏,还包含系统资源的泄漏( ),比如核心态, ,, 等,从根本上说这些由分配的也消耗内存,如果这些对象发生泄漏最终也会导致内存的泄漏。而且,某些对象消耗的是核心态内存,这些对象严重泄漏时会导致整个操作系统不稳定。所以相比之下,系统资源的泄漏比堆内存的泄漏更为严重。  GDI Object的泄漏是一种常见的泄漏:void CMyView::OnPaint( CDC* pDC )
 CBitmap* pOldB
 bmp.LoadBitmap(IDB_MYBMP);
 pOldBmp = pDC-&SelectObject( &bmp );
 if( Something() ){
 pDC-&SelectObject( pOldBmp );
}当函数Something()返回非零的时候,程序在退出没有把pOldBmp选回中,这会导致pOldBmp指向的对象发生泄 漏。这个程序如果长时间的运行,可能会导致整个花屏。这种问题在Win9x下比较容易暴露出来,因为Win9x的GDI堆比Win2k或的要小很 多。  内存泄漏的发生方式:  以发生的方式来,内存泄漏可以分为4:  1) 常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。比如例二,如果Something()函数一直返回True,那么pOldBmp指向的HBITMAP对象总是发生泄漏。 
2) 偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。比如例二,如果Something()函数只有在特定环境下才返回 True,那么pOldBmp指向的HBITMAP对象并不总是发生泄漏。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以 测试环境和测试方法对内存泄漏至关重要。  3) 一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的中分配内存,在析 构函数中却没有释放该内存,但是因为这个类是一个,所以内存泄漏只会发生一次。另一个例子:char* g_lpszFileName = NULL;
void SetFileName( const char* lpcszFileName )
 if( g_lpszFileName ){
  free( g_lpszFileName );
 g_lpszFileName = strdup( lpcszFileName );
} 如果程序在结束的时候没有释放g_lpszFileName指向的,那么,即使多次调用SetFileName(),总会有一块内存,而且仅有一块内存发生泄漏。   4)隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但 是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。举一 个例子:class Connection
  Connection( SOCKET s);
  ~Connection();
 private:
  SOCKET _
class ConnectionManager
  ConnectionManager(){}
  ~ConnectionManager(){
   list::
   for( it = _connlist.begin(); it != _connlist.end(); ++it ){
    delete (*it);
   _connlist.clear();
  void OnClientConnected( SOCKET s ){
   Connection* p = new Connection(s);
   _connlist.push_back(p);
  void OnClientDisconnected( Connection* pconn ){
   _connlist.remove( pconn );
 private:
  list _
};假设在从端断开后,Server并没有呼叫OnClientDisconnected()函数,那么代表那次的 对象就不会被及时的删除(在Server程序退出的时候,所有Connection对象会在ConnectionManager的析 构函数里被删除)。当不断的有连接建立、断开时隐式内存泄漏就发生了。  从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危 害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到。 2.检测内存泄漏  检测内存泄漏的关键是要能截获住对分配内存和释放内存的函数的调用。截获住这两个函数,我们就能跟踪每一 块内存的,比如,每当成功的分配一块内存后,就把它的指针加入一个的中;每当释放一块内存,再把它的指针从list中删除。这样,当 程序结束的时候,list中剩余的指针就是指向那些没有被释放的内存。这里只是简单的描述了检测内存泄漏的基本原理,详细的算法可以参见Steve Maguire的&& Solid &&。  如果要检测堆内存的泄漏,那么需要截获住 malloc/realloc/free和new/delete就可以了(其实new/delete最终也是用malloc/free的,所以只要截获前 面一组即可)。对于的泄漏,可以采用类似的,截获住相应的分配和释放函数。比如,要检测的泄漏,就需要截获 SysAllocString/SysFreeString;要检测HMENU的泄漏,就需要截获CreateMenu/ DestroyMenu。(有的资源的分配函数有多个,释放函数只有一个,比如,SysAllocStringLen也可以用来分配BSTR,这时就需要 截获多个分配函数)  在平台下,检测内存泄漏的工具的一般有三种, C- 内建的检测功能;外挂式的检测工具,诸如,,BoundsChecker等;利用Windows NT自带的 。这三种工具各有优缺点,MS C-Runtime Library虽然功能上较之外挂式的工具要弱,但是它是的;Performance Monitor虽然无法标示出发生问题的代码,但是它能检测出隐式的内存泄漏的存在,这是其他两类工具无能为力的地方。    内存泄漏是个大而复杂的问题,即使是java和这样有 gabarge collection机制的环境,也存在着泄漏的可能,比如隐式内存泄漏。3.避免
写服务器程序,最怕的就是内存泄露。因为程序经常运行好几个月不停,一点点内存泄露都会导致悲剧的发生。常规来说,首要是避免内存泄露,其次是检查内存泄露。1)不用newc++程序,尽量多用stl,避免用new。我自己写的代码,除了在函数里面有new外,其他地方不会再有任何new出现。这样就把交给stl去做。或许你会说,不用new怎么可能啊?很简单,用::代替,其他对象直接拷贝。除非你的对象很大很大,否则,一点点拷贝耗时,完全可以忽略不计。2)每个重要结构都提供函数给你的每个重要结构都加上一个Info函数,info函数返回一个string,描述当前结构的,如的大小,内存占用的大小。在最顶层,不定时的(或者根据命令输出)各个对象的info结果。这样可以避免隐形的内存泄露,即不是内存泄露,但某个对象保持的大量对象的,导致对象无法被删除;即某个对象内部的map,不断的添加,也在不断的,但在某些特殊情况下,它不会删除。3)stl内存泄露的问题stl几乎没有内存泄露,但它有一个内存,这个cache对小对象的分配很友好。stl的一个麻烦是,它几乎不会释放这些,这样的一个结果是,你看到自己的程序内存占用不断的上涨。其实,上是不用害怕的,因为它涨到一定范围(如,机器只有几百兆可用空间了),就不会涨了。可以通过在运行程序前, glibcxx_force_new=1,来让stl不要进行cache。注意,这个仅仅在() 3.3以后有效。4)等工具
直接,(注意,必须在的当前目录下执行configure,不能另外选一个目录),安装。执行:valgrind --num-callers=20 --leak-check=full --leak-=high ---reachable=yes ---=val.log xxx &,等过了几天后,把它,然后慢慢的看val.log。当你采用了前面3个策略后,valgrind几乎没有啥,反正我从来没有从它这里获得任何有用的过。主要是因为前面几步保证了没有显式的内存泄露,所以,valgrind也就找不出来啥内存泄露了。5)valgrind的工具massifmassif比valgrind好的地方在于,它会告诉你当前内存的分布情况。你可以看到占用了几百兆的程序到底是那些地方占用了内存。执行:valgrind --=massif xxx。一般通过这个都可以看到明显的内存泄露。这个工具很好,俺用它发现了一个十分的情况,这个情况是由的reserve导致的。本来应该reserve返回数据的个数,结果reserve了命中结果的个数。导致偶尔会出现内存占用过500M的情况,但因为没有内存泄露,所以其他几个工具都找不出来,就只有massif提供的堆栈可以发现这个问题。
您可能感兴趣的文章:
本站()旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。本站()站内文章除注明原创外,均为转载,整理或搜集自网络.欢迎任何形式的转载,转载请注明出处.转载请注明:文章转载自:[]本文标题:
相关文章推荐:
特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!
(C)2012-,E-mail:www_169it_(请将#改为@)西西软件园多重安全检测下载网站、值得信赖的软件下载站!
→ 常见C++编程出错对照表
v1.5 注册专业版
类型:编程辅助大小:1.8M语言:英文 评分:6.0
&Ambiguous operators need parentheses -----------不明确的运算需要用括号括起 Ambiguous symbol ''xxx'' ----------------不明确的符号 Argument list syntax error ----------------参数表语法错误 Array bounds missing ------------------丢失数组界限符 Array size toolarge -----------------数组尺寸太大 Bad character in paramenters ------------------参数中有不适当的字符 Bad file name format in include directive --------------------包含命令中文件名格式不正确 Bad ifdef directive synatax ------------------------------编译预处理ifdef有语法错 Bad undef directive syntax ---------------------------编译预处理undef有语法错 Bit field too large ----------------位字段太长 Call of non-function -----------------调用未定义的函数 Call to function with no prototype ---------------调用函数时没有函数的说明 Cannot modify a const object ---------------不允许修改常量对象 Case outside of switch ----------------漏掉了case 语句 Case syntax error ------------------ Case 语法错误 Code has no effect -----------------代码不可述不可能执行到 Compound statement missing{ --------------------分程序漏掉&{& Conflicting type modifiers ------------------不明确的类型说明符 Constant expression required ----------------要求常量表达式 Constant out of range in comparison -----------------在比较中常量超出范围 Conversion may lose significant digits -----------------转换时会丢失意义的数字 Conversion of near pointer not allowed -----------------不允许转换近指针 Could not find file ''xxx'' -----------------------找不到XXX文件 D ----------------说明缺少&;& houjiuming Declaration syntax error -----------------说明中出现语法错误 Default outside of switch ------------------ Default 出现在switch语句之外 Define directive needs an identifier ------------------定义编译预处理需要标识符 Division by zero ------------------用零作除数 Do statement must have while ------------------ Do-while语句中缺少while部分 Enum syntax error ---------------------枚举类型语法错误 Enumeration constant syntax error -----------------枚举常数语法错误 Error directive :xxx ------------------------错误的编译预处理命令 Error writing output file ---------------------写输出文件错误 Expression syntax error -----------------------表达式语法错误 Extra parameter in call ------------------------调用时出现多余错误 File name too long ----------------文件名太长 Function call missing -----------------函数调用缺少右括号 Fuction definition out of place ------------------函数定义位置错误 Fuction should return a value ------------------函数必需返回一个值 Goto statement missing label ------------------ Goto语句没有标号 Hexadecimal or octal constant too large ------------------16进制或8进制常数太大 Illegal character ''x'' ------------------非法字符x Illegal initialization ------------------非法的初始化 Illegal octal digit ------------------非法的8进制数字 houjiuming Illegal pointer subtraction ------------------非法的指针相减 Illegal structure operation ------------------非法的结构体操作 Illegal use of floating point -----------------非法的浮点运算 Illegal use of pointer --------------------指针使用非法 Improper use of a typedefsymbol ----------------类型定义符号使用不恰当 In-line assembly not allowed -----------------不允许使用行间汇编 Incompatible storage class -----------------存储类别不相容 Incompatible type conversion --------------------不相容的类型转换 Incorrect number format -----------------------错误的数据格式 Incorrect use of default --------------------- Default使用不当 Invalid indirection ---------------------无效的间接运算 Invalid pointer addition ------------------指针相加无效 Irreducible expression tree -----------------------无法执行的表达式运算 Lvalue required ---------------------------需要逻辑值0或非0值 Macro argument syntax error -------------------宏参数语法错误 Macro expansion too long ----------------------宏的扩展以后太长 Mismatched number of parameters in definition ---------------------定义中参数个数不匹配 Misplaced break ---------------------此处不应出现break语句 Misplaced continue ------------------------此处不应出现continue语句 Misplaced decimal point --------------------此处不应出现小数点 Misplaced elif directive --------------------不应编译预处理elif Misplaced else ----------------------此处不应出现else houjiuming Misplaced else directive ------------------此处不应出现编译预处理else Misplaced endif directive -------------------此处不应出现编译预处理endif Must be addressable ----------------------必须是可以编址的 Must take address of memory location ------------------必须存储定位的地址 No declaration for function ''xxx'' -------------------没有函数xxx的说明 No stack ---------------缺少堆栈 No type information ------------------没有类型信息 Non-portable pointer assignment --------------------不可移动的指针(地址常数)赋值 Non-portable pointer comparison --------------------不可移动的指针(地址常数)比较 Non-portable pointer conversion ----------------------不可移动的指针(地址常数)转换 Not a valid expression format type ---------------------不合法的表达式格式 Not an allowed type ---------------------不允许使用的类型 Numeric constant too large -------------------数值常太大 Out of memory -------------------内存不够用 houjiuming Parameter ''xxx'' is never used ------------------能数xxx没有用到 Pointer required on left side of -& -----------------------符号-&的左边必须是指针 Possible use of ''xxx'' before definition -------------------在定义之前就使用了xxx(警告) Possibly incorrect assignment ----------------赋值可能不正确 Redeclaration of ''xxx'' -------------------重复定义了xxx Redefinition of ''xxx'' is not identical ------------------- xxx的两次定义不一致 Register allocation failure ------------------寄存器定址失败 Repeat count needs an lvalue ------------------重复计数需要逻辑值 Size of structure or array not known ------------------结构体或数给大小不确定 S ------------------语句后缺少&;& Structure or union syntax error --------------结构体或联合体语法错误 Structure size too large ----------------结构体尺寸太大 Sub scripting missing ] ----------------下标缺少右方括号 Superfluous & with function or array ------------------函数或数组中有多余的&&& Suspicious pointer conversion ---------------------可疑的指针转换 Symbol limit exceeded ---------------符号超限 Too few parameters in call -----------------函数调用时的实参少于函数的参数不 Too many default cases ------------------- Default太多(switch语句中一个) Too many error or warning messages --------------------错误或警告信息太多 Too many type in declaration -----------------说明中类型太多 houjiuming Too much auto memory in function -----------------函数用到的局部存储太多 Too much global data defined in file ------------------文件中全局数据太多 Two consecutive dots -----------------两个连续的句点 Type mismatch in parameter xxx ----------------参数xxx类型不匹配 Type mismatch in redeclaration of ''xxx'' ---------------- xxx重定义的类型不匹配 Unable to create output file ''xxx'' ----------------无法建立输出文件xxx Unable to open include file ''xxx'' ---------------无法打开被包含的文件xxx Unable to open input file ''xxx'' ----------------无法打开输入文件xxx Undefined label ''xxx'' -------------------没有定义的标号xxx Undefined structure ''xxx'' -----------------没有定义的结构xxx Undefined symbol ''xxx'' -----------------没有定义的符号xxx Unexpected end of file in comment started on line xxx ----------从xxx行开始的注解尚未结束文件不能结束 Unexpected end of file in conditional started on line xxx ----从xxx 开始的条件语句尚未结束文件不能结束 Unknown assemble instruction ----------------未知的汇编结构 houjiuming Unknown option ---------------未知的操作 Unknown preprocessor directive: ''xxx'' -----------------不认识的预处理命令xxx Unreachable code ------------------无路可达的代码 Unterminated string or character constant -----------------字符串缺少引号 User break ----------------用户强行中断了程序 Void functions may not return a value ----------------- Void类型的函数不应有返回值 Wrong number of arguments -----------------调用函数的参数数目错 ''xxx'' not an argument ----------------- xxx不是参数 ''xxx'' not part of structure -------------------- xxx不是结构体的一部分 xxx statement missing ( -------------------- xxx语句缺少左括号 xxx statement missing ) ------------------ xxx语句缺少右括号 xx -------------------- xxx缺少分号 houjiuming xxx'' declared but never used -------------------说明了xxx但没有使用 xxx'' is assigned a value which is never used ----------------------给xxx赋了值但未用过 Zero length structure ------------------结构体的长度为零
08-0110-1607-1706-0603-2403-1201-2412-2712-1809-08
阅读本文后您有什么感想? 已有23人给出评价!
名称大小下载

我要回帖

更多关于 程序问题 的文章

 

随机推荐