- + P A

- 大内高手—常见内存错误

      C语言 2008-10-28 20:52

随着诸如代码重构和单元测试等方法引入实践,调试技能渐渐弱化了,甚至有人主张废除调试器。这是有道理的,原因在于调试的代价往往太大了,特别是调试系统集成之后的BUG,一个BUG花了几天甚至数周时间并非罕见。

 

而这些难以定位的BUG基本上可以归为两类:内存错误和并发问题。而又以内存错误最为普遍,即使是久经沙场的老手,也有时也难免落入陷阱。前事不忘,后世之师,了解这些常见的错误,在编程时就加以注意,把出错的概率降到最低,可以节省不少时间。

 

这些列举一些常见的内存错误,供新手参考。

 

1.         内存泄露。

大家都知道,在堆上分配的内存,如果不再使用了,应该把它释放掉,以便后面其它地方可以重用。在C/C++中,内存管理器不会帮你自动回收不再使用的内存。如果你忘了释放不再使用的内存,这些内存就不能被重用,就造成了所谓的内存泄露。

 

把内存泄露列为首位,倒并不是因为它有多么严重的后果,而因为它是最为常见的一类错误。一两处内存泄露通常不至于让程序崩溃,也不会出现逻辑上的错误,加上进程退出时,系统会自动释放该进程所有相关的内存,所以内存泄露的后果相对来说还是比较温和的。当然了,量变会产生质变,一旦内存泄露过多以致于耗尽内存,后续内存分配将会失败,程序可能因此而崩溃。

 

现在的PC机内存够大了,加上进程有独立的内存空间,对于一些小程序来说,内存泄露已经不是太大的威胁。但对于大型软件,特别是长时间运行的软件,或者嵌入式系统来说,内存泄露仍然是致命的因素之一。

 

不管在什么情

标签集:TAGS:
我要留言To Comment 阅读全文Read All | 回复Comments() 点击Count()

- 总结:三种传递动态分配内存的方法

      C语言 2008-10-28 20:33
在项目中,遇到到需要专门做一个函数来实现动态内存的分配,然后其他的函数都可以使用这块内存进行读写。但是比较怪异的是,在其他函数中对该块内存的标识是通过一个unsigned long的变量,而并非通过一个指针指向该块内存。思索良久,发现它的动态内存的传递可能是采用了不大常用的方法。
借着这个提示, 总结了三种方法实现动态分配内存的传递。当然,有的符合我们平时写程序的习惯,可能有些不大常用。
以下是程序代码,三个子程序以及测试方法:

#include <stdio.h>

#include

标签集:TAGS:
我要留言To Comment 阅读全文Read All | 回复Comments() 点击Count()

- 参数传递之指针传递

      C语言 2008-10-28 20:32

(1)基础知识
C课本上的一个程序:

void swap(int *p1,int *p2)
{
  int t=*p1;
  *p1=*p2;
  *p2=t;
}

void main()
{
  int a=1,b=2;
 
  swap(&a,&b);
 
  ...
}

a,b的值交换了是因为a,b的地址被传递给了函数swap,使得p1=&a,p2=&b。
为了看得更清楚些,更改一些:

void swap(int *p1,int *p2)
{
  int t=*p1;
  *p1=*p2;
  *p2=t;
}

void main()
{
  int a=1,b=2;
  int *pa=&a,*pb=&b;
 
  swap(pa,pb);
 
  ...
}

在上面,pa,pb是形参,p1,p2是实参。pa=&a,p1=&a;pb=&b,p2=&b。但pa与p1不是同一个内存区域的指针,pb与p2也一样。


(2)问题

再看一个程序:


为程序分配内存区域,你可以这样做:

#define SIZE 10

标签集:TAGS:
我要留言To Comment 阅读全文Read All | 回复Comments() 点击Count()

- Linux系统启动过程

      知识库 2008-10-23 20:52
