博文

[置顶] C语言高效编程的的四大绝招(2007-04-06 14:42:00)

摘要:   第一招:以空间换时间   计算机程序中最大的矛盾是空间和时间的矛盾,那么,从这个角度出发逆向思维来考虑程序的效率问题,我们就有了解决问题的第1招--以空间换时间。   例如:字符串的赋值。   方法A:通常的办法:   #define LEN 32   char string1 [LEN];   memset (string1,0,LEN);   strcpy (string1,"This is a example!!");   方法B:   const char string2[LEN] ="This is a example!";   char * cp;   cp = string2 ;   使用的时候可以直接用指针来操作。   从上面的例子可以看出,A和B的效率是不能比的。在同样的存储空间下,B直接使用指针就可以操作了,而A需要调用两个字符函数才能完成。B的缺点在于灵活性没有A好。在需要频繁更改一个字符串内容的时候,A具有更好的灵活性;如果采用方法B,则需要预存许多字符串,虽然占用了大量的内存,但是获得了程序执行的高效率。   如果系统的实时性要求很高,内存还有一些,那我推荐你使用该招数。该招数的变招--使用宏函数而不是函数。举例如下:   方法C:   #define bwMCDR2_ADDRESS 4   #define bsMCDR2_ADDRESS 17   int BIT_MASK(int __bf)   {    return ((1U << (bw ## __bf)) - 1) << (bs ## __bf);   }   void SET_BITS(int __dst, int __bf, int __val)   {    __dst = ((__dst) & ~(BIT_MASK(__bf)))   \    (((__val) << (bs ## __bf)) & (BIT_MASK(__bf))))   }      SET_BITS(MCDR2, MCDR2_ADDRESS, RegisterNumber);   方法D:   #define b......

阅读全文(1932) | 评论:1

面试题心得(2008-01-19 23:11:00)

摘要:面试题: 如何将a。b的值进行交换,并且不使用任何中间变量? 用异或的方法比较好,不会发生溢出,如果采用 a= a+b; b= a-b; a= a-b; 这样做的缺点是如果a,b很大 可能溢出,而采用: a= a^b; b= a^b; a=a^b; 面试题2: 在c++程序中调用被c编译器编译的的函数,为什么要加extern“c”? 因为c++支持函数重载,c语言不支持函数重载,函数被c++编译后在库中的名字与c语言的不同,假设某个函数的原型是:void foo(int x,int y)。该函数被c编译器编译后在库中的名字为_foo,而c++的为_foo_int_int之类的名字。 c++提供了c连接交换指定符号extern“c” 解决名字匹配的问题。  ......

阅读全文(310) | 评论:1

排序算法比较(2007-05-02 18:14:00)

摘要:排序算法是数据结构学科经典的内容,其中内部排序现有的算法有很多种,究竟各有什么特点呢?本文力图设计实现常用内部排序算法并进行比较。分别为起泡排序,直接插入排序,简单选择排序,快速排序,堆排序,针对关键字的比较次数和移动次数进行测试比较. 问题分析和总体设计 ADT OrderableList{
数据对象:D={ai| ai∈IntegerSet,i=1,2,…,n,n≥0}
数据关系:R1={〈ai-1,ai〉|ai-1, ai∈D, i=1,2,…,n}
基本操作:
InitList(n)
操作结果:构造一个长度为n,元素值依次为1,2,…,n的有序表。
Randomizel(d,isInverseOrser)
操作结果:随机打乱
BubbleSort( )
操作结果:进行起泡排序
InserSort( )
操作结果:进行插入排序
SelectSort( )
操作结果:进行选择排序
QuickSort( )
操作结果:进行快速排序
HeapSort( )
操作结果:进行堆排序
ListTraverse(visit( ))
操作结果:依次对L种的每个元素调用函数visit( )
}ADT OrderableList 待排序表的元素的关键字为整数.用正序,逆序和不同乱序程度的不同数据做测试比较,
对关键字的比较次数和移动次数(关键字交换计为3次移动)进行测试比较.
要求显示提示信息,用户由键盘输入待排序表的表长(100-1000)和不同测试数据的组数(8-18).每次测试完毕,要求列表现是比较结果.
要求对结果进行分析. 详细设计
1、起泡排序
算法:核心思想是扫描数据清单,寻找出现乱序的两个相邻的项目。当找到这两个项目后,交换项目的位置然后继续扫描。重复上面的操作直到所有的项目都按顺序排好 bubblesort(struct rec r[],int n)
{
int i,j;
struct rec w;
unsigned long int compare=0,move=0;
for(i=1;i<=n-1;i++)
for(j=n;j>=i+1;j--)
{......

阅读全文(2140) | 评论:0

c++心得(2007-04-01 15:38:00)

摘要: MSDN里面有一些专题值得读一下,至少知道MFC的目的和一些方法或者手段。随便乱写一些,如果以后发现还有价值的话就整理。 1)MFC是对平台SDK的一个大封装。 学了C++,还不知道C++能干嘛,不知道就算能干这些,又有什么用,甚至不知道为什么要设计类,为什么要封装。 WINDOWS里的资源是用句柄表示的,句柄这个词不知道是哪个中国IT菜手翻译的,handle干嘛要这么翻译?它的意义很明显嘛,处理,为什么要处理?有人说,它是微软要隐含内部实现,因为它是商业软件嘛,我觉得不是,这不是根本原因,它原本的目的还是为了代码的向后兼容和可复用性。比如最重要一种资源,文件,它是和具体设备相关的,但文件操作只对一个文件的HANDLE进行处理,就是把它的定义和处理分开,C语言里的FILE也是一样的道理。各种各样的资源统一处理,在系统里统一表示,这样系统就会有条不紊地工作。也算是一个小的封装吧,具体实现和外部代码的分开,封装。于是有了SDK编程。 MFC封装在外面,更大的封装,它是为了让程序员把搭建一个复杂的WIN32程序,从设计那些复杂的实现中解放出来,把开发重点放在软件的数据结构和算法上。由于SDK封装得低,所以可以认为那些handle本身就是资源本身,可以这样认为。再在这之上进行面向类的封装,就是MFC。 有人说懂得了继承,才真正懂得了面向对象,或者C++。C++的目标或许也是这样吧,虽然语言本身没告诉我们它的目的是什么,做为了个成熟的类库,比如MFC,我们不仅仅是简单的利用它的一些功能调用,比如用CCommonDialog,而关键是选择合适的类继承下来,设计自己的子类,来实现整个软件的功能。 在面对各种各样的MFC中的类,要记住一点,类生成的对象,本身并不代表资源本身,比如CEdit并不是EditBox,它们之间可以有联系,但这个联系可以人为的剪断,对象只是一个从操作到资源的一个纽带。这也是为什么它有构造函数,却要用::Create()创建的原因。 2)弄清消息分发的过程。 消息的机制是为了让WINDOWS变迟顿,让它‘慢’下来,只有你‘叫’它做事它才做,由主动工作变为被动工作。有时候发送消息本身也可以看成消息处理本身。MFC对消息的处理封装得可就复杂了,不是非要弄得非常清楚才行,要知道消息被MFC丢来丢去的先后顺序,比如一个按钮的COMMAND响应可以给......

