Wednesday, January 31, 2007

Google 编程竞赛题

ref:http://blog.csdn.net/sygb111/archive/2006/06/28/846835.aspx

-------------------------------------------------------------------------------------------------

Problem Statement
When editing a single line of text, there are four keys that can be used to move the cursor: end, home, left-arrow and right-arrow. As you would expect, left-arrow and right-arrow move the cursor one character left or one character right, unless the cursor is at the beginning of the line or the end of the line, respectively, in which case the keystrokes do nothing (the cursor does not wrap to the previous or next line). The home key moves the cursor to the beginning of the line, and the end key moves the cursor to the end of the line. You will be given a int, N, representing the number of character in a line of text. The cursor is always between two adjacent characters, at the beginning of the line, or at the end of the line. It starts before the first character, at position 0. The position after the last character on the line is position N. You should simulate a series of keystrokes and return the final position of the cursor. You will be given a String where characters of the String represent the keystrokes made, in order. 'L' and 'R' represent left and right, while 'H' and 'E' represent home and end.
Definition

Class:
CursorPosition
Method:
getPosition
Parameters:
String, int
Returns:
int
Method signature:
int getPosition(String keystrokes, int N)
(be sure your method is public)

Constraints

keystrokes will be contain between 1 and 50 'L', 'R', 'H', and 'E' characters, inclusive.

N will be between 1 and 100, inclusive.
Examples
0)

"ERLLL"
10
Returns: 7
First, we go to the end of the line at position 10. Then, the right-arrow does nothing because we are already at the end of the line. Finally, three left-arrows brings us to position 7.
1)

"EHHEEHLLLLRRRRRR"
2
Returns: 2
All the right-arrows at the end ensure that we end up at the end of the line.
2)

"ELLLELLRRRRLRLRLLLRLLLRLLLLRLLRRRL"
10
Returns: 3
3)

"RRLEERLLLLRLLRLRRRLRLRLRLRLLLLL"
19
Returns: 12

-------------------------------------------------------------------------------------------------


solve using C++

/************************************************************************************************

cursor.h

************************************************************************************************/ #ifndef _CURSOR_H
#define _CURSOR_H

#include "string"

class CCursor
{
private:
unsigned int ui_cursor_position;
unsigned int ui_character_number;

public:
CCursor();
CCursor( const unsigned int, const unsigned int );
~CCursor();

void left_move();
void right_move();
void home_move();
void end_move();

void keystroke_simulate( const char );

int get_position( const std :: string, const int );
};

#endif

/************************************************************************************************

cursor.cc

************************************************************************************************/

#include "cursor.h"

#include "string"

//default constructor
CCursor :: CCursor()
{
ui_cursor_position = 0;
ui_character_number = 0;
}

//constructor
CCursor :: CCursor( const unsigned int cursor_postion = 0,
const unsigned int character_number = 0 )
{
ui_cursor_position = cursor_postion;
ui_character_number = character_number;
}

//destructor
CCursor :: ~CCursor()
{
true;
}

//left move
void CCursor :: left_move()
{
if ( 0 == ui_cursor_position )
{
return;
}
else
{
--ui_cursor_position;
}
}

//right move
void CCursor :: right_move()
{
if ( ui_character_number == ui_cursor_position )
{
return;
}
else
{
++ui_cursor_position;
}
}

//end move
void CCursor :: end_move()
{
ui_cursor_position = ui_character_number;
}

//home move
void CCursor :: home_move()
{
ui_cursor_position = 0;
}

void CCursor :: keystroke_simulate( const char ch )
{
//left
if ( 'L' == ch )
{
return ( this -> left_move() );
}
//right
if ( 'R' == ch )
{
return ( this -> right_move() );
}
//end
if ( 'E' == ch )
{
return ( this -> end_move() );
}
//home
if ( 'H' == ch )
{
return ( this -> home_move() );
}
//false mode
return;
}

int CCursor :: get_position( const std :: string KEY, const int N )
{
ui_character_number = static_cast( N );

for ( int i = 0; i <= KEY.size(); ++i ) { this -> keystroke_simulate( KEY[i] );
}

return ui_cursor_position;
}

/***********************************************************************************************

test.cc

************************************************************************************************/

#include "cursor.h"

#include "iostream"
#include "string"


int main()
{
CCursor *cc = new CCursor();

std :: string s = "RRLEERLLLLRLLRLRRRLRLRLRLRLLLLL";
int N = 19;

std :: cout << ( cc -> get_position( s, N ) );

delete cc;

return 0;
}

compile and link

g++ -c cursor.cc