本文以RedHat9.0和i386平台为例,剖析了从用户打开电源直到屏幕出现命令行提示符的整个Linux启动过程。并且介绍了启动中涉及到的各种文件。

  阅读Linux源代码,无疑是深入学习Linux的最好方法。在本文对Linux启动过程的介绍中,我们也尝试从源代码的视角来更深入的剖析Linux的启动过程,所以其中也简单涉及到部分相关的Linux源代码,Linux启动这部分的源码主要使用的是C语言,也涉及到了少量的汇编。而启动过程中也执行了大量的shell(主要是bash shell)所写脚本。为了方便读者阅读,笔者将整个Linux启动过程分成以下几个部分逐一介绍,大家可以参考下图:

  当用户打开PC的电源,BIOS开机自检,按BIOS中设置的启动设备(通常是硬盘)启动,接着启动设备上安装的引导程序lilo或grub开始引导Linux,Linux首先进行内核的引导,接下来执行init程序,init程序调用了rc.sysinit和rc等程序,rc.sysinit和rc当完成系统初始化和运行服务的任务后,返回init;init启动了mingetty后,打开了终端供用户登录系统,用户登录成功后进入了Shell,这样就完成了从开机到登录的整个启动过程。

标签集:TAGS:
我要留言To Comment 阅读全文Read All | 回复Comments() 点击Count()

- Windows 启动原理

      知识库 2008-10-23 20:47
 一般来说,Windows XP的启动过程,主要包括以下几个步骤: 

电源开启自检过程。 

初始化启动过程。 

引导程序载入过程。 

检测和配置硬件过程。 

内核加载过程。 

用户登录过程。 

即插即用设备的检测过程。 

一、电源开启自检过程 

  在打开计算机电源时,首先开始电源启动自检过程。在BIOS中包含一些基本的指令,能够帮助计算机在没有安装任何操作系统的情况下进行基本的启动。电源启动自检过程首先会从BIOS中载入必要的指令,然后进行如下一系列的自检操作: 

进行硬件的初始化检查,例如检查内存的容量等。 

验证用于启动操作系统的设备是否正常,例如,检查硬盘是否存在等。 

从CMOS中读取系统配置信息。 

  在完成了电源启动的自检之后,每个带有固件的硬件设备,如显卡和磁盘控制器,都会根据需要完成内部的自检操作。 

二、初始化启动过程&nb
标签集:TAGS:
我要留言To Comment 阅读全文Read All | 回复Comments() 点击Count()

- 电子邮件中用的协议比如pop3 ,smtp,imap有什么区别

      知识库 2008-10-23 20:36

1.SMTP(Simple Mail Transfer Protocal)称为简单邮件传输协议,目标是向用户提供高效、可靠的邮件传输。

SMTP的一个重要特点是它能够在传送中接力传送邮件,即邮件可以通过不同网络上的主机接力式传送。工作在两种情况下:一是电子邮件从客户机传输到服务器;二是从某一个服务器传输到另一个服务器。 SMTP是个请求/响应协议,它监听25号端口,用于接收用户的邮件请求,并与远端邮件服务器建立SMTP连接。

SMTP工作机制
SMTP通常有两种工作模式:发送SMTP和接收SMTP。具体工作方式为:发送SMTP在接到用户的邮件请求后,判断此邮件是否为本地邮件,若是直接投送到用户的邮箱,否则向DNS查询远端邮件服务器的MX纪录,并建立与远端接收SMTP之间的一个双向传送通道,此后SMTP命令由发送SMTP 发出,由接收SMTP接收,而应答则反方面传送。一旦传送通道建立,SMTP发送者发送MAIL命令指明邮件发送者。如果SMTP接收者可以接收邮件则返回OK应答。SMTP发送者再发出RCPT命令确认邮件是否接收到。如果SMTP接收者接收,则返回OK应答;如果不能接收到,则发出拒绝接收应答(但不中止整个邮件操作),双方将如此重复多次。当接收者收到全部邮件后会接收到特别的序列,如果接收者成功处理了邮件,则返回OK应答。
2.POP协议简介
POP的全称是 Post Office Protocol ,即邮局协议,用于电子邮件的接收,它使用TCP的110端口,现在常用的是第三版,所以简称为 POP3。

POP3采用Client/Server工作模式。当客户机需要服务时,客户端的软件(Outlook Express或FoxMail)将与POP3服务器建立TCP连

标签集:TAGS:
我要留言To Comment 阅读全文Read All | 回复Comments() 点击Count()

- SQL语句 SELECT LIKE like用法详解

      数据库 2008-10-18 21:47

在SQL结构化查询语言中,LIKE语句有着至关重要的作用。
  
  LIKE语句的语法格式是:select * from 表名 where 字段名 like 对应值(子串),它主要是针对字符型字段的,它的作用是在一个字符型字段列中检索包含对应子串的。

