weitom1982

向各位技术前辈学习,学习再学习.
posts - 299, comments - 79, trackbacks - 0, articles - 0
  IT博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

习惯上很多教材中都把主函数写成如“void main()”的形式,这种写法上是说明主函数是没有任何反回值的,但更贴切的写法应该为“int main()”,因为在C++中如果主函数中没有“return”语句,那编译器就会自动在主函数最后加上“return 0”。

Feedback

# re: 关于主函数main()  回复  

2005-11-28 11:30 by 很土
补充下...
这里有篇文章是讲这个的
http://p5.club.163.com/viewArticleByWWW.m?boardId=clanguage&articleId=clanguage_1068cebb7ae5e3f
其中有段文字




3. 关于 void main

在 C 和 C++ 中,不接收任何参数也不返回任何信息的函数原型为 “void foo(void);”。可能正是因为这个,所以很多人都误认为如果不需要程序返回任何信息时可以把 main 函数定义成 void main(void) 。然而这是错误的!main 函数的返回值应该定义为 int 类型,C 和 C++ 标准中都是这样规定的。虽然在一些编译器中,void main 可以通过编译(如 vc6),但并非所有编译器都支持 void main ,因为标准中从来没有定义过 void main 。g++3.2 中如果 main 函数的返回值不是 int 类型,就根本通不过编译。而 gcc3.2 则会发出警告。所以,如果你想你的程序拥有很好的可移植性,请一定要用 int main 。



4. 返回值的作用

main 函数的返回值用于说明程序的退出状态。如果返回 0,则代表程序正常退出,否则代表程序异常退出。下面我们在 winxp 环境下做一个小实验。首先编译下面的程序:

int main( void )

{

return 0;

}

然后打开附件里的“命令提示符”,在命令行里运行刚才编译好的可执行文件,然后输入“echo %ERRORLEVEL%”,回车,就可以看到程序的返回值为 0 。假设刚才编译好的文件是 a.exe ,如果输入“a && dir”,则会列出当前目录下的文件夹和文件。但是如果改成 “return -1”,或者别的非 0 值,重新编译后输入“a && dir”,则 dir 不会执行。因为 && 的含义是:如果 && 前面的程序正常退出,则继续执行 && 后面的程序,否则不执行。也就是说,利用程序的返回值,我们可以控制要不要执行下一个程序。这就是 int main 的好处。如果你有兴趣,也可以把 main 函数的返回值类型改成非 int 类型(如 float),重新编译后执行“a && dir”,看看会出现什么情况,想想为什么会出现那样的情况。顺便提一下,如果输入 a || dir 的话,则表示如果 a 异常退出,则执行 dir 。

int main( int argc, char *argv[], char *env[] ) 也不是标准C里面定义的东西~char *env[]是某些编译器提供的扩展功能~用于获取系统的环境设定~因为不是标准~故而移植性差~不推荐使用 "

posted @ 2006-03-20 23:30 高山流水 阅读(86) | 评论 (0)编辑 收藏

初学C++,这是一个构造函数重载的小小程序。int 造成了溢出,我到现在还不知道是怎么一回事?把红色标志的int去掉输入就正确了。WHY?
#include<iostream.h>
class date{

    int dayth;
public:
    date(int day);
    date(int day,int month);
    date(int day,int month,int year);
    int getdate();
};

date::date(int day){

dayth=day;

}