g++ -c test.cc

g++ -o test test.o cursor.o




Monday, January 29, 2007

compiling Firefox

( For some stupid reasons, I have to post this article, sigh...... meaningless )
Linux version:

uname -a
Linux Paradise 2.6.17-10-generic #2 SMP Tue Dec 5 22:28:26 UTC 2006 i686 GNU/Linux

gcc -v
Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v --enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --program-suffix=-4.1 --enable-__cxa_atexit --enable-clocale=gnu --enable-libstdcxx-debug --enable-mpfr --enable-checking=release i486-linux-gnu
Thread model: posix
gcc version 4.1.2 20060928 (prerelease)

g++ -v
Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v --enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --program-suffix=-4.1 --enable-__cxa_atexit --enable-clocale=gnu --enable-libstdcxx-debug --enable-mpfr --enable-checking=release i486-linux-gnu
Thread model: posix
gcc version 4.1.2 20060928 (prerelease)

fetch the source code:
lftp ftp://ftp.mozilla.org:/pub/mozilla.org/firefox/releases/1.5.0.7/source
get firefox-1.5.0.7-source.tar.bz2
bye

untar the source code:
tar jxvf firefox-1.5.0.7-source.tar.bz2

enter the dirctory:
cd mozilla

config:
./configure --with-pthreads --enable-application=browser --enable-default-toolkit=gtk2 --with-distribution-id=Swiftfox --disable-freetype2 --enable-single-profile --enable-extensions=default,xforms,schema-validation --disable-installer --disable-tests '--enable-optimize=-O3 -march=pentium-m -freorder-blocks -fno-reorder-functions -msse2 -mmmx -mfpmath=sse -D_FORTIFY_SOURCE=2' --disable-shared --enable-static --disable-profilesharing --disable-debug --enable-xft --enable-crypto --enable-svg --enable-canvas --enable-update-packaging --enable-xinerama

compile:
make
make check


install:
sudo make install