A:%   包含零个或多个字符的任意字符串                                                                                  

标签集:TAGS:
我要留言To Comment 阅读全文Read All | 回复Comments() 点击Count()

- 多种数据库的比较

      数据库 2008-10-17 16:1
Orcale数据库

美国Orcale公司研制的一种关系型数据库管理系统,是一个协调服务器和用于支持任务决定型应用程序的开放型RDBMS。它可以支持多种不同的硬件和操作系统平台,从台式机到大型和超级计算机,为各种硬件结构提供高度的可伸缩性,支持对称多处理器、群集多处理器、大规模处理器等,并提供广泛的国际语言支持。 Orcale是一个多用户系统,能自动从批处理或在线环境的系统故障中恢复运行。系统提供了一个完整的软件开发工具Developer2000,包括交互式应用程序生成器、报表打印软件、字处理软件以及集中式数据字典,用户可以利用这些工具生成自己的应用程序。Orcale以二维表的形式表示数据,并提供了SQL(结构式查询语言),可完成数据查询、操作、定义和控制等基本数据库管理功能。Orcale具有很好的可移植性,通过它的通信功能,微型计算机上的程序可以同小型乃至大型计算机上的Orcale,并且能相互传递数据。另外Orcale还具有与C语言的接电子表格、图形处理等软件。 Orcale属于大型数据库系统,主要适用于大、中小型应用系统,或作为客户机/服务器系统中服务器端的数据库系统。

DB2数据库

IBM公司研制的一种关系型数据库系统。DB2主要应用于大型应用系统,具有较好的可伸缩性,可支持从大型机到单用户环境,应用于OS/2、Windows等平台下。 DB2提供了高层次的数据利用性、完整性、安全性、可恢复性,以及小规模到大规模应用程序的执行能力,具有与平台无关的基本功能和SQL命令。DB2采用了数据分级技术,能够使大型机数据很方便地下载到LAN数据库服务器,使得客户机/服务器用户和基于LAN的应用程序可以访问大型机数据,并使数据库本地化及远程连接透明化。 它以拥有一个非常完备的查询优化器而著称,其外部连接改善了查
标签集:TAGS:
我要留言To Comment 阅读全文Read All | 回复Comments() 点击Count()

- 面向对象(OOP)的基本特征

      C++ 2008-10-17 15:45
面向对象技术是目前流行的系统设计开发技术,它包括面向对象分析和面向对象程序设计。面向对象程序设计技术的提出,主要是为了解决传统程序设计方法——结构化程序设计所不能解决的代码重用问题。

  面向对象的编程方法具有四个基本特征:

 

1.

标签集:TAGS:
我要留言To Comment 阅读全文Read All | 回复Comments() 点击Count()

- 笔记

      C++ 2008-10-15 10:55

  a为基类,b为a的派生类。当通过基类的指针去删除派生类的对象,而基类又没有虚析构函数时,结果将是不可确定的。实际运行时经常发生的是,派生类的析构函数永远不会被调用。即若 a*   pa;    pa=new   b;  delete   pa; /*我知道析钩函数一定要声明为虚的,只有这样,在delete   pa以后,才能按正确的顺序依次调用。派生类的析构和基类的析构来释后内存自由存储区,但我不明白的是为什么不虚,就会只调用一 次基类的析构函数,而不是派生类的析构函数。*/  

如果函数不是   virtual   的,则进行的是静态绑定,即在编译期间就决定了其调用的函数。  对于上面的程序来说,   delete   pa;,即使基类指针   pa   实际上指向的是派生类对象,但是编译器也会把这个基类指针和指向类型(基类)的析构函数进行静态绑定,从而达不到调用派生类析构函数的目的。

标签集:TAGS:
我要留言To Comment 阅读全文Read All | 回复Comments() 点击Count()

- new malloc

      C++ 2008-10-14 18:2

1、mallocfree

标签集:TAGS:
我要留言To Comment 阅读全文Read All | 回复Comments() 点击Count()

- 构造函数与析构函数

      C++ 2008-10-14 11:45