阅读全文(2105) | 评论:0

c细节啊(2007-03-31 21:58:00)

摘要:** 非常好的程序:(考虑程序的可移植性) #include <stdio.h>
#include <limits.h>
#include <stdlib.h> void PRINTBIT(int); /* 打印 n 的每个比特位 */ void PRINTBIT(int n){ /* 这里开始我定义为 int 型,结果如下:
    2 : 0000 0000 0000 0000 0000 0000 0000 0011
    4 : 0000 0000 0000 0000 0000 0000 0000 0111
2 ^ 4 : 0000 0000 0000 0000 0000 0000 0000 0111
2 & 4 : 0000 0000 0000 0000 0000 0000 0000 0000
2 | 4 : 0000 0000 0000 0000 0000 0000 0000 0111
   最后改为unsigned int 则正确,仔细想了一下
   原因:
   check = 1;
   check <<= (i - 1);
   这样如果 check 为 int 则最高为永远为 1,且会
   向右移动,移完后
   check=bit(1111 1111 1111 1111 1111 1111 1111 1111);
 */
 unsigned int j;
 unsigned int i = sizeof(int) * CHAR_BIT;
 unsigned int check = 1;  check <<= (i - 1);
 for(j = 1; j <= i; j ++){
  putchar(((check & n) ? '1' : '0'));
&n......

阅读全文(2147) | 评论:0

函数指针(2007-03-31 21:24:00)

摘要:typedef void (*FunType)(int );   //这样只是定义一个函数指针类型
FunType FunP;              //然后用FunType类型来申明全局FunP变量

int main(int argc, char* argv[])
{
//FunType FunP;    //函数指针变量当然也是可以是局部的 ,那就请在这里申明了。
   MyFun(10);     
   FunP=&MyFun;  
   (*FunP)(20);    

      return 0;
}

void MyFun(int x)  
{
   printf(“%d\n”,x);
}

    看黑体部分:
    首先,在void (*FunType)(int ); 前加了一个typedef 。这样只是定义一个名为FunType函数指针类型,而不是一个FunType变量。
    然后,FunType FunP;  这句就如PINT px;一样地申明一个FunP变量。
    其它相同。整个程序完成了相同的事。
    这样做法的好处是:
    有了FunType类型后,我们就可以同样地、很方便地用FunType类型来申明......

阅读全文(1816) | 评论:1

读文件一点见解(2007-03-29 15:24:00)

摘要:做开发的经常碰到文件的操作,特别是文件的“读”操作。在java中,读文件有很多种方法,有FileReader、BufferReader等,当然,各种方法的效率是不一样的,FileReader经BufferReader包装后效率明显提高,在个别时候,我们可以用java.nio包进行文件操作,如下:
    private static String fileReader(File fileName) {
        String fileContent = null;
        FileInputStream fis = null;
        FileChannel fc = null;
        try {
            fis = new FileInputStream(fileName);
            // get a file channel
            fc = fis.getChannel();

        &nbs......

阅读全文(3332) | 评论:1

指针一小题(2007-03-24 16:02:00)

摘要:题:
 *   已知 int lstat(const char *file, struct stat *buf); 则请判断下面正误
 *
 *   A)
 *     struct stat *statbuf;
 *     lstat("a.txt", statbuf);
 *
 *   B)
 *     struct stat statbuf;
 *     lstat("a.txt", &statbuf);
 *
 *  答案请选择空白区域(做为学习用,贻笑大方了)
 *
 * 答案:
 *   1)错误
 *     由lstat原型知道第二个参数是要一个 struct stat 结构变量的指针(即变量内存地址)
 *     上面只是由 struct stat *statbuf; 定义了一个指针,此时指针所指内容未知,所以不能直接 lstat("a.txt", statbuf); 这样等于把lstat函数的结果放入未知内存,所以引起错误,  只有给它一个已经定义好的结构变量才可用
 *
 *     可以如下修正
阅读全文(3402) | 评论:0