compare:
(http://celtickane.com/projects/jsspeed.php)
the Mozilla distribution firefox(1.5.0.7)














Mine:














and some others:

opera:
(9.00 build344)














konqueror:
(3.5.5)

Thursday, January 18, 2007

Hello world!

在初学一门编程语言的时候,写一个“Hello world!”程序是最常见的入门方法。通过写一个成功的“Hello world!”,可以实践这门语言最基本的语法特性,还可以带给自己成就感,真是一举两得。C/C++语言本身有很多特性,如果能够将这些技术分解出来变成一个个的 “Hello world!”,并且将这些技术点到为止,貌似也算是一件善事。这里,列举了10个“Hello world!”程序,大家雅俗共赏一下。

1. 最经典的“Hello world!”

“Hello world!”最经典的写法当然是直接用 printf 输出“Hello world!”这几个字符了。无论用C还是 C++,写起来都非常的简洁明了。这里把最常见的几个全部列在下面。

#include "stdio.h"
#include "iostream"
int main()
{
printf("Hello world!"); // 教科书的写法
puts("Hello world!"); // 我最喜欢的
puts("Hello" " " "world!"); // 拼接字符串
std::cout << "Hello world!" << std::endl; // C++风格的教科书写法
return 0;
}
特别需要注意的是,在C/C++里,如果两个字符串之间除空白符以外没有任何东西,编译器会自动认为这两个字符串是连在一起的字符串。这样,如果一个字符串过长,可以用这种方法换行来写,既不浪费性能,又美观。

2. 用宏写的“Hello world!”

在C/C++里,宏是一个神奇的东西。特别是在C语言中,宏可以帮我们做一些“又脏又累”的活,包括拼接代码片断、隐藏繁琐的实现细节等等。其中特别有趣的是“#”的用法,它可以“提取”参数的名字,把它变成字符串。
#include "stdio.h"
#define Say(sth) puts(#sth)
int main()
{
return Say(Hello world!);
}
请注意,这个Hello world可是完全没有出现引号哦!

3. 断章取义的“Hello world!”

字符串是一种常量这当然毫无疑问,但是它的类型是什么,这就需要考虑一下了。使用C++的typeid就可以这个问题的答案,而且只要是符合C或C++标准的编译器就应该是一样的结果。比如字符串“Hello world!”,它的类型就是 char const [13]。
知道了这个,就可以写出以下的“Hello world!”:
#include "stdio.h"
int main()
{
return puts(&"Do not say: Hello world!"[12]);
}

4. 退出时运行的“Hello world!”

大家都知道 main 函数退出意味着程序结束,可是这并不完全正确,我们完全可以在 main 函数退出以后做很多事呢——比如说,输出 “Hello world!”。这个功能依赖于C标准库中提供的函数 atexit(),调用这个函数并注册自己的回调函数就行。需要注意,这个函数可以调用多次,最后注册的函数最先执行。
#include "stdio.h"
#include "stdlib.h"
void say()
{
printf("world!");
}
void sth()
{
printf("Hello ");
}
int main()
{
return atexit(say), atexit(sth);
}

5. 读取自己的“Hello world!”

C/C++的编译器提供了一些有用的内置宏,最常用的就是 __FILE__ 和 __LINE__ 了。其中,__FILE__ 代表当前的源文件的文件名,嗯,对了,如果我们让这个程序读取自己的源文件,不就可以做一个很有意思的“Hello world!”了么?
// Hello world!
#include "iostream"
#include "fstream"
#include "string"
int main()
{
std::ifstream ifs(__FILE__);
std::string say, some, word;
ifs << say << some << word;
std::cout << some << " " << word;
return 0;
}

6. 话分两头的“Hello world!”

有了C++的类,我们就可以光明正大的在 main 函数执行之前和之后做感兴趣的事情了。我们可以声明一个全局的类的实例,这样,在 main 函数执行之前会调用这个类的构造函数,结束之后则会调用析构函数。
#include "iostream"
class say
{
public:
say()
{
std::cout << "Hell";
}
~say()
{
std::cout << "world!";
}
}hello;
int main()
{
std::cout << "o ";
return 0;
}

7. 传入模板的“Hello world!”

C++的模板功能极为强大,可以说是C++里面最艰深、最经典、最时尚的部分。一个“Hello world!”当然无法使用很多很高级的模板技巧,我也不想只使用模板特化这样无阻挂齿的小技巧,嗯,那就来演示一个比较罕见的用法吧。
#include "iostream"
template "char * words"
class say
{
public:
void operator () ()
{
std::cout << words;
}
};
extern char hello[] = "Hello world!";
int main()
{
return say"hello"()(), 0;
}
请注意,这个 extern 是十分必要的,只有加上了 extern,这个指针才是一个编译器间可以确定的值,也才可以参与模板运算。还有,hello 必须为数组类型,而不能为 char*,这个道理和加 extern 是一样的。
此外,这里还演示了 functor 的用法,嗯,关于它的优点就不在这里多说了,反正是与原生指针相比有很多好处就是了。

8. 调用私有函数的“Hello world!”

我们知道,C++类的私有函数是不能被外界访问的,比如说 main 函数里面,它绝对不能访问类的私有函数,除非把它设为类的友元函数。不过我们还是可以用一些比较奇怪的方法访问类的私有函数——当然,这个私有函数必须满足一个条件:它是虚函数。
这里就涉及到一个问题,指向虚函数的虚表放在哪里?对于 VS.Net 2003 而言,虚表是类的第一个成员,虚函数指针按照函数声明的顺序放在虚表里面。当然,这个说法并不严谨,更细节的东西还是去看看那本“成人高钙奶粉”吧,它会给出最权威的解答。
这里是一个很有意思的例子:
#include "iostream"
#include "cstddef"
class secret
{
private:
virtual void say()
{
std::cout << "Hello world!";
}
};
int main()
{
secret word;
(reinterpret_cast"void (*)()"(**(intptr_t**)(&word)))();
return 0;
}

9. 最暴力的“Hello world!”

最暴力的调用函数的方法是:直接修改函数的返回地址,让这个地址指向我们想要调用的函数。这也就是缓冲区溢出漏洞的应用方法了,不过里面还涉及到很多问题,在这里就不一一列举,想要了解的话,还是去 Google 吧。这里只演示一个可以在 VS.Net 2003 下可以用的 “Hello world!”。
#include "stdio.h"
#include "stdlib.h"
#include "stddef.h"
void say()
{
puts("Hello world!");
exit(0);
}
int main()
{
volatile intptr_t a = 0;
volatile intptr_t * p = &a;
*(p + 2) = (intptr_t)say;
*(p + 3) = (intptr_t)say;
return 0;
}

10. 外星人说的“Hello world!”

好了,这个“Hello world!”是最匪夷所思的一个了!不过它并没有涉及任何复杂的C/C++语言特性,只是看起来有点酷。你能看懂外星人在说什么不?
#include "stdio.h"
void alien_say(char * p)
{
while (putchar(*(p += *(p + 1) - *p)));
}
int main()
{
return alien_say("BETHO! Altec oh liryom(a loadjudas!) dowd."), 0;
}