1.C++规定,每个类必须有默认的构造函数,没有构造函数就不能创建对象。

  2.若没有提供任何构造函数,那么c++提供自动提供一个默认的构造函数,该默认构造函数是一个没有参数的构造函数,它仅仅负责创建对象而不做任何赋值操作。

  3.只要类中提供了任意一个构造函数,那么c++就不在自动提供默认构造函数。

  4.类对象的定义和变量的定义类似,使用默认构造函数创建对象的时候,如果创建的是静态或者是全局对象,则对象的位模式全部为0,否则将会是随机的。

我们创建了一个带有字符指针的带有形参的Teacher(char *input_name)的构造函数,调用它创建对象的使用类名加对象名称加扩号和扩号内参数的方式调用,这和调用函数有点类似,但意义也有所不同,因为构造函数是为创建对象而设立的,这里的意义不单纯是调用函数,而是创建一个类对象。

标签集:TAGS:
我要留言To Comment 阅读全文Read All | 回复Comments() 点击Count()

- typedef

      C语言 2008-10-13 21:56

typedef在编译时解析,define在预处理时解析(只是简单替代)

typedef char * p;

const p; (= 编译变量从右char * const p);

  下面是三个变量的声明,我想使用typdef分别给它们定义一个别名,请问该如何做?
>1:int *(*a[5])(int, char*);
>2:void (*b[10]) (void (*)());
>3. doube(*)() (*pa)[9];
  答案与分析:
  对复杂变量建立一个类型别名的方法很简单,你只要在传统的变量声明表达式里用类型名替代变量名,然后把关键字typedef加在该语句的开头就行了。
>1:int *(*a[5])(int, char*);
//pFun是我们建的一个类型别名
typedef int *(*pFun)(int, char*);
//使用定义的新类型来声明对象,等价于int* (*a[5])(int, char*);
pFun a[5];
>2:void (*b[10]) (void (*)());
//首先为上面表达式蓝色部分声明一个新类型
typedef void (*pFunParam)();
//整体声明一个新类型
typedef void (*pFun)(pFunParam);
//使用定义的新类型来声明对象,等价于void (*b[10]) (void (*)());
pFun b[10];
>3. doube(*)() (*pa)[9];
//首先为上面表达式蓝色部分声明一个新

标签集:TAGS:
我要留言To Comment 阅读全文Read All | 回复Comments() 点击Count()

- (转)(精)const用法小结

      C语言 2008-10-13 21:54
前两天看代码的时候,发现很奇怪的const用法,于是在网上搜了一下,原来有这么多用法,不敢独享,拿上来和与我一样菜的小生们学习~

1.       const常量,如const int max = 100;  
优点:const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误(边际效应)

2.       const 修饰类的数据成员。如:
class A

{

    const int size;

    … 

}

const数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的。因为类可以创建多个对象,不同的对象其const数据成员的值可以不同。所以不能在类声明中初始化const数据成员,因为类的对象未被创建时,编译器不知道const 数据成员的值是什么。如

class A

{

 const int size = 100;    //错误

 int array[size]; 

标签集:TAGS:
我要留言To Comment 阅读全文Read All | 回复Comments() 点击Count()

- (转)排序算法小结

      数据结构 2008-10-13 20:52

排序小结
    排序算法是一种基本并且常用的算法。由于实际工作中处理的数量巨大,所以排序算法对算法本身的速度要求很高。
    而一般我们所谓的算法的性能主要是指算法的复杂度,一般用O方法来表示。在后面我将给出详细的说明。

    对于排序的算法我想先做一点简单的介绍,也是给这篇文章理一个提纲。
    我将按照算法的复杂度,从简单到难来分析算法。
    第一部分是简单排序算法,后面你将看到他们的共同点是算法复杂度为O(N*N)。
    第二部分是高级排序算法,复杂度为O(Log2(N))。这里我们只介绍一种算法。另外还有几种算法因为涉及树与堆的概念,所以这里不于讨论。
    第三部分类似动脑筋。这里的两种算法并不是最好的(甚至有最慢的),但是算法本身比较奇特,值得参考(编程的角度)。同时也可以让我们从另外的角度来认识这个问题。
    第四部分是我送给大家的一个餐后的甜点——一个基于模板的通用快速排序。由于是模板函数可以对任何数据类型排序(抱歉,里面使用了一些论坛专家的呢称)。
   
    现在,让我们开始吧:
   
一、简单排序算

标签集:TAGS:
我要留言To Comment 阅读全文Read All | 回复Comments() 点击Count()