<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
<channel>
<title>
<![CDATA[听机会的敲门声]]></title>
 <link>
http://thomasyangch.blogcn.com</link>
<description>
<![CDATA[我来自于江汉平原，出生在一个叫新里仁口的小镇。子曰：“里仁为美，择不处仁，焉得知？” 孔子说：“跟有仁德的人住在一起，才是好的。如果你选择的住处不是跟有仁德的人在一起，怎么能说你是明智的呢？”我的博客主要以技术和生活为主，希望能在这里与大家交流，欢迎您的宝贵留言！]]></description>
<managingEditor>
<![CDATA[thomasyangch]]></managingEditor>
<dc:creator>
<![CDATA[thomasyangch]]></dc:creator>
<blogcn_uid>
thomasyangch</blogcn_uid>
<blogcn_hits>
3943</blogcn_hits>
<item>
<blogcn_uid>
<![CDATA[200381637]]></blogcn_uid>
<title>
<![CDATA[如何做好一个主管]]></title>
<link>
http://thomasyangch.blogcn.com/diary,19082070.shtml</link>
<description>
<![CDATA[工作中，常听到周围的一些主管抱怨工作的繁忙，总有忙不完的事，总有加不完的班，总有挨不完的骂，总有吵不完的架，等等诸多的抱怨。在这里，粗浅的谈谈如何做好一个主管。或者说是如何做好一个执行面的主管、实务操作面的主管。 
<P></P>
<P>一、专业能力 </P>
<P>作为一个主管，你必须掌握一定的专业知识和专业能力，随着你的管理职位的不断提升，专业能力的重要性将逐渐减少。作为基层的主管，个人的专业能力将非常的重要，你要达到的程度是，能直接指导你的下属的实务工作，能够代理你下属的实务工作。专业能力的来源无非是两个方面：一是从书本中来，一是从实际工作中来。而实际工作中你需要向你的主管，你的同事，你的下属去学习。“不耻下问”是每一个主管所应具备的态度。 </P>
<P>二、管理能力 </P>
<P>管理能力对于一个主管而言，与专业能力是相对应的，当你的职位需要的专业越多，相对而言，需要你的管理能力就越少。反之，当你的职位越高，管理能力要求就越高。管理能力是一项综合能力，需要你的指挥能力，需要你的决断能力，需要你的沟通协调能力，需要你的专业能力，也需要你的工作分配能力，等等。管理能力来自书本，但更多的来自实践，因此要提高你的管理能力，需要不断的反思你的日常工作，用你的脑袋时常去回顾你的工作，总结你的工作。</P>
<P>三、沟通能力 </P>
<P>所谓沟通，是指疏通彼此的意见。这种沟通包括两个方面，跨部门间的沟通，本部门内的沟通（包括你的下属你的同事和你的上级）。公司是一个整体，你所领导的部门是整体中的一分子，必然会与其他部门发生联系，沟通也就必不可少。沟通的目的不是谁输谁赢的问题，而是为了解决问题，解决问题的出发点是公司利益，部门利益服从公司利益。部门内的沟通也很重要，下属工作中的问题，下属的思想动态，甚至下属生活上的问题，作为主管你需要了解和掌握，去指导，去协助，去关心。反之，对于你的主管，你也要主动去报告，报告也是一种沟通。 </P>
<P>四、培养下属的能力 </P>
<P>作为一个主管，培养下属是一项基本的，重要的工作。不管你所领导的单位有多大，你要牢记你所领导的单位是一个整体，要用团队的力量解决问题。很多主管都不愿将一些事交给下属去做，理由也很充分。交给下属做，要跟他讲，讲的时候还不一定明白，需要重复，然后还要复核，与其如此，还不如自己做来得快。但关键的问题是(全球品牌网)，如此发展下去，你将有永远有忙不完的事，下属永远做那些你认为可以做好的事。让下属会做事，能做事，教会下属做事，是主管的重要职责。一个部门的强弱，不是主管能力的强弱，而是所有下属工作的强弱。绵羊可以领导一群狮子轻易地去打败狮子领导的一群绵羊，作为主管，重要职责就是要将下属训练成狮子，而不需要将自己变成狮子。 </P>
<P>五、工作判断能力 </P>
<P>所谓工作能力，个人以为，本质上就是一种工作的判断能力，对于所有工作的人都非常的重要。培养一个人的判断能力，首先要有率直的心胸，或者说是要有良好的道德品质，这是工作判断的基础。对于世事的对错，才能有正确的判断，才能明辨是非。其次，对于你所从事的工作，不管是大事，还是小事，该怎么做，该如何做，该由谁做，作为一个主管，应该有清晰的判断，或者说是决断。其实工作的判断能力是上述四项能力的一个综合，主管能力的体现是其工作判断能力的体现。</P>
<P>六、学习能力 </P>
<P>当今的社会是学习型的社会，当今的企业也必须是学习型的企业，对于我们每个人也必须是学习型的主体。学习分两种，一是书本学习，一是实践学习，两者应交替进行。你只有不停的学习，你才能更好的、更快的进步，才能跟上赶上社会的发展。走上社会的我们，要完全主动的去学习，视学习为一种习惯，为生活的一种常态。学习应该是广泛的，专业的，管理的，经营的，生活的，休闲的，各种各样，都是一种学习。未来人与人之间的竞争，不是你过去的能力怎样，现在的能力怎样？而是你现在学习怎样，现在的学习是你未来竞争的根本。 </P>
<P>七、职业道德 </P>
<P>但丁有一句话：智慧上的缺陷可以用道德弥补，但道德的缺陷无法用智慧去弥补。对于工作中人，不管是员工，还是主管，职业道德是第一位的。这就好比对于一个人而言，健康、财富、地位、爱情等都很重要，但健康是“1”，其他的都是“0”，只要“1”（健康）的存在，个人的意义才能无限大。职业道德对于工作的人而言，就是那个“1”，只有良好的职业道德的存在，上述的六种能力才有存在的意义，对于公司而言，才是一个合格之人才。职业道德不等同于对企业的向心力，但作为一个员工，作为一个主管。不管公司的好与不好，不管职位的高低，不管薪水的多少，对自己职业的负责，是一种基本的素养，是个人发展的根基。“做一天和尚撞一天钟”，只要你在公司一天，就要好好的去撞一天钟。 </P>
<P>以上，仅仅是个人的一些看法，要做好一个主管，要做的事还很多。我坚信一句话：师傅领进门，修行靠个人。一切的一切，个人以为，都要靠自己去感悟，将一切的一切变成自己的东西。</P>]]></description>
<pubDate>
2008-08-27 17:20:00.0</pubDate>
<guid>
http://thomasyangch.blogcn.com/diary,19082070.shtml</guid>
<comments>
http://thomasyangch.blogcn.com/diary,19082070.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[200381637]]></blogcn_uid>
<title>
<![CDATA[喜悦]]></title>
<link>
http://thomasyangch.blogcn.com/diary,19069236.shtml</link>
<description>
<![CDATA[&nbsp;&nbsp;&nbsp; 在经历了漫长的等待后,终于迎来了考试顺利通过的喜悦。考试通过了，意味着我不用再埋头苦干三个月啃书本了。准备的过程很辛苦，考试时很懊悔（自己并不关注的地方居然考试了），等待的过程很漫长，但结果却很让人满意！我想这也就是传说中的苦尽甜来吧。<BR>&nbsp;&nbsp;&nbsp;&nbsp;感谢上帝，阿门！下一个目标就要开始了！]]></description>
<pubDate>
2008-08-27 08:02:00.0</pubDate>
<guid>
http://thomasyangch.blogcn.com/diary,19069236.shtml</guid>
<comments>
http://thomasyangch.blogcn.com/diary,19069236.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[200381637]]></blogcn_uid>
<title>
<![CDATA[四种人不适合担任项目经理]]></title>
<link>
http://thomasyangch.blogcn.com/diary,19074953.shtml</link>
<description>
<![CDATA[<P>&nbsp;&nbsp;&nbsp; 项目管理和一般的管理相比又非常独特的一面，表面看，项目管理和企业管理相比显得面很窄，领域很专，项目经理的目标很单一，就是保质保量按时达成项目目标，远没有企业管理者那么多头多绪；但话又说回来，保质保量按时达成项目目标，项目经理却又需要关注项目的方方面面，需要很宽的知识面、很强的沟通协调能力和目标意识。正因为项目的一次性和目标专一性，决定了项目管理者和企业管理者的不同，我认为有几种管理风格和性格倾向的不适合担任项目经理。</P>
<P><B>好好先生：</B></P>
<P>&nbsp;&nbsp;&nbsp; 可以把管理者的日常工作划分为两大类：管人和管事，不同的管理者有不同的倾向，一般而言，越是高阶的管理者管人的比重越大，越是低阶的管理者管事的比重越大，管人和管事要有一个合理的配称，管理才会真正有成效。而不同的人在管人和管事上有先天的偏向，有人更重管人，管理风格就是关系导向；有人更重管事，管理风格是任务导向。好好先生是指关系导向型的领导，这类领导更关心团队的关系，注重和睦相处，竭力维系团队和谐氛围，这类人被称为“和事佬”。和事佬把多数精力用到防止冲突和维系人际关系上，不知不觉就把任务放到次要位置。</P>
<P>&nbsp;&nbsp;&nbsp; 项目管理属于目标管理，这一特点决定了这类好好先生不适合担任项目经理。在项目管理中当然也要注重任务导向和人际导向的配称，但作为项目经理是绝对需要偏重任务导向的，因为项目是为既定的任务所作的一次性的努力，项目团队是临时的，任务是一次性的，所以任务导向比人际导向更重要，任务导向为主，适当兼顾团队关系的领导最适合当项目经理，纯粹的关系导向的领导，几乎很难胜任项目经理。</P>
<P>&nbsp;&nbsp;&nbsp; 关系导向的项目经理常常会因为维系人际关系的和睦而牺牲原则，一再妥协退让，导致项目目标严重偏离；还有一种倾向就是为了维持和谐相处的氛围，工作汇报的时候报喜不报忧，隐瞒不好的消息，贻误了处理问题的最好时机。</P>
<P><B>先锋勇士：</B></P>
<P>&nbsp;&nbsp;&nbsp; 和好好先生相反的另一个极端情况就是先锋勇士型的项目经理，这类经理是典型的任务导向性，并且能做到以身作则，亲自冲锋陷阵。这类项目经理可能是因为业务能力过硬被提拔为项目经理，通常自己干活干脆麻利，效率比较高，所以习惯事必亲躬，把其他成员沦为看他表演的“观众”。这样的项目经理本质上并不是管理者，绝大部分任务是靠项目经理亲自动手完成的，而管理的重点是透过他人的努力完成既定的任务，这类项目经理更像一个业务骨干，遗憾的是，这种管理风格会使其他项目成员非常迷茫且没有成就感，得不到应有的锻炼和提高。事实上，任何一个项目组成员参与到项目中来都有一个潜在的需求，就是通过参与项目来激烈经验、锻炼自己、提高自己，当一个项目结束时项目组成员是否得到长足的锻炼和提高也是考量项目经理是否优秀的一个软指标。很显然，先锋勇士型项目经理是不考虑这些的。</P>
<P>&nbsp;&nbsp;&nbsp; 不可否认，这类管理风格在一两个人参与的小项目中比较奏效，但项目规模稍微一大，涉及面稍微复杂一点，弊端就非常明显了。</P>
<P><B>马虎大王：</B></P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;第三类我称之为马虎大王，主要特点是凡事计划性不强，考虑不周全，丢三落四。项目经理是整个项目的核心和舵手，整个团队的人都唯项目经理的马首是瞻。这就要求项目经理有很强的规划能力和事件驱动能力，要有很好的全局观和协调能力，而“马虎大王”型的项目经理，论做事，他可能非常积极投入也有能力，比“先锋勇士”型并不逊色，论管人，也并不比“好好先生”差，也能很好把团队凝聚在一起，但他仍然不能胜任项目经理，原因是缺乏对项目的整体把握和规划，经常会顾此失彼，把项目陷入尴尬的境地。<BR>项目实施是变设计为实体，化蓝图为具体的过程。所以，要求项目经理在做项目时就胸有成竹，并且会很好统筹，知道先做什么，后做什么，更好很好分工，把合适的工作指派给合适的人干，最后还要把不同过程产出的中间结果组合起来，所以，不懂业务的项目经理实际上很难管控好项目，所以同样是国际认证的项目管理师，IT行业的项目管理师绝对不能胜任建筑项目的项目管理，而不懂具体业务的企业管理者却未必管理不好一个企业。从这个意义上讲，对项目管理的素质要求很高，要懂业务、懂规划、会做事、能管人，方方面面，林林总总，所以，西安工业大学赛云秀教授说，项目管理一尺深，一丈宽，涉猎广博然后能规划周到。在很多时候，尽管事前有周密的计划，也难免百密一疏，遇到一些意外，如果计划不够周密，到执行阶段就千疮百孔，整个项目必然处于失控状态。</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;所以，张飞、李逵式的人是不可能胜任项目经理的。</P>
<P><B>艺术大师：</B></P>
<P>&nbsp;&nbsp;&nbsp; 第四类不适合的项目经理我称作艺术大师型。这类人沉迷技术，有项目作为一种艺术品的倾向，喜欢精雕细琢，过分强调细节，追求完美。我曾经讲过，在项目中，唯美求全往往要付出沉重的代价，甚至偏离目标更远。项目具有时限性，更有资源限制性，项目投资者更希望的到的是合适的投入产出比和性能价格比，项目投资需要项目快速投入使用以便快速收回成本，赚取利润，所以，做项目不是做工艺品，最重要的一条是实用。所以，优秀的项目经理都是现实主义者，懂得用最经济的手段得到最实惠的回报，而不会投入很大的精力像艺术家一样追求卓越。</P>
<P>&nbsp;&nbsp;&nbsp; 沉迷技术的人担任项目经理，要防止两种倾向：一是片面追求新技术、高难度，而实际上新技术往往意味着高风险，高难度往往意味着项目成果难于被人接受，追求高新技术和追求实用经常会产生矛盾；二是追求完美，不管什么事情都追求尽善尽美，没有成本意识，过分沉溺于细节，导致工期拖延和成本增大。在项目组中需要艺术大师式的人物，但这类人物绝对不能担任经理。</P>
<P>&nbsp;&nbsp; 人无完人，全面优秀的项目经理非常难找，所以，有一些短板的项目经理也是非常正常。但是有明显的以上四种倾向的人不适合当项目经理。作为项目经理，也要时刻警惕在项目管理过程中犯以上四种类型的错误。</P>]]></description>
<pubDate>
2008-08-26 12:42:00.0</pubDate>
<guid>
http://thomasyangch.blogcn.com/diary,19074953.shtml</guid>
<comments>
http://thomasyangch.blogcn.com/diary,19074953.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[200381637]]></blogcn_uid>
<title>
<![CDATA[项目管理中的参考经验数据]]></title>
<link>
http://thomasyangch.blogcn.com/diary,19076428.shtml</link>
<description>
<![CDATA[◎工作分解结构(WBS)的层次一般要控制在4～6层，多了不易于管理。 
<P></P>
<P>◎项目经理把90%的时间花在沟通上面。 </P>
<P>◎在面对面的沟通中，有55%的信息是通过“非口头语言”的形式语言传递的。 </P>
<P>◎项目在完成了15%～20%以后，项目的累计成本绩效指数CPI就会比较稳定。所以在这之后的CPI就可以为预测项目完成时的项目总成本提供一个比较快捷的方法。 </P>
<P>◎大约 85%的质量问题是系统引起的，而建立与维护系统是管理者的责任，所有85%的质量成本应该由管理层来负责，一线人员只承担15%的责任。 </P>
<P>◎在质量控制的控制图中，如果连续有7个点落在控制平均线的同一侧，就可以判断是过程失控了。因为这7个点的分布是随机的原因引起的可能性非常的小。 </P>
<P>◎为了便于管理与操作，工作分解结构(WBS)中的每个工作包应该可以在80小时内完成。 </P>
<P>◎帕累托规则，也称二八定律，80%的问题是由20%的原因引起的。 </P>
<P>◎如果没有具体的计算依据，项目的不可预见费(应急储备金)可以按项目总成本的10%计算。 </P>
<P>◎项目的质量成本应该占项目总成本的3%～5%。 </P>]]></description>
<pubDate>
2008-08-26 12:00:00.0</pubDate>
<guid>
http://thomasyangch.blogcn.com/diary,19076428.shtml</guid>
<comments>
http://thomasyangch.blogcn.com/diary,19076428.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[200381637]]></blogcn_uid>
<title>
<![CDATA[企业IT服务管理需掌握的项目技巧]]></title>
<link>
http://thomasyangch.blogcn.com/diary,19069185.shtml</link>
<description>
<![CDATA[<P>　　在企业IT服务项目管理中，不但要有扎实的专业知识，而且，有时候还不得不掌握一些项目管理的技巧、一些为人处理的方法，如此的话，才能够在信息化项目管理中，无往不利。下面我以自己的工作经历为背景，谈谈在信息化项目管理中，常用的一些项目管理技巧。</P>
<P>　　<B>一、 把握各种限制之间的平衡。</B></P>
<P>　　人有时候在各种限制下，不得不进行妥协、进行平衡。在平时工作中是如此，在信息化项目管理中，也是如此。</P>
<P>　　如在信息化项目的管理中，我们要在用户需求与项目周期之间进行平衡;再如，项目的范围、二次开发的需求要与项目的成本预算进行平衡;再如，在部门之间发生矛盾时，我们做为项目管理者，也要在他们之间进行平衡。其实，确切的说，搞平衡有时候不一定是种妥协，更可能是一种进步。</P>
<P>　　如有一次我在负责公司的客户关系信息化管理系统的时候，就遇到了一个平衡的问题。那时候，财务要求把客户关系管理系统跟财务的总帐系统关联起来。但是，因为这是他们在系统开始实施的时候，才提出来的一个需求。按照原先的需求，只需要到应收为止就可以了。所以，若现在要考虑把客户关系管理系统跟财务系统的总帐关联起来的话，项目预算就不够了，而且，项目的周期也难以保证，肯定会延长。该怎么办呢?只能在这之间进行平衡。</P>
<P>　　当时，针对这种情况，我想了几个平衡方案。</P>
<P>　　一是先不考虑这个需求。把这个需求暂时放放，等到这个项目完工后，再考虑系统的集成问题。但是。这个方案很快被否定了。因为财务掌握着财政大权，若不帮他们实现需求的话，那我项目的资金就无法保障。俗话说，兵马未动，粮草先行。所以说，财政大臣还是不能得罪的。</P>
<P>　　二是增加项目预算，尽量加快项目进度。因为项目预算的权利最终是在财务总监身上，而财务总监跟财务经理又是一家。所以，我就让财务经理去向财务总件说明情况，要求增加项目预算。同时，我也督促相关人员做好需求，只要增加项目预算的决定一下来，我就可以马上启动项目集成的作业。果然不出我所料，财务经理出马，项目预算增加方案马上就批下来了。由于我在还没批下来之前，就开始做准备工作。所以，项目的周期没有受到多大影响。</P>
<P>　　所以，我们在平衡的过程中，还需要利用各种力量，去达到平衡的目的。若自己权利不够大，资格不够老，面子不够大，那就要其他人，特别是当事人去帮自己搞平衡，这比自己出马，要好得多。</P>
<P>　　<B>二、 不能随便答应别人的要求；一旦承诺，就需要兑现。</B></P>
<P>　　在信息化项目工作中，兑现承诺是非常重要的。若你刚开始答应别人可以实现某个需求，帮他们解决某个问题，而结果呢，在后续项目推进的过程中，没有实现。那么他们就会对你失去信心，同时，也会对项目失去信心。俗话说，好事不出门，坏事传千里。也就是说，你帮他们实现了十个需求，他们可能还不放在心上;但是，若你承诺他们的，有一个需求不能实现，那么企业员工就会缠住你不放了，会把你一棒子打死。再这方面，我深有感触。</P>
<P>　　我刚开始负责的第一个信息化项目就是ERP项目。那是，我们作为企业ERP项目的内部负责人，可谓是初生牛犊不怕虎;同时因为没有实际业务经验，对企业的操作流程也不是很熟悉。只要用户提出的需求，我觉得比较可行，就信誓旦旦的承诺，一定帮他们实现这个需求。那时，也没有考虑这个需求是否合理，对其他操作是否有冲突。结果呢，当然是弄得伤痕累累。虽然，ERP项目最后成功上线了，但是，用户的一些不合理的需求，还是没能在ERP系统中实现。如成本会计需要按销售订单来进行产品成本的统计，但是，实际管理中，由于有些订单使用的是库存，而有些销售订单又是合并采购与生产，所以，根本无法实现按销售订单来统计生产成本的需求。结果呢，我虽然帮助财务用户及成本会计实现了大部分需求，帮助他们解决了大部分问题，但是，在最后项目的评估上，还是遭受到了成本会计的责问。这也是我咎由自取，在不了解业务的情况下，信口开河，对别人乱承诺。</P>
<P>　　从此以后，我对于我不熟悉的领域，就再也不会随便答应了。我会礼貌的说，先回去进行测试后，再看行不行。一旦给用户有了承诺，就要想法设法的实现，不然的话，对于项目的进展是不利的;对于你自己个人的考核，也会有很大影响。</P>
<P>　　<B>三、 实现全程质量管理。</B></P>
<P>　　说实话，很多人在信息化项目的管理过程中，没有质量管理的概念。他们在实施信息化项目的时候，觉得刚开始只需要过得去就可以了，等到项目上线了，我们再花时间慢慢的改善系统。其实，这是一个很不科学的管理方法。</P>
<P>　　如我认识一个朋友，他们也刚要上一套ERP系统。他们再上ERP系统之前，在企业中，已经有一套产品管理系统，有产品基本信息、价格、物料清单、供应商信息等等。但是，在实施这套产品管理系统的时候，由于种种原因，如编码不够规范、系统控制不够严格、操作人员责任心不够等等，导致这套系统中的数据不是很准确。要么就是数据重复，相同的产品对应不同的编码，即一物多码情况普遍存在;要么就是价格过时，好几年没更新了;又或者因为生产工艺的更新等等，物料清单的用量没有及时更改，等等。但是，我朋友为了赶项目进度，同时，也确实因为产品基本信息数量庞大，物料清单更是复杂，所以，在对原由数据没有进行核对的情况下，不管数据质量，只管项目进度，盲目的把这些不准确的数据都导入到了新的ERP系统中去。他的想法是，现在由于时间紧迫，没有这么多的时间，也没有这么多的人来核对这些信息。只有等遇到问题时，再去进行修改、核对。可是，事与愿违。因为基础数据存在严重的错误，所以，在跑ERP系统的时候，如系统模拟运行时，就无法进行下去。因为ERP系统计算出来的数据，是马头不对马尾，企业用户根本无法使用。最后，不得不返工。把原先的数据整理、核对完毕后，再进行后续的工作。本来想节省一点时间的，没想到，反而因为返工浪费了更多的时间。</P>
<P>　　其实，类似的案例在很多人身上都发生过，包括在我身上。所以，我觉得很多CIO身上所缺少的就是那种质量管理的理念。我个人认为，我们在负责信息化项目的过程中，一定要脚踏实地，抓好每个环节的质量管理。否则的话，项目即使顺利上线了，其结果也不会很理想。</P>
<P>　　<B>四、 注意项目管理中的风险。</B></P>
<P>　　在项目管理的风险意识上，我很同意一位前辈说的话。他说，我们在项目管理的过程中，若不去控制风险，那么，风险反过来就是控制你。所以，在信息化项目实施之前，先花一定的时间去了解项目存在的风险，对于我们控制项目风险，保障项目的最后成功，是具有非常重大的利益的。</P>
<P>　　其实，大部分信息化项目的风险都是有迹可循的。</P>
<P>　　如对于一些信息化管理系统，例如企业资源计划系统或者客户关系管理系统等等这些大型的信息化管理系统，其存在的风险无非是以下几类。</P>
<P>　　一是安全风险。其包括两个部分，一是来源与系统与网络的风险，因为系统的漏洞或者网络的故障，可能使得信息化管理系统无法运行，从而到企业员工对信息化管理系统产生依赖后，没有系统就不知道该做什么事情了。如我公司有一次停电，系统全部不能用，办公室人员就不知道该干什么了，个个都做在一起聊天。其实，当员工对信息化系统形成依赖后，当系统当机后，他们就会很不习惯，也不会再去做手工作业。所以，我们在考虑项目实施的时候，再这个方面要充分重视。不要妄想着，系统当机也没事情，他们可以手工作业。若有这个想法的话，那你离“死期”也就不远了。二是数据的安全。在系统刚开始实施的时候，一般的情况下，可能不会设置很负责的管理权限。所以，在项目刚开始的时候，很多员工就可以看到系统里的大部分数据，包括产品价格、客户信息等内容。我认识一家企业，他们的员工就利用ERP系统刚开始上线的时候，对于权限控制不完善，把系统里的客户信息其他们的产品价格泄露给了公司的竞争对手，导致企业流失了不少的客户。所以，在项目上线的时候，我们就要充分认识到系统的安全风险，先做防范。</P>
<P>　　二是流程冲突的风险。我们都知道，信息化管理的本质就是标准化管理。所以，在信息化管理软件项目推进的过程中，必然会遇到企业现有流程跟标准流程存在的一种冲突。不在沉默中死亡，就在冲突中爆发。要调和这两着的冲突，实现业务流程重组，实现系统的平稳过度，企业是要承担一定的风险的。这个风险我们也要预先估计到，不要等到事情来临了，我们才想法子去处理他，那就显得太迟了。</P>]]></description>
<pubDate>
2008-08-19 07:59:00.0</pubDate>
<guid>
http://thomasyangch.blogcn.com/diary,19069185.shtml</guid>
<comments>
http://thomasyangch.blogcn.com/diary,19069185.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[200381637]]></blogcn_uid>
<title>
<![CDATA[奥运湖北]]></title>
<link>
http://thomasyangch.blogcn.com/diary,18823475.shtml</link>
<description>
<![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <STRONG><FONT face=楷体_GB2312 color=#ff0000 size=4>欢笑、泪水、拥抱，当杨威和他的队友们尽情释放激情时，湖北的奥运英雄传，悄然地续上了新的一章。<BR>　　1984年洛杉矶奥运会，年轻的武汉姑娘周继红在跳水女子10米台上技压群芳，夺得金牌！从此，奥运画卷里，开始写下荆楚英雄的篇章。<BR>　　1988年汉城，武汉姑娘陈静夺得乒乓球女单冠军。<BR>　　1992年巴塞罗那，湖北健儿再下三金：武汉姑娘伏明霞继承周继红的传统，再夺10米台金牌；武汉姑娘乔红与邓亚萍合作，拿下乒乓球女双冠军；仙桃人李小双，勇夺男子自由体操金牌。<BR>　　1996年亚特兰大，荆楚健儿更进一步，勇夺四金，占据了中国军团金牌总数的四分之一：伏明霞卫冕10米台，再夺三米板；乔红与邓亚萍合作卫冕乒乓球女双；李小双夺得体操个人全能金牌。<BR>　　2000年悉尼，湖北选手再下四城：跳水皇后伏明霞卫冕三米板金牌；仙桃人杨威、郑李辉作为主力成员，夺得体操男团冠军；武汉小伙肖海亮与熊倪合作，在男子三米板称雄；武汉姑娘高崚与张军合作，摘下羽毛球混双金牌。<BR>　　2004年雅典，湖北诸将又摘两金：高崚卫冕，另一位武汉姑娘李婷与孙甜甜合作，夺取网球女双冠军。<BR>　　20多年里，虽然也有波折，但在各级政府的关心下，体育主管部门齐心协力，体育健儿奋勇争先，荆楚体育努力屹立不倒。截至2004年，湖北健儿所获奥运金牌数仅次于辽宁省，列全国第二；湖北与浙江一起，也成为六届奥运会，届届有金牌的两个省。武汉市贡献了7位奥运冠军，列全国第三；仙桃市贡献了3位奥运冠军，亦列前10！<BR>　　如今，辉煌继续。<BR>&nbsp;&nbsp;&nbsp; 截止今天中午12:00时,共有5位湖北籍选手获得金牌,他们是:<BR>&nbsp;&nbsp;&nbsp; 杨威--籍贯：湖北仙桃，男子体操团体冠军、男子个人全能冠军；<BR>&nbsp;&nbsp;&nbsp; 廖辉--籍贯：湖北仙桃，男子举重69公斤级冠军；<BR>&nbsp;&nbsp;&nbsp; 程菲--籍贯：湖北黄石，女子体操团体冠军；<BR>&nbsp;&nbsp;&nbsp; 李珊珊--籍贯：湖北黄石，女子体操团体冠军；<BR>&nbsp;&nbsp;&nbsp;&nbsp;王鑫--籍贯：湖北武汉，女子跳水10米双人冠军；<BR>&nbsp;&nbsp;&nbsp; 此外，宜昌姑娘魏轶力与队友张亚雯合作夺得奥运会羽毛球女双铜牌。8月14日武汉姑娘李娜直落两盘以两个7-5爆冷击败赛会7号种子美国名将大威廉姆斯，挺进女单4强，这是中国金花历史上首次杀入奥运会女单四强......<BR>&nbsp;&nbsp;&nbsp; 他们是咱湖北人的骄傲，湖北健儿，加油！</FONT></STRONG> ]]></description>
<pubDate>
2008-08-16 14:16:00.0</pubDate>
<guid>
http://thomasyangch.blogcn.com/diary,18823475.shtml</guid>
<comments>
http://thomasyangch.blogcn.com/diary,18823475.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[200381637]]></blogcn_uid>
<title>
<![CDATA[关于软件开发过程中若干常见问题的探讨分析]]></title>
<link>
http://thomasyangch.blogcn.com/diary,18712485.shtml</link>
<description>
<![CDATA[&nbsp;&nbsp;&nbsp; 综观自己经历过的大大小小的项目,我总结出项目中多数存在这样的问题:<br>1、开发之前没有认真地进行项目可行性和工作量的估计。<br>　　往往由于项目较小，便很草率地制定一个开发日程表，没有认真地估计项目难度，结果实际完成时间与估计完成时间往往有较大差距。 <br>　　<br>2、没有真正的设计过程 。<br>　　开发人员少，不同人员的程序之间交互、接口相对少一些。开发周期短往往是几个人从头到尾负责一个项目，几个人碰一下头，讨论一下最基本的数据结构、函数接口便分头去做自己的工作了，没有一份较正式的文档来规范各自职责和项目细节。 <br>　　这种做法潜在的危险之一是有人可能会对所讨论的接口、结构理解有偏差，可能会造成以后的返工。 <br>　　另一个潜在的危险是由于讨论时忽略了某些情况，等大家都按时完成分工任务后，才发现各个模块组合起来却无法形成一个完整的系统。其根源在于没有一个负责协调的人员不断监控整个开发过程。 <br>　　第三个潜在的危险是一旦有人中途退出开发队伍，其他人加入时，难以理解以前别人做好的代码，又要从头做起。另外，没有文档的程序，日后维护和版本升级都比较困难。 <br><br>3、不经过单元测试而直接进入系统测试 。<br>&nbsp;&nbsp;&nbsp; <br>]]></description>
<pubDate>
2008-08-11 13:13:00.0</pubDate>
<guid>
http://thomasyangch.blogcn.com/diary,18712485.shtml</guid>
<comments>
http://thomasyangch.blogcn.com/diary,18712485.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[200381637]]></blogcn_uid>
<title>
<![CDATA[浅谈软件开发项目的实施控制与进度管理]]></title>
<link>
http://thomasyangch.blogcn.com/diary,18712261.shtml</link>
<description>
<![CDATA[<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 18pt;"><span style="font-size: 9pt; font-family: 宋体;">信息技术和现代管理学知识的飞速发展和迅速普及，使得政府、企业对于<font face="宋体"><span lang="EN-US">IT</span>应用的需求越来越强烈和苛刻，但是不容忽视的事实却是<span lang="EN-US">“</span>软件项目的规模和复杂程度在不断增加<span lang="EN-US">”</span>。对政府、企业中的软件项目管理人员来说，把项目管理的理论和方法落实到工作实践中去，是提高软件开发质量的重要手段。</font><font face="宋体"><span lang="EN-US">&nbsp; <br><br></span>　　<strong><span style="color: black; font-family: 宋体;">精确管理，保质保量<span lang="EN-US"> </span></span></strong><strong><span style="color: white; font-family: 宋体;" lang="EN-US"></span></strong></font><b><span lang="EN-US"><br></span></b><span lang="EN-US"><br></span>　　软件质量的高低，由符合软件质量要素要求的程度来决定。软件的质量要素包括功能性、可靠性、易用性、效率、可维护性、可移植性等<font face="宋体"><span lang="EN-US">6</span>个方面。软件开发过程中从需求、设计、编码、测试到上线验收的任何一个环节，都将对软件质量要素产生重要影响，因此为了开发出符合高质量的软件产品，必须加强对软件开发全过程的项目管理。</font><font face="宋体"><span lang="EN-US">&nbsp; <br><span style="color: white;">http://blog.mypm.net</span><br></span>　
　软件项目管理是按需求确定范围、按目标制定项目计划、按计划执行管理的过程。对软件开发各阶段加强项目管理的根本目的在于增强对软件开发的控制能力，提
升软件开发的质量。软件项目的建设按软件工程的生命周期法可分为项目立项、启动、需求分析、系统设计、系统开发、系统测试、系统上线、项目验收和上线后评
估等<span lang="EN-US">9</span>个阶段进行。</font><font face="宋体"><span lang="EN-US">&nbsp; <br><br></span>　　加强软件项目管理，就是以软件工程的各个环节为管理主线，将动态项目管理贯穿其中，通过对软件开发的项目范围、项目进度、项目质量、项目沟通、人力资源、项目成本六大核心要素的集成管理，实现软件开发管理效能的最大化，从而大大提高软件开发质量。</font><font face="宋体"><span lang="EN-US">&nbsp; <br><br></span>　<strong><span style="color: black; font-family: 宋体;">　明确需求，准确立项<span lang="EN-US">&nbsp; </span></span></strong></font><b><span lang="EN-US"><br></span></b><span lang="EN-US"><br></span>　
　软件开发项目的提出，应由迫切的业务需求来驱动。很多不成功的软件项目，往往是由信息技术部门提出，按照技术人员的思路主导开发，并理所当然地认为能够
在业务部门取得良好的应用效果。这样的项目由于得不到业务部门的理解和支持，脱离业务需求，多数面临失败或半途而废的命运。<font face="宋体"><span lang="EN-US">&nbsp; <br><br></span>　
　软件项目的立项，应由软件的需求单位根据自身业务的工作需要，向信息技术管理部门提出软件项目的立项建议，对立项目的、业务需求范围、技术经济指标、开
发周期要求等方面做简要概述，由信息技术管理部门组织业务专家和信息技术专家组成联合专家组，进行项目立项的可行性论证。</font><font face="宋体"><span lang="EN-US">&nbsp; <br><br></span>　
　通过专家组论证审核后，项目提出单位需要进行开题设计，进一步明确软件开发范围、技术路线、进度安排、经费预算、研究人员组成、合作队伍，并以此为基础
编制完成开题设计书。信息技术管理部门组织专家组对开题设计进行论证，只有业务需求合理、技术路线可行、开发队伍落实的项目，才能通过专家组审核，进入项
目启动阶段。</font><font face="宋体"><span lang="EN-US">&nbsp; <br></span><span style="color: white;">项目管理者联盟，项目管理问题。</span></font><span lang="EN-US"><br></span>　　《需求分析说明书》是对软件开发范围的书面表达依据。由于《需求分析说明书》往往是采用软件设计的术语编写，因此常常令计算机背景知识较少的业务需求方难以理解，也就很难发现需求报告中与实际需求不符之处，更难提出建设性的意见。<font face="宋体"><span lang="EN-US">&nbsp; <br><br></span>　
　软件监督要对软件开发范围进行管理，首先要确定双方都能认可的《需求分析说明书》。在软件开发过程中，双方应严格按照签字确认的《需求分析说明书》中规
定的业务范围进行开发。有些需求可能在项目初期很难确定，在开发过程中需要不断地加以修正，项目软件监督要及时与用户充分沟通，建立可以直接联系的渠道，
共同进行需求确认，保证项目范围可控。<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 18pt;"><span style="font-size: 9pt; font-family: 宋体;" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 18.05pt;"><b style=""><span style="font-size: 9pt; font-family: 宋体;">适时督导，掌控进度</span></b><span style="font-size: 9pt; font-family: 宋体;" lang="EN-US">&nbsp; <br><br></span><span style="font-size: 9pt; font-family: 宋体;">　　软件开发项目具有建设范围难界定、技术含量高、人员流动快、协作性强、开发成功率低等特点，在目前国内对软件项目的监理制度尚未普及，对软件开发仍然缺乏有效控制的情况下，由企业的信息技术管理部门设立软件监督岗位，加强对软件项目的开发过程管理，就显得尤为重要。<font face="宋体"><span lang="EN-US">&nbsp; <span style="color: white;">http://bbs.mypm.net</span><br><br></span>　　软件监督的主要职责是在项目进行过程中，协调业务需求部门和软件开发方的关系，监控软件开发任务的执行情况，给开发人员和管理层提供反映软件过程质量的信息和数据，提高项目透明度，从而保证项目按照计划实施，实现预期目标。</font><font face="宋体"><span lang="EN-US">&nbsp; <br><br></span>　　所选的软件监督人员应具备<span lang="EN-US">3</span>方面基本素质：具有较强的工作责任感和良好的沟通能力<span lang="EN-US">;</span>熟悉业务管理流程，掌握软件开发流程、开发规范以及相关标准<span lang="EN-US">;</span>具有软件开发项目的建设和管理经验，掌握项目管理知识。</font><font face="宋体"><span lang="EN-US">&nbsp; <br><br></span>　　监督人员除了监督职责外，还应该协调各个部门对软件进度及时调整。为确保项目按时、按量、按质完成，督导人员必须控制任务和跟踪里程碑。按照软件项目的开发规律，将软件开发过程分为几个重要阶段，对这几个阶段的关键事件设立里程碑进行跟踪管理。<span lang="EN-US"><o:p></o:p></span></font></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 18pt;"><span style="font-size: 9pt; font-family: 宋体;" lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; text-indent: 18pt;"><span style="font-size: 9pt; font-family: 宋体;">项目进度管理可以通过以下方式完成：制定项目里程碑管理运行表<font face="宋体"><span lang="EN-US">(</span>见下<span lang="EN-US">);</span>定期举行项目状态会议，由软件开发方报告进度和问题，用户方提出意见<span lang="EN-US">;</span>比较各项任务的实际开始日期与计划开始日期是否吻合<span lang="EN-US">;</span>确定正式的项目里程碑是否在预期完成。</font><font face="宋体"><span lang="EN-US">&nbsp; <br><br></span>　　当然，软件开发不像加工螺钉、螺母，有具体的标准和检验方法。软件的标准柔性很大，往往在用户的心里，用户好用是软件成功的标准，而这个标准在软件开发前很难确切地、完整地表达出来。因此，开发过程项目组和用户的沟通互动是解决这一现实问题的最好办法。</font><font face="宋体"><span lang="EN-US">&nbsp; <br><br></span>　　<strong><span style="color: black; font-family: 宋体;">把握要点，有效验收<span lang="EN-US">&nbsp; </span></span></strong></font><b><span lang="EN-US"><br></span></b><span style="color: white;" lang="EN-US"><font face="宋体">http://blog.mypm.net</font></span><span lang="EN-US"><br></span>　　软件验收应是一个循环渐进的述程，包括验收前的系统测试、系统上线和正式验收<font face="宋体"><span lang="EN-US">3</span>个阶段。</font><font face="宋体"><span lang="EN-US">&nbsp; <br><br></span>　　系统测试：系统测试是对系统进行全面的测试，应在测试环境中进行，以确保系统的功能和技术设计满足企业的业务需求，并能正常运行。系统测试阶段应包括以下主要流程和工作内容：制订测试计划，编制测试用例，建立测试环境<span lang="EN-US">;</span>测试：在测试环境中，项目组根据需要，对系统依次进行单元测试、集成测试、压力测试和用户接受测试<span lang="EN-US">;</span>提交测试报告、用户确认签字：项目组撰写测试报告，将测试报告提交给各相关用户，用户应在测试报告上签字确认。</font><font face="宋体"><span lang="EN-US">&nbsp; <br><br></span>　　系统上线：<span lang="EN-US">&nbsp;</span>系统上线前应做好准备工作，在上线前，软件监督要组织软件开发方制定系统上线计划，系统上线计划应经过信息技术部门和业务部门管理层的正式批准，并通知各相关部门。</font><font face="宋体"><span lang="EN-US">&nbsp; <br><br></span>　　所有的上线准备工作做好之后，由软件监督确认上线系统版本正确性后，与用户确认系统上线时间，下达上线指令。系统上线操作人员将最后版本的系统程序移植到生产环境。</font><font face="宋体"><span lang="EN-US">&nbsp; <br><br></span>　
　正式验收：正式验收前，软件开发方应向信息技术管理部门提交软件开发过程中各阶段性文档，包括需求分析说明书、概要设计说明书、详细设计说明书、数据库
设计说明书、源程序代码、可供安装使用的系统安装程序、系统管理员手册、用户使用手册、测试计划、测试报告、用户报告、数据移植计划及报告、系统上线计划
及报告、用户意见书、验收申请等。</font><font face="宋体"><span lang="EN-US">&nbsp; <br><br></span>　　信息技术管理部门接到验收申请后，组织专家对项目进行初审。初审通过后，组织管理层领导、业务管理人员和信息技术专家成立项目验收委员会，负责对软件项目进行正式验收。</font><font face="宋体"><span lang="EN-US">&nbsp; <br><br></span>　
　软件监督应根据软件开发方在整个软件开发过程中的表现，向验收委员会提出全面的软件监督报告，并根据开题设计书、软件开发合同以及《需求分析说明书》，
制定验收标准，提交验收委员会。信息技术管理部门组织由验收委员会、软件监督、软件开发方参加的项目验收会，软件开发方以项目汇报、现场应用演示等方式汇
报项目完成情况，验收委员会根据验收标准对项目进行评审，形成最终验收意见。<span lang="EN-US"><o:p></o:p></span></font></span></p> 
      
      
        ]]></description>
<pubDate>
2008-08-11 13:11:00.0</pubDate>
<guid>
http://thomasyangch.blogcn.com/diary,18712261.shtml</guid>
<comments>
http://thomasyangch.blogcn.com/diary,18712261.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[200381637]]></blogcn_uid>
<title>
<![CDATA[Tomcat服务器配置参考[转载]]]></title>
<link>
http://thomasyangch.blogcn.com/diary,18112630.shtml</link>
<description>
<![CDATA[<TABLE cellSpacing=4 width="100%" border=0>
<TBODY>
<TR>
<TD vAlign=top align=left true="">
<H2>Tomcat服务器配置参考</H2>
<H3>Valve组件</H3></TD>
<TD vAlign=top align=right true=""><IMG height=1 hspace=0 src="http://www.cnjsp.org/document/images/void.gif" width=1 border=0></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=2 border=0>
<TBODY>
<TR>
<TD bgColor=#525d76><FONT face=arial,helvetica.sanserif color=#ffffff><A name=Introduction><STRONG>概述</STRONG></A></FONT></TD></TR>
<TR>
<TD vAlign=top>
<BLOCKQUOTE>
<P>Valve元素是插入在Catalina容器（包括Engine,Host或者Context）处理流程中的组件。不同的组件有不同的处理能力。下面将对每个Valve组件进行描述</P><I>以下的描述使用变量</I><EM>$CATALINA_HOME来指Tomcat 5安装的目录。大多数的相对路径都是以该目录为基准。但是，通过设置CATALINA_BASE目录，可以运行多个Tomcat 5实例，这时你应该使用$CATALINA_BASE来作为目录基准，而不是使用$CATALINA_HOME。</EM> </BLOCKQUOTE></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=2 border=0>
<TBODY>
<TR>
<TD vAlign=top bgColor=#525d76><FONT face=arial,helvetica.sanserif color=#ffffff><A name="Access Log Valve"><STRONG>访问日志Valve</STRONG></A></FONT></TD></TR>
<TR>
<TD>
<BLOCKQUOTE>
<TABLE cellSpacing=0 cellPadding=2 border=0>
<TBODY>
<TR>
<TD bgColor=#828da6><FONT face=arial,helvetica.sanserif color=#ffffff><A name=Introduction><STRONG>概述</STRONG></A></FONT></TD></TR>
<TR>
<TD vAlign=top>
<BLOCKQUOTE>
<P>Access Log Valve用来创建日志文件，格式与标准的web server日志文件相同。可以使用用日志分析工具对日志进行分析，跟踪页面点击次数、用户会话的活动等。Access Log Valve的很多配置和行为特性与File Logger相同，包括每晚午夜自动切换日志文件。Access Log Valve可以和任何Catalina容器关联，记录该容器处理的所有请求。</P></BLOCKQUOTE></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=2 border=0>
<TBODY>
<TR>
<TD bgColor=#828da6><FONT face=arial,helvetica.sanserif color=#ffffff><A name=Attributes><STRONG>属性</STRONG></A></FONT></TD></TR>
<TR>
<TD vAlign=top>
<BLOCKQUOTE>
<P>Access Log Valve支持如下配置属性：</P>
<TABLE cellPadding=5 border=1>
<TBODY>
<TR>
<TH width="15%" bgColor=#023264><FONT color=#ffffff>属性</FONT></TH>
<TH width="85%" bgColor=#023264><FONT color=#ffffff>描述</FONT></TH></TR>
<TR>
<TD vAlign=center align=left><STRONG><CODE>className</CODE></STRONG></TD>
<TD vAlign=center align=left>
<P>实现的Java类名。必须被设置成org.apache.catalina.valves.AccessLogValve。</P></TD></TR>
<TR>
<TD vAlign=center align=left><CODE>directory</CODE></TD>
<TD vAlign=center align=left>
<P>存放日志文件的目录，可以是相对路径或者绝对路径。如果使用相对路径，是指相对于 $CATALINA_HOME的路径。如果不指定directory属性，缺省值是“logs”（相对于 $CATALINA_HOME）</P></TD></TR>
<TR>
<TD vAlign=center align=left><CODE>pattern</CODE></TD>
<TD vAlign=center align=left>
<P>需要记录的请求/响应不同信息域的格式布局。如果是“common”或者“combine”，说明选择标准格式。下面会有关于配置这个属性的更多信息。</P></TD></TR>
<TR>
<TD vAlign=center align=left><CODE>prefix</CODE></TD>
<TD vAlign=center align=left>
<P>日志文件名的前缀。如果没有指定，缺省值是“access_log.”。如果不想使用前缀，使用长度为0的字符串。</P>
<P>&nbsp;</P></TD></TR>
<TR>
<TD vAlign=center align=left><CODE>resolveHosts</CODE></TD>
<TD vAlign=top align=left>
<P>将远端主机的IP地址通过DNS查询转换成主机名，设为true。如果为false，忽略DNS查询，报告远端的IP地址。</P>
<P>&nbsp;</P></TD></TR>
<TR>
<TD vAlign=center align=left><CODE>suffix</CODE></TD>
<TD vAlign=top align=left>
<P>日志文件名的后缀。如果没有指定，缺省值是“”。如果不想使用后缀，使用长度为0的字符串。</P>
<P>&nbsp;</P></TD></TR>
<TR>
<TD vAlign=center align=left><CODE>rotatable</CODE></TD>
<TD vAlign=top align=left>
<P>缺省值为true，用来决定日志是否翻转的标志。如果为false，日志文件永远不翻转，并且忽略fileDataFormat。要谨慎使用。</P>
<P>&nbsp;</P></TD></TR>
<TR>
<TD vAlign=center align=left><CODE>condition</CODE></TD>
<TD vAlign=center align=left>
<P>打开条件日志。如果设置了这个属性，只有在ServletRequest.getAttribute()是null的时候，才会为请求创建日志。比如，如果 condition设为junk，则只有在Servlet.getAttribute("junk")==null的时候，才会记录这个请求。使用过滤器，可以很容易设置（或者取消设置）不同请求的属性。</P></TD></TR>
<TR>
<TD vAlign=center align=left><CODE>fileDateFormat</CODE></TD>
<TD vAlign=center align=left>允许在日志文件名称中使用定制的日期格式。日志的格式也决定了日志文件翻转的频率。如果想每个小时翻转一次，将这个值设为yyyy-MM-dd.HH</TD></TR></TBODY></TABLE>
<P>pattern属性值由字符串常量和pattern标识符加上前缀"%"组合而成。pattern标识符加上前缀"%"，用来代替当前请求/响应中的对应的变量值。目前支持如下的pattern：</P>
<UL>
<LI><B>%a</B> - 远端IP地址 
<LI><B>%A</B> - 本地IP地址 
<LI><B>%b</B> - 发送的字节数，不包括HTTP头，如果为0，使用"－" 
<LI><B>%B</B> - 发送的字节数，不包括HTTP头 
<LI><B>%h</B> - 远端主机名(如果resolveHost=false，远端的IP地址） 
<LI><B>%H</B> - 请求协议 
<LI><B>%l</B> - 从identd返回的远端逻辑用户名（总是返回 '-'） 
<LI><B>%m</B> - 请求的方法（GET，POST，等） 
<LI><B>%p</B> - 收到请求的本地端口号 
<LI><B>%q</B> - 查询字符串(如果存在，以 '?'开始) 
<LI><B>%r</B> - 请求的第一行，包含了请求的方法和URI 
<LI><B>%s</B> - 响应的状态码 
<LI><B>%S</B> - 用户的session ID 
<LI><B>%t</B> - 日志和时间，使用通常的Log格式 
<LI><B>%u</B> - 认证以后的远端用户（如果存在的话，否则为'-'） 
<LI><B>%U</B> - 请求的URI路径 
<LI><B>%v</B> - 本地服务器的名称 
<LI><B>%D</B> - 处理请求的时间，以毫秒为单位 
<LI><B>%T</B> - 处理请求的时间，以秒为单位</LI></UL>
<P>Access Log Valve还可以记录cookie，消息头，Session或者ServletRequest中的信息。使用与apache类似的语法： </P>
<UL>
<LI><B><CODE>%{xxx}i</CODE></B> 消息头 
<LI><B><CODE>%{xxx}c</CODE></B> 特定的cookie 
<LI><B><CODE>%{xxx}r</CODE></B> xxx 是ServletRequest中的某个属性 
<LI><B><CODE>%{xxx}s</CODE></B> xxx 是HttpSession中的某个属性</LI></UL>
<P>上面提到"common"模式（也是缺省的模式）实际上是<B>"%h %l %u %t "%r" %s %b"</B>的一种简单表示方法</P>
<P>"common"模式后面加上"Referer"和用户代理头<CODE>(User-Agent</CODE> headers)的信息，就是前面提到的"combined"模式。</P></BLOCKQUOTE></TD></TR></TBODY></TABLE></BLOCKQUOTE></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=2 border=0>
<TBODY>
<TR>
<TD bgColor=#525d76><FONT face=arial,helvetica.sanserif color=#ffffff><A name="Remote Address Filter"><STRONG>远端地址过滤器</STRONG></A>(Remote Address Filter)</FONT></TD></TR>
<TR>
<TD>
<BLOCKQUOTE>
<TABLE cellSpacing=0 cellPadding=2 border=0>
<TBODY>
<TR>
<TD bgColor=#828da6><FONT face=arial,helvetica.sanserif color=#ffffff><A name=Introduction><STRONG>概述</STRONG></A></FONT></TD></TR>
<TR>
<TD vAlign=top>
<BLOCKQUOTE>
<P>远端地址过滤器将发起请求的客户端的IP地址和一个或多个正则表达式进行比较，以决定接受或者拒绝这个请求。远端地址过滤器可以嵌套在任何Catalina容器中（Engine，Host或者Contxt）。在过滤器起作用之前，容器必须接受所有的请求。</P></BLOCKQUOTE></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=2 border=0>
<TBODY>
<TR>
<TD bgColor=#828da6><FONT face=arial,helvetica.sanserif color=#ffffff><A name=Attributes><STRONG>属性</STRONG></A></FONT></TD></TR>
<TR>
<TD>
<BLOCKQUOTE>
<P>远端地址过滤器支持如下的配置属性：</P>
<TABLE cellPadding=5 border=1>
<TBODY>
<TR>
<TH width="15%" bgColor=#023264><FONT color=#ffffff>属性</FONT></TH>
<TH width="85%" bgColor=#023264><FONT color=#ffffff>描述</FONT></TH></TR>
<TR>
<TD vAlign=center align=left><STRONG><CODE>className</CODE></STRONG></TD>
<TD vAlign=center align=left>
<P>实现的Java类名，必须设置成org.apache.catalina.valves.RemoteAddrValve.</P></TD></TR>
<TR>
<TD vAlign=center align=left><CODE>allow</CODE></TD>
<TD vAlign=top align=left>
<P>用逗号分开的一串正则表达式，客户端的IP地址与这些正则表达式进行比较。如果指定了这个属性，客户端的地址必须匹配这些表达式，其请求才会被处理。如果没有指定这个属性，所有的请求都被接受，除非客户端地址匹配了一个deny模式。</P></TD></TR>
<TR>
<TD vAlign=center align=left><CODE>deny</CODE></TD>
<TD vAlign=center align=left>
<P>用逗号分开的一串正则表达式，客户端的IP地址与这些正则表达式进行比较。如果指定了这个属性，客户端的地址一定不能匹配这些表达式，其请求才会被接受。如果没有指定这个属性，仅仅由"accept“属性决定是否接受这个请求。</P></TD></TR></TBODY></TABLE></BLOCKQUOTE></TD></TR></TBODY></TABLE></BLOCKQUOTE></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=2 border=0>
<TBODY>
<TR>
<TD bgColor=#525d76><FONT face=arial,helvetica.sanserif color=#ffffff><A name="Remote Host Filter"><STRONG>远端主机过滤器</STRONG></A>（Remote Host Filter）</FONT></TD></TR>
<TR>
<TD>
<BLOCKQUOTE>
<TABLE cellSpacing=0 cellPadding=2 border=0>
<TBODY>
<TR>
<TD bgColor=#828da6><FONT face=arial,helvetica.sanserif color=#ffffff><A name=Introduction><STRONG>概述</STRONG></A></FONT></TD></TR>
<TR>
<TD vAlign=top>
<BLOCKQUOTE>
<P>远端主机过滤器将发起请求的客户端的主机名和一个或者多个正则表达式进行比较，以决定接受或者拒绝这个请求。远端主机过滤器可以嵌套在任何Catalina容器中（Engine，Host或者Context）。在过滤器起作用之前，容器必须接受所有的请求。</P></BLOCKQUOTE></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=2 border=0>
<TBODY>
<TR>
<TD bgColor=#828da6><FONT face=arial,helvetica.sanserif color=#ffffff><A name=Attributes><STRONG>属性</STRONG></A></FONT></TD></TR>
<TR>
<TD>
<BLOCKQUOTE>
<P>远端主机过滤器支持如下属性：</P>
<TABLE cellPadding=5 border=1>
<TBODY>
<TR>
<TH width="15%" bgColor=#023264><FONT color=#ffffff>属性</FONT></TH>
<TH width="85%" bgColor=#023264><FONT color=#ffffff>描述</FONT></TH></TR>
<TR>
<TD vAlign=center align=left><STRONG><CODE>className</CODE></STRONG></TD>
<TD vAlign=center align=left>
<P>实现的Java类名，必须设为<STRONG>org.apache.catalina.valves.RemoteHostValve</STRONG>.</P></TD></TR>
<TR>
<TD vAlign=center align=left><CODE>allow</CODE></TD>
<TD vAlign=top align=left>
<P>用逗号分开的一串正则表达式，客户端的主机名与这些正则表达式进行比较。如果指定了这个属性，客户端的主机名必须匹配这些表达式，其请求才会被处理。如果没有指定这个属性，所有的请求都被接受，除非客户端主机名匹配了一个deny模式。</P></TD></TR>
<TR>
<TD vAlign=center align=left><CODE>deny</CODE></TD>
<TD vAlign=center align=left>用逗号分开的一串正则表达式，客户端的主机名与这些正则表达式进行比较。如果指定了这个属性，客户端的主机名一定不能匹配这些表达式，其请求才会被接受。如果没有指定这个属性，仅仅由"accept“属性决定是否接受这个请求。</TD></TR></TBODY></TABLE></BLOCKQUOTE></TD></TR></TBODY></TABLE></BLOCKQUOTE></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=2 border=0>
<TBODY>
<TR>
<TD bgColor=#525d76><FONT face=arial,helvetica.sanserif color=#ffffff><A name="Request Dumper Valve"><STRONG>Request Dumper Valve</STRONG></A></FONT></TD></TR>
<TR>
<TD>
<BLOCKQUOTE>
<TABLE cellSpacing=0 cellPadding=2 border=0>
<TBODY>
<TR>
<TD bgColor=#828da6><FONT face=arial,helvetica.sanserif color=#ffffff><A name=Introduction><STRONG>概述</STRONG></A></FONT></TD></TR>
<TR>
<TD vAlign=top>
<BLOCKQUOTE>
<P>Request Dumper Valve在调试与客户端的交互非常有用。如果配置，它会利用容器（Engine，Host或者Context）的Logger记录下每个请求的详细信息。</P></BLOCKQUOTE></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=2 border=0>
<TBODY>
<TR>
<TD bgColor=#828da6><FONT face=arial,helvetica.sanserif color=#ffffff><A name=Attributes><STRONG>属性</STRONG></A></FONT></TD></TR>
<TR>
<TD>
<BLOCKQUOTE>
<P><STRONG>Request Dumper Valve</STRONG>支持如下配置属性：</P>
<TABLE cellPadding=5 border=1>
<TBODY>
<TR>
<TH width="15%" bgColor=#023264><FONT color=#ffffff>属性</FONT></TH>
<TH width="85%" bgColor=#023264><FONT color=#ffffff>描述</FONT></TH></TR>
<TR>
<TD vAlign=center align=left><STRONG><CODE>className</CODE></STRONG></TD>
<TD vAlign=center align=left>
<P>实现的Java类名，必须设为<STRONG>org.apache.catalina.valves.RequestDumperValve</STRONG>.</P></TD></TR></TBODY></TABLE></BLOCKQUOTE></TD></TR></TBODY></TABLE></BLOCKQUOTE></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=2 border=0>
<TBODY>
<TR>
<TD bgColor=#525d76><FONT face=arial,helvetica.sanserif color=#ffffff><A name="Single Sign On Valve"><STRONG>单次登录Valve（Single Sign On Valve</STRONG></A>）</FONT></TD></TR>
<TR>
<TD>
<BLOCKQUOTE>
<TABLE cellSpacing=0 cellPadding=2 border=0>
<TBODY>
<TR>
<TD bgColor=#828da6><FONT face=arial,helvetica.sanserif color=#ffffff><A name=Introduction><STRONG>概述</STRONG></A></FONT></TD></TR>
<TR>
<TD>
<BLOCKQUOTE>
<P>如果希望用户可以登录到虚拟主机中的任意一个web应用，而且登录以后所有其他的web应用都能使用用户的身份信息（即不需要重新登录），就可以使用单次登录Valve。</P>
<P>在Host元素中有更多关于单次登录Valve的信息。</P></BLOCKQUOTE></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=2 border=0>
<TBODY>
<TR>
<TD bgColor=#828da6><FONT face=arial,helvetica.sanserif color=#ffffff><A name=Attributes><STRONG>属性</STRONG></A></FONT></TD></TR>
<TR>
<TD>
<BLOCKQUOTE>
<P>单次登录Valve支持如下的配置属性：</P>
<TABLE cellPadding=5 border=1>
<TBODY>
<TR>
<TH width="15%" bgColor=#023264><FONT color=#ffffff>属性</FONT></TH>
<TH width="85%" bgColor=#023264><FONT color=#ffffff>描述</FONT></TH></TR>
<TR>
<TD vAlign=center align=left><STRONG><CODE>className</CODE></STRONG></TD>
<TD vAlign=center align=left>
<P>实现的Java类名，必须设为：<STRONG>org.apache.catalina.authenticator.SingleSignOn</STRONG>.</P></TD></TR>
<TR>
<TD vAlign=center align=left><CODE>debug</CODE></TD>
<TD vAlign=center align=left>
<P>这个组件的调试信息的详细程度，缺省值为0，即没有调试输出。</P></TD></TR></TBODY></TABLE></BLOCKQUOTE></TD></TR></TBODY></TABLE></BLOCKQUOTE></TD></TR></TBODY></TABLE><!--FOOTER SEPARATOR-->]]></description>
<pubDate>
2008-07-25 14:20:00.0</pubDate>
<guid>
http://thomasyangch.blogcn.com/diary,18112630.shtml</guid>
<comments>
http://thomasyangch.blogcn.com/diary,18112630.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[200381637]]></blogcn_uid>
<title>
<![CDATA[微笑是一种修养]]></title>
<link>
http://thomasyangch.blogcn.com/diary,18061042.shtml</link>
<description>
<![CDATA[<font style="color: rgb(0, 0, 153);" size="4" face="楷体_GB2312"><span style="text-decoration: underline;"></span>&nbsp;&nbsp;&nbsp;&nbsp; 生活并没有拖欠我们任何东西，所以没有必要总苦着脸。应对生活充满感激，至少，它给了我们生命，给了我们生存的空间。</font>
<p style="color: rgb(0, 0, 153);"><font size="4" face="楷体_GB2312">　　微笑是对生活的一种态度，跟贫富，地位，处境没有必然的联系。一个富翁可能整天忧心忡忡，而一个穷人可能心情舒畅：一位残疾人可能坦然乐观；一位处境顺利的人可能会愁眉不展，一位身处逆境的人可能会面带微笑。。。。。。。</font></p>
<p style="color: rgb(0, 0, 153);"><font size="4" face="楷体_GB2312">　　　一个人的情绪受环境的影响，这是很正常的，但你苦着脸，一副苦大仇深的样子，对处境并不会有任何的改变，相反，如果微笑着去生活，那会增加亲和力，别人更乐于跟你交往，得到的机会也会更多。</font></p>
<p style="color: rgb(0, 0, 153);"><font size="4" face="楷体_GB2312">　　　只有心里有阳光的人，才能感受到现实的阳光，如果连自己都常苦着脸，那生活如何美好？生活始终是一面镜子，照到的是我们的影像，当我们哭泣时，生活在哭泣，当我们微笑时，生活也在微笑。</font></p>
<p style="color: rgb(0, 0, 153);"><font size="4" face="楷体_GB2312">　　 微笑发自内心，不卑不亢，既不是对弱者的愚弄，也不是对强者的奉承。奉承时的笑容，是一种假笑，而面具是不会长久的，一旦有机会，他们变会除下面具，露出本来的面目。</font></p>
<p style="color: rgb(0, 0, 153);"><font size="4" face="楷体_GB2312">　　 微笑没有目的，，无论是对上层，还是对门卫，那笑容都是一样，微笑是对他人的尊重，同时是对生活的尊重。微笑是有"回报"的，人际关系就像物理学上所说的力的平衡，你怎样对别人，别人就会怎样对你，你对别人的微笑越多，别人对你的微笑也会越多。</font></p>
<p style="color: rgb(0, 0, 153);"><font size="4" face="楷体_GB2312">　　 在受到别人的曲解后，可以选择暴怒，也可以选择微笑，通常微笑的力量会更大，因为微笑会震撼对方的心灵，显露出来的豁达气度让对方觉得自己渺小，丑陋。</font></p>
<p style="color: rgb(0, 0, 153);"><font size="4" face="楷体_GB2312">　　 清者自清，浊者自浊。有时候过多的解释、争执是没有必要的。对于那些无理取闹、蓄意诋毁的人，给他一个微笑，剩下的事就让时间去正证明好了。</font></p>
<p style="color: rgb(0, 0, 153);"><font size="4" face="楷体_GB2312">　　 当年，有人出说说爱因斯坦的理论错了，并且说有一百位科学家联合作证，爱因斯坦知道了这件事，只是淡淡的笑了笑，说，一百位？要这么多人？只要证明我真的错了，一个人出面便行了。</font></p>
<p style="color: rgb(0, 0, 153);"><font size="4" face="楷体_GB2312">　&nbsp; 爱因斯坦的理论经历了时间的考验，而那些人却被一个微笑打败了。</font></p>
<p style="color: rgb(0, 0, 153);"><font size="4" face="楷体_GB2312">　&nbsp; 微笑发自内心，无法伪装。保持"微笑"的心态，人生</font><font size="4" face="楷体_GB2312">会更加美好。人生中有挫折有失败，有误解，那是很正常的，要想生活中一片坦途，那么首先就应清除心中的障碍。微笑的实质便是爱uyige懂得爱的人，一定不会是平庸的。</font></p>
<p style="color: rgb(0, 0, 153);"><font size="4" face="楷体_GB2312">　&nbsp; 微笑是人生最好的名片，谁不希望跟一个乐观向上的人交朋友呢？微笑能给自己一种信心，也能给别人一种信心，从而更好地激发潜能。</font></p>
<p style="color: rgb(0, 0, 153);"><font size="4" face="楷体_GB2312">　　微笑是朋友间最好的语言，一个自然流露的微笑，胜过千言万语，无论是初次谋面也好，相识已久也好，微笑能拉近人与人之间的距离，另彼此之间倍感温暖。</font></p>
<p style="color: rgb(0, 0, 153);"><font size="4" face="楷体_GB2312">　　微笑是一种修养，并且是一种很重要的修养，微笑的实质是亲切，是鼓励，是温馨。真正懂得微笑的人，总是容易活得比别更多的机会，总是容易取得成功。 </font></p>]]></description>
<pubDate>
2008-07-24 12:58:00.0</pubDate>
<guid>
http://thomasyangch.blogcn.com/diary,18061042.shtml</guid>
<comments>
http://thomasyangch.blogcn.com/diary,18061042.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[200381637]]></blogcn_uid>
<title>
<![CDATA[谈常见的十大人力资源管理浪费 ]]></title>
<link>
http://thomasyangch.blogcn.com/diary,17813817.shtml</link>
<description>
<![CDATA[<STRONG>&nbsp; </STRONG>最近下载了余世维先生在正泰讲的视频，其中他讲到了有关人力资源管理的问题，他说了一个很搞笑的事情。一个月薪4万元的女员工因为怀孕，公司需要找人替代她的工作。主管向总经理报告此事时，希望能在外面招聘一个新员工以替代那位女员工的工作。但是总经理给的答案居然是：在公司内部提拔四个人，将该女职员的工作分配给这四人，然后每人加5千。余先生谈的这个问题主要想说：企业其实没有真正完全使用自己的员工，存在着人力资源管理的浪费。<BR>&nbsp;&nbsp; 下面我们主要谈谈常见的十大人力资源管理浪费问题。<BR><STRONG>一 没有将合适的人放在合适的岗位上</STRONG>　 
<DIV>　&nbsp; 这是企业中最常见的一种人力资源浪费，我们通常说一个萝卜一个坑，但是这里存在三种情况：第一种，坑大萝卜小，也就是说，对能力差的员工委以重任，结果通常是工作任务不能有效完成，企业受到损失，员工自信心受到了打击，工作没有了积极性和动力，也就是所谓的拔苗助长；第二种，坑小萝卜大，那么该员工的能力没有被充分的发挥出来，所谓大材小用，造成了人才的浪费，要么导致人才流失，要么企业要多付薪水；第三种，坑和萝卜一样大，这是最合适不过的了，只有做到这种情况才没有造成人力资源的浪费。<BR>　　解决这个问题要考虑两个方面的影响因素。第一，企业是否通过有效的组织设计和岗位分析来建立有效的岗位体系，也就是通常说的的“坑”；第二，企业是否能准确的对员工进行有效的衡量和评价，也就是“萝卜”。企业完成了上述两项基础工作，才能有效地将合适的人放到合适的岗位上。当然，上面的阐述表达的是静态的状况，企业是不断的发展壮大的，只有根据企业的发展状况不断调整组织和岗位要求，调整坑的大小，才能保证人力资源的最有效利用。<BR><BR><STRONG>二 不懂得培养员工</STRONG><BR>　　不懂得培养员工是另一种常见的浪费。很多管理者以为，培养员工的投入太大，而且往往效果不甚明显，有些时候，公司辛辛苦苦培养的员工，却被别的公司挖了墙角，有点太不值了。<BR>　　实际上，这仅仅是事物的一个表面。我们可以盘点一下，由于没有有效的培养员工会给企业带来哪些浪费。<BR>　　首先，员工的工作技能得不到有效改善，工作任务不能有效、快速的完成，为了完成既定的工作目标，需要增加更多的人手；<BR>　　第二，增加了很多犯错误的机会，尤其是犯同样的错误；<BR>　　第三，扼杀了组织的创新意识和创新能力，实际上很多创新行为是在不断的培训和学习中产生的；<BR>　　第四，导致消极心态，影响团队氛围，影响执行力，降低员工之间的竞争压力；<BR>　　……<BR>　　企业为这些负面影响支付的费用，要比培训花费大的多！<BR><STRONG><BR>三 管理的各个模块没有有效整合</STRONG><BR>　　企业人力资源部门往往是按照薪酬、绩效、招聘、培训、人事等模块进行职位设置的，这种按照职能模块进行划分的方式，降低了管理难度，提高了管理的效率，但是却极易导致人力资源成本的增加。<BR>　　我们知道，人力资源管理的各个模块之间是相互影响、相互联系的。比如，过度的控制员工的工资水平，往往会导致不容易招聘到合适的员工，使招聘、培训的成本增加；为了增加绩效考核的缜密性和公平性，而提高了考核工作的复杂程度，导致人工成本增加。类似的情况在企业中屡见不鲜，实际上是管理过程中缺乏系统性、整合性造成的。<BR><STRONG><BR>四 没有绩效管理</STRONG><BR>　　引用管理的一句名言——没有绩效管理的企业就等于没有管理，来说明绩效对企业来说的重要意义。<BR>　　由于没有绩效管理给企业会带来什么样的浪费呢？<BR>　　首先，组织和员工的工作是在没有方向、没有目标的状态下进行的，那么，白忙乎、南辕北辙的情况会时有发生，这大大提高了人工成本和机会成本；<BR>　　其次，各项工作的开展，是在失控的状态下进行的，大大提高了出现错误的机率；<BR>　　第三，在没有绩效管理的前提下，要有效的完成工作，就必须增加沟通的次数，影响了工作效率，丧失了市场机遇。<BR><STRONG><BR>五 只依靠加班解决人员紧缺问题</STRONG><BR>　　加班所带来的负面影响是显而易见的。加班使公司支付更多的工资，增加了更多的管理成本（一般情况，一个部门的员工加班，都会影响到相关部门的工作，比如增加职能服务部门的工作压力）；员工对加班也大多抱着抵触的情绪，笔者以前在一家高技术企业的调查显示，加班时间内的员工的工作效率还达不到平时的一半。另外，加班影响了员工的正常休息的权利，影响了员工身体和心理健康，对员工的家人也会造成影响。有一家IT企业由于加班成了家常便饭，公司内有很大一部分大龄员工还是单身，用员工的话说，我目前的工作状态，是没有人愿意和我生活在一起的。<BR>　　实际上，除了加班之外，我们还有很多更有效的办法来解决人员紧缺的问题。比如，通过业务外包、雇佣临时人员、增加人员储备等办法。另外，企业在对待加班频繁的问题时，首先必须理清造成加班的本质原因是什么。比如，是否由于组织设计和流程问题，导致工作不顺畅、效率低下，如果是这样的问题，那么首要解决的不是加班的问题，而是组织设计和流程再造的问题。<BR>　　笔者在从事咨询的过程中，也接触过一种很有意思、也很可悲的现象。A公司加班现象严重，但我们了解员工的工作任务并不饱满。经我们仔细研究发现，由于公司严格执行劳动法规定的加班工资制度，但是却在加班审批的环节把关不严，导致员工在正常工作时间不好好完成工作，而去争取加班，骗取更多的加班工资。实际上这类现象是由制度本身造成的问题，这样的问题加再多的班也是没有办法解决的。<BR><STRONG><BR>六 只有惩罚没有奖励</STRONG><BR>　　可能有人会问，奖励不是增加成本吗？实际上，我们看问题不能局限于短期的局部，应该系统的分析问题。我不想拿企业管理中的例子来说明这个问题到底给企业带来什么样的影响，只想拿我们周围生活中常见的现象来说明这个问题。<BR>　　望子成龙、望女成凤是家长的共同心愿，但是教育的方式不同，结果却大相径庭。一般说来，以鼓励、引导方式来教育孩子的，孩子成才的概率要远远大于以惩罚为主的教育方式。实际上，这个规律在企业中也同样适用，因为这就是人的本性。<BR><STRONG><BR>七 职责不够明确</STRONG><BR>　　笔者在给企业做内训的时候，喜欢做这样一个小测试：找出一名员工和他的直接上级，要求两个人用一句话描述该员工所在职位的职责概述。几乎是100%的情况，两个人的回答是有差异的。当然这是可以理解的，毕竟每个人看待事物的观点是有差异的，但是如果两个人回答的结果差异很大，则说明企业在职责管理上出现了问题。<BR>　　这种差异，造成了隐性的人力资源管理浪费。试想，员工工作的目标、工作的内容、工作的标准和秉承的原则与管理者是有差异的，那么，为了实现既定的组织目标，管理者要投入更多的精力去指导、控制、沟通、协调下属的工作，这既增加了管理的成本，又降低了工作效率。而理想的状态是，管理者和员工对员工所在职位的描述不存在任何的差异。<BR><STRONG><BR>八 稀里糊涂招聘</STRONG><BR>　　很多企业在招聘的时候，都使用这三板斧——打广告、筛简历、面试一气呵成，倒也简单。打广告的时候稀里糊涂，不懂得策划和设计；筛简历时看看学历，看看经验；面试的时候，则来也匆匆、去也匆匆，不做任何准备，不经任何讨论。实际上，企业对招聘不重视，带来的负面影响是深远的和显而易见的。<BR>　　由于招聘管理不科学带来的负面影响包括：<BR>　　第一，增加了员工流失的可能，招聘过程不科学，企业和求职者双方了解不彻底，增加了员工流失的可能性；<BR>　　第二，增加了人员培训和管理的成本，对求职者考察的不全面，能力达不到公司的要求，势必要增加培训成本和管理成本；<BR>　　第三，存在商业风险。<BR><STRONG><BR>九 不注重文化建设</STRONG><BR>　　笔者把不注重文化建设的企业分成两类：一类是企业没有文化建设，顺其自然，这一般是中小企业；另一类是企业培养一种傀儡式文化，也就是说，文化建设浮于表面，表面一套背后一套。笔者认为傀儡式文化比顺其自然的文化对企业的危害更大。<BR>　　文化就是企业的灵魂，企业沉浮于商海，就好比是战场上的军队一样，军队没有军魂，就不会赢得战争，企业没有文化就不会持续生存。因此我们讨论企业文化就不能简单地与人力资源成本联系起来，应以更大的视野，着眼于企业的核心竞争力和持续发展。<BR><STRONG><BR>十 不懂得利用业务外包</STRONG><BR>　　与所有的业务外包一样，提供人力资源外包服务的企业，必须想尽办法为客户提供更优质、更专业的服务，而且保证成本更低，否则这个行业就不可能生存。企业如果明白这个道理，就会懂得，把部分人力资源管理的业务进行外包是一个既经济又高效的办法。<BR>　　目前，人力资源外包业务包括，管理咨询、数据调查、代理招聘、人事外包等等。当然目前，在国内提供外包业务的公司良莠不齐，企业在选择外包服务商时还是要选择市场信誉较好、知名度高的单位作为合作方。</DIV>]]></description>
<pubDate>
2008-07-17 06:18:00.0</pubDate>
<guid>
http://thomasyangch.blogcn.com/diary,17813817.shtml</guid>
<comments>
http://thomasyangch.blogcn.com/diary,17813817.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[200381637]]></blogcn_uid>
<title>
<![CDATA[浅谈C中的malloc和free]]></title>
<link>
http://thomasyangch.blogcn.com/diary,17762635.shtml</link>
<description>
<![CDATA[<div style="color: rgb(0, 0, 153);" id="blog_text" class="cnt">
<p style="text-indent: 2em;"><font size="2">在
C语言的学习中，对内存管理这部分的知识掌握尤其重要！之前对C中的malloc()和free()两个函数的了解甚少，只知道大概该怎么用——就是
malloc然后free就一切OK了。当然现在对这两个函数的体会也不见得多，不过对于本文章第三部分的内容倒是有了转折性的认识，所以写下这篇文章作为一个对知识的总结。这篇文章之所以命名中有个“浅谈”的字眼，也就是这个意思了！希望对大家有一点帮助！</font></p>
<p style="text-indent: 2em;"><font size="2">如果不扯得太远的话（比如说操作系统中虚拟内存和物理内存如何运做如何管理之类的知识等），我感觉这篇文章应该是比较全面地谈了一下malloc()和free().这篇文章由浅入深（不见得有多深）分三个部分介绍主要内容。</font></p>
<p style="text-indent: 2em;"><font size="2">废话了那么多，下面立刻进入主题================》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》</font></p>
<p style="text-indent: 2em;"><font size="2">一、malloc()和free()的基本概念以及基本用法：</font></p>
<p style="text-indent: 2em;"><font size="2">1、函数原型及说明：</font></p>
<p style="text-indent: 2em;"><font size="2">void *malloc(long NumBytes)：该函数分配了NumBytes个字节，并返回了指向这块内存的指针。如果分配失败，则返回一个空指针（NULL）。</font></p>
<p style="text-indent: 2em;"><font size="2">关于分配失败的原因，应该有多种，比如说空间不足就是一种。</font></p>
<p style="text-indent: 2em;"><font size="2">void free(void *FirstByte)： 该函数是将之前用malloc分配的空间还给程序或者是操作系统，也就是释放了这块内存，让它重新得到自由。</font></p>
<p style="text-indent: 2em;"><font size="2">2、函数的用法：</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其实这两个函数用起来倒不是很难，也就是malloc()之后觉得用够了就甩了它把它给free()了，举个简单例子：</font></p>
<p style="text-indent: 2em;"><font size="2">程序代码：</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Code... </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char *Ptr = NULL; </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Ptr = (char *)malloc(100 * sizeof(char)); </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (NULL == Ptr) </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp; { </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exit (1); </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp; } </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gets(Ptr); </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // code... </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; free(Ptr); </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Ptr = NULL; </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // code...</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp; 就是这样！当然，具体情况要具体分析以及具体解决。比如说，你定义了一个指针，在一个函数里申请了一块内存然后通过函数返回传递给这个指针，那么也许释放这块内存这项工作就应该留给其他函数了。</font></p>
<p style="text-indent: 2em;"><font size="2">3、关于函数使用需要注意的一些地方：</font></p>
<p style="text-indent: 2em;"><font size="2">A、申请了内存空间后，必须检查是否分配成功。</font></p>
<p style="text-indent: 2em;"><font size="2">B、当不需要再使用申请的内存时，记得释放；释放后应该把指向这块内存的指针指向NULL，防止程序后面不小心使用了它。</font></p>
<p style="text-indent: 2em;"><font size="2">C、这两个函数应该是配对。如果申请后不释放就是内存泄露；如果无故释放那就是什么也没有做。释放只能一次，如果释放两次及两次以上会</font></p>
<p style="text-indent: 2em;"><font size="2">出现错误（释放空指针例外，释放空指针其实也等于啥也没做，所以释放空指针释放多少次都没有问题）。</font></p>
<p style="text-indent: 2em;"><font size="2">D、虽然malloc()函数的类型是(void *),任何类型的指针都可以转换成(void *),但是最好还是在前面进行强制类型转换，因为这样可以躲过一</font></p>
<p style="text-indent: 2em;"><font size="2">些编译器的检查。</font></p>
<p style="text-indent: 2em;"><font size="2">好了！最基础的东西大概这么说！现在进入第二部分：</font></p>
<p style="text-indent: 2em;"><font size="2">二、malloc()到底从哪里得来了内存空间：</font></p>
<p style="text-indent: 2em;"><font size="2">1、malloc()到底从哪里得到了内存空间？答案是从堆
里面获得空间。也就是说函数返回的指针是指向堆里面的一块内存。操作系统中有一个记录空闲内存地址的链表。当操作系统收到程序的申请时，就会遍历该链表，
然后就寻找第一个空间大于所申请空间的堆结点，然后就将该结点从空闲结点链表中删除，并将该结点的空间分配给程序。就是这样！</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp; 说到这里，不得不另外插入一个小话题，相信大家也知道是什么话题了。什么是堆？说到堆，又忍不住说到了栈！什么是栈？下面就另外开个小部分专门而又简单地说一下这个题外话：</font></p>
<p style="text-indent: 2em;"><font size="2">2、什么是堆：堆是大家共有的空间，分全局堆和局部堆。全局堆就是所有没有分配的空间，局部堆就是用户分配的空间。堆在操作系统对进程 初始化的时候分配，运行过程中也可以向系统要额外的堆，但是记得用完了要还给操作系统，要不然就是内存泄漏。</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;
什么是栈：栈是线程独有的，保存其运行状态和局部自动变量的。栈在线程开始的时候初始化，每个线程的栈互相独立。每个函数都有自己的栈，栈被用来在函数之
间传递参数。操作系统在切换线程的时候会自动的切换栈，就是切换SS/ESP寄存器。栈空间不需要在高级语言里面显式的分配和释放。 </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp; 以上的概念描述是标准的描述，不过有个别语句被我删除，不知道因为这样而变得不标准了^_^.</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp; 通过上面对概念的描述，可以知道：</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp; 栈是由编译器自动分配释放，存放函数的参数值、局部变量的值等。操作方式类似于数据结构中的栈。</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp; 堆一般由程序员分配释放，若不释放，程序结束时可能由OS回收。注意这里说是可能，并非一定。所以我想再强调一次，记得要释放！</font></p>
<p style="text-indent: 2em;"><font size="2">注意它与数据结构中的堆是两回事，分配方式倒是类似于链表。（这点我上面稍微提过）</font></p>
<p style="text-indent: 2em;"><font size="2"> 所以，举个例子，如果你在函数上面定义了一个指针变量，然后在这个函数里申请了一块内存让指针指向它。实际上，这个指针的地址是在栈上，但是它所指向的内容却是在堆上面的！这一点要注意！所以，再想想，在一个函数里申请了空间后，比如说下面这个函数：</font></p>
<p style="text-indent: 2em;"><font size="2">程序代码：</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp; // code... </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void Function(void) </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char *p = (char *)malloc(100 * sizeof(char)); </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp; }</font></p>
<p style="text-indent: 2em;"> </p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp; 就这个例子，千万不要认为函数返回，函数所在的栈被销毁指针也跟着销毁，申请的内存也就一样跟着销毁了！这绝对是错误的！因为申请的内存在堆上，而函数所在的栈被销毁跟堆完全没有啥关系。所以，还是那句话：记得释放！</font></p>
<p style="text-indent: 2em;"><font size="2">3、free()到底释放了什么</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;
这个问题比较简单，其实我是想和第二大部分的题目相呼应而已！哈哈！free()释放的是指针指向的内存！注意！释放的是内存，不是指针！这点非常非常重
要！指针是一个变量，只有程序结束时才被销毁。释放了内存空间后，原来指向这块空间的指针还是存在！只不过现在指针指向的内容的垃圾，是未定义的，所以说
是垃圾。因此，前面我已经说过了，释放内存后把指针指向NULL，防止指针在后面不小心又被解引用了。非常重要啊这一点！</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp; 好了！这个“题外话”终于说完了。就这么简单说一次，知道个大概就可以了！下面就进入第三个部分：</font></p>
<p style="text-indent: 2em;"><font size="2">三、malloc()以及free()的机制：</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp; 这个部分我今天才有了新的认识！而且是转折性的认识！所以，这部分可能会有更多一些认识上的错误！不对的地方请大家帮忙指出！</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp; 事实上，仔细看一下free()的函数原型，也许也会发现似乎很神奇，free()函数非常简单，只有一个参数，只要把指向申请空间的指针传递</font></p>
<p style="text-indent: 2em;"><font size="2">给free()中的参数就可以完成释放工作！这里要追踪到malloc()的申请问题了。申请的时候实际上占用的内存要比申请的大。因为超出的空间是用来记录对这块内存的管理信息。先看一下在《UNIX环境高级编程》中第七章的一段话：</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;
大多数实现所分配的存储空间比所要求的要稍大一些，额外的空间用来记录管理信息——分配块的长度，指向下一个分配块的指针等等。这就意味着如果写过一个已
分配区的尾端，则会改写后一块的管理信息。这种类型的错误是灾难性的，但是因为这种错误不会很快就暴露出来，所以也就很难发现。将指向分配块的指针向后移
动也可能会改写本块的管理信息。</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp; 以上这段话已经给了我们一些信息了。malloc()申请的空间实际我觉得就是分了两个不同性质的空间。一个就是用来记录管理信息的空间，另外一个就是可用空间了。而用来记录管理信息的实际上是一个结构体。在C语言中，用结构体来记录同一个对象的不同信息是</font></p>
<p style="text-indent: 2em;"><font size="2">天经地义的事！下面看看这个结构体的原型：</font></p>
<p style="text-indent: 2em;"><font size="2">程序代码：</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp; struct mem_control_block { </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp; int is_available;&nbsp;&nbsp;&nbsp;&nbsp; //这是一个标记？ </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp; int size;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //这是实际空间的大小 </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp; };</font></p>
<p style="text-indent: 2em;"> </p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp; 对于size,这个是实际空间大小。这里其实我有个疑问，is_available是否是一个标记？因为我看了free()的源代码之后对这个变量感觉有点纳闷（源代码在下面分析）。这里还请大家指出！</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;
所以，free()就是根据这个结构体的信息来释放malloc()申请的空间！而结构体的两个成员的大小我想应该是操作系统的事了。但是这里有一个问
题，malloc()申请空间后返回一个指针应该是指向第二种空间，也就是可用空间！不然，如果指向管理信息空间的话，写入的内容和结构体的类型有可能不
一致，或者会把管理信息屏蔽掉，那就没法释放内存空间了，所以会发生错误！（感觉自己这里说的是废话）</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp; 好了！下面看看free()的源代码，我自己分析了一下，觉得比起malloc()的源代码倒是容易简单很多。只是有个疑问，下面指出！</font></p>
<p style="text-indent: 2em;"><font size="2">程序代码：</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp; // code... </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void free(void *ptr)&nbsp;&nbsp;</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp; { </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct mem_control_block *free; </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; free = ptr - sizeof(struct mem_control_block); </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; free-&gt;is_available = 1; </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return; </font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp; }</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;
看一下函数第二句，这句非常重要和关键。其实这句就是把指向可用空间的指针倒回去，让它指向管理信息的那块空间，因为这里是在值上减去了一个结构体的大
小！后面那一句free-&gt;is_available =
1;我有点纳闷！我的想法是：这里is_available应该只是一个标记而已！因为从这个变量的名称上来看，is_available
翻译过来就是“是可以用”。不要说我土！我觉得变量名字可以反映一个变量的作用，特别是严谨的代码。这是源代码，所以我觉得绝对是严谨的！！这个变量的值
是1，表明是可以用的空间！只是这里我想了想，如果把它改为0或者是其他值不知道会发生什么事？！但是有一点我可以肯定，就是释放绝对不会那么顺利进行！
因为这是一个标记！</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;
当然，这里可能还是有人会有疑问，为什么这样就可以释放呢？？我刚才也有这个疑问。后来我想到，释放是操作系统的事，那么就free()这个源代码来看，
什么也没有释放，对吧？但是它确实是确定了管理信息的那块内存的内容。所以，free()只是记录了一些信息，然后告诉操作系统那块内存可以去释放，具体
怎么告诉操作系统的我不清楚，但我觉得这个已经超出了我这篇文章的讨论范围了。</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;
那么，我之前有个错误的认识，就是认为指向那块内存的指针不管移到那块内存中的哪个位置都可以释放那块内存！但是，这是大错特错！释放是不可以释放一部分
的！首先这点应该要明白。而且，从free()的源代码看，ptr只能指向可用空间的首地址，不然，减去结构体大小之后一定不是指向管理信息空间的首地
址。所以，要确保指针指向可用空间的首地址！不信吗？自己可以写一个程序然后移动指向可用空间的指针，看程序会有会崩！</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp; 最后可能想到malloc()的源代码看看malloc()到底是怎么分配空间的，这里面涉及到很多其他方面的知识！有兴趣的朋友可以自己去下载源</font></p>
<p style="text-indent: 2em;"><font size="2">代码去看看。</font></p>
<p style="text-indent: 2em;"><font size="2">四、关于其他：</font></p>
<p style="text-indent: 2em;"><font size="2">&nbsp;&nbsp;&nbsp;&nbsp; 关于C中的malloc()和free()的讨论就写到这里吧！写了三个钟头，感觉有点累！希望对大家有所帮助！有不对的地方欢迎大家指出！最后</font></p>
<p style="text-indent: 2em;"><font size="2">，谢谢参与这个帖子讨论的所有朋友，帖
子：http://www.bc-cn.net/bbs/dispbbs.asp?boardID=5&amp;ID=81781&amp;
page=1。也谈到版权问题，如果哪位想转载这篇文章（如果我有这个荣幸的话），最起码请标明“来自bc-cn
C语言论坛”这几个字眼，我的ID可以不用写上！谢谢合作！</font></p>
<p style="text-indent: 2em;"><font size="2">五、参考文献：（只写书名）</font></p>
<p style="text-indent: 2em;"><font size="2">——《UNIX环境高级编程》</font></p>
<p style="text-indent: 2em;"><font size="2">——《计算机组成原理》</font></p>
<p style="text-indent: 2em;"><font size="2">——《高质量C/C++编程指南》</font></p></div>]]></description>
<pubDate>
2008-07-15 14:13:00.0</pubDate>
<guid>
http://thomasyangch.blogcn.com/diary,17762635.shtml</guid>
<comments>
http://thomasyangch.blogcn.com/diary,17762635.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[200381637]]></blogcn_uid>
<title>
<![CDATA[标准c内存函数]]></title>
<link>
http://thomasyangch.blogcn.com/diary,17762323.shtml</link>
<description>
<![CDATA[<div id="blog_text" class="cnt"><p><font size="3">标准c内存函数</font></p>
<p><font size="3">--------------------------------------------------------------------------------</font></p>
<p><font size="3">calloc <br>
语法:</font></p>
<p><font size="3"><br>
#include &lt;stdlib.h&gt;<br>
void *calloc( size_t num, size_t size );</font></p>
<p><font size="3">功能： 函数返回一个指向num 数组空间，每一数组元素的大小为size。如果错误发生返回NULL。</font></p>
<p><font size="3">相关主题:<br>
free(), malloc(), and realloc().</font></p>
<p><font size="3"><br>
--------------------------------------------------------------------------------</font></p>
<p><font size="3">free <br>
语法:</font></p>
<p><font size="3"><br>
#include &lt;stdlib.h&gt;<br>
void free( void *ptr );</font></p>
<p><font size="3">功能： 函数释放指针ptr指向的空间，以供以后使用。指针ptr 必须由先前对malloc(), calloc(), realloc()的调用返回。例如:</font></p>
<p><font size="3">&nbsp;&nbsp;&nbsp;  typedef struct data_type {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  int age;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  char name[20];<br>
&nbsp;&nbsp;&nbsp;  } data;<br>
&nbsp;&nbsp;&nbsp;  <br>
&nbsp;&nbsp;&nbsp;  data *willy;<br>
&nbsp;&nbsp;&nbsp;  willy = (data*) malloc( sizeof(willy) );<br>
&nbsp;&nbsp;&nbsp;  ...<br>
&nbsp;&nbsp;&nbsp;  free( willy );<br>
相关主题:<br>
calloc(), malloc(), and realloc().</font></p>
<p><font size="3"><br>
--------------------------------------------------------------------------------</font></p>
<p><font size="3">malloc <br>
语法:</font></p>
<p><font size="3"><br>
#include &lt;stdlib.h&gt;<br>
void *malloc( size_t size );</font></p>
<p><font size="3">功能： 函数指向一个大小为size的空间，如果错误发生返回NULL。 存储空间的指针必须为堆，不能是栈。这样以便以后用free函数释放空间。例如:</font></p>
<p><font size="3">&nbsp;&nbsp;&nbsp;  typedef struct data_type {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  int age;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  char name[20];<br>
&nbsp;&nbsp;&nbsp;  } data;<br>
&nbsp;&nbsp;&nbsp;  <br>
&nbsp;&nbsp;&nbsp;  data *bob;<br>
&nbsp;&nbsp;&nbsp;  bob = (data*) malloc( sizeof(data) );<br>
&nbsp;&nbsp;&nbsp;  if( bob != NULL ) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  bob-&gt;age = 22;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  strcpy( bob-&gt;name, "Robert" );<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  printf( "%s is %d years old\n", bob-&gt;name, bob-&gt;age );<br>
&nbsp;&nbsp;&nbsp;  }<br>
&nbsp;&nbsp;&nbsp;  free( bob );<br>
相关主题:<br>
free(), realloc(), and calloc().</font></p>
<p><font size="3"><br>
--------------------------------------------------------------------------------</font></p>
<p><font size="3">realloc <br>
语法:</font></p>
<p><font size="3"><br>
#include &lt;stdlib.h&gt;<br>
void *realloc( void *ptr, size_t size );</font></p>
<p><font size="3">功能： 函数将ptr 对象的储存空间改变为给定的大小size。 参数size可以是任意大小，大于或小于原尺寸都可以。 返回值是指向新空间的指针，如果错误发生返回NULL。</font></p>
<p><font size="3">相关主题:<br>
free(), malloc(), and calloc().</font></p></div>]]></description>
<pubDate>
2008-07-15 14:08:00.0</pubDate>
<guid>
http://thomasyangch.blogcn.com/diary,17762323.shtml</guid>
<comments>
http://thomasyangch.blogcn.com/diary,17762323.shtml#comment</comments>
</item>
<item>
<blogcn_uid>
<![CDATA[200381637]]></blogcn_uid>
<title>
<![CDATA[Linux编程C++内存管理之内存分配详解]]></title>
<link>
http://thomasyangch.blogcn.com/diary,17760757.shtml</link>
<description>
<![CDATA[<font size="2"><span style="color: rgb(51, 51, 255);" id="zoom" class="a14c"><p style="text-indent: 2em;">程序员们经常编写内存管理程序，往往提心吊胆。如果不想触雷，唯一的解决办法就是发现所有潜伏的地雷并且排除它们，躲是躲不了的。
</p><p style="text-indent: 2em;"><b>内存分配方式</b>
</p><p style="text-indent: 2em;">内存分配方式有三种：
</p><p style="text-indent: 2em;">（1）从静态存储区域分配。内存在程序编译的时候就已经分配好，这块内存在程序的整个运行期间都存在。例如全局变量，static变量。
</p><p style="text-indent: 2em;">（2）在栈上创建。在执行函数时，函数内局部变量的存储单元都可以在栈上创建，函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中，效率很高，但是分配的内存容量有限。
</p><p style="text-indent: 2em;">（3） 从堆上分配，亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存，程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定，使用非常灵活，但问题也最多。
</p><p style="text-indent: 2em;"><b>常见的内存错误及其对策</b>
</p><p style="text-indent: 2em;">发生内存错误是件非常麻烦的事情。编译器不能自动发现这些错误，通常是在程序运行时才能捕捉到。而这些错误大多没有明显的症状，时隐时现，增加了改错的难度。有时用户怒气冲冲地把你找来，程序却没有发生任何问题，你一走，错误又发作了。 常见的内存错误及其对策如下：
</p><p style="text-indent: 2em;">* 内存分配未成功，却使用了它。
</p><p style="text-indent: 2em;">编程新手常犯这种错误，因为他们没有意识到内存分配会不成功。常用解决办法是，在使
用内存之前检查指针是否为NULL。如果指针p是函数的参数，那么在函数的入口处用assert(p!=NULL)进行检查。如果是用malloc或
new来申请内存，应该用if(p==NULL) 或if(p!=NULL)进行防错处理。
</p><p style="text-indent: 2em;">* 内存分配虽然成功，但是尚未初始化就引用它。
</p><p style="text-indent: 2em;">犯这种错误主要有两个起因：一是没有初始化的观念；二是误以为内存的缺省初值全为
零，导致引用初值错误（例如数组）。内存的缺省初值究竟是什么并没有统一的标准，尽管有些时候为零值，我们宁可信其无不可信其有。所以无论用何种方式创建
数组，都别忘了赋初值，即便是赋零值也不可省略，不要嫌麻烦。
</p><p style="text-indent: 2em;">* 内存分配成功并且已经初始化，但操作越过了内存的边界。
</p><p style="text-indent: 2em;">例如在使用数组时经常发生下标“多1”或者“少1”的操作。特别是在for循环语句中，循环次数很容易搞错，导致数组操作越界。
</p><p style="text-indent: 2em;">* 忘记了释放内存，造成内存泄露。
</p><p style="text-indent: 2em;">含有这种错误的函数每被调用一次就丢失一块内存。刚开始时系统的内存充足，你看不到错误。终有一次程序突然死掉，系统出现提示：内存耗尽。
</p><p style="text-indent: 2em;">动态内存的申请与释放必须配对，程序中malloc与free的使用次数一定要相同，否则肯定有错误（new/delete同理）。
</p><p style="text-indent: 2em;">* 释放了内存却继续使用它。
</p><p style="text-indent: 2em;">有三种情况：
</p><p style="text-indent: 2em;">（1）程序中的对象调用关系过于复杂，实在难以搞清楚某个对象究竟是否已经释放了内存，此时应该重新设计数据结构，从根本上解决对象管理的混乱局面。
</p><p style="text-indent: 2em;">（2）函数的return语句写错了，注意不要返回指向“栈内存”的“指针”或者“引用”，因为该内存在函数体结束时被自动销毁。 <br></p><p style="text-indent: 2em;"><span id="zoom" class="a14c"><p style="text-indent: 2em;">（3）使用free或delete释放了内存后，没有将指针设置为NULL。导致产生“野指针”。
</p><p style="text-indent: 2em;">【规则1】用malloc或new申请内存之后，应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存。
</p><p style="text-indent: 2em;">【规则2】不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。
</p><p style="text-indent: 2em;">【规则3】避免数组或指针的下标越界，特别要当心发生“多1”或者“少1”操作。
</p><p style="text-indent: 2em;">【规则4】动态内存的申请与释放必须配对，防止内存泄漏。
</p><p style="text-indent: 2em;">【规则5】用free或delete释放了内存之后，立即将指针设置为NULL，防止产生“野指针”。
</p><p style="text-indent: 2em;"><b>指针与数组的对比</b>
</p><p style="text-indent: 2em;">C++/C程序中，指针和数组在不少地方可以相互替换着用，让人产生一种错觉，以为两者是等价的。
</p><p style="text-indent: 2em;">数组要么在静态存储区被创建（如全局数组），要么在栈上被创建。数组名对应着（而不是指向）一块内存，其地址与容量在生命期内保持不变，只有数组的内容可以改变。
</p><p style="text-indent: 2em;">指针可以随时指向任意类型的内存块，它的特征是“可变”，所以我们常用指针来操作动态内存。指针远比数组灵活，但也更危险。
</p><p style="text-indent: 2em;">下面以字符串为例比较指针与数组的特性。
</p><p style="text-indent: 2em;"><b>1 修改内容</b>
</p><p style="text-indent: 2em;">示例3-1中，字符数组a的容量是6个字符，其内容为hello。a的内容可以改
变，如a[0]=
‘X’。指针p指向常量字符串“world”（位于静态存储区，内容为world），常量字符串的内容是不可以被修改的。从语法上看，编译器并不觉得语句
p[0]= ‘X’有什么不妥，但是该语句企图修改常量字符串的内容而导致运行错误。
</p><center style="font-family: 宋体;"><ccid_nobr>
<table bordercolorlight="black" bordercolordark="#FFFFFF" align="center" border="1" cellpadding="2" cellspacing="0" width="400">
<tbody><tr>
    <td class="code" style="font-size: 9pt;" bgcolor="#e6e6e6">
    <pre><ccid_code>char a[] = “hello”;<br>a[0] = ‘X’;<br>cout &lt;&lt; a &lt;&lt; endl;<br>char *p = “world”; // 注意p指向常量字符串<br>p[0] = ‘X’; // 编译器不能发现该错误<br>cout &lt;&lt; p &lt;&lt; endl;</ccid_code></pre> 
   </td>
  </tr>
</tbody></table>
</ccid_nobr></center>
<center>示例3.1 修改数组和指针的内容<br><div style="text-align: left;"><span id="zoom" class="a14c"><p style="text-indent: 2em;"><b>2 内容复制与比较</b>
</p><p style="text-indent: 2em;">不能对数组名进行直接复制与比较。示例7-3-2中，若想把数组a的内容复制给数组
b，不能用语句 b = a ，否则将产生编译错误。应该用标准库函数strcpy进行复制。同理，比较b和a的内容是否相同，不能用if(b==a)
来判断，应该用标准库函数strcmp进行比较。
</p><p style="text-indent: 2em;">语句p = a
并不能把a的内容复制指针p，而是把a的地址赋给了p。要想复制a的内容，可以先用库函数malloc为p申请一块容量为strlen(a)+1个字符的
内存，再用strcpy进行字符串复制。同理，语句if(p==a) 比较的不是内容而是地址，应该用库函数strcmp来比较。
</p><center style="font-family: 宋体;"><ccid_nobr>
<table bordercolorlight="black" bordercolordark="#FFFFFF" align="center" border="1" cellpadding="2" cellspacing="0" width="400">
<tbody><tr>
    <td class="code" style="font-size: 9pt;" bgcolor="#e6e6e6">
    <pre><ccid_code>// 数组…<br>char a[] = "hello";<br>char b[10];<br>strcpy(b, a); // 不能用 b = a;<br>if(strcmp(b, a) == 0) // 不能用 if (b == a)<br>…<br>// 指针…<br>int len = strlen(a);<br>char *p = (char *)malloc(sizeof(char)*(len+1));<br>strcpy(p,a); // 不要用 p = a;<br>if(strcmp(p, a) == 0) // 不要用 if (p == a)<br>…</ccid_code></pre> 
   </td>
  </tr>
</tbody></table>
</ccid_nobr></center>
<center>示例3.2 数组和指针的内容复制与比较</center> 
<p style="text-indent: 2em;"><b>3 计算内存容量</b>
</p><p style="text-indent: 2em;">用运算符sizeof可以计算出数组的容量（字节数）。示例7-3-3（a）
中，sizeof(a)的值是12（注意别忘了’’）。指针p指向a，但是
sizeof(p)的值却是4。这是因为sizeof(p)得到的是一个指针变量的字节数，相当于sizeof(char*)，而不是p所指的内存容量。
C++/C语言没有办法知道指针所指的内存容量，除非在申请内存时记住它。注意当数组作为函数的参数进行传递时，该数组自动退化为同类型的指针。示例
7-3-3（b）中，不论数组a的容量是多少，sizeof(a)始终等于sizeof(char *)。
</p><center style="color: rgb(51, 51, 255);"><ccid_nobr>
<table bordercolorlight="black" bordercolordark="#FFFFFF" align="center" border="1" cellpadding="2" cellspacing="0" width="400">
<tbody><tr>
    <td class="code" style="font-size: 9pt;" bgcolor="#e6e6e6">
    <pre><ccid_code>char a[] = "hello world";<br>char *p = a;<br>cout&lt;&lt; sizeof(a) &lt;&lt; endl; // 12字节<br>cout&lt;&lt; sizeof(p) &lt;&lt; endl; // 4字节</ccid_code></pre> 
   </td>
  </tr>
</tbody></table>
</ccid_nobr></center>
<center style="color: rgb(51, 51, 255);">示例3.3（a） 计算数组和指针的内存容量</center> 
<center style="color: rgb(51, 51, 255);"><ccid_nobr>
<table bordercolorlight="black" bordercolordark="#FFFFFF" align="center" border="1" cellpadding="2" cellspacing="0" width="400">
<tbody><tr>
    <td class="code" style="font-size: 9pt;" bgcolor="#e6e6e6">
    <pre><ccid_code>void Func(char a[100])<br>{<br>　cout&lt;&lt; sizeof(a) &lt;&lt; endl; // 4字节而不是100字节<br>}</ccid_code></pre> 
   </td>
  </tr>
</tbody></table>
</ccid_nobr></center>
<center><span style="color: rgb(51, 51, 255);">示例3.3（b） 数组退化为指针</span><br style="color: rgb(51, 51, 255);"><div style="text-align: left;"><div id="blog_text" class="cnt"><div style="color: rgb(51, 51, 255);"><strong><span style="font-size: 14pt;">4</span></strong><strong><span style="font-size: 14pt;">、指针参数是如何传递内存的？ </span></strong></div>
<div style="text-indent: 21pt; color: rgb(51, 51, 255);">&nbsp;如果函数的参数是一个指针，不要指望用该指针去申请动态内存。示例7-4-1中，Test函数的语句GetMemory(str, 200)并没有使str获得期望的内存，str依旧是NULL，为什么?<br><br></div>
<table style="border: medium none ; background: rgb(230, 230, 230) none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; border-collapse: collapse; width: 585px; height: 213px; color: rgb(51, 51, 255);" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td style="border: 1pt solid windowtext; padding: 0cm 5.4pt; width: 426.1pt; background-color: transparent;" valign="top" width="568">
            <div>void GetMemory(char *p, int num)<br>
            {<br>
            　p = (char *)malloc(sizeof(char) * num);<br>
            }<br>
            void Test(void)<br>
            {<br>
            　char *str = NULL;<br>
            　GetMemory(str, 100); // str 仍然为 NULL<br>
            　strcpy(str, "hello"); // 运行错误<br>
            }<br>
            　　　　　　示例4.1 试图用指针参数申请动态内存</div>
            </td>
        </tr>
    </tbody>
</table>
<div style="text-indent: 21pt; color: rgb(51, 51, 255);"> </div>
<div style="text-indent: 21pt; color: rgb(51, 51, 255);"><br>&nbsp;&nbsp;&nbsp;&nbsp; 毛病出在函数GetMemory中。编译器总是要为函
数的每个参数制作临时副本，指针参数p的副本是 _p，编译器使 _p =
p。如果函数体内的程序修改了_p的内容，就导致参数p的内容作相应的修改。这就是指针可以用作输出参数的原因。在本例中，_p申请了新的内存，只是把
_p所指的内存地址改变了，但是p丝毫未变。所以函数GetMemory并不能输出任何东西。事实上，每执行一次GetMemory就会泄露一块内存，因
为没有用free释放内存。<br>
<br>
　　如果非得要用指针参数去申请内存，那么应该改用“指向指针的指针”，见示例4.2。</div>
<table style="border: medium none ; background: rgb(230, 230, 230) none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; border-collapse: collapse; color: rgb(51, 51, 255);" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td style="border: 1pt solid windowtext; padding: 0cm 5.4pt; width: 426.1pt; background-color: transparent;" valign="top" width="568">
            <div>void GetMemory2(char **p, int num)<br>
            {<br>
            　*p = (char *)malloc(sizeof(char) * num);<br>
            }<br>
            void Test2(void)<br>
            {<br>
            　char *str = NULL;<br>
            　GetMemory2(&amp;str, 100); // 注意参数是 &amp;str，而不是str<br>
            　strcpy(str, "hello");<br>
            　cout&lt;&lt; str &lt;&lt; endl;<br>
            　free(str);<br>
            }<br>
            　　　　　　示例4.2用指向指针的指针申请动态内存</div>
            </td>
        </tr>
    </tbody>
</table>
<div style="text-indent: 21pt; color: rgb(51, 51, 255);"> </div>
<div style="text-indent: 21pt; color: rgb(51, 51, 255);"> </div>
<div style="text-indent: 21pt; color: rgb(51, 51, 255);"><br>&nbsp;&nbsp;&nbsp;&nbsp; 由于“指向指针的指针”这个概念不容易理解，我们可以用函数返回值来传递动态内存。这种方法更加简单，见示例4.3。<br>
<br>
</div>
<table style="border: medium none ; background: rgb(230, 230, 230) none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; border-collapse: collapse; color: rgb(51, 51, 255);" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td style="border: 1pt solid windowtext; padding: 0cm 5.4pt; width: 426.1pt; background-color: transparent;" valign="top" width="568">
            <div>char *GetMemory3(int num)<br>
            {<br>
            　char *p = (char *)malloc(sizeof(char) * num);<br>
            　return p;<br>
            }<br>
            void Test3(void)<br>
            {<br>
            　char *str = NULL;<br>
            　str = GetMemory3(100);<br>
            　strcpy(str, "hello");<br>
            　cout&lt;&lt; str &lt;&lt; endl;<br>
            　free(str);<br>
            }<br>
            　　　　　　　示例4.3 用函数返回值来传递动态内存</div>
            </td>
        </tr>
    </tbody>
</table>
<div style="text-indent: 21pt; color: rgb(51, 51, 255);"> </div>
<div style="text-indent: 21pt; color: rgb(51, 51, 255);"><br>&nbsp;&nbsp;&nbsp;&nbsp; 用函数返回值来传递动态内存这种方法虽然好用，但是常常有人把return语句用错了。这里强调不要用return语句返回指向“栈内存”的指针，因为该内存在函数结束时自动消亡，见示例4.4。</div>
<div style="text-indent: 21pt; color: rgb(51, 51, 255);"> </div>
<table style="border: medium none ; background: rgb(230, 230, 230) none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; border-collapse: collapse; color: rgb(51, 51, 255);" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td style="border: 1pt solid windowtext; padding: 0cm 5.4pt; width: 426.1pt; background-color: transparent;" valign="top" width="568">
            <div>char *GetString(void)<br>
            {<br>
            　char p[] = "hello world";<br>
            　return p; // 编译器将提出警告<br>
            }<br>
            void Test4(void)<br>
            {<br>
            　char *str = NULL;<br>
            　str = GetString(); // str 的内容是垃圾<br>
            　cout&lt;&lt; str &lt;&lt; endl;<br>
            }<br>
            　　　　　　示例4.4 return语句返回指向“栈内存”的指针</div>
            </td>
        </tr>
    </tbody>
</table>
<div style="text-indent: 21pt; color: rgb(51, 51, 255);"> </div>
<div style="text-indent: 21pt; color: rgb(51, 51, 255);"> </div>
<div style="text-indent: 21pt; color: rgb(51, 51, 255);"><br>&nbsp;&nbsp;&nbsp;&nbsp; 用调试器逐步跟踪Test4，发现执行str = GetString语句后str不再是NULL指针，但是str的内容不是“hello world”而是垃圾。<br>
如果把示例4.4改写成示例4.5，会怎么样？<br>
<br>
</div>
<table style="border: medium none ; background: rgb(230, 230, 230) none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; border-collapse: collapse; color: rgb(51, 51, 255);" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td style="border: 1pt solid windowtext; padding: 0cm 5.4pt; width: 426.1pt; background-color: transparent;" valign="top" width="568">
            <div>char *GetString2(void)<br>
            {<br>
            　char *p = "hello world";<br>
            　return p;<br>
            }<br>
            void Test5(void)<br>
            {<br>
            　char *str = NULL;<br>
            　str = GetString2();<br>
            　cout&lt;&lt; str &lt;&lt; endl;<br>
            }<br>
            　　　　　示例4.5 return语句返回常量字符串<br>
            <br>
            </div>
            </td>
        </tr>
    </tbody>
</table>
<div style="text-indent: 21pt; color: rgb(51, 51, 255);"><br>
<br>
　　函数Test5运行虽然不会出错，但是函数GetString2的设计概念却是错误的。因为GetString2内的
“hello
world”是常量字符串，位于静态存储区，它在程序生命期内恒定不变。无论什么时候调用GetString2，它返回的始终是同一个“只读”的内存块。</div>
<div style="text-indent: 21pt; color: rgb(51, 51, 255);"> </div>
<div style="color: rgb(51, 51, 255);"><strong><span style="font-size: 14pt;">5</span></strong><strong><span style="font-size: 14pt;">、杜绝</span></strong><strong><span style="font-size: 14pt;">“</span></strong><strong><span style="font-size: 14pt;">野指针</span></strong><strong><span style="font-size: 14pt;">”</span></strong></div>
<div style="text-indent: 21pt; color: rgb(51, 51, 255);"> </div>
<div style="text-indent: 21pt; color: rgb(51, 51, 255);">“野指针”不是NULL指针，是指向“垃圾”内存的指针。人们一般不会错用NULL指针，因为用if语句很容易判断。但是“野指针”是很危险的，if语句对它不起作用。 “野指针”的成因主要有两种：<br>
<br>
　　（1）指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针，它的缺省值是随机的，它会乱指一气。所以，指针变量在创建的同时应当被初始化，要么将指针设置为NULL，要么让它指向合法的内存。例如<br>
<br>
<br>
</div>
<table style="border: medium none ; background: rgb(230, 230, 230) none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; border-collapse: collapse; color: rgb(51, 51, 255);" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td style="border: 1pt solid windowtext; padding: 0cm 5.4pt; width: 426.1pt; background-color: transparent;" valign="top" width="568">
            <div>char *p = NULL;<br>
            char *str = (char *) malloc(100);</div>
            </td>
        </tr>
    </tbody>
</table>
<div style="text-indent: 21pt; color: rgb(51, 51, 255);"><br>
<br>
　　（2）指针p被free或者delete之后，没有置为NULL，让人误以为p是个合法的指针。<br>
<br>
　　（3）指针操作超越了变量的作用范围。这种情况让人防不胜防，示例程序如下：<br>
<br>
</div>
<table style="border: medium none ; background: rgb(230, 230, 230) none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; border-collapse: collapse; color: rgb(51, 51, 255);" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td style="border: 1pt solid windowtext; padding: 0cm 5.4pt; width: 426.1pt; background-color: transparent;" valign="top" width="568">
            <div>class A<br>
            {<br>
            　public:<br>
            　　void Func(void){ cout &lt;&lt; “Func of class A” &lt;&lt; endl; }<br>
            };<br>
            void Test(void)<br>
            {<br>
            　A *p;<br>
            　{<br>
            　　A a;<br>
            　　p = &amp;a; // 注意 a 的生命期<br>
            　}<br>
            　p-&gt;Func(); // p是“野指针”<br>
            }<br>
            <br>
            </div>
            </td>
        </tr>
    </tbody>
</table>
<div style="text-indent: 21pt; color: rgb(51, 51, 255);"><br>
<br>
　　函数Test在执行语句p-&gt;Func()时，对象a已经消失，而p是指向a的，所以p就成了“野指针”。但奇怪的是我运行这个程序时居然没有出错，这可能与编译器有关。<br>
<br>
<strong><span style="font-size: 14pt;">6</span></strong><strong><span style="font-size: 14pt;">、有了</span></strong><strong><span style="font-size: 14pt;">malloc/free</span></strong><strong><span style="font-size: 14pt;">为什么还要</span></strong><strong><span style="font-size: 14pt;">new/delete</span></strong><strong><span style="font-size: 14pt;">？</span></strong><br>
<br>
　　malloc与free是C++/C语言的标准库函数，new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。<br>
<br>
　　对于非内部数据类型的对象而言，光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数，对象在消亡之前要自动执行析
构函数。由于malloc/free是库函数而不是运算符，不在编译器控制权限之内，不能够把执行构造函数和析构函数的任务强加于malloc
/free。<br>
<br>
　　因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new，以及一个能完成清理与释放内存工作的运算符delete。注意
new/delete不是库函数。我们先看一看malloc/free和new/delete如何实现对象的动态内存管理，见示例6。<br>
<br>
<br>
</div>
<table style="border: medium none ; background: rgb(230, 230, 230) none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; border-collapse: collapse; color: rgb(51, 51, 255);" border="1" cellpadding="0" cellspacing="0">
    <tbody>
        <tr>
            <td style="border: 1pt solid windowtext; padding: 0cm 5.4pt; width: 426.1pt; background-color: transparent;" valign="top" width="568">
            <div>class Obj<br>
            {<br>
            　public :<br>
            　　Obj(void){ cout &lt;&lt; “Initialization” &lt;&lt; endl; }<br>
            　　~Obj(void){ cout &lt;&lt; “Destroy” &lt;&lt; endl; }<br>
            　　void Initialize(void){ cout &lt;&lt; “Initialization” &lt;&lt; endl; }<br>
            　　void Destroy(void){ cout &lt;&lt; “Destroy” &lt;&lt; endl; }<br>
            };<br>
            void UseMallocFree(void)<br>
            {<br>
            　Obj *a = (obj *)malloc(sizeof(obj)); // 申请动态内存<br>
            　a-&gt;Initialize(); // 初始化<br>
            　//…<br>
            　a-&gt;Destroy(); // 清除工作<br>
            　free(a); // 释放内存<br>
            }<br>
            void UseNewDelete(void)<br>
            {<br>
            　Obj *a = new Obj; // 申请动态内存并且初始化<br>
            　//…<br>
            　delete a; // 清除并且释放内存<br>
            }<br>
            　　　　　示例6 用malloc/free和new/delete如何实现对象的动态内存管理<br>
            <br>
            </div>
            </td>
        </tr>
    </tbody>
</table>
<div style="text-indent: 21pt; color: rgb(51, 51, 255);"><br>
　　类Obj的函数Initialize模拟了构造函数的功能，函数Destroy模拟了析构函数的功能。函数
UseMallocFree中，由于
malloc/free不能执行构造函数与析构函数，必须调用成员函数Initialize和Destroy来完成初始化与清除工作。函数
UseNewDelete则简单得多。<br>
<br>
　　所以我们不要企图用malloc/free来完成动态对象的内存管理，应该用new/delete。由于内部数据类型的“对象”没有构造与析构的过程，对它们而言malloc/free和new/delete是等价的。<br>
<br>
　　既然new/delete的功能完全覆盖了malloc/free，为什么C++不把malloc/free淘汰出局呢？这是因为C++程序经常要调用C函数，而C程序只能用malloc/free管理动态内存。</div>
<div style="text-indent: 21pt;"><span style="color: rgb(51, 51, 255);">如果用free释放“new创建的动态对象”，那么该
对象因无法执行析构函数而可能导致程序出错。如果用delete释放“malloc申请的动态内存”，理论上讲程序不会出错，但是该程序的可读性很差。所
以new/delete必须配对使用，malloc/free也一样。</span><br style="color: rgb(51, 51, 255);"><div id="blog_text" class="cnt"><p class="MsoNormal" style="margin: 0cm 0cm 12pt; line-height: 15pt; text-align: left; color: rgb(51, 51, 255);" align="left"><strong><span style="font-size: 9pt;">7</span></strong><strong><span style="font-size: 9pt;">、内存耗尽怎么办？</span></strong><span style="font-size: 9pt;"><br>
</span><span style="font-size: 9pt;">　　如果在申请动态内存时找不到足够大的内存块，</span><span style="font-size: 9pt;">malloc</span><span style="font-size: 9pt;">和</span><span style="font-size: 9pt;">new</span><span style="font-size: 9pt;">将返回</span><span style="font-size: 9pt;">NULL</span><span style="font-size: 9pt;">指针，宣告内存申请失败。通常有三种方式处理</span><span style="font-size: 9pt;">“</span><span style="font-size: 9pt;">内存耗尽</span><span style="font-size: 9pt;">”</span><span style="font-size: 9pt;">问题。</span><span style="font-size: 9pt;"><br>
</span><span style="font-size: 9pt;">　　（</span><span style="font-size: 9pt;">1</span><span style="font-size: 9pt;">）判断指针是否为</span><span style="font-size: 9pt;">NULL</span><span style="font-size: 9pt;">，如果是则马上用</span><span style="font-size: 9pt;">return</span><span style="font-size: 9pt;">语句终止本函数。例如：</span><span style="font-size: 9pt;"></span></p>
<div style="color: rgb(51, 51, 255);" align="center">
<table style="border: 0.75pt outset rgb(204, 204, 204); background: rgb(227, 227, 227) none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; width: 90%;" bgcolor="#e3e3e3" border="1" cellpadding="0" width="90%">
<tbody>
    <tr>
        <td style="border: 0.75pt inset rgb(204, 204, 204); padding: 0.75pt; background-color: transparent;">
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: 150%; text-align: left;" align="left"><span style="font-size: 9pt;">void Func(void)<br>
{<br>
</span><span style="font-size: 9pt;">　</span><span style="font-size: 9pt;">A *a = new A;<br>
</span><span style="font-size: 9pt;">　</span><span style="font-size: 9pt;">if(a == NULL)<br>
</span><span style="font-size: 9pt;">　</span><span style="font-size: 9pt;">{<br>
</span><span style="font-size: 9pt;">　　</span><span style="font-size: 9pt;">return;<br>
</span><span style="font-size: 9pt;">　</span><sp