date::date(int day,int month){
    int i;
    int th[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
    int dayth=0;
    for(i=0;i<month;i++)
    {dayth=dayth+th[i];}
    dayth=dayth+day;
}

date::date(int day,int month,int year){
    int i;
    int th[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
    int dayth=0;

    if((year%4==0&&year%100!=0)||year%400==0)
 {

         for(i=0;i<month;i++)
         {dayth=dayth+th[i];}
         dayth=dayth+day;
         if(month>2)
         dayth=dayth+1;
 }
else{


   for(i=0;i<month;i++)
   {dayth=dayth+th[i];}
   dayth=dayth+day;

}

}

   int date::getdate(){
   return dayth;
}

int main(){

int day;
int month;
int year;
cout<<"输入日期:";
cin>>day;
cout<<"输入月份:";
cin>>month;
cout<<"输入年份:";
cin>>year;
date q1(day);
date q2(day,month);
date q3(day,month,year);
cout<<"此日是一年的第"<<q1.getdate()<<"天\n";
cout<<"此日是一年的第"<<q2.getdate()<<"天\n";
cout<<"此日是一年的第"<<q3.getdate()<<"天\n";
return 1;
}

posted on 2005-12-12 21:23 10003 阅读(131) 评论(6)  编辑 收藏收藏至365Key

评论

# re: int 到底在干什么? 2005-12-13 01:31 蔡蔡
你不是在class date声明中声明了一个成员变量是dayth了嘛,在date的范畴中,dayth被认为已经定义了,不能再在date类中定义其他叫做dayth的变量了。  回复
  

# re: int 到底在干什么? 2005-12-13 10:01 e夜星空
'int'在干你让他干的事!
就像以下语句中的类型'float'一样,是声明其后变量的类型:
float fool_donkey;
自然以下语句是在声明clever_donkey为int类型变量同时初始化其值为748:
int clever_donkey = 748;

如果你把函数中的两个dayth前的类型'int'改为'float',就好解释一些了:
在类date里声明了一个整型的变量名为dayth,而在date的成员函数date::date()里又声明了一个float型变量,它的名字也叫dayth。
注意上面的*‘也’*字,它表明函数里的dayth并不是类成员的dayth,
它们只是同名的不同变量,
所以函数对dayth赋值都是对它自己声明的临时变量操作(与那个同名的类成员无关)。

可以把class date的声明改成以下形式,整个程序效果是一样的。
class date{
//int dayth;
int not_used_dayth;

public:
date(int day);
date(int day,int month);
date(int day,int month,int year);
int getdate();
};

这个问题就是C++中的命名空间相关的,
一个class是一个空间,就如中国
类的成员函数是其下的子空间,你可以当作是北京市。
中国国家主席是锦涛,
北京市某家庭刚出生的一个小孩也被你父亲起名为锦涛。
这样在他们家里每次叫锦涛的时候,
你觉得他们在叫谁?

那么回到你的程序中,
明明类已经有一个锦涛(dayth),
你就是给你的孩子起名叫锦涛(dayth),甚至连姓都和人家一样(int),
你还说不清楚你在干什么?还问人家我那个'int'起什么作用?

笑话!
你把红色的'int'去掉又是什么意思呢?
没有int的语句如下:
clever_donkey = you;
是一个赋值语句,就像你在家说“锦涛吃饭了”,
毫没有给你们家的小孩起名为锦涛的意思,
以后每行语句中出现的“锦涛”都是我们的国家主席该做什么什么。

  回复
  

# re: int 到底在干什么? 2005-12-13 15:40 初始化
不知道楼上两位是不是真的懂点语言,或者OO,
这是一个很基础的关于全局变量和局部变量的问题,当在函数内部定义了与全局变量同名的变量时,本函数内处理局部变量,但是在你调用getdate()时,是返回的这个类的全局变量,而不是类中某个函数的局部变量。函数中的局部变量在离开这个类后就释放了。
拜托各位先好好学习基础知识,这种问题都没有人愿意来理了。

date::date(int day,int month){
int i;
int th[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int dayth=0;
for(i=0;i<month;i++)
{dayth=dayth+th[i];}
dayth=dayth+day;
}
举这个例子,
你在函数内部定义了一个新的变量:
int dayth=0; 赋值为0,所以在这个函数中类的属性(或者变量)就不再包含。当该函数结束时,这个函数内部的变量就被释放了,而在调用这个函数date(int day,int month)的过程中,都没有改变你的类属性dayth,而调用类函数getdate()时,使返回的类的属性dayth。
拜托,真的应该先看完书再做这些,居然还问int做了什么。
还有楼上两位,如果是命名冲突,在编译时就会报错了。  回复
  

# re: int 到底在干什么? 2005-12-15 09:16 e夜星空
不知道上一楼在卖弄什么?
1. 是说它很懂语言,很懂面向对象OO?可是在它的字里行间并没有什么面向对象的东西。
2. 是说它本人不是人吗(见第4行“这种问题都没有人愿意来理了”),那能否以真面目示人,你是猪呢还是狗?
3. 另外它在卖弄一些概念也是乱七八糟的,大部分与原问题毫不相干.原问题只是构造函数自动变量覆盖同名的成员变量。你扯什么全局变量与局部变量?另外你愿意解答问题固然是好,虽然你自认为不是人,大家也不会怪你,答得不好也没什么。但你不应该通过攻击人来显示你的智商能与人相当。
4. 你还卖弄在函数内定义了与成员变量同名的变量,在这个函数就不能再包含类的那个成员变量了?自己回去看看书吧。
5. 什么?看不懂,那以后你少在公众场合放屁。  回复
  

# re: int 到底在干什么? 2005-12-15 09:30 e夜星空
重新回到原来的问题,解答一下:
1. 本程序不是整数溢出的事。getdate输出的值是一个未经初始化的整数值。与以下代码类似:
int a;
std::cout << a << std::endl;
2. 本这段代码先后定义了3个名为dayth的变量,互不相干。同名却不冲突,因为他们在不同的作用域范围。
3. 重载的两个构造函数中所操作的是它们通过int定义的自动本地变量dayth,而始终未修改类成员变量dayth。
构造函数使用如下的初始化列表后,q2.getdate()和q3.getdate()返回的都是初始化的值(下例为0).
date::date(int day,int month) : dayth(0){
...
}

date::date(int day,int month,int year) : dayth(0){
...
}  回复
  

# re: int 到底在干什么?2005-12-16 11:51 fancy
是可以运行的啊,函数里面的那个变量在函数退出去的时候就被销毁了,要想保存到class类里的dayth可以这样调用this->dayth=dayth+day  回复

posted @ 2006-03-20 23:27 高山流水 阅读(758) | 评论 (0)编辑 收藏

     摘要: 这个程序应该是我在2004年写的当时还只是一个读化工专业的大四学生基本上对什么编程规范、什么算法,什么性能优化没什么了解只是简单地用字符串模拟实现了任意大整数的四则运算现在看来当然很幼稚了不过为保持原来面目,一直没改,留做纪念。供有需要的朋友参考敬请指教  1//long integer operation , inclue addition,substracttion,multiplicaton...  阅读全文

posted @ 2006-03-20 23:26 高山流水 阅读(1421) | 评论 (7)编辑 收藏

  在C/C++中,数据指针是最直接,也最常用的,因此,理解起来也比较容易。而函数指针,作为运行时动态调用(比如回调函数 CallBack Function)是一种常见的,而且是很好用的手段。

  我们先简单的说一下函数指针。(这一部份没什么价值,纯是为了引出下一节的内容)
   
 2 常规函数指针

         void ( * fp)();

  fp 是一个典型的函数指针,用于指向无参数,无返回值的函数。

         void ( * fp2)( int );

  fp2 也是一个函数指针,用于指向有一个整型参数,无返回值的函数。
  当然,有经验人士一般都会建议使用typedef来定义函数指针的类型,如:

        typedef  void ( *  FP)();
        FP fp3; 
//  和上面的fp一样的定义。

  函数指针之所以让初学者畏惧,最主要的原因是它的括号太多了;某些用途的函数指针,往往会让人陷在括号堆中出不来,这里就不举例了,因为不是本文讨论的范围;typedef 方法可以有效的减少括号的数量,以及理清层次,所以受到推荐。本文暂时只考虑简单的函数指针,因此暂不用到typedef。

  假如有如下两个函数:

   void  f1()
  
{
      std::cout 
<<   " call f  "   <<  std::endl;
  }

  
  
void  f2( int  a)
  
{
      std::cout 
<<   " call f2(  "   <<  a  <<   "  ) "   <<  std::endl;
  }

  现在需要通过函数指针来调用,我们需要给指针指定函数:

  fp  =   & f1;  //  也可以用:fp = f1;
  fp2 =   & f2;  //  也可以用:fp2= f2;
   void  ( * fp3)()  =   & f1;  //  也可以用:void (*fp3)() = f1;  
  
// 调用时如下:
  fp();  //  或 (*fp)();
  fp2( 1 );  //  或 (*fp2)(1);
  fp3();   //  或 (*fp3)();

  对于此两种调用方法,效果完全一样,我推荐用前一种。后一种不仅仅是多打了键盘,而且也损失了一些灵活性。这里暂且不说它。
  
  C++强调类型安全。也就是说,不同类型的变量是不能直接赋值的,否则轻则警告,重则报错。这是一个很有用的特性,常常能帮我们找到问题。因此,有识之士认为,C++中的任何一外警告都不能忽视。甚至有人提出,编译的时候不能出现任何警告信息,也就是说,警告应该当作错误一样处理。
  
  比如,我们把f1赋值给fp2,那么C++编译器(vc7.1)就会报错:

  fp2  =   & f1;  //  error C2440: “=” : 无法从“void (__cdecl *)(void)”转换为“void (__cdecl *)(int)”
  fp1  =   & f1;  //  OK

  这样,编译器可以帮我们找出编码上的错误,节省了我们的排错时间。
  
  考虑一下C++标准模板库的sort函数:

   //  快速排序函数
  template<typename RandomAccessIterator, typename BinaryPredicate>
     
void  sort(
        RandomAccessIterator _First, 
//  需排序数据的第一个元素位置
        RandomAccessIterator _Last,   //  需排序数据的最后一个元素位置(不参与排序)
        BinaryPredicate _Comp      //  排序使用的比较算法(可以是函数指针、函数对象等)
     );

  比如,我们有一个整型数组:

   int  n[ 5 =   { 3 , 2 , 1 , 8 , 9 } ;

  要对它进行升序排序,我们需定义一个比较函数:

   bool  less( int  a,  int  b)
  
{
      
return  a  <  b; 
  }

  然后用:

  sort(n, n + 5 , less);

  要是想对它进行降序排序,我们只要换一个比较函数就可以了。C/C++的标准模板已经提供了less和great函数,因此我们可以直接用下面的语句来比较:  

  sort(n, n + 5 , great);


  这样,不需要改变sort函数的定义,就可以按任意方法进行排序,是不是很灵活?  
  这种用法以C++的标准模板库(STL)中非常流行。另外,操作系统中也经常使用回调(CallBack)函数,实际上,所谓回调函数,本质就是函数指针。

  看起来很简单吧,这是最普通的C语言指针的用法。本来这是一个很美妙的事情,但是当C++来临时,世界就开始变了样。
  假如,用来进行sort的比较函数是某个类的成员,那又如何呢?

posted @ 2006-03-20 23:24 高山流水 阅读(227) | 评论 (0)编辑 收藏

Java中最值得C++借鉴的特性s

Posted on 2006-01-25 11:40 小明 阅读(594) 评论(8)  编辑 收藏收藏至365Key 所属分类: C/C++
1995年出现的Java语言确实是一门伟大的语言,尽管它也不是完美的语言,而C++是一门比较"古老"的预言了,Java中有很多值得C++借鉴的东西。不知道未来的C++ 0x标准出来以后,C++会变成怎样?


1.强大的反射机制和RTTI特性
这个特性是当前流行的J2EE framework的基础,如Spring,Hibernate,无不利用了Java强大的反射机制。
Java可以在运行期动态创建class,并且invoke某一个方法。

MyClass helper = (MyClass) Class.forName(className).newInstance();

2.内建对多线程的支持和synchronized关键字
C++标准本没有提供比如创建thread的方法,不过现在出现了boost::thread应该是将来的C++标准。Java中有synchronized这个关键字,这是一种很简单,安全的锁机制。多线程编程很重要,但是也很复杂。希望新的C++ 0x标准能支持。

synchronized void initConfig() {
    
if (!loaded) {
      load();
      loaded 
= true;
    }
  }

3.匿名类
匿名类可以有效的减少类的数目,是一种很有用的语言特性

new Thread(new Runnable() {
              
public void run() {
                downloader.download();
              }
            }).start();
上面是启动一个新的thread来执行下载任务

4.final关键字
final使得更有效的表达设计者不希望被继承的意图。Java里面的final不等于C++的const。final用于class前面表示class不希望被继承,用于成员函数之前表示不希望被覆盖。这对于类库的设计是很重要的。毕竟不是每个类都为被继承做好了准备。

5.构造函数可以互相调用
这个特性使得写构造函数更加方便

class Test
{
    
public Test()
    {
          
this(1);
    }
    
public Test(int i)
    {
          
this.i = i;
    }
    
private int i;
}

6.package的概念
package不但有比C++ namespace更加强大避免冲突的功能,而且提供了一种更清晰的源代码结构。
比如java中
package com.cppblog.io.*;
C++要实现这样的,必须
namespace com
{
   namespace cppblog 
   {
       namespace io
       {
       }
   }
}

7.finally关键字
finally使得exception设计更加完备.很遗憾,C++里面只有try catch,虽然可以通过一些方法来work around,但是毕竟不是很方便。

try{
    openConnection();
}
catch(ConnectionException e){
    e.printStackTrace();
}
finally{
    closeConnection();
}



Feedback

# re: Java中最值得C++借鉴的特性s  回复  

2006-01-26 11:31 by Becky
终于写了一点偶能看得懂的文章了。

# re: Java中最值得C++借鉴的特性s  回复  

2006-01-27 11:17 by cyt
想法是好,但太不了解C++了。

# re: Java中最值得C++借鉴的特性s  回复  

2006-01-27 13:33 by 思春贴调查员(Khan)
c++中也有匿名对象吧,只是由于匿名对象通常产生在栈中,很难保证被安全释放
早些年也用java做过东西

# re: Java中最值得C++借鉴的特性s  回复  

2006-01-27 14:09 by huangyi
强大的反射机制 应该不会有 需要运行时的标准 制定标准估计太复杂 毕竟c++不是java 不过rtti肯定会有所加强

内建对多线程的支持和synchronized关键字 同意

匿名类 匿名函数这些东西 也同意 虽然不认为很有必要 应用性强的代码可以用python等脚本配合

final关键字 同意

构造函数可以互相调用 貌似有了吧

package的概念 我觉得是对源代码结构的限制 不喜欢

finally关键字 同意

# re: Java中最值得C++借鉴的特性s  回复  

2006-02-09 12:08 by mis98zb
不能
namespace A::B::C::D{
.
.
.
}
让人觉得很不爽!!!!!!!!

# re: Java中最值得C++借鉴的特性s  回复  

2006-02-11 16:36 by 3×7=51
union Test
{
  struct
  {
    short low;
    short high;
  };
  int content;
};

里面的struct即为匿名类,不过和java的匿名类不是一个东西。怎么说了各有所长。其实.net里面可以指定结构成员layout的的特性也蛮不错的,我特喜欢,不过最近很久没玩.net了。

# re: Java中最值得C++借鉴的特性s  回复  

2006-02-17 16:31 by 晓晓
有朋友能告诉我在MFC中用socket的具体方法吗?

# re: Java中最值得C++借鉴的特性s  回复  

2006-03-04 20:25 by hsen
C++中不能被继承可以这样写,

class T{
private:
T(){}
public:
virtual ~(){}
T* Create(){return new T;}
}

posted @ 2006-03-20 22:36 高山流水 阅读(613) | 评论 (0)编辑 收藏

对容器中的元素:排序,查找,替换,分段,求和 。。。。。。。swap  ratate  sort  search   merge  range copy 。。。。。。。。。太多拉,说不完啊,希望那位有所有函数的列表啊,给一个吧,找的时候好找啊!看看下面的有没有见过啊!

#include <iostream>

#include <algorithm>

#include <string>

using namespace std;

 

int main()

{

    copy (istream_iterator<string>(cin),         // beginning of source

          istream_iterator<string>(),            // end of source

          ostream_iterator<string>(cout,"\n"));  // destination

}

 

#include <cstdlib>

#include "algostuff.hpp"

using namespace std;

 

class MyRandom {

  public:

    ptrdiff_t operator() (ptrdiff_t max) {

        double tmp;

        tmp = static_cast<double>(rand())

                / static_cast<double>(RAND_MAX);

        return static_cast<ptrdiff_t>(tmp * max);

    }

};

 

int main()

{

    vector<int> coll;

 

    INSERT_ELEMENTS(coll,1,20);

    PRINT_ELEMENTS(coll,"coll:     ");

 

    // shuffle all elements randomly

    random_shuffle (coll.begin(), coll.end());

 

    PRINT_ELEMENTS(coll,"shuffled: ");

 

    // sort them again

    sort (coll.begin(), coll.end());

    PRINT_ELEMENTS(coll,"sorted:   ");

 

    /* shuffle elements with self-written random number generator

     * - to pass an lvalue we have to use a temporary object

     */

    MyRandom rd;

    random_shuffle (coll.begin(), coll.end(),    // range

                    rd);                 // random number generator

 

    PRINT_ELEMENTS(coll,"shuffled: ");

}

 

#include "algostuff.hpp"

using namespace std;

 

// checks whether an element is even or odd

bool checkEven (int elem, bool even)

{

    if (even) {

        return elem % 2 == 0;

    }

    else {

        return elem % 2 == 1;

    }

}

 

int main()

{

    vector<int> coll;

 

    INSERT_ELEMENTS(coll,1,9);

    PRINT_ELEMENTS(coll,"coll: ");

 

    /* arguments for checkEven()

     * - check for: ``even odd even''

     */

    bool checkEvenArgs[3] = { true, false, true };

 

    // search first subrange in coll

    vector<int>::iterator pos;

    pos = search (coll.begin(), coll.end(),       // range

                  checkEvenArgs, checkEvenArgs+3, // subrange values

                  checkEven);                     // subrange criterion

 

    // loop while subrange found

    while (pos != coll.end()) {

        // print position of first element

        cout << "subrange found starting with element "

             << distance(coll.begin(),pos) + 1

             << endl;

 

        // search next subrange in coll

        pos = search (++pos, coll.end(),              // range

                      checkEvenArgs, checkEvenArgs+3, // subr. values

                      checkEven);                     // subr. criterion

    }

}

 

#include "algostuff.hpp"

using namespace std;

 

int main()

{

    int c1[] = { 1, 2, 2, 4, 6, 7, 7, 9 };

    int num1 = sizeof(c1) / sizeof(int);

 

    int c2[] = { 2, 2, 2, 3, 6, 6, 8, 9 };

    int num2 = sizeof(c2) / sizeof(int);

 

    // print source ranges

    cout << "c1:                         " ;

    copy (c1, c1+num1,

          ostream_iterator<int>(cout," "));

    cout << endl;

    cout << "c2:                         " ;

    copy (c2, c2+num2,

          ostream_iterator<int>(cout," "));

    cout << '\n' << endl;

 

    // sum the ranges by using merge()

    cout << "merge():                    ";

    merge (c1, c1+num1,

           c2, c2+num2,

           ostream_iterator<int>(cout," "));

    cout << endl;

 

    // unite the ranges by using set_union()

    cout << "set_union():                ";

    set_union (c1, c1+num1,

               c2, c2+num2,

               ostream_iterator<int>(cout," "));

    cout << endl;

 

    // intersect the ranges by using set_intersection()

    cout << "set_intersection():         ";

    set_intersection (c1, c1+num1,

                      c2, c2+num2,

                      ostream_iterator<int>(cout," "));

    cout << endl;

 

    // determine elements of first range without elements of second range

    // by using set_difference()

    cout << "set_difference():           ";

    set_difference (c1, c1+num1,

                    c2, c2+num2,

                    ostream_iterator<int>(cout," "));

    cout << endl;

 

    // determine difference the ranges with set_symmetric_difference()

    cout << "set_symmetric_difference(): ";

    set_symmetric_difference (c1, c1+num1,

                              c2, c2+num2,

                              ostream_iterator<int>(cout," "));

    cout << endl;

}
--------------------------------------------------------
一个简单的函数列表:希望给大家查找带来方便!来自:http://www.csci.csusb.edu/dick/samples/stl.algorithms.html

Glossary for the C++ Standard Library

  1. binary_function::=A function that has two arguments f(x,y).
  2. binary_predicate::=a function or function_object that returns a bool value when given two items, used for testing to see if items match, or that they are in order.
  3. function::=Something f that can be called like this f(x) for an argument x.
  4. function_object::=any instance of a class that has defined and operator() and so can be called as if it was a function.
  5. interval::=a range.
  6. iterator::=an object that indicates an item in a container,
  7. iterators::=plutral of iterator.
  8. predicate::=a function or function_object that returns a bool value when given an item.
  9. range::= a sequence of items in a container given by a pair of iterators indicating the beginning and the point after the last one.

    Search


    (find): looks for a value in a range.
    (find_if): looks for items in a range that satisfy a predicate.
    (find_first_of): looks for items in first range that is also in the second range or uses a binary_predicate to find first matching item.
    (find_end): looks backward for items in first range that are not also in the second range or uses a binary_predicate to find first non_matching item.
    (adjacent_find): looks for first pair in range that are equal, or match under a binary_predicate.


    (max): returns larger of two items, possible using a binary_predicate.
    (max_element): finds largest item in a range, may use a binary_predicate. [timeSelectionSort.cpp]
    (min): returns larger of two items, possible using a binary_predicate.
    (min_element): finds largest item in a range, may use a binary_predicate.


    (mismatch): search two parallel ranges and returns position of the first one that is unequal or doesn't satisfy a binary_predicate.


    (search): look in first range for an occurrence of the second range, possibly using a binary_predicate.
    (search_n): look in range for an occurrence of n items equal to a value, possibly using a binary_predicate.

    Scan, compare, and count


    (count): scan range and count occurrence of a value.
    (count_if): scan range and count times a predicate is true.
    (equal): test if a range equals, element another parallel range, possibly using a binary_predicate.
    (for_each): Apply a function to every item in a range.

    Copy, Move and swap


    (copy): Copy items in range to another place indicate by its start. There is a surprising way to read and write data to/from an input/output stream by using copy and adapters that give iterators accessing a stream. For example, suppose we have a range [begin, end) ints and want to output them separated by tabs we can write:

     		copy(begin, end, ostream_iterator<int> (cout, "\t") );
    To read ints into a vector v we would write
     		copy(istream_iterator<int>(cin), istream_iterator<int>(), back_inserter(v));


    (copy_backward): Copy items in range to another place indicated by its end.


    (swap): swaps values of two given variables.
    (iter_swap): swaps two items in a container indicated by iterators. Used in [timeSelectionSort.cpp] [timeQuickSort.cpp]


    (swap_ranges): interchanges value between two ranges.
    (reverse): places the elements in the reverse order.
    (reverse_copy): creates a backwards copy of a range.
    (rotate): given a middle point in a range, reorganizes range so that middle comes first...
    (rotate_copy): creates a rotated copy.


    (partition): takes a range and reorganizes the items so that a predicate is true at first and then false... A key part of QuickSort! [timeQuickSort.cpp]
    (stable_partition): takes a range and reorganizes the items so that a predicate is true at first and then false... but in each part the items are still in the same sequence (with some gaps).


    (random_shuffle): shuffles a range, you can supply your own random number generator.

    Change and Delete


    (replace): scan a range and replace given old values by given new value.
    (replace_if): scan a range and replace given old values by given new value IF a predicate is true.
    (replace_copy): make a copy of a range but replace given old values by given new value.
    (replace_copy_if): make a copy of a range but replace given old values by given new value IF a predicate is true.
    (remove): deletes items in a range that equal a given value.
    (remove_if): deletes items in a range if a predicate is true.
    (remove_copy): makes a copy of items in a range but not those with a given value.
    (remove_if): makes a copy of items in a range but not those where a predicate is true.


    (unique): deletes duplicated items, leaves the first. Can use a binary_predicate.
    (unique_copy): copies range but not duplicated items, leaves the first. Can use a binary_predicate.

    Generate and Fill


    (fill): change a range to all have the same given value.
    (fill_n): change n items to all have the same given value.
    (generate): change items in a range to be values produced by a function_object.
    (generate_n): change n items to be values produced by function_object.
    (transform): scans a range and for each use a function to generate a new object put in a second container, OR takes two intervals and applies a binary operation to items to generate a new container.

    Sort


    (sort): reorganize a range to be in order, can use a binary_predicate. For example: [timeVectorSort.cpp]

    Also some containers have a sort member function: [timeListSort.cpp]


    (stable_sort): like sort but equivalent items are kept in the same sequence.
    (partial_sort): Sorts part of a range.
    (partial_sort_copy): makes a copy of a range but with part sorted.


    (nth_element): Sorts out just the nth element!

    Search, Merge and Permute Sorted Containers


    (binary_search): search a sorted range for a value.
    (lower_bound): finds first place in a sorted range which is not less than a given value.
    (upper_bound): finds first place in a sorted range which is not greater than a given value.
    (equal_range): finds a range that brackets a given value.


    (merge): Combines two sorted ranges to give a new sorted range both all their items.
    (inplace_merge): Combines two sorted halves of a range to give a sorted range both all their items. [timeMergeSort.cpp]


    (next_permutation): permutes items in a range... will generate each possible order once until it returns false.
    (prev_permutation): undoes next_permutation

    Set Operations: union, intersection, complement,...

    [timeMultisetSort.cpp]


    (includes): set theoretic test.
    (set_union ): set theoretic operation.
    (set_intersection): set theoretic operation.
    (set_difference): set theoretic operation.
    (set_symmetric_difference): set theoretic operation.

    Numeric algorithms


    (accumulate): adds up items in range starting with given initial value, can also do any binary operation if it is given as an function of two arguments(binary_function).Used to code the math \Sigma and \Pi symbols.
    (inner_product): the heart of linear algebra, but can be generalized to do other things by supplying two binary_function s.
    (partial_sum): scans range and replaces items by sum so far, can use general binary_function.
    (adjacent_difference): Scans range and replace items by differences

    Heaps

    The big lumps rise to the top. Seriously! A heap is an array of vector where the first item is always the biggest tiem. Further, the next two smallest items are in the second and third places. After the second you have the fourth and fithf, and after the third the sixth and seventh. As a rule the n'th item is larger than the 2*n'th and (2*n+1)'th items. For more take CSCI330 Data Structures.


    (make_heap): rearranges a range so that it becomes a heap.
    (sort_heap): takes a heap and creates a sorted container from it (by popping items).

    Combining make_heap and sort_heap gives a pretty good [O(n log n)] sort: [timeHeapSort.cpp]


    (push_heap): puts a new element into a heap and rearranges it to still be a heap.
    (pop_heap): removes the top/largest element and rearranges to leave a heap behind.

posted @ 2006-03-20 22:35 高山流水 阅读(148) | 评论 (0)编辑 收藏

今天研究了一下vc6函数调用,看看vc6调用函数时候都做了什么。有些意思。

我写下了如下代码:
int fun(int a,int b)
{
    
int i = 3;
    
return a+b+i;
}

int main()
{
    
int a = 1,b=2;
    
int result ;
    result 
= fun(1,2);
    
return result;
}

非常简单。反汇编后(Debug版)变成这样

1:    int fun(int a,int b)
2:    {
00401020   push        ebp
00401021   mov         ebp,esp
00401023   sub         esp,44h
00401026   push        ebx
00401027   push        esi
00401028   push        edi
00401029   lea         edi,[ebp-44h]
0040102C   mov         ecx,11h
00401031   mov         eax,0CCCCCCCCh
00401036   rep stos    dword ptr [edi]
3:        int i = 3;
00401038   mov         dword ptr [ebp-4],3
4:        return a+b+i;
0040103F   mov         eax,dword ptr [ebp
+8]
00401042   add         eax,dword ptr [ebp+0Ch]
00401045   add         eax,dword ptr [ebp-4]
5:    }
00401048   pop         edi
00401049   pop         esi
0040104A   pop         ebx
0040104B   mov         esp,ebp
0040104D   pop         ebp
0040104E   ret

7:    int main()
8:    {
00401060   push        ebp
00401061   mov         ebp,esp
00401063   sub         esp,4Ch
00401066   push        ebx
00401067   push        esi
00401068   push        edi
00401069   lea         edi,[ebp-4Ch]
0040106C   mov         ecx,13h
00401071   mov         eax,0CCCCCCCCh
00401076   rep stos    dword ptr [edi]
9:        int a = 1,b=2;
00401078   mov         dword ptr [ebp-4],1
0040107F   mov         dword ptr [ebp
-8],2
10:       int result ;
11:       result = fun(1,2);
00401086   push        2
00401088   push        1
0040108A   call        @ILT
+5(fun) (0040100a)
0040108F   add         esp,
8
00401092   mov         dword ptr [ebp-0Ch],eax
12:       return result;
00401095   mov         eax,dword ptr [ebp-0Ch]
13:   }
00401098   pop         edi
00401099   pop         esi
0040109A   pop         ebx
0040109B   add         esp,4Ch
0040109E   cmp         ebp,esp
004010A0   call        __chkesp (004010c0)
004010A5   mov         esp,ebp
004010A7   pop         ebp
004010A8   ret

我们主要来看看函数调用部分

1.参数压栈
push 2
push 1
参数从右向左压栈(__cdcel),esp递减

2.调用函数
 call        @ILT+5(fun) (0040100a)
这条指令会把下一行代码的地址压栈,也就是函数返回地址。同时跳转到函数入口处

3.进入函数体
push        ebp
mov         ebp,esp
首先保存ebp的地址,然后把esp保存到ebp中去
00401023   sub         esp,44h
00401026   push        ebx
00401027   push        esi
00401028   push        edi
减小stack的指针(注意,stack是从内存的高端向低端生长的),为局部变量保留一些空间,这里的44h不是固定的,由编译器计算得来
00401029   lea         edi,[ebp-44h]
0040102C   mov         ecx,11h
00401031   mov         eax,0CCCCCCCCh
00401036   rep stos    dword ptr [edi]
用0xCC填充局部变量空间。这是Debug模式特有的,如果是字符串,你就看到被初始化成"烫烫烫烫烫烫"
至此,整个堆栈变成
|-----------------|
|    局部变量2   |
|-----------------|
|    局部变量1    |<----ebp-4
|-----------------|
|    old ebp          |<----ebp
|-----------------|
| 函数返回地址| <----ebp+4
|-----------------|
|      参数1         | <----ebp+8
|-----------------|
|      参数2         |
|-----------------|

Next:
int i = 3;
00401038   mov         dword ptr [ebp-4],3
这里你看到[ebp-4]就是第一个局部变量i了
0040103F   mov         eax,dword ptr [ebp+8]
00401042   add         eax,dword ptr [ebp+0Ch]
00401045   add         eax,dword ptr [ebp-4]
[ebp+8],[ebp+0Ch]分别是a和b了

4.函数返回
函数的结果都是放在eax中(ps:你可以在vc的watch窗口输入@EAX,就可以直接看到函数返回值了)
00401048   pop         edi
00401049   pop         esi
0040104A   pop         ebx
0040104B   mov         esp,ebp
0040104D   pop         ebp
0040104E   ret
把edi,esi,ebx恢复,然后恢复esp,ebp,这时函数的返回地址就在栈顶,调用ret就可以返回了。


那如果改变函数的返回地址会怎样?
ok,我们修改一下代码:
#include <stdio.h>
void fun2()
{
    printf(
"fun2() called");
}

int fun(int a,int b)
{
    
int i = 3;
    printf(
"return address:0x%x\n",&i+2);
    printf(
"fun2 address:0x%x\n",&fun2);
    
/*int *p = (int*)&fun2;
    __asm
    {
        mov ebx,p
        mov dword ptr[ebp+4],ebx
    }
*/
    
*(&i+2)=(int)&fun2; //modify return address
    return a+b+i;
}

int main()
{
    
int a = 1,b=2;
    
int result ;
    result 
= fun(1,2);
    
return result;
}

Wow,这时,我们就会发现fun2被调用了。这就是Buffer overrun(缓冲溢出)所做的事情吧。


5.最后一步,调用者调整堆栈指针
call        @ILT+5(fun) (0040100a)
 add         esp,8
为什么要调整呢,因为调用之前push两个参数进入栈,现在要恢复它
 mov         dword ptr [ebp-0Ch],eax
这句话就是享用函数调用的果实了(EAX保存了函数的返回值)

------end--------

posted @ 2006-03-20 17:26 高山流水 阅读(535) | 评论 (0)编辑 收藏

Web开发者向桌面应用开发转型之数据结构学习

任何应用程序其实就是对于数据的操作,完成商业逻辑。操作的方法无异于添加、修改、更新、删除、查找、访问等。而操作的过程中需要对数据进行存储,抑或为了加快速度,可能对数据进行二次存储(缓存)。对数据进行存储就设计到数据结构的概念,可以说就是设计一个存储数据的容器,容纳数据且支持对数据的操作。针对不同的需求,数据结构的设计也不同,比如装石头,我们可以用篮子,而装水就不可以。任何一本数据结构的书大概讲的差不多,无论是何种语言,只要支持数据结构的设计都可以实现书本中讲到的结构:数组、列表、栈、队列、树、图、哈西表等。每一种结构都是对显示世界中模型的一种抽象,比如数组可以表示向量、或者集合模型,列表和数组类似,只不过各有优缺点,它删除、插入速度快,而不支持随即访问,树一般是搜索用。开始听海天一线说不明白数据结构怎么用,我觉得很奇怪,细细思考才发现问题。在Web开发中,数据一般都在数据库中,所以对数据的操作都是在数据库里面实现了,而应用开发中很少需要自己关心,所以转向桌面应用开发(具体到C++)就不明白数据结构了,其实就相当于数据库里面的操作。

当然,数据结构各种语言基本都实现了并各自有扩展,我们学习数据结构,学习的抽象问题的思想,而不是会使用数据结构,或者会设计一个具体的容器。STL(SGI公司开发)里面有vector、list、deque、set、map等,且据说这个可以移植,MFC有CArray、CMap、CList等,在Java里面也有Array、HashTable至少(因为我了解很少),Boost里面也有全部实现。所以真正开发中,我们可以根据语言和实际选择已有的实现,除非已有的容器无法满足需求,我们可以对已有容器封装来设计或者完全自己实现。一般新建一个基于控制台的项目设计数据结构,并加入数据检验正确性,当正确后在加入到项目中使用。

建议看一下别人设计的数据结构源码,最好是公认的或者流行的,有模板知识的可以看下STL的实现,对于模板有很强的认识且C++语法掌握很好的建议看看Boost,说句实话,我自己不行,只看了2个结构,一个Any,一个Array,别的没有继续看下去,太难!!

具体到学习数据结构里面的小问题,建议看书,本文只是本人对数据结构的一个浅薄认识,如果学习中遇到问题,可以提出来,尽本人最大努力提供帮助。

posted @ 2006-03-20 17:08 高山流水 阅读(175) | 评论 (0)编辑 收藏

书上说,当无法列出传递函数的所有实参的类型和数目时,可用省略号指定参数表
(...)

如:void foo(...);
     void foo(parm_list,...);
void foo(...)
{
    //...
}
调用:foo(a,b,c);

就是不懂,把a,b,c的值传进函数里面后,用什么变量来接收???如果不能接收,(...)岂不是没意义?
还有就是不明白
int printf(const char*...);
printf("hello,&s\n",userName);

这个c的输出函数是怎么用(...)实现的.

先谢了:)
posted on 2005-12-30 00:21 阅读(260) 评论(9)  编辑 收藏收藏至365Key 所属分类: C++之梦

FeedBack:
# re: 看 c++primer 后的一个问题
2005-12-30 09:09 | skinny
首先函数体中声明一个va_list,然后用va_start函数来获取参数列表中的参数,使用完毕后调用va_end()结束。像这段代码:
void TestFun(char* pszDest, int DestLen, const char* pszFormat, ...)
{
va_list args;
va_start(args, pszFormat);
_vsnprintf(pszDest, DestLen, pszFormat, args);
va_end(args);
}  回复
  
# re: 看 c++primer 后的一个问题
2005-12-30 09:22 | 芋头
va_list
va_start
loop:
va_arg
va_end

可查看C运行库源代码。  回复
  
# re: 看 c++primer 后的一个问题
2005-12-30 09:38 |
两位说的是printf的实现吧.有点懂了:)

但是普通函数作参数时候,没理由也用va_start(args, pszFormat)吧??

那普通函数怎样获得实参值?

:)  回复
  
# re: 看 c++primer 后的一个问题
2005-12-30 12:25 | 可冰
其实原理很简单,只要知道栈是如何运作的就可以.
栈其实就相当于一个数组,函数的参数都被储存到这个数组中.C方式的参数传递是从后向前的,由于栈顶是大的地址,入栈时栈顶指针减小,所以以这种方式存储参数的话,最后参数在内存中的映象就是想于从前到后的一个数组了.
所以,只要知道第一个元素(即这里的参数)的地址及后面的元素个数和类型,就可以一个一个的把参数取出来.在使用变长参数时一定至少要有一个固定参数就是这个道理.
知道这样的原理的话就可以在程序在通过第一个参数的地址来取得后面的元素了.比如这样一个函数:
void foo( int n, ... );
其中n表示后面的参数的个数.而我在使用时隐式约定后面的参数都是整型的,即int,就可以这样获得后面的参数了:
void* p = &n + 1; //指向后面的第一个参数
while( n-- ) {
int* num = (int*)p;
//use *num
p = (int*)p + 1; //通过类型转换才可以知道1是多少字节.
}
这样就可以不用stdarg.h而使用变长参数了.
其实stdarg.h里面没有什么内容,只是定义了几个宏,有几个还是空的宏.
但最好还是用它里面定义的宏,而且在普通函数中也是完全有理由用它的,并不是只有库函数才可以.  回复
  
# re: 看 c++primer 后的一个问题
2005-12-30 13:28 |
虽然不是很明白,但是还要谢谢大家,又上了一课:)  回复
  
# re: 看 c++primer 后的一个问题
2005-12-30 14:19 | Yetimmy
#include <iostream>
using namespace std;
void fun(int a, ...)
{
int *temp = &a;
temp++;
for (int i = 0; i < a; ++i)
{
cout << *temp << endl;
temp++;
}
}

int main()
{
int a = 1;
int b = 2;
int c = 3;
int d = 4;
fun(4, a, b, c, d);
system("pause");
return 0;
}
Output::
1
2
3
4
照着自己对栈的理解写的
  回复
  
# re: 看 c++primer 后的一个问题
2005-12-30 16:11 |
原来是这样啊,明啦:)  回复
  
# re: 看 c++primer 后的一个问题
2005-12-30 22:25 |
不知道有没有不用n记下参数个数的方法?就是foo(...)怎么用?:)  回复
  
# re: 看 c++primer 后的一个问题
2006-01-10 23:06 | 飞虫
看了 可冰 的回复后总算是清楚了c函数中参数传递的内幕

posted @ 2006-03-20 16:58 高山流水 阅读(144) | 评论 (0)编辑 收藏

     摘要: 1. struct 的巨大作用   面对一个人的大型 C/C++ 程序时,只看其对 struct 的使用情况我们就可以对其编写者的编程经验进行评估。因为一个大型的 C/C++ ...  阅读全文

posted @ 2006-03-20 16:43 高山流水 阅读(231) | 评论 (0)编辑 收藏

仅列出标题
共30页: First 20 21 22 23 24 25 26 27 28 Last